implement the start live location handling in the LocationSharingScreenViewModel
This commit is contained in:
@@ -680,6 +680,13 @@
|
||||
"screen_media_upload_preview_item_count" = "Item %1$d of %2$d";
|
||||
"screen_media_upload_preview_optimize_image_quality_title" = "Optimize image quality";
|
||||
"screen_media_upload_preview_processing" = "Processing...";
|
||||
"screen_missing_key_backup_open_element_classic" = "Open Element Classic";
|
||||
"screen_missing_key_backup_step_1" = "Open Element Classic on your device";
|
||||
"screen_missing_key_backup_step_2" = "Go to \"Settings\" > \"Security &Privacy\"";
|
||||
"screen_missing_key_backup_step_3" = "In the section \"Cryptography Keys Management\", click on \"Encrypted Messages Recovery\"";
|
||||
"screen_missing_key_backup_step_4" = "Follow instructions";
|
||||
"screen_missing_key_backup_step_5" = "Done!";
|
||||
"screen_missing_key_backup_title" = "We need you to enable your key storage before processing to %1$@";
|
||||
"screen_onboarding_welcome_back" = "Welcome back";
|
||||
"screen_pinned_timeline_empty_state_description" = "Press on a message and choose “%1$@” to include here.";
|
||||
"screen_pinned_timeline_empty_state_headline" = "Pin important messages so that they can be easily discovered";
|
||||
@@ -758,6 +765,7 @@
|
||||
"screen_security_and_privacy_room_visibility_section_footer" = "Addresses are a way to find and access rooms and spaces. This also ensures you can easily share them with others.";
|
||||
"screen_security_and_privacy_room_visibility_section_header" = "Visibility";
|
||||
"screen_security_and_privacy_title" = "Security & privacy";
|
||||
"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_sharing_location_option_sheet_title" = "Sharing options";
|
||||
"screen_space_add_room_action" = "Room";
|
||||
|
||||
@@ -680,6 +680,13 @@
|
||||
"screen_media_upload_preview_item_count" = "Item %1$d of %2$d";
|
||||
"screen_media_upload_preview_optimize_image_quality_title" = "Optimise image quality";
|
||||
"screen_media_upload_preview_processing" = "Processing...";
|
||||
"screen_missing_key_backup_open_element_classic" = "Open Element Classic";
|
||||
"screen_missing_key_backup_step_1" = "Open Element Classic on your device";
|
||||
"screen_missing_key_backup_step_2" = "Go to \"Settings\" > \"Security &Privacy\"";
|
||||
"screen_missing_key_backup_step_3" = "In the section \"Cryptography Keys Management\", click on \"Encrypted Messages Recovery\"";
|
||||
"screen_missing_key_backup_step_4" = "Follow instructions";
|
||||
"screen_missing_key_backup_step_5" = "Done!";
|
||||
"screen_missing_key_backup_title" = "We need you to enable your key storage before processing to %1$@";
|
||||
"screen_onboarding_welcome_back" = "Welcome back";
|
||||
"screen_pinned_timeline_empty_state_description" = "Press on a message and choose “%1$@” to include here.";
|
||||
"screen_pinned_timeline_empty_state_headline" = "Pin important messages so that they can be easily discovered";
|
||||
@@ -758,6 +765,7 @@
|
||||
"screen_security_and_privacy_room_visibility_section_footer" = "Addresses are a way to find and access rooms and spaces. This also ensures you can easily share them with others.";
|
||||
"screen_security_and_privacy_room_visibility_section_header" = "Visibility";
|
||||
"screen_security_and_privacy_title" = "Security & privacy";
|
||||
"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_sharing_location_option_sheet_title" = "Sharing options";
|
||||
"screen_space_add_room_action" = "Room";
|
||||
|
||||
@@ -2200,6 +2200,22 @@ internal enum L10n {
|
||||
internal static var screenMigrationMessage: String { return L10n.tr("Localizable", "screen_migration_message") }
|
||||
/// Setting up your account.
|
||||
internal static var screenMigrationTitle: String { return L10n.tr("Localizable", "screen_migration_title") }
|
||||
/// Open Element Classic
|
||||
internal static var screenMissingKeyBackupOpenElementClassic: String { return L10n.tr("Localizable", "screen_missing_key_backup_open_element_classic") }
|
||||
/// Open Element Classic on your device
|
||||
internal static var screenMissingKeyBackupStep1: String { return L10n.tr("Localizable", "screen_missing_key_backup_step_1") }
|
||||
/// Go to "Settings" > "Security &Privacy"
|
||||
internal static var screenMissingKeyBackupStep2: String { return L10n.tr("Localizable", "screen_missing_key_backup_step_2") }
|
||||
/// In the section "Cryptography Keys Management", click on "Encrypted Messages Recovery"
|
||||
internal static var screenMissingKeyBackupStep3: String { return L10n.tr("Localizable", "screen_missing_key_backup_step_3") }
|
||||
/// Follow instructions
|
||||
internal static var screenMissingKeyBackupStep4: String { return L10n.tr("Localizable", "screen_missing_key_backup_step_4") }
|
||||
/// Done!
|
||||
internal static var screenMissingKeyBackupStep5: String { return L10n.tr("Localizable", "screen_missing_key_backup_step_5") }
|
||||
/// We need you to enable your key storage before processing to %1$@
|
||||
internal static func screenMissingKeyBackupTitle(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "screen_missing_key_backup_title", String(describing: p1))
|
||||
}
|
||||
/// You can change your settings later.
|
||||
internal static var screenNotificationOptinSubtitle: String { return L10n.tr("Localizable", "screen_notification_optin_subtitle") }
|
||||
/// Allow notifications and never miss a message
|
||||
@@ -3183,6 +3199,8 @@ internal enum L10n {
|
||||
internal static var screenSessionVerificationWaitingToAcceptSubtitle: String { return L10n.tr("Localizable", "screen_session_verification_waiting_to_accept_subtitle") }
|
||||
/// Waiting to accept request
|
||||
internal static var screenSessionVerificationWaitingToAcceptTitle: String { return L10n.tr("Localizable", "screen_session_verification_waiting_to_accept_title") }
|
||||
/// Your live location history will be stored in the room and visible to members after the session ends.
|
||||
internal static var screenShareLocationLiveLocationDisclaimerTitle: String { return L10n.tr("Localizable", "screen_share_location_live_location_disclaimer_title") }
|
||||
/// 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") }
|
||||
/// Share location
|
||||
|
||||
@@ -10,9 +10,11 @@ import CoreLocation
|
||||
import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
enum LocationSharingViewError: Error, Hashable {
|
||||
enum LocationSharingViewAlert: Hashable {
|
||||
case missingAuthorization
|
||||
case missingAlwaysAuthorization
|
||||
case liveLocationDisclaimer
|
||||
case liveLocationDurationSelection
|
||||
case mapError(MapLibreError)
|
||||
}
|
||||
|
||||
@@ -130,12 +132,12 @@ struct LocationSharingScreenBindings {
|
||||
return nil
|
||||
}
|
||||
set {
|
||||
alertInfo = newValue.map { AlertInfo(locationSharingViewError: .mapError($0)) }
|
||||
alertInfo = newValue.map { AlertInfo(alertID: .mapError($0)) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Information describing the currently displayed alert.
|
||||
var alertInfo: AlertInfo<LocationSharingViewError>?
|
||||
var alertInfo: AlertInfo<LocationSharingViewAlert>?
|
||||
|
||||
var showShareSheet = false
|
||||
}
|
||||
@@ -148,30 +150,42 @@ enum LocationSharingScreenViewAction {
|
||||
case userDidPan
|
||||
}
|
||||
|
||||
extension AlertInfo where T == LocationSharingViewError {
|
||||
init(locationSharingViewError error: LocationSharingViewError,
|
||||
extension AlertInfo where T == LocationSharingViewAlert {
|
||||
init(alertID: LocationSharingViewAlert,
|
||||
primaryButton: AlertButton = AlertButton(title: L10n.actionOk, action: nil),
|
||||
secondaryButton: AlertButton? = nil) {
|
||||
switch error {
|
||||
secondaryButton: AlertButton? = nil,
|
||||
verticalButtons: [AlertButton]? = nil) {
|
||||
switch alertID {
|
||||
case .missingAuthorization:
|
||||
self.init(id: error,
|
||||
self.init(id: alertID,
|
||||
title: L10n.dialogAllowAccess,
|
||||
message: L10n.dialogPermissionLocationDescriptionIos(InfoPlistReader.main.bundleDisplayName),
|
||||
primaryButton: primaryButton,
|
||||
secondaryButton: secondaryButton)
|
||||
case .missingAlwaysAuthorization:
|
||||
self.init(id: error,
|
||||
self.init(id: alertID,
|
||||
title: L10n.dialogAllowAccess,
|
||||
message: L10n.dialogPermissionLiveLocationDescriptionIos(InfoPlistReader.main.bundleDisplayName),
|
||||
primaryButton: primaryButton,
|
||||
secondaryButton: secondaryButton)
|
||||
case .liveLocationDisclaimer:
|
||||
self.init(id: alertID,
|
||||
title: L10n.screenShareLocationLiveLocationDisclaimerTitle,
|
||||
primaryButton: primaryButton,
|
||||
secondaryButton: secondaryButton)
|
||||
case .liveLocationDurationSelection:
|
||||
self.init(id: alertID,
|
||||
title: L10n.screenShareLocationLiveLocationDurationPickerTitle,
|
||||
primaryButton: primaryButton,
|
||||
secondaryButton: nil,
|
||||
verticalButtons: verticalButtons)
|
||||
case .mapError(.failedLoadingMap):
|
||||
self.init(id: error,
|
||||
self.init(id: alertID,
|
||||
title: L10n.errorFailedLoadingMap(InfoPlistReader.main.bundleDisplayName),
|
||||
primaryButton: primaryButton,
|
||||
secondaryButton: secondaryButton)
|
||||
case .mapError(.failedLocatingUser):
|
||||
self.init(id: error,
|
||||
self.init(id: alertID,
|
||||
title: L10n.errorFailedLocatingUser(InfoPlistReader.main.bundleDisplayName),
|
||||
primaryButton: primaryButton,
|
||||
secondaryButton: secondaryButton)
|
||||
|
||||
@@ -72,7 +72,7 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
|
||||
state.bindings.showsUserLocationMode = .showAndFollow
|
||||
case .some(false):
|
||||
let action: () -> Void = { [weak self] in self?.actionsSubject.send(.openSystemSettings) }
|
||||
state.bindings.alertInfo = .init(locationSharingViewError: .missingAuthorization,
|
||||
state.bindings.alertInfo = .init(alertID: .missingAuthorization,
|
||||
primaryButton: .init(title: L10n.actionNotNow, role: .cancel, action: nil),
|
||||
secondaryButton: .init(title: L10n.commonSettings, action: action))
|
||||
}
|
||||
@@ -112,13 +112,23 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
|
||||
}
|
||||
}
|
||||
|
||||
private static let durationFormatter: DateComponentsFormatter = {
|
||||
let formatter = DateComponentsFormatter()
|
||||
formatter.unitsStyle = .full
|
||||
formatter.allowedUnits = [.hour, .minute]
|
||||
return formatter
|
||||
}()
|
||||
|
||||
private func startLiveLocationSharing() {
|
||||
requestAlwaysLocationPermission()
|
||||
}
|
||||
|
||||
private func requestAlwaysLocationPermission() {
|
||||
authorizationStatusSubscription = nil
|
||||
let authorizationStatus = liveLocationManager.authorizationStatus.value
|
||||
switch authorizationStatus {
|
||||
case .authorizedAlways:
|
||||
// TODO: Start sending live location updates to the room
|
||||
break
|
||||
showLiveLocationDisclaimer()
|
||||
case .notDetermined:
|
||||
// This is to solve a race condition with map libre which always tries first
|
||||
// to request the when in use permission, we wait for it and then try again
|
||||
@@ -127,7 +137,7 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
|
||||
.first() // this publisher only fires when there is an actual change, and if the user is done with permissions
|
||||
.sink { [weak self] newValue in
|
||||
guard newValue == .authorizedWhenInUse else { return }
|
||||
self?.startLiveLocationSharing()
|
||||
self?.requestAlwaysLocationPermission()
|
||||
}
|
||||
case .authorizedWhenInUse:
|
||||
guard liveLocationManager.requestAlwaysAuthorizationIfPossible() else {
|
||||
@@ -139,17 +149,59 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
|
||||
authorizationStatusSubscription = liveLocationManager.authorizationStatus
|
||||
.filter { $0 != authorizationStatus } // skip current status
|
||||
.first() // this publisher only fires when there is an actual change, and if the user is done with permissions
|
||||
.sink { newValue in
|
||||
.sink { [weak self] newValue in
|
||||
guard newValue == .authorizedAlways else { return }
|
||||
// TODO: Start sending live location updates to the room
|
||||
self?.showLiveLocationDisclaimer()
|
||||
}
|
||||
default:
|
||||
showMissingAlwaysAuthorizedAlert()
|
||||
}
|
||||
}
|
||||
|
||||
private func showLiveLocationDisclaimer() {
|
||||
state.bindings.alertInfo = .init(alertID: .liveLocationDisclaimer,
|
||||
primaryButton: .init(title: L10n.actionDecline, role: .cancel, action: nil),
|
||||
secondaryButton: .init(title: L10n.actionAccept) { [weak self] in
|
||||
// Delay so SwiftUI finishes dismissing the current alert
|
||||
// before presenting the next one.
|
||||
DispatchQueue.main.async {
|
||||
self?.showLiveLocationDurationPicker()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private func showLiveLocationDurationPicker() {
|
||||
let durations: [TimeInterval] = [15 * 60, // 15 minutes
|
||||
60 * 60, // 1 hour
|
||||
8 * 60 * 60] // 8 hours
|
||||
|
||||
let durationButtons: [AlertInfo<LocationSharingViewAlert>.AlertButton] = durations.compactMap { duration in
|
||||
guard let title = Self.durationFormatter.string(from: duration) else { return nil }
|
||||
return .init(title: title) { [weak self] in
|
||||
Task { [weak self] in await self?.startLiveLocationSharingInRoom(durationMillis: UInt64(duration * 1000)) }
|
||||
}
|
||||
}
|
||||
|
||||
state.bindings.alertInfo = .init(alertID: .liveLocationDurationSelection,
|
||||
primaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil),
|
||||
verticalButtons: durationButtons)
|
||||
}
|
||||
|
||||
private func startLiveLocationSharingInRoom(durationMillis: UInt64) async {
|
||||
let result = await liveLocationManager.startLiveLocation(roomID: roomProxy.id,
|
||||
durationMillis: durationMillis)
|
||||
|
||||
switch result {
|
||||
case .success:
|
||||
actionsSubject.send(.close)
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed to start live location sharing: \(error)")
|
||||
showErrorIndicator()
|
||||
}
|
||||
}
|
||||
|
||||
private func showMissingAlwaysAuthorizedAlert() {
|
||||
state.bindings.alertInfo = .init(locationSharingViewError: .missingAlwaysAuthorization,
|
||||
state.bindings.alertInfo = .init(alertID: .missingAlwaysAuthorization,
|
||||
primaryButton: .init(title: L10n.actionNotNow, role: .cancel, action: nil),
|
||||
secondaryButton: .init(title: L10n.commonSettings) { [weak self] in self?.actionsSubject.send(.openSystemSettings) })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user