Skip to content

Commit dcfaadb

Browse files
Merge pull request #6016 from vector-im/maximee/5982_ls_static_share_viewer
[Location Sharing] Add separate screen for viewing static shared location
2 parents 6711976 + 39c625b commit dcfaadb

23 files changed

+699
-162
lines changed

Riot/Assets/en.lproj/Vector.strings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,6 +2139,7 @@ Tap the + to start adding people.";
21392139
"live_location_sharing_banner_stop" = "Stop";
21402140
"location_sharing_static_share_title" = "Send my current location";
21412141
"location_sharing_pin_drop_share_title" = "Send this location";
2142+
"location_sharing_live_map_callout_title" = "Share location";
21422143

21432144
// MARK: - MatrixKit
21442145

Riot/Generated/Strings.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2759,6 +2759,10 @@ public class VectorL10n: NSObject {
27592759
public static var locationSharingInvalidAuthorizationSettings: String {
27602760
return VectorL10n.tr("Vector", "location_sharing_invalid_authorization_settings")
27612761
}
2762+
/// Share location
2763+
public static var locationSharingLiveMapCalloutTitle: String {
2764+
return VectorL10n.tr("Vector", "location_sharing_live_map_callout_title")
2765+
}
27622766
/// Share live location
27632767
public static var locationSharingLiveShareTitle: String {
27642768
return VectorL10n.tr("Vector", "location_sharing_live_share_title")

Riot/Modules/Room/RoomCoordinator.swift

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,54 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol {
246246

247247
completion?()
248248
}
249+
250+
private func showLocationCoordinatorWithEvent(_ event: MXEvent, bubbleData: MXKRoomBubbleCellDataStoring) {
251+
guard #available(iOS 14.0, *) else {
252+
return
253+
}
254+
255+
guard let navigationRouter = self.navigationRouter,
256+
let mediaManager = mxSession?.mediaManager,
257+
let locationContent = event.location else {
258+
MXLog.error("[RoomCoordinator] Invalid location showing coordinator parameters. Returning.")
259+
return
260+
}
261+
262+
let avatarData = AvatarInput(mxContentUri: bubbleData.senderAvatarUrl,
263+
matrixItemId: bubbleData.senderId,
264+
displayName: bubbleData.senderDisplayName)
265+
266+
267+
let location = CLLocationCoordinate2D(latitude: locationContent.latitude, longitude: locationContent.longitude)
268+
let coordinateType = locationContent.assetType
269+
270+
guard let locationSharingCoordinatetype = coordinateType.locationSharingCoordinateType() else {
271+
fatalError("[LocationSharingCoordinator] event asset type is not supported: \(coordinateType)")
272+
}
273+
274+
let parameters = StaticLocationViewingCoordinatorParameters(mediaManager: mediaManager,
275+
avatarData: avatarData,
276+
location: location,
277+
coordinateType: locationSharingCoordinatetype)
278+
279+
let coordinator = StaticLocationViewingCoordinator(parameters: parameters)
280+
281+
coordinator.completion = { [weak self, weak coordinator] in
282+
guard let self = self, let coordinator = coordinator else {
283+
return
284+
}
285+
286+
self.navigationRouter?.dismissModule(animated: true, completion: nil)
287+
self.remove(childCoordinator: coordinator)
288+
}
289+
290+
add(childCoordinator: coordinator)
291+
292+
navigationRouter.present(coordinator, animated: true)
293+
coordinator.start()
294+
}
249295

250-
private func startLocationCoordinatorWithEvent(_ event: MXEvent? = nil, bubbleData: MXKRoomBubbleCellDataStoring? = nil) {
296+
private func startLocationCoordinator() {
251297
guard #available(iOS 14.0, *) else {
252298
return
253299
}
@@ -259,29 +305,13 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol {
259305
return
260306
}
261307

262-
var avatarData: AvatarInputProtocol
263-
if event != nil, let bubbleData = bubbleData {
264-
avatarData = AvatarInput(mxContentUri: bubbleData.senderAvatarUrl,
265-
matrixItemId: bubbleData.senderId,
266-
displayName: bubbleData.senderDisplayName)
267-
} else {
268-
avatarData = AvatarInput(mxContentUri: user.avatarUrl,
308+
let avatarData = AvatarInput(mxContentUri: user.avatarUrl,
269309
matrixItemId: user.userId,
270310
displayName: user.displayname)
271-
}
272-
273-
var location: CLLocationCoordinate2D?
274-
var coordinateType: MXEventAssetType = .user
275-
if let locationContent = event?.location {
276-
location = CLLocationCoordinate2D(latitude: locationContent.latitude, longitude: locationContent.longitude)
277-
coordinateType = locationContent.assetType
278-
}
279311

280312
let parameters = LocationSharingCoordinatorParameters(roomDataSource: roomViewController.roomDataSource,
281313
mediaManager: mediaManager,
282-
avatarData: avatarData,
283-
location: location,
284-
coordinateType: coordinateType)
314+
avatarData: avatarData)
285315

286316
let coordinator = LocationSharingCoordinator(parameters: parameters)
287317

@@ -411,11 +441,11 @@ extension RoomCoordinator: RoomViewControllerDelegate {
411441
}
412442

413443
func roomViewControllerDidRequestLocationSharingFormPresentation(_ roomViewController: RoomViewController) {
414-
startLocationCoordinatorWithEvent()
444+
startLocationCoordinator()
415445
}
416446

417447
func roomViewController(_ roomViewController: RoomViewController, didRequestLocationPresentationFor event: MXEvent, bubbleData: MXKRoomBubbleCellDataStoring) {
418-
startLocationCoordinatorWithEvent(event, bubbleData: bubbleData)
448+
showLocationCoordinatorWithEvent(event, bubbleData: bubbleData)
419449
}
420450

421451
func roomViewController(_ roomViewController: RoomViewController, locationShareActivityViewControllerFor event: MXEvent) -> UIActivityViewController? {

RiotSwiftUI/Modules/Room/LocationSharing/Coordinator/LocationSharingCoordinator.swift

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ struct LocationSharingCoordinatorParameters {
2323
let roomDataSource: MXKRoomDataSource
2424
let mediaManager: MXMediaManager
2525
let avatarData: AvatarInputProtocol
26-
let location: CLLocationCoordinate2D?
27-
let coordinateType: MXEventAssetType
2826
}
2927

3028
// Map between type from MatrixSDK and type from SwiftUI target, as we don't want
@@ -79,16 +77,8 @@ final class LocationSharingCoordinator: Coordinator, Presentable {
7977
init(parameters: LocationSharingCoordinatorParameters) {
8078
self.parameters = parameters
8179

82-
// TODO: Make this check before creating LocationSharingCoordinator
83-
// Use LocationSharingCoordinateType in parameters
84-
guard let locationSharingCoordinatetype = parameters.coordinateType.locationSharingCoordinateType() else {
85-
fatalError("[LocationSharingCoordinator] event asset type is not supported: \(parameters.coordinateType)")
86-
}
87-
8880
let viewModel = LocationSharingViewModel(mapStyleURL: BuildSettings.tileServerMapStyleURL,
8981
avatarData: parameters.avatarData,
90-
location: parameters.location,
91-
coordinateType: locationSharingCoordinatetype,
9282
isLiveLocationSharingEnabled: BuildSettings.liveLocationSharingEnabled)
9383
let view = LocationSharingView(context: viewModel.context)
9484
.addDependency(AvatarService.instantiate(mediaManager: parameters.mediaManager))
@@ -111,14 +101,7 @@ final class LocationSharingCoordinator: Coordinator, Presentable {
111101
case .cancel:
112102
self.completion?()
113103
case .share(let latitude, let longitude, let coordinateType):
114-
115-
// Show share sheet on existing location display
116-
if let location = self.parameters.location {
117-
self.presentShareLocationActivity(with: location)
118-
} else {
119-
self.shareStaticLocation(latitude: latitude, longitude: longitude, coordinateType: coordinateType)
120-
}
121-
104+
self.shareStaticLocation(latitude: latitude, longitude: longitude, coordinateType: coordinateType)
122105
case .shareLiveLocation(let timeout):
123106
self.startLiveLocationSharing(with: timeout)
124107
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//
2+
// Copyright 2022 New Vector Ltd
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
import Foundation
18+
import CoreLocation
19+
20+
/// Build a UIActivityViewController to share a location
21+
class ShareLocationActivityControllerBuilder {
22+
23+
func build(with location: CLLocationCoordinate2D) -> UIActivityViewController {
24+
return UIActivityViewController(activityItems: [ShareToMapsAppActivity.urlForMapsAppType(.apple, location: location)],
25+
applicationActivities: [ShareToMapsAppActivity(type: .apple, location: location),
26+
ShareToMapsAppActivity(type: .google, location: location),
27+
ShareToMapsAppActivity(type: .osm, location: location)])
28+
}
29+
}

RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingModels.swift

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,6 @@ struct LocationSharingViewState: BindableState {
5555
/// Current user avatarData
5656
let userAvatarData: AvatarInputProtocol
5757

58-
/// Shared annotation to display existing location
59-
let sharedAnnotation: LocationAnnotation?
60-
6158
/// Map annotations to display on map
6259
var annotations: [LocationAnnotation]
6360

@@ -77,14 +74,6 @@ struct LocationSharingViewState: BindableState {
7774
/// Used to hide live location sharing features until is finished
7875
var isLiveLocationSharingEnabled: Bool = false
7976

80-
var shareButtonVisible: Bool {
81-
return self.displayExistingLocation == false
82-
}
83-
84-
var displayExistingLocation: Bool {
85-
return sharedAnnotation != nil
86-
}
87-
8877
var shareButtonEnabled: Bool {
8978
!showLoadingIndicator
9079
}

RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingScreenState.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,16 @@ import CoreLocation
2121
@available(iOS 14.0, *)
2222
enum MockLocationSharingScreenState: MockScreenState, CaseIterable {
2323
case shareUserLocation
24-
case displayExistingLocation
2524

2625
var screenType: Any.Type {
2726
LocationSharingView.self
2827
}
2928

3029
var screenView: ([Any], AnyView) {
3130

32-
var location: CLLocationCoordinate2D?
33-
if self == .displayExistingLocation {
34-
location = CLLocationCoordinate2D(latitude: 51.4932641, longitude: -0.257096)
35-
}
36-
3731
let mapStyleURL = URL(string: "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx")!
3832
let viewModel = LocationSharingViewModel(mapStyleURL: mapStyleURL,
3933
avatarData: AvatarInput(mxContentUri: "", matrixItemId: "alice:matrix.org", displayName: "Alice"),
40-
location: location,
41-
coordinateType: .user,
4234
isLiveLocationSharingEnabled: true)
4335
return ([viewModel],
4436
AnyView(LocationSharingView(context: viewModel.context)

RiotSwiftUI/Modules/Room/LocationSharing/LocationSharingViewModel.swift

Lines changed: 4 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -41,38 +41,12 @@ class LocationSharingViewModel: LocationSharingViewModelType, LocationSharingVie
4141

4242
// MARK: - Setup
4343

44-
init(mapStyleURL: URL, avatarData: AvatarInputProtocol, location: CLLocationCoordinate2D? = nil, coordinateType: LocationSharingCoordinateType, isLiveLocationSharingEnabled: Bool = false) {
45-
46-
var sharedAnnotation: LocationAnnotation?
47-
var annotations: [LocationAnnotation] = []
48-
var highlightedAnnotation: LocationAnnotation?
49-
var showsUserLocation: Bool = false
50-
51-
// Displaying an existing location
52-
if let sharedCoordinate = location {
53-
let sharedLocationAnnotation: LocationAnnotation
54-
switch coordinateType {
55-
case .user:
56-
sharedLocationAnnotation = UserLocationAnnotation(avatarData: avatarData, coordinate: sharedCoordinate)
57-
case .pin:
58-
sharedLocationAnnotation = PinLocationAnnotation(coordinate: sharedCoordinate)
59-
}
60-
61-
annotations.append(sharedLocationAnnotation)
62-
highlightedAnnotation = sharedLocationAnnotation
63-
64-
sharedAnnotation = sharedLocationAnnotation
65-
} else {
66-
// Share current location
67-
showsUserLocation = true
68-
}
69-
44+
init(mapStyleURL: URL, avatarData: AvatarInputProtocol, isLiveLocationSharingEnabled: Bool = false) {
7045
let viewState = LocationSharingViewState(mapStyleURL: mapStyleURL,
7146
userAvatarData: avatarData,
72-
sharedAnnotation: sharedAnnotation,
73-
annotations: annotations,
74-
highlightedAnnotation: highlightedAnnotation,
75-
showsUserLocation: showsUserLocation,
47+
annotations: [],
48+
highlightedAnnotation: nil,
49+
showsUserLocation: true,
7650
isLiveLocationSharingEnabled: isLiveLocationSharingEnabled)
7751

7852
super.init(initialViewState: viewState)
@@ -90,12 +64,6 @@ class LocationSharingViewModel: LocationSharingViewModelType, LocationSharingVie
9064
case .cancel:
9165
completion?(.cancel)
9266
case .share:
93-
// Share existing location
94-
if let location = state.sharedAnnotation?.coordinate {
95-
completion?(.share(latitude: location.latitude, longitude: location.longitude, coordinateType: .user))
96-
return
97-
}
98-
9967
// Share current user location
10068
guard let location = state.bindings.userLocation else {
10169
processError(.failedLocatingUser)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//
2+
// Copyright 2022 New Vector Ltd
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
import Foundation
18+
19+
struct MapViewErrorAlertInfoBuilder {
20+
21+
func build(with error: LocationSharingViewError, dimissalCallback: (() -> Void)?) -> AlertInfo<LocationSharingAlertType>? {
22+
23+
let alertInfo: AlertInfo<LocationSharingAlertType>?
24+
25+
switch error {
26+
case .failedLoadingMap:
27+
alertInfo = AlertInfo(id: .mapLoadingError,
28+
title: VectorL10n.locationSharingLoadingMapErrorTitle(AppInfo.current.displayName),
29+
primaryButton: (VectorL10n.ok, dimissalCallback))
30+
case .failedLocatingUser:
31+
alertInfo = AlertInfo(id: .userLocatingError,
32+
title: VectorL10n.locationSharingLocatingUserErrorTitle(AppInfo.current.displayName),
33+
primaryButton: (VectorL10n.ok, dimissalCallback))
34+
case .invalidLocationAuthorization:
35+
alertInfo = AlertInfo(id: .authorizationError,
36+
title: VectorL10n.locationSharingInvalidAuthorizationErrorTitle(AppInfo.current.displayName),
37+
primaryButton: (VectorL10n.locationSharingInvalidAuthorizationNotNow, dimissalCallback),
38+
secondaryButton: (VectorL10n.locationSharingInvalidAuthorizationSettings, {
39+
if let applicationSettingsURL = URL(string:UIApplication.openSettingsURLString) {
40+
UIApplication.shared.open(applicationSettingsURL)
41+
}
42+
}))
43+
default:
44+
alertInfo = nil
45+
}
46+
47+
return alertInfo
48+
}
49+
50+
}
51+

RiotSwiftUI/Modules/Room/LocationSharing/Test/UI/LocationSharingUITests.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,6 @@ class LocationSharingUITests: XCTestCase {
3636
XCTAssertTrue(app.otherElements["Map"].exists)
3737
}
3838

39-
func testInitialExistingLocation() {
40-
goToScreenWithIdentifier(MockLocationSharingScreenState.displayExistingLocation.title)
41-
42-
XCTAssertTrue(app.buttons["Cancel"].exists)
43-
XCTAssertTrue(app.buttons["LocationSharingView.shareButton"].exists)
44-
XCTAssertTrue(app.otherElements["Map"].exists)
45-
}
46-
4739
// Need a delay when showing the map otherwise the simulator breaks
4840
private func goToScreenWithIdentifier(_ identifier: String) {
4941
app.goToScreenWithIdentifier(identifier)

0 commit comments

Comments
 (0)