mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 10:33:45 +00:00
Show alert if user has not beacon and beaconInfo permissions in the room.
This commit is contained in:
@@ -1408,6 +1408,7 @@
|
|||||||
"screen_session_verification_waiting_to_accept_title" = "Waiting to accept request";
|
"screen_session_verification_waiting_to_accept_title" = "Waiting to accept request";
|
||||||
"screen_share_location_live_location_disclaimer_title" = "Your live location history will be stored in the room and visible to members after the session ends.";
|
"screen_share_location_live_location_disclaimer_title" = "Your live location history will be stored in the room and visible to members after the session ends.";
|
||||||
"screen_share_location_live_location_duration_picker_title" = "Choose how long to share your live location.";
|
"screen_share_location_live_location_duration_picker_title" = "Choose how long to share your live location.";
|
||||||
|
"screen_share_location_live_location_missing_permissions" = "You do not have permissions to share your live location in this room";
|
||||||
"screen_share_location_title" = "Share location";
|
"screen_share_location_title" = "Share location";
|
||||||
"screen_share_my_location_action" = "Share my location";
|
"screen_share_my_location_action" = "Share my location";
|
||||||
"screen_share_open_apple_maps" = "Open in Apple Maps";
|
"screen_share_open_apple_maps" = "Open in Apple Maps";
|
||||||
|
|||||||
@@ -1408,6 +1408,7 @@
|
|||||||
"screen_session_verification_waiting_to_accept_title" = "Waiting to accept request";
|
"screen_session_verification_waiting_to_accept_title" = "Waiting to accept request";
|
||||||
"screen_share_location_live_location_disclaimer_title" = "Your live location history will be stored in the room and visible to members after the session ends.";
|
"screen_share_location_live_location_disclaimer_title" = "Your live location history will be stored in the room and visible to members after the session ends.";
|
||||||
"screen_share_location_live_location_duration_picker_title" = "Choose how long to share your live location.";
|
"screen_share_location_live_location_duration_picker_title" = "Choose how long to share your live location.";
|
||||||
|
"screen_share_location_live_location_missing_permissions" = "You do not have permissions to share your live location in this room";
|
||||||
"screen_share_location_title" = "Share location";
|
"screen_share_location_title" = "Share location";
|
||||||
"screen_share_my_location_action" = "Share my location";
|
"screen_share_my_location_action" = "Share my location";
|
||||||
"screen_share_open_apple_maps" = "Open in Apple Maps";
|
"screen_share_open_apple_maps" = "Open in Apple Maps";
|
||||||
|
|||||||
@@ -3265,6 +3265,8 @@ internal enum L10n {
|
|||||||
internal static var screenShareLocationLiveLocationDisclaimerTitle: String { return L10n.tr("Localizable", "screen_share_location_live_location_disclaimer_title") }
|
internal static var screenShareLocationLiveLocationDisclaimerTitle: String { return L10n.tr("Localizable", "screen_share_location_live_location_disclaimer_title") }
|
||||||
/// Choose how long to share your live location.
|
/// Choose how long to share your live location.
|
||||||
internal static var screenShareLocationLiveLocationDurationPickerTitle: String { return L10n.tr("Localizable", "screen_share_location_live_location_duration_picker_title") }
|
internal static var screenShareLocationLiveLocationDurationPickerTitle: String { return L10n.tr("Localizable", "screen_share_location_live_location_duration_picker_title") }
|
||||||
|
/// You do not have permissions to share your live location in this room
|
||||||
|
internal static var screenShareLocationLiveLocationMissingPermissions: String { return L10n.tr("Localizable", "screen_share_location_live_location_missing_permissions") }
|
||||||
/// Share location
|
/// Share location
|
||||||
internal static var screenShareLocationTitle: String { return L10n.tr("Localizable", "screen_share_location_title") }
|
internal static var screenShareLocationTitle: String { return L10n.tr("Localizable", "screen_share_location_title") }
|
||||||
/// Share my location
|
/// Share my location
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import MatrixRustSDK
|
|||||||
enum LocationSharingViewAlert: Hashable {
|
enum LocationSharingViewAlert: Hashable {
|
||||||
case missingAuthorization
|
case missingAuthorization
|
||||||
case missingAlwaysAuthorization
|
case missingAlwaysAuthorization
|
||||||
|
case missingLiveLocationSharingPermission
|
||||||
case liveLocationDisclaimer
|
case liveLocationDisclaimer
|
||||||
case liveLocationDurationSelection
|
case liveLocationDurationSelection
|
||||||
case mapError(MapLibreError)
|
case mapError(MapLibreError)
|
||||||
@@ -213,6 +214,10 @@ extension AlertInfo where T == LocationSharingViewAlert {
|
|||||||
message: L10n.dialogPermissionLiveLocationDescriptionIos(InfoPlistReader.main.bundleDisplayName),
|
message: L10n.dialogPermissionLiveLocationDescriptionIos(InfoPlistReader.main.bundleDisplayName),
|
||||||
primaryButton: primaryButton,
|
primaryButton: primaryButton,
|
||||||
secondaryButton: secondaryButton)
|
secondaryButton: secondaryButton)
|
||||||
|
case .missingLiveLocationSharingPermission:
|
||||||
|
self.init(id: alertID,
|
||||||
|
title: L10n.screenShareLocationLiveLocationMissingPermissions,
|
||||||
|
primaryButton: primaryButton)
|
||||||
case .liveLocationDisclaimer:
|
case .liveLocationDisclaimer:
|
||||||
self.init(id: alertID,
|
self.init(id: alertID,
|
||||||
title: L10n.screenShareLocationLiveLocationDisclaimerTitle,
|
title: L10n.screenShareLocationLiveLocationDisclaimerTitle,
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
|
|||||||
case .close:
|
case .close:
|
||||||
actionsSubject.send(.close)
|
actionsSubject.send(.close)
|
||||||
case .startLiveLocation:
|
case .startLiveLocation:
|
||||||
checkAlwaysShareLocationPermission()
|
startLiveLocation()
|
||||||
case .selectLocation:
|
case .selectLocation:
|
||||||
guard let coordinate = state.bindings.mapCenterLocation else { return }
|
guard let coordinate = state.bindings.mapCenterLocation else { return }
|
||||||
let uncertainty = state.isSharingUserLocation ? context.geolocationUncertainty : nil
|
let uncertainty = state.isSharingUserLocation ? context.geolocationUncertainty : nil
|
||||||
@@ -171,12 +171,16 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static let durationFormatter: DateComponentsFormatter = {
|
private func startLiveLocation() {
|
||||||
let formatter = DateComponentsFormatter()
|
guard let powerLevels = roomProxy.infoPublisher.value.powerLevels,
|
||||||
formatter.unitsStyle = .full
|
powerLevels.canOwnUser(sendStateEvent: .beaconInfo),
|
||||||
formatter.allowedUnits = [.hour, .minute]
|
powerLevels.canOwnUser(sendMessage: .beacon) else {
|
||||||
return formatter
|
state.bindings.alertInfo = .init(alertID: .missingLiveLocationSharingPermission)
|
||||||
}()
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
checkAlwaysShareLocationPermission()
|
||||||
|
}
|
||||||
|
|
||||||
private func checkAlwaysShareLocationPermission() {
|
private func checkAlwaysShareLocationPermission() {
|
||||||
authorizationStatusSubscription = nil
|
authorizationStatusSubscription = nil
|
||||||
@@ -231,6 +235,15 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// It's easier to achieve the format we want with a DateComponentsFormatter
|
||||||
|
/// than using the `.formatted` function of Duration.
|
||||||
|
private static let durationFormatter: DateComponentsFormatter = {
|
||||||
|
let formatter = DateComponentsFormatter()
|
||||||
|
formatter.unitsStyle = .full
|
||||||
|
formatter.allowedUnits = [.hour, .minute]
|
||||||
|
return formatter
|
||||||
|
}()
|
||||||
|
|
||||||
private func showLiveLocationDurationPicker() {
|
private func showLiveLocationDurationPicker() {
|
||||||
let durations: [Duration] = [.seconds(15 * 60), // 15 minutes
|
let durations: [Duration] = [.seconds(15 * 60), // 15 minutes
|
||||||
.seconds(60 * 60), // 1 hour
|
.seconds(60 * 60), // 1 hour
|
||||||
|
|||||||
@@ -172,6 +172,16 @@ struct LocationSharingScreenViewModelTests {
|
|||||||
#expect(context.viewState.isLocationLoading)
|
#expect(context.viewState.isLocationLoading)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Live Location Permission Tests
|
||||||
|
|
||||||
|
@Test
|
||||||
|
mutating func startLiveLocationWithoutPermission() {
|
||||||
|
setupViewModel(liveLocationManagerConfiguration: .init(authorizationStatus: .authorizedAlways),
|
||||||
|
members: .allMembers)
|
||||||
|
context.send(viewAction: .startLiveLocation)
|
||||||
|
#expect(context.alertInfo?.id == .missingLiveLocationSharingPermission)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Live Location Authorization Tests
|
// MARK: - Live Location Authorization Tests
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -415,11 +425,12 @@ struct LocationSharingScreenViewModelTests {
|
|||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private mutating func setupViewModel(liveLocationManagerConfiguration: LiveLocationManagerMock.Configuration = .init()) {
|
private mutating func setupViewModel(liveLocationManagerConfiguration: LiveLocationManagerMock.Configuration = .init(),
|
||||||
|
members: [RoomMemberProxyMock] = .allMembersAsAdmin) {
|
||||||
timelineProxy = TimelineProxyMock(.init())
|
timelineProxy = TimelineProxyMock(.init())
|
||||||
viewModel = LocationSharingScreenViewModel(interactionMode: .picker,
|
viewModel = LocationSharingScreenViewModel(interactionMode: .picker,
|
||||||
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
|
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
|
||||||
roomProxy: JoinedRoomProxyMock(.init()),
|
roomProxy: JoinedRoomProxyMock(.init(members: members)),
|
||||||
timelineController: MockTimelineController(timelineProxy: timelineProxy),
|
timelineController: MockTimelineController(timelineProxy: timelineProxy),
|
||||||
liveLocationManager: LiveLocationManagerMock(liveLocationManagerConfiguration),
|
liveLocationManager: LiveLocationManagerMock(liveLocationManagerConfiguration),
|
||||||
analytics: ServiceLocator.shared.analytics,
|
analytics: ServiceLocator.shared.analytics,
|
||||||
@@ -428,11 +439,12 @@ struct LocationSharingScreenViewModelTests {
|
|||||||
viewModel.state.bindings.isLocationAuthorized = true
|
viewModel.state.bindings.isLocationAuthorized = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private mutating func setupViewModel(liveLocationManagerMock: LiveLocationManagerMock) {
|
private mutating func setupViewModel(liveLocationManagerMock: LiveLocationManagerMock,
|
||||||
|
members: [RoomMemberProxyMock] = .allMembersAsAdmin) {
|
||||||
timelineProxy = TimelineProxyMock(.init())
|
timelineProxy = TimelineProxyMock(.init())
|
||||||
viewModel = LocationSharingScreenViewModel(interactionMode: .picker,
|
viewModel = LocationSharingScreenViewModel(interactionMode: .picker,
|
||||||
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
|
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
|
||||||
roomProxy: JoinedRoomProxyMock(.init()),
|
roomProxy: JoinedRoomProxyMock(.init(members: members)),
|
||||||
timelineController: MockTimelineController(timelineProxy: timelineProxy),
|
timelineController: MockTimelineController(timelineProxy: timelineProxy),
|
||||||
liveLocationManager: liveLocationManagerMock,
|
liveLocationManager: liveLocationManagerMock,
|
||||||
analytics: ServiceLocator.shared.analytics,
|
analytics: ServiceLocator.shared.analytics,
|
||||||
|
|||||||
Reference in New Issue
Block a user