mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-22 09:32:52 +02:00
Show own location in map views (#7375)
* show own location on static sharing * show own location on live sharing * add tests and changelog * check location authorisation, fix center to current user location button * it moves request to LocationManager in proper service * add static location viewer service
This commit is contained in:
+2
-1
@@ -53,7 +53,8 @@ final class StaticLocationViewingCoordinator: Coordinator, Presentable {
|
||||
mapStyleURL: parameters.session.vc_homeserverConfiguration().tileServer.mapStyleURL,
|
||||
avatarData: parameters.avatarData,
|
||||
location: parameters.location,
|
||||
coordinateType: parameters.coordinateType
|
||||
coordinateType: parameters.coordinateType,
|
||||
service: StaticLocationSharingViewerService()
|
||||
)
|
||||
let view = StaticLocationView(viewModel: viewModel.context)
|
||||
.environmentObject(AvatarViewModel(avatarService: AvatarService(mediaManager: parameters.mediaManager)))
|
||||
|
||||
+2
-1
@@ -46,7 +46,8 @@ enum MockStaticLocationViewingScreenState: MockScreenState, CaseIterable {
|
||||
let viewModel = StaticLocationViewingViewModel(mapStyleURL: mapStyleURL,
|
||||
avatarData: AvatarInput(mxContentUri: "", matrixItemId: "alice:matrix.org", displayName: "Alice"),
|
||||
location: location,
|
||||
coordinateType: coordinateType)
|
||||
coordinateType: coordinateType,
|
||||
service: MockStaticLocationSharingViewerService())
|
||||
|
||||
return ([viewModel],
|
||||
AnyView(StaticLocationView(viewModel: viewModel.context)
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Copyright 2023 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 CoreLocation
|
||||
import Foundation
|
||||
|
||||
class StaticLocationSharingViewerService: StaticLocationSharingViewerServiceProtocol {
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let locationManager = CLLocationManager()
|
||||
|
||||
// MARK: Public
|
||||
|
||||
func requestAuthorizationIfNeeded() -> Bool {
|
||||
locationManager.requestAuthorizationIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Copyright 2023 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
|
||||
|
||||
class MockStaticLocationSharingViewerService: StaticLocationSharingViewerServiceProtocol {
|
||||
|
||||
func requestAuthorizationIfNeeded() -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// Copyright 2023 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
|
||||
|
||||
protocol StaticLocationSharingViewerServiceProtocol {
|
||||
|
||||
func requestAuthorizationIfNeeded() -> Bool
|
||||
}
|
||||
+3
@@ -23,6 +23,7 @@ import Foundation
|
||||
enum StaticLocationViewingViewAction {
|
||||
case close
|
||||
case share
|
||||
case showUserLocation
|
||||
}
|
||||
|
||||
enum StaticLocationViewingViewModelResult {
|
||||
@@ -42,6 +43,8 @@ struct StaticLocationViewingViewState: BindableState {
|
||||
/// Shared annotation to display existing location
|
||||
let sharedAnnotation: LocationAnnotation
|
||||
|
||||
var showsUserLocation = false
|
||||
|
||||
var showLoadingIndicator = false
|
||||
|
||||
var shareButtonEnabled: Bool {
|
||||
|
||||
+15
-1
@@ -24,6 +24,7 @@ class StaticLocationViewingViewModel: StaticLocationViewingViewModelType, Static
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var staticLocationSharingViewerService: StaticLocationSharingViewerServiceProtocol
|
||||
private var mapViewErrorAlertInfoBuilder: MapViewErrorAlertInfoBuilder
|
||||
|
||||
// MARK: Public
|
||||
@@ -32,7 +33,10 @@ class StaticLocationViewingViewModel: StaticLocationViewingViewModelType, Static
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(mapStyleURL: URL, avatarData: AvatarInputProtocol, location: CLLocationCoordinate2D, coordinateType: LocationSharingCoordinateType) {
|
||||
init(mapStyleURL: URL, avatarData: AvatarInputProtocol, location: CLLocationCoordinate2D, coordinateType: LocationSharingCoordinateType, service: StaticLocationSharingViewerServiceProtocol) {
|
||||
|
||||
staticLocationSharingViewerService = service
|
||||
|
||||
let sharedAnnotation: LocationAnnotation
|
||||
switch coordinateType {
|
||||
case .user:
|
||||
@@ -63,6 +67,8 @@ class StaticLocationViewingViewModel: StaticLocationViewingViewModelType, Static
|
||||
completion?(.close)
|
||||
case .share:
|
||||
completion?(.share(state.sharedAnnotation.coordinate))
|
||||
case .showUserLocation:
|
||||
showsCurrentUserLocation()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,4 +95,12 @@ class StaticLocationViewingViewModel: StaticLocationViewingViewModelType, Static
|
||||
|
||||
state.bindings.alertInfo = alertInfo
|
||||
}
|
||||
|
||||
private func showsCurrentUserLocation() {
|
||||
if staticLocationSharingViewerService.requestAuthorizationIfNeeded() {
|
||||
state.showsUserLocation = true
|
||||
} else {
|
||||
state.errorSubject.send(.invalidLocationAuthorization)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -79,10 +79,18 @@ class StaticLocationViewingViewModelTests: XCTestCase {
|
||||
waitForExpectations(timeout: 3)
|
||||
}
|
||||
|
||||
func testToggleShowUserLocation() {
|
||||
let viewModel = buildViewModel()
|
||||
XCTAssertFalse(viewModel.context.viewState.showsUserLocation)
|
||||
viewModel.context.send(viewAction: .showUserLocation)
|
||||
XCTAssertTrue(viewModel.context.viewState.showsUserLocation)
|
||||
}
|
||||
|
||||
private func buildViewModel() -> StaticLocationViewingViewModel {
|
||||
StaticLocationViewingViewModel(mapStyleURL: URL(string: "http://empty.com")!,
|
||||
avatarData: AvatarInput(mxContentUri: "", matrixItemId: "", displayName: ""),
|
||||
location: CLLocationCoordinate2D(latitude: 51.4932641, longitude: -0.257096),
|
||||
coordinateType: .user)
|
||||
coordinateType: .user,
|
||||
service: MockStaticLocationSharingViewerService())
|
||||
}
|
||||
}
|
||||
|
||||
+15
-8
@@ -29,19 +29,26 @@ struct StaticLocationView: View {
|
||||
|
||||
// MARK: Views
|
||||
|
||||
var mapView: LocationSharingMapView {
|
||||
LocationSharingMapView(tileServerMapURL: viewModel.viewState.mapStyleURL,
|
||||
annotations: [viewModel.viewState.sharedAnnotation],
|
||||
highlightedAnnotation: viewModel.viewState.sharedAnnotation,
|
||||
userAvatarData: nil,
|
||||
showsUserLocation: viewModel.viewState.showsUserLocation,
|
||||
userLocation: Binding.constant(nil),
|
||||
mapCenterCoordinate: Binding.constant(nil),
|
||||
errorSubject: viewModel.viewState.errorSubject)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
ZStack(alignment: .bottom) {
|
||||
LocationSharingMapView(tileServerMapURL: viewModel.viewState.mapStyleURL,
|
||||
annotations: [viewModel.viewState.sharedAnnotation],
|
||||
highlightedAnnotation: viewModel.viewState.sharedAnnotation,
|
||||
userAvatarData: viewModel.viewState.userAvatarData,
|
||||
showsUserLocation: false,
|
||||
userLocation: Binding.constant(nil),
|
||||
mapCenterCoordinate: Binding.constant(nil),
|
||||
errorSubject: viewModel.viewState.errorSubject)
|
||||
mapView
|
||||
MapCreditsView()
|
||||
}
|
||||
.overlay(CenterToUserLocationButton(action: {
|
||||
viewModel.send(viewAction: .showUserLocation)
|
||||
}).offset(x: -11.0, y: 52), alignment: .topTrailing)
|
||||
.ignoresSafeArea(.all, edges: [.bottom])
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
|
||||
Reference in New Issue
Block a user