diff --git a/Gemfile.lock b/Gemfile.lock index 0e5694c1..3e0e8625 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -88,11 +88,10 @@ GEM zeitwerk (2.5.4) PLATFORMS - arm64-darwin-21 x86_64-darwin-20 DEPENDENCIES cocoapods (~> 1.11) BUNDLED WITH - 2.3.18 + 2.3.10 diff --git a/Package.resolved b/Package.resolved index 57d7e0b5..64252c9e 100644 --- a/Package.resolved +++ b/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/Alamofire/Alamofire.git", "state": { "branch": null, - "revision": "8dd85aee02e39dd280c75eef88ffdb86eed4b07b", - "version": "5.6.2" + "revision": "f96b619bcb2383b43d898402283924b80e2c4bae", + "version": "5.4.3" } }, { @@ -24,8 +24,8 @@ "repositoryURL": "https://github.com/petropavel13/Cursors", "state": { "branch": null, - "revision": "52f27b82cb1cbbc2b5fd09514c48b9c75e3b0300", - "version": "0.6.0" + "revision": "a1561869135e72832eff3b1e729075c56c2eebf6", + "version": "0.5.1" } }, { diff --git a/TIUIElements/Sources/Helpers/Protocols/CollectionDirectorRepresenter.swift b/TIUIElements/Sources/Helpers/Protocols/CollectionDirectorRepresenter.swift new file mode 100644 index 00000000..7708cfcd --- /dev/null +++ b/TIUIElements/Sources/Helpers/Protocols/CollectionDirectorRepresenter.swift @@ -0,0 +1,36 @@ +// +// 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 UIKit + +public protocol CollectionDirectorRepresenter: UICollectionViewDataSource, UICollectionViewDelegate { + + associatedtype Item + + var collectionView: UICollectionView? { get set } + var delegate: FilterItemsDelegate? { get set } + + func insertItem(_ item: Item, at index: Int) + func deleteItem(at index: Int) + func update(item: Item, at index: Int) + func scrollToItem(at indexPath: IndexPath, animated: Bool) +} diff --git a/TIUIElements/Sources/Helpers/Protocols/FiltersCollectionHolder.swift b/TIUIElements/Sources/Helpers/Protocols/FiltersCollectionHolder.swift new file mode 100644 index 00000000..7e951cc4 --- /dev/null +++ b/TIUIElements/Sources/Helpers/Protocols/FiltersCollectionHolder.swift @@ -0,0 +1,27 @@ +// +// 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 FiltersCollectionHolder: AnyObject { + func select(_ items: [FilterPropertyValueRepresenter]) + func deselect(_ items: [FilterPropertyValueRepresenter]) + func updateView() +} diff --git a/TIUIElements/Sources/Helpers/Protocols/FiltersViewModelProtocol.swift b/TIUIElements/Sources/Helpers/Protocols/FiltersViewModelProtocol.swift index 96e96382..10fe8cb6 100644 --- a/TIUIElements/Sources/Helpers/Protocols/FiltersViewModelProtocol.swift +++ b/TIUIElements/Sources/Helpers/Protocols/FiltersViewModelProtocol.swift @@ -22,12 +22,6 @@ import Foundation -public protocol FiltersCollectionHolder: AnyObject { - func select(_ items: [FilterPropertyValueRepresenter]) - func deselect(_ items: [FilterPropertyValueRepresenter]) - func updateView() -} - public protocol FiltersViewModelProtocol: AnyObject { associatedtype Filter: FilterPropertyValueRepresenter, Hashable @@ -42,23 +36,17 @@ public protocol FiltersViewModelProtocol: AnyObject { public extension FiltersViewModelProtocol { - /// Method of filtering items - /// - Algorithm: - /// 1. Determine if current item is selected; - /// 2. If it was selected: - /// - Remove the item from the array of selected items; - /// 3. if it wasn't selected: - /// - Insert the item in the array of selected items; - /// - Run excluding filtering (remove every item that should be excluded from list of selected items). - /// 4. Notify the collection of filters about updating of the item at indexPath func filterItem(atIndexPath indexPath: IndexPath) { guard let item = getItemSafely(indexPath.item) else { return } - filterItem(item) + let (s, d) = filterItem(item) + filtersCollectionHolder?.select(s) + filtersCollectionHolder?.deselect(d) filtersCollectionHolder?.updateView() } - private func filterItem(_ item: Filter) { + @discardableResult + private func filterItem(_ item: Filter) -> (selected: [Filter], deselected: [Filter]) { var itemsToDeselect = [Filter]() var itemsToSelect = [Filter]() let selectedItem = selectedFilters.first { selectedItem in @@ -67,12 +55,10 @@ public extension FiltersViewModelProtocol { if let selectedItem = selectedItem { selectedFilters.remove(selectedItem) - itemsToDeselect.append(item) } else { selectedFilters.insert(item) itemsToSelect.append(item) - itemsToDeselect.append(contentsOf: exclude(withItem: item)) if let itemsToExclude = item.excludingProperties, !itemsToExclude.isEmpty { for itemIdToExclude in itemsToExclude { @@ -81,25 +67,14 @@ public extension FiltersViewModelProtocol { } if let itemToExclude = itemToExclude { - filterItem(itemToExclude) + let (_, deselected) = filterItem(itemToExclude) + itemsToDeselect.append(contentsOf: deselected) } } } } - - itemsToSelect.forEach { item in - if let index = filters.firstIndex(of: item) { - filters[index].isSelected = true - } - } - - itemsToDeselect.forEach { item in - if let index = filters.firstIndex(of: item) { - filters[index].isSelected = false - } - } -// filtersCollectionHolder?.select(itemsToSelect) -// filtersCollectionHolder?.deselect(itemsToDeselect) + + return (itemsToSelect, itemsToDeselect) } private func getItemSafely(_ index: Int) -> Filter? { @@ -109,25 +84,4 @@ public extension FiltersViewModelProtocol { return filters[index] } - - private func exclude(withItem item: Filter) -> [Filter] { - guard let itemsToExclude = item.excludingProperties, !itemsToExclude.isEmpty else { - return [] - } - - var deselectedItems = [Filter]() - - for itemIdToExclude in itemsToExclude { - let itemToExclude = selectedFilters.first { item in - item.id == itemIdToExclude - } - - if let itemToExclude = itemToExclude { - selectedFilters.remove(itemToExclude) - deselectedItems.append(itemToExclude) - } - } - - return deselectedItems - } } diff --git a/TIUIElements/Sources/Helpers/Protocols/SelectableCell.swift b/TIUIElements/Sources/Helpers/Protocols/SelectableCell.swift new file mode 100644 index 00000000..7ba05da3 --- /dev/null +++ b/TIUIElements/Sources/Helpers/Protocols/SelectableCell.swift @@ -0,0 +1,35 @@ +// +// 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 UIKit + +public protocol SelectableCell: UICollectionViewCell { + var isFilterSelected: Bool { get set } + + func toggleSelection() +} + +public extension SelectableCell { + func toggleSelection() { + isFilterSelected.toggle() + } +} \ No newline at end of file diff --git a/TIUIElements/Sources/Helpers/ViewModels/DefaultFiltersCollectionDirector.swift b/TIUIElements/Sources/Helpers/ViewModels/DefaultFiltersCollectionDirector.swift index 25a612e7..ef137b8f 100644 --- a/TIUIElements/Sources/Helpers/ViewModels/DefaultFiltersCollectionDirector.swift +++ b/TIUIElements/Sources/Helpers/ViewModels/DefaultFiltersCollectionDirector.swift @@ -22,15 +22,16 @@ import UIKit -open class CollectionDirector: NSObject, - UICollectionViewDataSource, - UICollectionViewDelegate { +open class DefaultFiltersCollectionDirector: NSObject, + CollectionDirectorRepresenter, + UICollectionViewDataSource, + UICollectionViewDelegate { - private(set) weak var collectionView: UICollectionView? - private weak var scrollDelegate: UIScrollViewDelegate? - private var _collectionItems: [FilterItem] = [] - + + public weak var collectionView: UICollectionView? + public weak var delegate: FilterItemsDelegate? + public var collectionItems: [FilterItem] { get { _collectionItems @@ -41,11 +42,7 @@ open class CollectionDirector: NSObject, } } - public weak var delegate: FilterItemsDelegate? - - public init(collectionView: UICollectionView, scrollDelegate: UIScrollViewDelegate? = nil) { - self.scrollDelegate = scrollDelegate - + public init(collectionView: UICollectionView) { super.init() bind(to: collectionView) @@ -70,19 +67,8 @@ open class CollectionDirector: NSObject, scrollToItem(at: indexPath) } - public func replaceItem(with item: FilterItem, at index: Int) { - collectionItems[index] = item - - let indexPath = IndexPath(row: index, section: .zero) - scrollToItem(at: indexPath) - } - - public func replaceItem(with item: FilterItem, at indexPath: IndexPath) { - collectionItems[indexPath.row] = item - } - - public func update(item: FilterItem, at indexPath: IndexPath) { - _collectionItems[indexPath.item] = item + public func update(item: FilterItem, at index: Int) { + _collectionItems[index] = item } public func scrollToItem(at indexPath: IndexPath, animated: Bool = true) { @@ -108,7 +94,7 @@ open class CollectionDirector: NSObject, viewModel.configure(item: cell) return cell } - + // MARK: - UICollectionViewDelegate public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { @@ -116,15 +102,11 @@ open class CollectionDirector: NSObject, didSelectItem(atIndexPath: indexPath, cell: cell) } - public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { - scrollDelegate?.scrollViewDidEndDecelerating?(scrollView) - } - private func didSelectItem(atIndexPath indexPath: IndexPath, cell: UICollectionViewCell?) { guard let item = item(at: indexPath) else { return } - + delegate?.didSelectItem(atIndexPath: indexPath) item.didSelectItem(atIndexPath: indexPath, cell: cell) diff --git a/TIUIElements/Sources/Views/FiltersCollectionView/BaseFilterCollectionCell.swift b/TIUIElements/Sources/Views/FiltersCollectionView/BaseFilterCollectionCell.swift index e93adb67..bf8e1547 100644 --- a/TIUIElements/Sources/Views/FiltersCollectionView/BaseFilterCollectionCell.swift +++ b/TIUIElements/Sources/Views/FiltersCollectionView/BaseFilterCollectionCell.swift @@ -62,13 +62,13 @@ open class BaseFilterCollectionCell: UICollectionViewCell, open func addViews() { addSubview(titleLabel) } - + open func configureLayout() { titleLabel.translatesAutoresizingMaskIntoConstraints = false - + NSLayoutConstraint.activate(titleLabel.edgesEqualToSuperview()) } - + open func bindViews() { // override in subclass } diff --git a/TIUIElements/Sources/Views/FiltersCollectionView/BaseFilterCollectionItem.swift b/TIUIElements/Sources/Views/FiltersCollectionView/BaseFilterCollectionItem.swift index 27508059..44a76027 100644 --- a/TIUIElements/Sources/Views/FiltersCollectionView/BaseFilterCollectionItem.swift +++ b/TIUIElements/Sources/Views/FiltersCollectionView/BaseFilterCollectionItem.swift @@ -23,18 +23,6 @@ import UIKit import TIUIKitCore -public protocol SelectableCell: UICollectionViewCell { - var isFilterSelected: Bool { get set } - - func toggleSelection() -} - -public extension SelectableCell { - func toggleSelection() { - isFilterSelected.toggle() - } -} - public typealias AnyCollectionCell = SelectableCell & ConfigurableView open class BaseFilterCollectionItem> +typealias DefaultBaseFiltersCollectionView = BaseFiltersCollectionView> open class BaseFiltersCollectionView: BaseInitializableView, ConfigurableView { - typealias Director = CollectionDirector + typealias Director = DefaultFiltersCollectionDirector private var collectionDirector: Director @@ -91,10 +92,9 @@ open class BaseFiltersCollectionView: BaseInitializa // MARK: - FiltersCollectionHolder extension BaseFiltersCollectionView: FiltersCollectionHolder { - public func select(_ items: [FilterPropertyValueRepresenter]) { + open func select(_ items: [FilterPropertyValueRepresenter]) { guard let viewModel = viewModel else { return } - // TODO: replace instead of make new items.forEach { item in if let index = viewModel.filters.firstIndex(of: item as! DefaultFilterPropertyValue) { viewModel.filters[index].isSelected = true @@ -102,10 +102,9 @@ extension BaseFiltersCollectionView: FiltersCollectionHolder { } } - public func deselect(_ items: [FilterPropertyValueRepresenter]) { + open func deselect(_ items: [FilterPropertyValueRepresenter]) { guard let viewModel = viewModel else { return } - // TODO: replace instead of make new items.forEach { item in if let index = viewModel.filters.firstIndex(of: item as! DefaultFilterPropertyValue) { viewModel.filters[index].isSelected = false @@ -113,7 +112,7 @@ extension BaseFiltersCollectionView: FiltersCollectionHolder { } } - public func updateView() { + open func updateView() { guard let viewModel = viewModel else { return } collectionDirector.collectionItems = viewModel.filters.map { diff --git a/project-scripts/push_to_podspecs.sh b/project-scripts/push_to_podspecs.sh index fce76350..9196b6fc 100755 --- a/project-scripts/push_to_podspecs.sh +++ b/project-scripts/push_to_podspecs.sh @@ -23,5 +23,5 @@ ORDERED_PODSPECS="../TISwiftUtils/TISwiftUtils.podspec ../TIYandexMapUtils/TIYandexMapUtils.podspec" for podspec_path in ${ORDERED_PODSPECS}; do - bundle exec pod repo push git@github.com:castlele/Podspecs-castle ${podspec_path} --allow-warnings + bundle exec pod repo push git@github.com:TouchInstinct/Podspecs ${podspec_path} --allow-warnings done