fix: update table director with diffable data source
This commit is contained in:
parent
ec1fe892ad
commit
0bc8574a32
|
|
@ -1,43 +0,0 @@
|
|||
//
|
||||
// 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 struct DefaultFilterRowViewModel: FilterRowRepresentable, Equatable {
|
||||
public let id: String
|
||||
public let title: String
|
||||
public var appearance: FilterCellAppearanceProtocol
|
||||
public var isSelected: Bool
|
||||
|
||||
public init(id: String,
|
||||
title: String,
|
||||
appearance: FilterCellAppearanceProtocol,
|
||||
isSelected: Bool) {
|
||||
|
||||
self.id = id
|
||||
self.title = title
|
||||
self.appearance = appearance
|
||||
self.isSelected = isSelected
|
||||
}
|
||||
|
||||
public static func == (lhs: Self, rhs: Self) -> Bool {
|
||||
lhs.id == rhs.id
|
||||
}
|
||||
}
|
||||
|
|
@ -20,13 +20,13 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
public protocol FilterListPickerConfigurator: AnyObject {
|
||||
|
||||
associatedtype RowViewModel: FilterRowRepresentable & Equatable
|
||||
|
||||
var visibleValues: [RowViewModel] { get }
|
||||
var isMultiselectionEnabled: Bool { get set }
|
||||
var isFinishWithSeparator: Bool { get }
|
||||
|
||||
func setSelected(model: RowViewModel, isSelected: Bool)
|
||||
}
|
||||
//public protocol FilterListPickerConfigurator: AnyObject {
|
||||
//
|
||||
// associatedtype RowViewModel: FilterRowRepresentable & Equatable
|
||||
//
|
||||
// var visibleValues: [RowViewModel] { get }
|
||||
// var isMultiselectionEnabled: Bool { get set }
|
||||
// var isFinishWithSeparator: Bool { get }
|
||||
//
|
||||
// func setSelected(model: RowViewModel, isSelected: Bool)
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@
|
|||
import TableKit
|
||||
import TIUIElements
|
||||
|
||||
public protocol FilterTableSectionBuilder {
|
||||
associatedtype CellType: BaseSeparatorCell & ConfigurableCell
|
||||
|
||||
func makeSection<ViewModel: FilterListPickerConfigurator>(with viewModel: ViewModel) -> TableSection where ViewModel.RowViewModel == CellType.CellData
|
||||
}
|
||||
//public protocol FilterTableSectionBuilder {
|
||||
// associatedtype CellType: BaseSeparatorCell & ConfigurableCell
|
||||
//
|
||||
// func makeSection<ViewModel: FilterListPickerConfigurator>(with viewModel: ViewModel) -> TableSection where ViewModel.RowViewModel == CellType.CellData
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -21,5 +21,5 @@
|
|||
//
|
||||
|
||||
public protocol FiltersPickerDelegate: AnyObject {
|
||||
func filters(didSelect filters: [FilterRowRepresentable])
|
||||
func filters(didSelect filters: [FilterPropertyValueRepresenter])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,74 +20,74 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
open class BaseListFilterViewModel<RowViewModelType: FilterRowRepresentable & Equatable>: FilterListPickerConfigurator {
|
||||
|
||||
public typealias RowViewModel = RowViewModelType
|
||||
|
||||
public var rowViewModels: [RowViewModelType]
|
||||
|
||||
public weak var delegate: FiltersPickerDelegate?
|
||||
|
||||
public var initiallySelectedValues: [RowViewModelType]?
|
||||
|
||||
open var isFinishWithSeparator: Bool {
|
||||
true
|
||||
}
|
||||
|
||||
open var isMultiselectionEnabled: Bool = false
|
||||
|
||||
open var areInitiallySelectedValuesTheSame: Bool {
|
||||
guard let initiallySelectedValues = initiallySelectedValues else {
|
||||
return false
|
||||
}
|
||||
|
||||
return initiallySelectedValues == selectedValues
|
||||
}
|
||||
|
||||
open var areThereAnyValuesSelected: Bool {
|
||||
if let _ = rowViewModels.first(where: { $0.isSelected }) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
open var selectedValues: [RowViewModelType] {
|
||||
rowViewModels.filter { $0.isSelected }
|
||||
}
|
||||
|
||||
open var visibleValues: [RowViewModelType] {
|
||||
rowViewModels
|
||||
}
|
||||
|
||||
open var visibleSelectedIndexes: [Int] {
|
||||
visibleValues.enumerated().compactMap {
|
||||
$0.element.isSelected ? $0.offset : nil
|
||||
}
|
||||
}
|
||||
|
||||
public init(rowViewModels: [RowViewModelType], isMultiselectionEnabled: Bool) {
|
||||
self.rowViewModels = rowViewModels
|
||||
self.isMultiselectionEnabled = isMultiselectionEnabled
|
||||
}
|
||||
|
||||
open func viewDidLoad() {
|
||||
initiallySelectedValues = selectedValues
|
||||
}
|
||||
|
||||
open func setSelected(model: RowViewModelType, isSelected: Bool) {
|
||||
if !isMultiselectionEnabled {
|
||||
rowViewModels.enumerated().forEach {
|
||||
rowViewModels[$0.offset].isSelected = false
|
||||
}
|
||||
}
|
||||
|
||||
if let index = rowViewModels.firstIndex(of: model) {
|
||||
rowViewModels[index].isSelected = isSelected
|
||||
}
|
||||
|
||||
if !selectedValues.isEmpty {
|
||||
delegate?.filters(didSelect: selectedValues)
|
||||
}
|
||||
}
|
||||
}
|
||||
//open class BaseListFilterViewModel<RowViewModelType: FilterRowRepresentable & Equatable>: FilterListPickerConfigurator {
|
||||
//
|
||||
// public typealias RowViewModel = RowViewModelType
|
||||
//
|
||||
// public var rowViewModels: [RowViewModelType]
|
||||
//
|
||||
// public weak var delegate: FiltersPickerDelegate?
|
||||
//
|
||||
// public var initiallySelectedValues: [RowViewModelType]?
|
||||
//
|
||||
// open var isFinishWithSeparator: Bool {
|
||||
// true
|
||||
// }
|
||||
//
|
||||
// open var isMultiselectionEnabled: Bool = false
|
||||
//
|
||||
// open var areInitiallySelectedValuesTheSame: Bool {
|
||||
// guard let initiallySelectedValues = initiallySelectedValues else {
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
// return initiallySelectedValues == selectedValues
|
||||
// }
|
||||
//
|
||||
// open var areThereAnyValuesSelected: Bool {
|
||||
// if let _ = rowViewModels.first(where: { $0.isSelected }) {
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
// return true
|
||||
// }
|
||||
//
|
||||
// open var selectedValues: [RowViewModelType] {
|
||||
// rowViewModels.filter { $0.isSelected }
|
||||
// }
|
||||
//
|
||||
// open var visibleValues: [RowViewModelType] {
|
||||
// rowViewModels
|
||||
// }
|
||||
//
|
||||
// open var visibleSelectedIndexes: [Int] {
|
||||
// visibleValues.enumerated().compactMap {
|
||||
// $0.element.isSelected ? $0.offset : nil
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public init(rowViewModels: [RowViewModelType], isMultiselectionEnabled: Bool) {
|
||||
// self.rowViewModels = rowViewModels
|
||||
// self.isMultiselectionEnabled = isMultiselectionEnabled
|
||||
// }
|
||||
//
|
||||
// open func viewDidLoad() {
|
||||
// initiallySelectedValues = selectedValues
|
||||
// }
|
||||
//
|
||||
// open func setSelected(model: RowViewModelType, isSelected: Bool) {
|
||||
// if !isMultiselectionEnabled {
|
||||
// rowViewModels.enumerated().forEach {
|
||||
// rowViewModels[$0.offset].isSelected = false
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if let index = rowViewModels.firstIndex(of: model) {
|
||||
// rowViewModels[index].isSelected = isSelected
|
||||
// }
|
||||
//
|
||||
// if !selectedValues.isEmpty {
|
||||
// delegate?.filters(didSelect: selectedValues)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -24,26 +24,26 @@ import TableKit
|
|||
import TITableKitUtils
|
||||
import TIUIElements
|
||||
|
||||
open class DefaultFilterListSectionBuilder<CellType: BaseSeparatorCell & ConfigurableCell>: FilterTableSectionBuilder {
|
||||
|
||||
open func makeSection<ViewModel: FilterListPickerConfigurator>(with viewModel: ViewModel) -> TableSection where ViewModel.RowViewModel == CellType.CellData {
|
||||
let rows = viewModel.visibleValues.map { item in
|
||||
TableRow<CellType>(item: item)
|
||||
.on(.select) { [weak viewModel] _ in
|
||||
viewModel?.setSelected(model: item, isSelected: !item.isSelected)
|
||||
}
|
||||
.on(.deselect) { [weak viewModel] _ in
|
||||
viewModel?.setSelected(model: item, isSelected: false)
|
||||
}
|
||||
}
|
||||
|
||||
let separatedRows: [SeparatorRowBox] = rows.map { $0.separatorRowBox }
|
||||
let separator = SeparatorConfiguration(color: .gray)
|
||||
|
||||
separatedRows.configureSeparators(first: separator,
|
||||
middle: separator,
|
||||
last: viewModel.isFinishWithSeparator ? separator : SeparatorConfiguration(color: .clear))
|
||||
|
||||
return .init(rows: separatedRows.rows)
|
||||
}
|
||||
}
|
||||
//open class DefaultFilterListSectionBuilder<CellType: BaseSeparatorCell & ConfigurableCell>: FilterTableSectionBuilder {
|
||||
//
|
||||
// open func makeSection<ViewModel: FilterListPickerConfigurator>(with viewModel: ViewModel) -> TableSection where ViewModel.RowViewModel == CellType.CellData {
|
||||
// let rows = viewModel.visibleValues.map { item in
|
||||
// TableRow<CellType>(item: item)
|
||||
// .on(.select) { [weak viewModel] _ in
|
||||
// viewModel?.setSelected(model: item, isSelected: !item.isSelected)
|
||||
// }
|
||||
// .on(.deselect) { [weak viewModel] _ in
|
||||
// viewModel?.setSelected(model: item, isSelected: false)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// let separatedRows: [SeparatorRowBox] = rows.map { $0.separatorRowBox }
|
||||
// let separator = SeparatorConfiguration(color: .gray)
|
||||
//
|
||||
// separatedRows.configureSeparators(first: separator,
|
||||
// middle: separator,
|
||||
// last: viewModel.isFinishWithSeparator ? separator : SeparatorConfiguration(color: .clear))
|
||||
//
|
||||
// return .init(rows: separatedRows.rows)
|
||||
// }
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -20,46 +20,147 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import TableKit
|
||||
import TISwiftUtils
|
||||
import TIUIElements
|
||||
import TIUIKitCore
|
||||
import UIKit
|
||||
|
||||
open class BaseListFilterPickerView<CellType: BaseSeparatorCell & ConfigurableCell>: BaseCustomTableView where CellType.CellData: FilterRowRepresentable & Equatable {
|
||||
@available(iOS 13.0, *)
|
||||
open class BaseFiltersTableView<CellType: UITableViewCell & ConfigurableView,
|
||||
PropertyValue: FilterPropertyValueRepresenter & Hashable>:
|
||||
UITableView,
|
||||
InitializableViewProtocol,
|
||||
Updatable,
|
||||
UITableViewDelegate where CellType.ViewModelType: FilterCellViewModelProtocol & Hashable {
|
||||
|
||||
public let builder = DefaultFilterListSectionBuilder<CellType>()
|
||||
public weak var viewModel: BaseListFilterViewModel<CellType.CellData>?
|
||||
|
||||
public init(viewModel: BaseListFilterViewModel<CellType.CellData>) {
|
||||
self.viewModel = viewModel
|
||||
|
||||
super.init(frame: .zero)
|
||||
|
||||
tableView.allowsMultipleSelection = viewModel.isMultiselectionEnabled
|
||||
public enum DefaultSection: String {
|
||||
case main
|
||||
}
|
||||
|
||||
public typealias DataSource = UITableViewDiffableDataSource<String, CellType.ViewModelType>
|
||||
public typealias Snapshot = NSDiffableDataSourceSnapshot<String, CellType.ViewModelType>
|
||||
|
||||
public weak var viewModel: BaseFilterViewModel<CellType.ViewModelType, PropertyValue>?
|
||||
|
||||
public lazy var collectionViewDataSource = createDataSource()
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
public init(viewModel: BaseFilterViewModel<CellType.ViewModelType, PropertyValue>, allowsMultipleSelection: Bool = true) {
|
||||
self.viewModel = viewModel
|
||||
|
||||
super.init(frame: .zero, style: .plain)
|
||||
|
||||
self.allowsMultipleSelection = allowsMultipleSelection
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
open override func configureAppearance() {
|
||||
super.configureAppearance()
|
||||
// MARK: - Life cycle
|
||||
|
||||
tableView.alwaysBounceVertical = false
|
||||
viewModel?.viewDidLoad()
|
||||
// MARK: - Life cycle
|
||||
|
||||
reloadData(with: viewModel?.visibleSelectedIndexes ?? [])
|
||||
open func addViews() {
|
||||
// override in subclass
|
||||
}
|
||||
|
||||
open func reloadData(with selectedIndexes: [Int]) {
|
||||
open func configureLayout() {
|
||||
// override in subclass
|
||||
}
|
||||
|
||||
open func bindViews() {
|
||||
delegate = self
|
||||
}
|
||||
|
||||
open func configureAppearance() {
|
||||
alwaysBounceVertical = false
|
||||
|
||||
// reloadData(with: viewModel?.visibleSelectedIndexes ?? [])
|
||||
}
|
||||
|
||||
open func localize() {
|
||||
// override in subclass
|
||||
}
|
||||
|
||||
open func viewDidLoad() {
|
||||
registerCell()
|
||||
|
||||
viewModel?.filtersCollection = self
|
||||
}
|
||||
|
||||
open func viewDidAppear() {
|
||||
applySnapshot()
|
||||
}
|
||||
|
||||
// MARK: - UICollectionViewDelegate
|
||||
|
||||
open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
filterDidTapped(atIndexPath: indexPath)
|
||||
}
|
||||
|
||||
open func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
|
||||
filterDidTapped(atIndexPath: indexPath)
|
||||
}
|
||||
|
||||
// MARK: - UpdatableView
|
||||
|
||||
open func update() {
|
||||
applySnapshot()
|
||||
}
|
||||
|
||||
// MARK: - Open methods
|
||||
|
||||
open func registerCell() {
|
||||
register(CellType.self, forCellReuseIdentifier: CellType.reuseIdentifier)
|
||||
}
|
||||
|
||||
open func filterDidTapped(atIndexPath indexPath: IndexPath) {
|
||||
guard let viewModel = viewModel else { return }
|
||||
|
||||
let elements = builder.makeSection(with: viewModel)
|
||||
updateTableView(elements)
|
||||
let changes = viewModel.filterDidSelected(atIndexPath: indexPath)
|
||||
|
||||
selectedIndexes.forEach {
|
||||
tableView.selectRow(at: IndexPath(row: $0, section: .zero),
|
||||
animated: false,
|
||||
scrollPosition: .none)
|
||||
applyChange(changes)
|
||||
}
|
||||
|
||||
open func applySnapshot() {
|
||||
guard let viewModel = viewModel else {
|
||||
return
|
||||
}
|
||||
|
||||
var snapshot = Snapshot()
|
||||
|
||||
snapshot.appendSections([DefaultSection.main.rawValue])
|
||||
snapshot.appendItems(viewModel.cellsViewModels, toSection: DefaultSection.main.rawValue)
|
||||
|
||||
collectionViewDataSource.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 DataSource(tableView: self, cellProvider: cellProvider)
|
||||
}
|
||||
|
||||
open func applyChange(_ changes: [BaseFilterViewModel<CellType.ViewModelType, PropertyValue>.Change]) {
|
||||
changes.forEach { change in
|
||||
guard let cell = cellForRow(at: change.indexPath) as? CellType else {
|
||||
return
|
||||
}
|
||||
|
||||
cell.configure(with: change.viewModel)
|
||||
|
||||
change.viewModel.isSelected
|
||||
? selectRow(at: change.indexPath, animated: false, scrollPosition: ScrollPosition.none)
|
||||
: deselectRow(at: change.indexPath, animated: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,91 +20,123 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import TableKit
|
||||
import TIUIElements
|
||||
import TIUIKitCore
|
||||
import UIKit
|
||||
|
||||
open class DefaultFilterListCell: BaseSeparatorCell, ConfigurableCell {
|
||||
open class DefaultPickerView: BaseInitializableView {
|
||||
|
||||
private var titleLeadingConstraint: NSLayoutConstraint!
|
||||
private var titleTopConstraint: NSLayoutConstraint!
|
||||
private var titleBottomConstraint: NSLayoutConstraint!
|
||||
private let titleLabel = UILabel()
|
||||
private let selectionStateImageView = UIImageView()
|
||||
|
||||
private var imageTrailingConstraint: NSLayoutConstraint!
|
||||
private var imageTopConstraint: NSLayoutConstraint!
|
||||
private var imageBottomConstraint: NSLayoutConstraint!
|
||||
|
||||
public lazy var titleLabel = UILabel()
|
||||
public lazy var selectionCheckmarkImageView = UIImageView()
|
||||
|
||||
open var selectedImage: UIImage? {
|
||||
if #available(iOS 13.0, *) {
|
||||
return UIImage(systemName: "checkmark")!
|
||||
open var image: UIImage? {
|
||||
get {
|
||||
selectionStateImageView.image
|
||||
}
|
||||
set {
|
||||
selectionStateImageView.image = newValue
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
open var deselectedImage: UIImage? {
|
||||
nil
|
||||
open var text: String? {
|
||||
get {
|
||||
titleLabel.text
|
||||
}
|
||||
set {
|
||||
titleLabel.text = newValue
|
||||
}
|
||||
}
|
||||
|
||||
open var textColor: UIColor {
|
||||
get {
|
||||
titleLabel.textColor
|
||||
}
|
||||
set {
|
||||
titleLabel.textColor = newValue
|
||||
}
|
||||
}
|
||||
|
||||
open override func addViews() {
|
||||
super.addViews()
|
||||
|
||||
contentView.addSubviews(titleLabel, selectionCheckmarkImageView)
|
||||
addSubviews(titleLabel, selectionStateImageView)
|
||||
}
|
||||
|
||||
open override func configureLayout() {
|
||||
super.configureLayout()
|
||||
|
||||
titleLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
selectionCheckmarkImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
titleLeadingConstraint = titleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor)
|
||||
titleTopConstraint = titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor)
|
||||
titleBottomConstraint = titleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
|
||||
|
||||
imageTrailingConstraint = selectionCheckmarkImageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
|
||||
imageTopConstraint = selectionCheckmarkImageView.topAnchor.constraint(equalTo: contentView.topAnchor)
|
||||
imageBottomConstraint = selectionCheckmarkImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
|
||||
|
||||
selectionStateImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
titleLeadingConstraint,
|
||||
titleTopConstraint,
|
||||
titleBottomConstraint,
|
||||
imageTrailingConstraint,
|
||||
imageTopConstraint,
|
||||
imageBottomConstraint
|
||||
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(equalTo: heightAnchor),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
open func configure(with viewModel: DefaultFilterRowViewModel) {
|
||||
titleLabel.text = viewModel.title
|
||||
open class DefaultFilterListCell: ContainerTableViewCell<DefaultPickerView>, ConfigurableView {
|
||||
|
||||
setContentInsets(viewModel.appearance.contentInsets)
|
||||
contentView.backgroundColor = viewModel.appearance.deselectedBgColor
|
||||
open var selectedStateAppearance: FilterCellStateAppearance {
|
||||
.defaultSelectedRowAppearance
|
||||
}
|
||||
|
||||
open func setContentInsets(_ insets: UIEdgeInsets) {
|
||||
titleLeadingConstraint.constant = insets.left
|
||||
imageTrailingConstraint.constant = -insets.right
|
||||
|
||||
titleTopConstraint.constant = insets.top
|
||||
imageTopConstraint.constant = insets.top
|
||||
|
||||
titleBottomConstraint.constant = -insets.bottom
|
||||
imageBottomConstraint.constant = -insets.bottom
|
||||
open var normalStateAppearance: FilterCellStateAppearance {
|
||||
.defaultNormalRowAppearance
|
||||
}
|
||||
|
||||
open override func setSelected(_ selected: Bool, animated: Bool) {
|
||||
super.setSelected(selected, animated: animated)
|
||||
|
||||
if selected {
|
||||
selectionCheckmarkImageView.image = selectedImage
|
||||
} else {
|
||||
selectionCheckmarkImageView.image = deselectedImage
|
||||
open override var isSelected: Bool {
|
||||
didSet {
|
||||
let appearance = isSelected ? selectedStateAppearance : normalStateAppearance
|
||||
updateAppearance(with: appearance)
|
||||
}
|
||||
}
|
||||
|
||||
open override func configureAppearance() {
|
||||
super.configureAppearance()
|
||||
|
||||
updateAppearance(with: normalStateAppearance)
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
backgroundColor = appearance.backgroundColor
|
||||
layer.borderColor = appearance.borderColor.cgColor
|
||||
layer.borderWidth = appearance.borderWidth
|
||||
layer.round(corners: .allCorners, radius: appearance.cornerRadius)
|
||||
}
|
||||
}
|
||||
|
||||
extension FilterCellStateAppearance {
|
||||
static var defaultSelectedRowAppearance: FilterCellStateAppearance {
|
||||
var selectionImage: UIImage?
|
||||
|
||||
if #available(iOS 13, *) {
|
||||
selectionImage = UIImage(systemName: "checkmark")
|
||||
}
|
||||
|
||||
return .init(borderColor: .systemGreen,
|
||||
backgroundColor: .white,
|
||||
fontColor: .systemGreen,
|
||||
borderWidth: 1,
|
||||
selectionImage: selectionImage)
|
||||
}
|
||||
|
||||
static var defaultNormalRowAppearance: FilterCellStateAppearance {
|
||||
|
||||
.init(borderColor: .lightGray, backgroundColor: .lightGray, fontColor: .black, borderWidth: 0)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,14 +20,5 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
public protocol FilterRowRepresentable {
|
||||
var id: String { get }
|
||||
var title: String { get }
|
||||
var isSelected: Bool { get set }
|
||||
var appearance: FilterCellAppearanceProtocol { get set }
|
||||
|
||||
init(id: String,
|
||||
title: String,
|
||||
appearance: FilterCellAppearanceProtocol,
|
||||
isSelected: Bool)
|
||||
}
|
||||
@available(iOS 13.0, *)
|
||||
public typealias DefaultFiltersTableView = BaseFiltersTableView<DefaultFilterListCell, DefaultFilterPropertyValue>
|
||||
|
|
@ -32,12 +32,15 @@ public struct FilterCellStateAppearance {
|
|||
public let contentInsets: UIEdgeInsets
|
||||
public let cornerRadius: CGFloat
|
||||
|
||||
public let selectionImage: UIImage?
|
||||
|
||||
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,
|
||||
selectionImage: UIImage? = nil) {
|
||||
|
||||
self.borderColor = borderColor
|
||||
self.backgroundColor = backgroundColor
|
||||
|
|
@ -45,5 +48,6 @@ public struct FilterCellStateAppearance {
|
|||
self.borderWidth = borderWidth
|
||||
self.contentInsets = contentInsets
|
||||
self.cornerRadius = cornerRadius
|
||||
self.selectionImage = selectionImage
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ open class BaseFiltersCollectionView<CellType: UICollectionViewCell & Configurab
|
|||
// override in subclass
|
||||
}
|
||||
|
||||
open func bindViews() {
|
||||
delegate = self
|
||||
}
|
||||
|
||||
open func configureLayout() {
|
||||
// override in subclass
|
||||
}
|
||||
|
||||
open func bindViews() {
|
||||
delegate = self
|
||||
}
|
||||
|
||||
open func configureAppearance() {
|
||||
backgroundColor = .white
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,3 +32,9 @@ extension UICollectionViewCell: ReuseIdentifierProtocol {
|
|||
.init(describing: Self.self)
|
||||
}
|
||||
}
|
||||
|
||||
extension UITableViewCell: ReuseIdentifierProtocol {
|
||||
public static var reuseIdentifier: String {
|
||||
.init(describing: Self.self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue