Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Mage/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,9 @@
}
}
},
"Delete" : {
"comment" : "Alert delete button"
},
"Downloaded %@ of %@" : {
"localizations" : {
"en" : {
Expand Down
4 changes: 2 additions & 2 deletions Mage/Mixins/MapDirectionsMixin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ class MapDirectionsMixin: NSObject, MapMixin {
@Injected(\.feedItemRepository)
var feedItemRepository: FeedItemRepository

@Injected(\.observationImageRepository)
var imageRepository: ObservationImageRepository

var directionsToItemObserver: Any?
Expand All @@ -49,7 +48,8 @@ class MapDirectionsMixin: NSObject, MapMixin {
var feedItemFetchedResultsController: NSFetchedResultsController<FeedItem>?
private var timer: Timer?

init(mapDirections: MapDirections, viewController: UIViewController, mapStack: UIStackView?, scheme: MDCContainerScheming?, locationManager: CLLocationManager? = nil, sourceView: UIView? = nil) {
init(mapDirections: MapDirections, viewController: UIViewController, mapStack: UIStackView?, scheme: MDCContainerScheming?, locationManager: CLLocationManager? = nil, sourceView: UIView? = nil, imageRepository: ObservationImageRepository = ObservationImageRepositoryImpl.shared) {
self.imageRepository = imageRepository
self.mapDirections = mapDirections
self.mapView = mapDirections.mapView
self.viewController = viewController
Expand Down
21 changes: 8 additions & 13 deletions Mage/Model/Observation/ObservationMapItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct ObservationMapItem: Equatable, Hashable {
var error: Bool = false
var syncing: Bool = false
var important: ObservationImportantModel?
var iconPath: String?

var coordinate: CLLocationCoordinate2D? {
guard let geometry = geometry, let point = geometry.centroid() else {
Expand Down Expand Up @@ -76,22 +77,10 @@ struct ObservationMapItem: Equatable, Hashable {
)
)
}

var iconPath: String? {
@Injected(\.observationImageRepository)
var imageRepository: ObservationImageRepository

return imageRepository.imageName(
eventId: eventId,
formId: formId,
primaryFieldText: primaryFieldText,
secondaryFieldText: secondaryFieldText
)
}
}

extension ObservationMapItem {
init(observation: ObservationLocation) {
init(observation: ObservationLocation, imageRepository: ObservationImageRepository = ObservationImageRepositoryImpl.shared) {
self.observationId = observation.observation?.objectID.uriRepresentation()
self.observationLocationId = observation.objectID.uriRepresentation()
self.formId = Int(observation.formId)
Expand All @@ -106,6 +95,12 @@ extension ObservationMapItem {
self.minLongitude = observation.minLongitude
self.primaryFieldText = observation.primaryFieldText
self.secondaryFieldText = observation.secondaryFieldText
self.iconPath = imageRepository.imageName(
eventId: eventId,
formId: formId,
primaryFieldText: primaryFieldText,
secondaryFieldText: secondaryFieldText
)
// TODO: should we store the primary and secondary feed field text too?
if let observation = observation.observation {
let style = ObservationShapeStyleParser.style(
Expand Down
24 changes: 13 additions & 11 deletions Mage/Observation/ObservationMap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import DataSourceTileOverlay
import MapFramework

class ObservationMap: DataSourceMap {
@Injected(\.observationImageRepository)
var imageRepository: ObservationImageRepository

override var REFRESH_KEY: String {
Expand All @@ -22,16 +21,17 @@ class ObservationMap: DataSourceMap {

init(
repository: TileRepository? = nil,
mapFeatureRepository: MapFeatureRepository? = nil
mapFeatureRepository: MapFeatureRepository? = nil,
imageRepository: ObservationImageRepository = ObservationImageRepositoryImpl.shared
) {
self.imageRepository = imageRepository
super.init(dataSource: DataSources.observation)
viewModel = DataSourceMapViewModel(
dataSource: dataSource,
key: uuid.uuidString,
repository: repository,
mapFeatureRepository: mapFeatureRepository
)
// , repository: repository, mapFeatureRepository: mapFeatureRepository)
}

override func handleFeatureChanges(annotations: [DataSourceAnnotation]) -> Bool {
Expand All @@ -55,14 +55,16 @@ class ObservationMap: DataSourceMap {
annotationView?.isEnabled = true
}

if let iconPath = annotation.mapItem.iconPath, let annotationView = annotationView {
let image = imageRepository.imageAtPath(imagePath: iconPath)
annotationView.image = image
annotationView.centerOffset = CGPoint(x: 0, y: -(image.size.height/2.0))
annotationView.accessibilityLabel = "Observation"
annotationView.accessibilityValue = "Observation"
annotationView.displayPriority = .required
annotationView.canShowCallout = true
Task {
if let iconPath = annotation.mapItem.iconPath, let annotationView = annotationView {
let image = await imageRepository.imageAtPath(imagePath: iconPath)
annotationView.image = image
annotationView.centerOffset = CGPoint(x: 0, y: -(image.size.height/2.0))
annotationView.accessibilityLabel = "Observation"
annotationView.accessibilityValue = "Observation"
annotationView.displayPriority = .required
annotationView.canShowCallout = true
}
}
return annotationView
}
Expand Down
89 changes: 57 additions & 32 deletions Mage/Observation/ObservationsMap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,12 @@ class ObservationsMap: DataSourceMap {
@Injected(\.observationIconRepository)
var iconRepository: ObservationIconRepository

@Injected(\.observationImageRepository)
var imageRepository: ObservationImageRepository

init() {
init(imageRepository: ObservationImageRepository = ObservationImageRepositoryImpl.shared) {
self.imageRepository = imageRepository
super.init(
dataSource: DataSources.observation
// ,
// repository: repository,
// mapFeatureRepository: mapFeatureRepository
)
viewModel = DataSourceMapViewModel(
dataSource: dataSource,
Expand Down Expand Up @@ -178,44 +175,72 @@ class ObservationsMap: DataSourceMap {
}
}
}

override func viewForAnnotation(annotation: MKAnnotation, mapView: MKMapView) -> MKAnnotationView? {
guard let mapItemAnnotation = annotation as? ObservationMapItemAnnotation else {
return nil
}
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: OBSERVATION_MAP_ITEM_ANNOTATION_VIEW_REUSE_ID)

if let annotationView = annotationView {
annotationView.annotation = annotation
var annotationView = mapView.dequeueReusableAnnotationView(
withIdentifier: OBSERVATION_MAP_ITEM_ANNOTATION_VIEW_REUSE_ID
)

if let view = annotationView {
view.annotation = annotation
} else {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: OBSERVATION_MAP_ITEM_ANNOTATION_VIEW_REUSE_ID)
annotationView = MKAnnotationView(
annotation: annotation,
reuseIdentifier: OBSERVATION_MAP_ITEM_ANNOTATION_VIEW_REUSE_ID
)
annotationView?.isEnabled = true
}

let image = imageRepository.imageAtPath(imagePath: mapItemAnnotation.mapItem.iconPath)
if let annotationView = annotationView {
annotationView.image = image

var size = CGSize(width: 40, height: 40)
let max = max(image.size.height, image.size.width)
size.width *= ((image.size.width) / max)
size.height *= ((image.size.height) / max)
annotationView.frame.size = size
annotationView.canShowCallout = false
annotationView.isEnabled = false
annotationView.accessibilityLabel = "Enlarged"
annotationView.zPriority = .max
annotationView.selectedZPriority = .max


annotationView.centerOffset = CGPoint(x: 0, y: -(image.size.height/2.0))
// annotationView.accessibilityLabel = "Observation"
// annotationView.accessibilityValue = "Observation"
annotationView.displayPriority = .required
// annotationView.canShowCallout = true
// --- Default placeholder immediately ---
let placeholder = UIImage(named: "defaultMarker")!
annotationView?.image = placeholder
annotationView?.frame.size = CGSize(width: 40, height: 40)
annotationView?.centerOffset = CGPoint(x: 0, y: -(placeholder.size.height/2.0))
annotationView?.displayPriority = .required

// --- Kick off async image load ---
if let iconPath = mapItemAnnotation.mapItem.iconPath,
let annotationView = annotationView {

Task {
let image = await imageRepository.imageAtPath(imagePath: iconPath)

await MainActor.run {
// double-check the annotationView is still in use
guard currentAnnotationViews[mapItemAnnotation.id] === annotationView else { return }

annotationView.image = image

// Recalculate size based on real image
var size = CGSize(width: 40, height: 40)
let max = max(image.size.height, image.size.width)
if max > 0 {
size.width *= (image.size.width / max)
size.height *= (image.size.height / max)
}
annotationView.frame.size = size

annotationView.canShowCallout = false
annotationView.isEnabled = false
annotationView.accessibilityLabel = "Enlarged"
annotationView.zPriority = .max
annotationView.selectedZPriority = .max
annotationView.centerOffset = CGPoint(x: 0, y: -(image.size.height / 2.0))
}
}
}

// keep references
mapItemAnnotation.annotationView = annotationView
currentAnnotationViews[mapItemAnnotation.id] = annotationView
if let annotationView = annotationView {
currentAnnotationViews[mapItemAnnotation.id] = annotationView
}

return annotationView
}

}
54 changes: 34 additions & 20 deletions Mage/ObservationAnnotation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,38 +83,52 @@ import DateTools
return viewForAnnotation(on: on, with: nil, scheme: scheme)
}

@objc public override func viewForAnnotation(on: MKMapView, with: AnnotationDragCallback?, scheme: MDCContainerScheming) -> MKAnnotationView {
@objc public override func viewForAnnotation(
on: MKMapView,
with: AnnotationDragCallback?,
scheme: MDCContainerScheming
) -> MKAnnotationView {
var annotationView = on.dequeueReusableAnnotationView(withIdentifier: OBSERVATION_ANNOTATION_VIEW_REUSE_ID)
if let annotationView = annotationView {
annotationView.annotation = self

if let view = annotationView {
view.annotation = self
} else {
annotationView = ObservationAnnotationView(annotation: self, reuseIdentifier: OBSERVATION_ANNOTATION_VIEW_REUSE_ID, mapView: on, dragCallback: with)
annotationView = ObservationAnnotationView(
annotation: self,
reuseIdentifier: OBSERVATION_ANNOTATION_VIEW_REUSE_ID,
mapView: on,
dragCallback: with
)
annotationView?.isEnabled = true
}

if point {
if let observation = observation {
@Injected(\.observationImageRepository)
var imageRepository: ObservationImageRepository

let image = imageRepository.image(observation: observation);
annotationView?.image = image;
annotationView?.centerOffset = CGPoint(x: 0, y: -(image.size.height/2.0))

// --- Default placeholder immediately ---
annotationView?.image = UIImage(named: "defaultMarker")
annotationView?.centerOffset = .zero

if point, let observation = observation, let annotationView {
// --- Kick off async image load ---
Task {
let image = await ObservationImageRepositoryImpl.shared.image(observation: observation)
await MainActor.run {
annotationView.image = image
annotationView.centerOffset = CGPoint(x: 0, y: -(image.size.height/2.0))
}
}
} else {
annotationView?.image = nil
annotationView?.frame = .zero
annotationView?.centerOffset = .zero
}
if let annotationView = annotationView {

if let annotationView {
annotationView.accessibilityLabel = "Observation"
annotationView.accessibilityValue = "Observation"
annotationView.displayPriority = .required
view = annotationView
return annotationView
} else {
return MKAnnotationView(annotation: self, reuseIdentifier: OBSERVATION_ANNOTATION_VIEW_REUSE_ID)
return MKAnnotationView(
annotation: self,
reuseIdentifier: OBSERVATION_ANNOTATION_VIEW_REUSE_ID
)
}
}

}
Loading