stop showing live location disclaimer when accepted.

This commit is contained in:
Mauro Romito
2026-04-22 17:03:10 +02:00
committed by Mauro
parent 37d0863835
commit b1d82add91
6 changed files with 47 additions and 14 deletions

View File

@@ -65,8 +65,11 @@ final class AppSettings {
case elementCallBaseURLOverride
case voiceMessagePlaybackSpeed
// Live Location
case liveLocationSharingTimeoutDatesByRoomID
case liveLocationMinimumDistanceUpdate
case liveLocationDisclaimerDisplayed
// Feature flags
case publicSearchEnabled
@@ -347,14 +350,19 @@ final class AppSettings {
@UserPreference(key: UserDefaultsKeys.hasRequestedLocationAlwaysLocationAuthorization, defaultValue: false, storageType: .userDefaults(store))
var hasRequestedLocationAlwaysLocationAuthorization
@UserPreference(key: UserDefaultsKeys.frequentlyUsedSystemEmojis, defaultValue: [FrequentlyUsedEmoji](), storageType: .userDefaults(store))
var frequentlyUsedSystemEmojis
// MARK: - Live Location
@UserPreference(key: UserDefaultsKeys.liveLocationSharingTimeoutDatesByRoomID, defaultValue: [String: Date](), storageType: .userDefaults(store))
var liveLocationSharingTimeoutDatesByRoomID
@UserPreference(key: UserDefaultsKeys.liveLocationMinimumDistanceUpdate, defaultValue: 10, storageType: .userDefaults(store))
var liveLocationMinimumDistanceUpdate
@UserPreference(key: UserDefaultsKeys.frequentlyUsedSystemEmojis, defaultValue: [FrequentlyUsedEmoji](), storageType: .userDefaults(store))
var frequentlyUsedSystemEmojis
@UserPreference(key: UserDefaultsKeys.liveLocationDisclaimerDisplayed, defaultValue: false, storageType: .userDefaults(store))
var liveLocationDisclaimerDisplayed
// MARK: - Home Screen

View File

@@ -12041,6 +12041,11 @@ class LinkNewDeviceServiceMock: LinkNewDeviceServiceProtocol, @unchecked Sendabl
}
}
class LiveLocationManagerMock: LiveLocationManagerProtocol, @unchecked Sendable {
var hasDisplayedLiveLocationDisclaimer: Bool {
get { return underlyingHasDisplayedLiveLocationDisclaimer }
set(value) { underlyingHasDisplayedLiveLocationDisclaimer = value }
}
var underlyingHasDisplayedLiveLocationDisclaimer: Bool!
var authorizationStatus: CurrentValuePublisher<CLAuthorizationStatus, Never> {
get { return underlyingAuthorizationStatus }
set(value) { underlyingAuthorizationStatus = value }

View File

@@ -12,6 +12,7 @@ extension LiveLocationManagerMock {
struct Configuration {
var authorizationStatus: CLAuthorizationStatus = .notDetermined
var requestAlwaysAuthorizationIfPossibleReturnValue = true
var hasDisplayedLiveLocationDisclaimer = false
}
convenience init(_ configuration: Configuration) {
@@ -22,5 +23,7 @@ extension LiveLocationManagerMock {
requestAlwaysAuthorizationIfPossibleReturnValue = configuration.requestAlwaysAuthorizationIfPossibleReturnValue
startLiveLocationRoomIDDurationReturnValue = .success(())
underlyingHasDisplayedLiveLocationDisclaimer = configuration.hasDisplayedLiveLocationDisclaimer
}
}

View File

@@ -170,7 +170,7 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
let authorizationStatus = liveLocationManager.authorizationStatus.value
switch authorizationStatus {
case .authorizedAlways:
showLiveLocationDisclaimer()
showLiveLocationFlow()
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
@@ -193,23 +193,29 @@ 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 == .authorizedAlways else { return }
self?.showLiveLocationDisclaimer()
self?.showLiveLocationFlow()
}
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 showLiveLocationFlow() {
if liveLocationManager.hasDisplayedLiveLocationDisclaimer {
showLiveLocationDurationPicker()
} else {
state.bindings.alertInfo = .init(alertID: .liveLocationDisclaimer,
primaryButton: .init(title: L10n.actionDecline, role: .cancel, action: nil),
secondaryButton: .init(title: L10n.actionAccept) { [weak self] in
guard let self else { return }
liveLocationManager.hasDisplayedLiveLocationDisclaimer = true
// Delay so SwiftUI finishes dismissing the current alert
// before presenting the next one.
DispatchQueue.main.async {
self.showLiveLocationDurationPicker()
}
})
}
}
private func showLiveLocationDurationPicker() {

View File

@@ -58,6 +58,15 @@ class LiveLocationManager: NSObject, LiveLocationManagerProtocol, CLLocationMana
// MARK: - LiveLocationManagerProtocol
var hasDisplayedLiveLocationDisclaimer: Bool {
get {
appSettings.liveLocationDisclaimerDisplayed
}
set {
appSettings.liveLocationDisclaimerDisplayed = newValue
}
}
@discardableResult
func requestAlwaysAuthorizationIfPossible() -> Bool {
guard !appSettings.hasRequestedLocationAlwaysLocationAuthorization else { return false }

View File

@@ -16,6 +16,8 @@ enum LiveLocationManagerError: Error {
// sourcery: AutoMockable
protocol LiveLocationManagerProtocol: AnyObject {
/// True if the live location disclaimer has been displayed already, will only be displayed once.
var hasDisplayedLiveLocationDisclaimer: Bool { get set }
/// Publishes the current location authorization status.
var authorizationStatus: CurrentValuePublisher<CLAuthorizationStatus, Never> { get }