`BaseClusterPlacemarkManager` added

This commit is contained in:
Vladimir Makarov 2023-03-10 14:03:59 +01:00
parent 0090c83f87
commit 4c973b393d
9 changed files with 110 additions and 58 deletions

View File

@ -24,7 +24,10 @@ import TIMapUtils
import MapKit
import UIKit
open class AppleClusterPlacemarkManager<Model>: BasePlacemarkManager<MKAnnotationView, [ApplePlacemarkManager<Model>], MKMapRect>,
open class AppleClusterPlacemarkManager<Model>: BaseClusterPlacemarkManager<MKAnnotationView,
[ApplePlacemarkManager<Model>],
MKMapRect,
CLLocationCoordinate2D>,
MKMapViewDelegate {
public weak var mapViewDelegate: MKMapViewDelegate?
@ -51,16 +54,6 @@ open class AppleClusterPlacemarkManager<Model>: BasePlacemarkManager<MKAnnotatio
open func removeMarkers(from map: MKMapView) {
map.removeAnnotations(dataModel)
}
/// Manual selecting of a placemark with an incoming point coordinates
open func selectMarker(with point: CLLocationCoordinate2D) {
dataModel.filter { $0.coordinate == point }.forEach { $0.state = .selected }
}
/// Manual state resetting of all placemarks with currently selected state
open func resetMarkersState() {
dataModel.filter { $0.state == .selected }.forEach { $0.state = .default }
}
// MARK: - PlacemarkManager

View File

@ -31,17 +31,19 @@ open class ApplePlacemarkManager<Model>: BasePlacemarkManager<MKAnnotationView,
/// A map where all placemarks are placed
public let map: MKMapView
/// Point (coordinates) itself of the current placemark manager
public let coordinate: CLLocationCoordinate2D
/// Identifier required for correct cluster placement
public var clusteringIdentifier: String?
/// Point (coordinates) itself of the current placemark manager
public var coordinate: CLLocationCoordinate2D {
placemarkPosition ?? .init()
}
/// Placemark itself of the current placemark manager
public private(set) var placemark: MKAnnotationView?
/// The current state of a manager's placemark
public var state: MarkerState = .default {
override public var state: MarkerState {
didSet {
guard let placemark = placemark else {
return
@ -67,10 +69,10 @@ open class ApplePlacemarkManager<Model>: BasePlacemarkManager<MKAnnotationView,
tapHandler: TapHandlerClosure?) {
self.map = map
self.coordinate = position
self.clusteringIdentifier = clusteringIdentifier
super.init(dataModel: dataModel,
super.init(placemarkPosition: position,
dataModel: dataModel,
iconFactory: iconFactory,
tapHandler: tapHandler)
}

View File

@ -24,7 +24,10 @@ import TIMapUtils
import GoogleMapsUtils
import GoogleMaps
open class GoogleClusterPlacemarkManager<Model>: BasePlacemarkManager<GMSMarker, [GooglePlacemarkManager<Model>], GMSCoordinateBounds>,
open class GoogleClusterPlacemarkManager<Model>: BaseClusterPlacemarkManager<GMSMarker,
[GooglePlacemarkManager<Model>],
GMSCoordinateBounds,
CLLocationCoordinate2D>,
GMUClusterRendererDelegate,
GMUClusterManagerDelegate,
GMUClusterIconGenerator {
@ -77,16 +80,6 @@ open class GoogleClusterPlacemarkManager<Model>: BasePlacemarkManager<GMSMarker,
open func removeMarkers() {
clusterManager?.clearItems()
}
/// Manual selecting of a placemark with an incoming point coordinates
open func selectMarker(with point: CLLocationCoordinate2D) {
dataModel.filter { $0.position == point }.forEach { $0.state = .selected }
}
/// Manual state resetting of all placemarks with currently selected state
open func resetMarkersState() {
dataModel.filter { $0.state == .selected }.forEach { $0.state = .default }
}
// MARK: - GMUClusterRendererDelegate
@ -121,7 +114,7 @@ open class GoogleClusterPlacemarkManager<Model>: BasePlacemarkManager<GMSMarker,
return false
}
return tapHandler?(placemarkManagers, .from(coordinates: placemarkManagers.map { $0.position }) ?? .init()) ?? false
return tapHandler?(placemarkManagers, .from(coordinates: placemarkManagers.compactMap { $0.position }) ?? .init()) ?? false
}
open func clusterManager(_ clusterManager: GMUClusterManager, didTap clusterItem: GMUClusterItem) -> Bool {

View File

@ -30,13 +30,15 @@ open class GooglePlacemarkManager<Model>: BasePlacemarkManager<GMSMarker, Model,
// MARK: - GMUClusterItem
/// Point (coordinates) itself of the current placemark manager
public let position: CLLocationCoordinate2D
public var position: CLLocationCoordinate2D {
placemarkPosition ?? .init()
}
/// Placemark itself of the current placemark manager
public private(set) var placemark: GMSMarker?
/// The current state of a manager's placemark
public var state: MarkerState = .default {
override public var state: MarkerState {
didSet {
guard let placemark = placemark else {
return
@ -51,9 +53,8 @@ open class GooglePlacemarkManager<Model>: BasePlacemarkManager<GMSMarker, Model,
iconFactory: AnyMarkerIconFactory<DataModel>?,
tapHandler: TapHandlerClosure?) {
self.position = position
super.init(dataModel: dataModel,
super.init(placemarkPosition: position,
dataModel: dataModel,
iconFactory: iconFactory,
tapHandler: tapHandler)
}

View File

@ -0,0 +1,62 @@
//
// Copyright (c) 2023 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.
//
/**
Base cluster placemark manager
- Parameters:
- `Placemark`: a generic parameter describing a cluster placemark itself
- `ClusterDataModel`: an array of single placemarks managers for a cluster
- `ClusterPoints`: a collection of cluster placemark objects
- `Position`: a type of a single manager's placemark position
*/
open class BaseClusterPlacemarkManager<Placemark, ClusterDataModel, ClusterPoints, Position: Equatable>:
BasePlacemarkManager<Placemark, ClusterDataModel, ClusterPoints> {
/// Manual selecting of a placemark with an incoming point coordinates
open func selectMarker(with point: Position) {
guard let dataModel = dataModel as? Array<any PlacemarkManager> else {
return
}
dataModel
.filter {
guard let placemarkPosition = $0.placemarkPosition as? Position else {
return false
}
return placemarkPosition == point
}
.forEach {
$0.state = .selected
}
}
/// Manual state resetting of all placemarks with currently selected state
open func resetMarkersState() {
guard let dataModel = dataModel as? Array<any PlacemarkManager> else {
return
}
dataModel.filter { $0.state == .selected }.forEach { $0.state = .default }
}
}

View File

@ -23,17 +23,27 @@
import ObjectiveC
open class BasePlacemarkManager<Placemark, DataModel, Location>: NSObject, PlacemarkManager, PlacemarkConfigurator {
public typealias TapHandlerClosure = (DataModel, Location) -> Bool
/// The current state of a manager's placemark
open var state: MarkerState = .default
/// Point (coordinates) itself of the current placemark manager
public let placemarkPosition: Location?
/// Model for the current placemark manager
public let dataModel: DataModel
public var tapHandler: TapHandlerClosure?
public var iconFactory: AnyMarkerIconFactory<DataModel>?
public let dataModel: DataModel
public init(dataModel: DataModel,
public init(placemarkPosition: Location? = nil,
dataModel: DataModel,
iconFactory: AnyMarkerIconFactory<DataModel>?,
tapHandler: TapHandlerClosure?) {
self.placemarkPosition = placemarkPosition
self.dataModel = dataModel
self.iconFactory = iconFactory
self.tapHandler = tapHandler

View File

@ -20,13 +20,15 @@
// THE SOFTWARE.
//
public protocol PlacemarkManager {
public protocol PlacemarkManager: AnyObject {
associatedtype DataModel
associatedtype Position
typealias TapHandlerClosure = (DataModel, Position) -> Bool
var placemarkPosition: Position? { get }
var dataModel: DataModel { get }
var state: MarkerState { get set }
///
/// Validates whether the current tap could be handled or not

View File

@ -25,7 +25,10 @@ import YandexMapsMobile
import UIKit
import CoreLocation
open class YandexClusterPlacemarkManager<Model>: BasePlacemarkManager<YMKCluster, [YandexPlacemarkManager<Model>], [YMKPoint]>,
open class YandexClusterPlacemarkManager<Model>: BaseClusterPlacemarkManager<YMKCluster,
[YandexPlacemarkManager<Model>],
[YMKPoint],
YMKPoint>,
YMKClusterListener,
YMKClusterTapListener {
@ -46,7 +49,7 @@ open class YandexClusterPlacemarkManager<Model>: BasePlacemarkManager<YMKCluster
let clusterizedPlacemarkCollection = map.mapObjects.addClusterizedPlacemarkCollection(with: self)
let emptyPlacemarks = clusterizedPlacemarkCollection.addEmptyPlacemarks(with: dataModel.map { $0.position })
let emptyPlacemarks = clusterizedPlacemarkCollection.addEmptyPlacemarks(with: dataModel.compactMap { $0.placemarkPosition })
let placemarksZip = zip(emptyPlacemarks, dataModel)
@ -65,16 +68,6 @@ open class YandexClusterPlacemarkManager<Model>: BasePlacemarkManager<YMKCluster
placemarkCollection?.clear()
}
/// Manual selecting of a placemark with an incoming point coordinates
open func selectMarker(with point: YMKPoint) {
dataModel.filter { $0.position == point }.forEach { $0.state = .selected }
}
/// Manual state resetting of all placemarks with currently selected state
open func resetMarkersState() {
dataModel.filter { $0.state == .selected }.forEach { $0.state = .default }
}
// MARK: - YMKClusterListener
open func onClusterAdded(with cluster: YMKCluster) {
@ -90,7 +83,7 @@ open class YandexClusterPlacemarkManager<Model>: BasePlacemarkManager<YMKCluster
let managersInCluster = managers(in: cluster)
return tapHandler(managersInCluster, managersInCluster.map { $0.position })
return tapHandler(managersInCluster, managersInCluster.compactMap { $0.placemarkPosition })
}
open func managers(in cluster: YMKCluster) -> [YandexPlacemarkManager<Model>] {

View File

@ -26,14 +26,11 @@ import YandexMapsMobile
open class YandexPlacemarkManager<Model>: BasePlacemarkManager<YMKPlacemarkMapObject, Model, YMKPoint>,
YMKMapObjectTapListener {
/// Point (coordinates) itself of the current placemark manager
public let position: YMKPoint
/// Placemark itself of the current placemark manager
public private(set) var placemark: YMKPlacemarkMapObject?
/// The current state of a manager's placemark
public var state: MarkerState = .default {
override public var state: MarkerState {
didSet {
guard let placemark = placemark else {
return
@ -50,9 +47,8 @@ open class YandexPlacemarkManager<Model>: BasePlacemarkManager<YMKPlacemarkMapOb
iconFactory: AnyMarkerIconFactory<Model>,
tapHandler: TapHandlerClosure?) {
self.position = position
super.init(dataModel: dataModel,
super.init(placemarkPosition: position,
dataModel: dataModel,
iconFactory: iconFactory,
tapHandler: tapHandler)
}