BaseChatTableViewCell+Location.swift 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. //
  2. // SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
  3. // SPDX-License-Identifier: GPL-3.0-or-later
  4. //
  5. extension BaseChatTableViewCell {
  6. func setupForLocationCell(with message: NCChatMessage) {
  7. if self.locationPreviewImageView == nil {
  8. // Location preview image view
  9. let locationPreviewImageView = UIImageView(frame: .init(x: 0, y: 0, width: locationMessageCellPreviewWidth, height: locationMessageCellPreviewHeight))
  10. self.locationPreviewImageView = locationPreviewImageView
  11. locationPreviewImageView.translatesAutoresizingMaskIntoConstraints = false
  12. locationPreviewImageView.layer.cornerRadius = chatMessageCellPreviewCornerRadius
  13. locationPreviewImageView.layer.masksToBounds = true
  14. locationPreviewImageView.contentMode = .scaleAspectFit
  15. self.messageBodyView.addSubview(locationPreviewImageView)
  16. let previewTap = UITapGestureRecognizer(target: self, action: #selector(locationPreviewTapped))
  17. locationPreviewImageView.addGestureRecognizer(previewTap)
  18. locationPreviewImageView.isUserInteractionEnabled = true
  19. // Add everything to messageBodyView
  20. let heightConstraint = locationPreviewImageView.heightAnchor.constraint(equalToConstant: locationMessageCellPreviewHeight)
  21. let widthConstraint = locationPreviewImageView.widthAnchor.constraint(equalToConstant: locationMessageCellPreviewWidth)
  22. self.locationPreviewImageViewHeightConstraint = heightConstraint
  23. self.locationPreviewImageViewWidthConstraint = widthConstraint
  24. let messageTextView = MessageBodyTextView()
  25. self.messageTextView = messageTextView
  26. messageTextView.translatesAutoresizingMaskIntoConstraints = false
  27. self.messageBodyView.addSubview(messageTextView)
  28. NSLayoutConstraint.activate([
  29. locationPreviewImageView.leftAnchor.constraint(equalTo: self.messageBodyView.leftAnchor),
  30. locationPreviewImageView.topAnchor.constraint(equalTo: self.messageBodyView.topAnchor),
  31. heightConstraint,
  32. widthConstraint,
  33. messageTextView.leftAnchor.constraint(equalTo: self.messageBodyView.leftAnchor),
  34. messageTextView.rightAnchor.constraint(equalTo: self.messageBodyView.rightAnchor),
  35. messageTextView.topAnchor.constraint(equalTo: locationPreviewImageView.bottomAnchor, constant: 10),
  36. messageTextView.bottomAnchor.constraint(equalTo: self.messageBodyView.bottomAnchor)
  37. ])
  38. }
  39. guard let locationPreviewImageView = self.locationPreviewImageView,
  40. let messageTextView = self.messageTextView,
  41. let geoLocationRichObject = message.geoLocation()
  42. else { return }
  43. let geoLocation = GeoLocationRichObject(from: geoLocationRichObject)
  44. guard let latitude = Double(geoLocation.latitude),
  45. let longitude = Double(geoLocation.longitude)
  46. else { return }
  47. let mapView = MKMapView(frame: .init(x: 0, y: 0, width: locationMessageCellPreviewWidth, height: locationMessageCellPreviewHeight))
  48. let mapRegion = MKCoordinateRegion(center: .init(latitude: latitude, longitude: longitude),
  49. span: .init(latitudeDelta: 0.005, longitudeDelta: 0.005))
  50. let options: MKMapSnapshotter.Options = .init()
  51. options.region = mapRegion
  52. options.size = mapView.frame.size
  53. options.scale = UIScreen.main.scale
  54. let locationMapSnapshooter = MKMapSnapshotter(options: options)
  55. self.locationMapSnapshooter = locationMapSnapshooter
  56. locationMapSnapshooter.start { snapshot, _ in
  57. guard let snapshot else { return }
  58. let pin = MKPinAnnotationView(annotation: nil, reuseIdentifier: nil)
  59. let image = snapshot.image
  60. UIGraphicsBeginImageContextWithOptions(image.size, true, image.scale)
  61. image.draw(at: CGPoint.zero)
  62. let rect = CGRect(origin: CGPoint.zero, size: image.size)
  63. let annotation = MKPointAnnotation()
  64. annotation.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
  65. var point = snapshot.point(for: annotation.coordinate)
  66. if rect.contains(point) {
  67. point.x += pin.centerOffset.x - (pin.bounds.size.width / 2)
  68. point.y += pin.centerOffset.y - (pin.bounds.size.height / 2)
  69. pin.pinTintColor = NCAppBranding.elementColor()
  70. pin.image?.draw(at: point)
  71. }
  72. let compositeImage = UIGraphicsGetImageFromCurrentImageContext()
  73. self.locationPreviewImageView?.image = compositeImage
  74. UIGraphicsEndImageContext()
  75. }
  76. messageTextView.attributedText = message.parsedMarkdownForChat()
  77. }
  78. func prepareForReuseLocationCell() {
  79. self.locationMapSnapshooter?.cancel()
  80. self.locationPreviewImageView?.image = nil
  81. }
  82. @objc func locationPreviewTapped() {
  83. guard let geoLocationRichObject = self.message?.geoLocation()
  84. else { return }
  85. let geoLocation = GeoLocationRichObject(from: geoLocationRichObject)
  86. self.delegate?.cellWants(toOpenLocation: geoLocation)
  87. }
  88. }