Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Location Sharing]: Pin drop location sharing #5957

Merged
merged 7 commits into from
Apr 4, 2022
Merged
Show file tree
Hide file tree
Changes from 5 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"images" : [
{
"filename" : "location_center_map_icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "[email protected]",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "[email protected]",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions Riot/Generated/Images.swift
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ internal class Asset: NSObject {
internal static let voiceCallHangonIcon = ImageAsset(name: "voice_call_hangon_icon")
internal static let voiceCallHangupIcon = ImageAsset(name: "voice_call_hangup_icon")
internal static let liveLocationIcon = ImageAsset(name: "live_location_icon")
internal static let locationCenterMapIcon = ImageAsset(name: "location_center_map_icon")
internal static let locationLiveIcon = ImageAsset(name: "location_live_icon")
internal static let locationMarkerIcon = ImageAsset(name: "location_marker_icon")
internal static let locationPinIcon = ImageAsset(name: "location_pin_icon")
Expand Down
3 changes: 3 additions & 0 deletions Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#import "MXKDataSource.h"
#import "MXKRoomBubbleCellDataStoring.h"
#import "MXKEventFormatter.h"
#import "MXEventContentLocation.h"

@class MXKQueuedEvent;

Expand Down Expand Up @@ -614,13 +615,15 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
@param latitude the location's latitude
@param longitude the location's longitude
@param description an optional description
@param assetType the location's type
@param success A block object called when the operation succeeds. It returns
the event id of the event generated on the homeserver
@param failure A block object called when the operation fails.
*/
- (void)sendLocationWithLatitude:(double)latitude
longitude:(double)longitude
description:(NSString *)description
coordinateType:(MXEventAssetType)coordinateType
success:(void (^)(NSString *))success
failure:(void (^)(NSError *))failure;

Expand Down
2 changes: 2 additions & 0 deletions Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m
Original file line number Diff line number Diff line change
Expand Up @@ -2104,6 +2104,7 @@ - (void)sendMessageWithContent:(NSDictionary *)msgContent success:(void (^)(NSSt
- (void)sendLocationWithLatitude:(double)latitude
longitude:(double)longitude
description:(NSString *)description
coordinateType:(MXEventAssetType)coordinateType
success:(void (^)(NSString *))success
failure:(void (^)(NSError *))failure
{
Expand All @@ -2115,6 +2116,7 @@ - (void)sendLocationWithLatitude:(double)latitude
description:description
threadId:self.threadId
localEcho:&localEchoEvent
assetType:coordinateType
success:success failure:failure];

if (localEchoEvent)
Expand Down
1 change: 1 addition & 0 deletions Riot/Modules/Room/Location/LocationMarkerView.xib
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="location_user_marker" translatesAutoresizingMaskIntoConstraints="NO" id="ldO-kc-R5W">
<rect key="frame" x="0.0" y="0.0" width="50" height="54"/>
<color key="tintColor" red="0.050980392159999999" green="0.74117647060000003" blue="0.5450980392" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="width" constant="50" id="41S-fj-tn4"/>
<constraint firstAttribute="height" constant="54" id="MAX-5E-xvS"/>
Expand Down
6 changes: 5 additions & 1 deletion Riot/Modules/Room/RoomCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import Foundation
import UIKit
import CommonKit
import MatrixSDK

final class RoomCoordinator: NSObject, RoomCoordinatorProtocol {

Expand Down Expand Up @@ -269,14 +270,17 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol {
}

var location: CLLocationCoordinate2D?
var coordinateType: MXEventAssetType = .user
if let locationContent = event?.location {
location = CLLocationCoordinate2D(latitude: locationContent.latitude, longitude: locationContent.longitude)
coordinateType = locationContent.assetType
}

let parameters = LocationSharingCoordinatorParameters(roomDataSource: roomViewController.roomDataSource,
mediaManager: mediaManager,
avatarData: avatarData,
location: location)
location: location,
coordinateType: coordinateType)

let coordinator = LocationSharingCoordinator(parameters: parameters)

Expand Down
33 changes: 33 additions & 0 deletions RiotSwiftUI/Modules/Common/Extensions/CLLocationCoordinate2D.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation
import CoreLocation

extension CLLocationCoordinate2D {

/// Compare two coordinates
/// - parameter coordinate: another coordinate to compare
/// - parameter precision:it represente how close you want the two coordinates
/// - return: bool value
func isEqual(to coordinate: CLLocationCoordinate2D, precision: Double) -> Bool {

if fabs(self.latitude - coordinate.latitude) <= precision && fabs(self.longitude - coordinate.longitude) <= precision {
return true
}
return false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,48 @@
import Foundation
import UIKit
import SwiftUI
import MatrixSDK

struct LocationSharingCoordinatorParameters {
let roomDataSource: MXKRoomDataSource
let mediaManager: MXMediaManager
let avatarData: AvatarInputProtocol
let location: CLLocationCoordinate2D?
let coordinateType: MXEventAssetType
}

// Map between type from MatrixSDK and type from SwiftUI target, as we don't want
// to add the SDK as a dependency to it. We need to translate from one to the other on this level.
extension MXEventAssetType {
func locationSharingCoordinateType() -> LocationSharingCoordinateType {
let coordinateType: LocationSharingCoordinateType
switch self {
case .user:
coordinateType = .user
case .pin:
coordinateType = .pin
case .generic:
coordinateType = .generic
@unknown default:
coordinateType = .generic
}
return coordinateType
}
}

extension LocationSharingCoordinateType {
func eventAssetType() -> MXEventAssetType {
let eventAssetType: MXEventAssetType
switch self {
case .user:
eventAssetType = .user
case .pin:
eventAssetType = .pin
case .generic:
eventAssetType = .generic
}
return eventAssetType
}
}

final class LocationSharingCoordinator: Coordinator, Presentable {
Expand Down Expand Up @@ -50,6 +86,7 @@ final class LocationSharingCoordinator: Coordinator, Presentable {
let viewModel = LocationSharingViewModel(mapStyleURL: BuildSettings.tileServerMapStyleURL,
avatarData: parameters.avatarData,
location: parameters.location,
coordinateType: parameters.coordinateType.locationSharingCoordinateType(),
isLiveLocationSharingEnabled: BuildSettings.liveLocationSharingEnabled)
let view = LocationSharingView(context: viewModel.context)
.addDependency(AvatarService.instantiate(mediaManager: parameters.mediaManager))
Expand All @@ -71,7 +108,7 @@ final class LocationSharingCoordinator: Coordinator, Presentable {
switch result {
case .cancel:
self.completion?()
case .share(let latitude, let longitude):
case .share(let latitude, let longitude, let coordinateType):

// Show share sheet on existing location display
if let location = self.parameters.location {
Expand All @@ -81,7 +118,7 @@ final class LocationSharingCoordinator: Coordinator, Presentable {

self.locationSharingViewModel.startLoading()

self.parameters.roomDataSource.sendLocation(withLatitude: latitude, longitude: longitude, description: nil) { [weak self] _ in
self.parameters.roomDataSource.sendLocation(withLatitude: latitude, longitude: longitude, description: nil, coordinateType: coordinateType.eventAssetType()) { [weak self] _ in
guard let self = self else { return }

self.locationSharingViewModel.stopLoading()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,23 @@ import SwiftUI
import Combine
import CoreLocation

// This is the equivalent of MXEventAssetType in the MatrixSDK
enum LocationSharingCoordinateType {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can make just 2 cases in the app side. case pin, case user. As you will not handle generic case in your screens.

case user
case pin
case generic
}

enum LocationSharingViewAction {
case cancel
case share
case sharePinLocation
case goToUserLocation
}

enum LocationSharingViewModelResult {
case cancel
case share(latitude: Double, longitude: Double)
case share(latitude: Double, longitude: Double, coordinateType: LocationSharingCoordinateType)
}

enum LocationSharingViewError {
Expand All @@ -45,8 +54,8 @@ struct LocationSharingViewState: BindableState {
/// Current user avatarData
let userAvatarData: AvatarInputProtocol

/// User map annotation to display existing location
let userAnnotation: UserLocationAnnotation?
/// Shared annotation to display existing location
let sharedAnnotation: UserLocationAnnotation?

/// Map annotations to display on map
var annotations: [UserLocationAnnotation]
Expand All @@ -55,7 +64,9 @@ struct LocationSharingViewState: BindableState {
var highlightedAnnotation: UserLocationAnnotation?

/// Indicates whether the user has moved around the map to drop a pin somewhere other than their current location
var isPinDropSharing: Bool = false
var isPinDropSharing: Bool {
return bindings.pinLocation != nil
}

var showLoadingIndicator: Bool = false

Expand All @@ -70,7 +81,7 @@ struct LocationSharingViewState: BindableState {
}

var displayExistingLocation: Bool {
return userAnnotation != nil
return sharedAnnotation != nil
}

var shareButtonEnabled: Bool {
Expand All @@ -85,6 +96,7 @@ struct LocationSharingViewState: BindableState {
struct LocationSharingViewStateBindings {
var alertInfo: AlertInfo<LocationSharingAlertType>?
var userLocation: CLLocationCoordinate2D?
var pinLocation: CLLocationCoordinate2D?
}

enum LocationSharingAlertType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ enum MockLocationSharingScreenState: MockScreenState, CaseIterable {
let viewModel = LocationSharingViewModel(mapStyleURL: mapStyleURL,
avatarData: AvatarInput(mxContentUri: "", matrixItemId: "alice:matrix.org", displayName: "Alice"),
location: location,
coordinateType: .user,
isLiveLocationSharingEnabled: true)
return ([viewModel],
AnyView(LocationSharingView(context: viewModel.context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,29 +35,29 @@ class LocationSharingViewModel: LocationSharingViewModelType, LocationSharingVie

// MARK: - Setup

init(mapStyleURL: URL, avatarData: AvatarInputProtocol, location: CLLocationCoordinate2D? = nil, isLiveLocationSharingEnabled: Bool = false) {
init(mapStyleURL: URL, avatarData: AvatarInputProtocol, location: CLLocationCoordinate2D? = nil, coordinateType: LocationSharingCoordinateType, isLiveLocationSharingEnabled: Bool = false) {

var userAnnotation: UserLocationAnnotation?
var sharedAnnotation: UserLocationAnnotation?
var annotations: [UserLocationAnnotation] = []
var highlightedAnnotation: UserLocationAnnotation?
var showsUserLocation: Bool = false

// Displaying an existing location
if let userCoordinate = location {
let userLocationAnnotation = UserLocationAnnotation(avatarData: avatarData, coordinate: userCoordinate)
if let sharedCoordinate = location {
let sharedLocationAnnotation = UserLocationAnnotation(avatarData: avatarData, coordinate: sharedCoordinate, coordinateType: coordinateType)

annotations.append(userLocationAnnotation)
highlightedAnnotation = userLocationAnnotation
annotations.append(sharedLocationAnnotation)
highlightedAnnotation = sharedLocationAnnotation

userAnnotation = userLocationAnnotation
sharedAnnotation = sharedLocationAnnotation
} else {
// Share current location
showsUserLocation = true
}

let viewState = LocationSharingViewState(mapStyleURL: mapStyleURL,
userAvatarData: avatarData,
userAnnotation: userAnnotation,
sharedAnnotation: sharedAnnotation,
annotations: annotations,
highlightedAnnotation: highlightedAnnotation,
showsUserLocation: showsUserLocation,
Expand All @@ -79,8 +79,8 @@ class LocationSharingViewModel: LocationSharingViewModelType, LocationSharingVie
completion?(.cancel)
case .share:
// Share existing location
if let location = state.userAnnotation?.coordinate {
completion?(.share(latitude: location.latitude, longitude: location.longitude))
if let location = state.sharedAnnotation?.coordinate {
completion?(.share(latitude: location.latitude, longitude: location.longitude, coordinateType: .generic))
return
}

Expand All @@ -90,7 +90,16 @@ class LocationSharingViewModel: LocationSharingViewModelType, LocationSharingVie
return
}

completion?(.share(latitude: location.latitude, longitude: location.longitude))
completion?(.share(latitude: location.latitude, longitude: location.longitude, coordinateType: .user))
case .sharePinLocation:
guard let pinLocation = state.bindings.pinLocation else {
processError(.failedLocatingUser)
return
}

completion?(.share(latitude: pinLocation.latitude, longitude: pinLocation.longitude, coordinateType: .pin))
case .goToUserLocation:
state.bindings.pinLocation = nil
}
}

Expand Down
Loading