// // Copyright 2022 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 /// UserLocationServiceProvider enables to automatically store UserLocationService per user id and retrieve existing UserLocationService. /// Note: UserLocationService management is not set inside UserSessionsService at the moment to avoid to expose user location management to extension targets. class UserLocationServiceProvider { // MARK: - Constants static let shared = UserLocationServiceProvider() // MARK: - Properties private var locationServices: [String: UserLocationServiceProtocol] = [:] // MARK: - Setup private init() { guard RiotSettings.shared.enableLiveLocationSharing else { return } self.registerUserSessionsServiceNotifications() } // MARK: - Public func locationService(for userId: String) -> UserLocationServiceProtocol? { return self.locationServices[userId] } // MARK: - Private // MARK: Store private func addLocationService(_ userLocationService: UserLocationServiceProtocol, for userId: String) { self.locationServices[userId] = userLocationService } private func removeLocationService(for userId: String) { self.locationServices[userId] = nil } // MARK: UserLocationService setup private func setupUserLocationService(for userSession: UserSession) { self.tearDownUserLocationService(for: userSession.userId) let userLocationService = UserLocationService(session: userSession.matrixSession) self.addLocationService(userLocationService, for: userSession.userId) userLocationService.start() MXLog.debug("Start monitoring user live location sharing") } func setupUserLocationServiceIfNeeded(for userSession: UserSession) { // Be sure Matrix session has is store setup to access beacon info summaries guard userSession.matrixSession.state.rawValue >= MXSessionState.storeDataReady.rawValue else { return } let locationService = self.locationService(for: userSession.userId) guard locationService == nil else { return } self.setupUserLocationService(for: userSession) } private func tearDownUserLocationService(for userId: String) { guard let locationService = self.locationService(for: userId) else { return } locationService.stop() self.removeLocationService(for: userId) MXLog.debug("Stop monitoring user live location sharing") } // MARK: UserSessions management private func registerUserSessionsServiceNotifications() { NotificationCenter.default.addObserver(self, selector: #selector(userSessionsServiceDidAddUserSession(_:)), name: UserSessionsService.didAddUserSession, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(userSessionsServiceDidUpdateUserSession(_:)), name: UserSessionsService.userSessionDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(userSessionsServiceDidRemoveUserSession(_:)), name: UserSessionsService.didRemoveUserSession, object: nil) } @objc private func userSessionsServiceDidAddUserSession(_ notification: Notification) { guard let userInfo = notification.userInfo, let userSession = userInfo[UserSessionsService.NotificationUserInfoKey.userSession] as? UserSession else { return } self.setupUserLocationServiceIfNeeded(for: userSession) } @objc private func userSessionsServiceDidUpdateUserSession(_ notification: Notification) { guard let userInfo = notification.userInfo, let userSession = userInfo[UserSessionsService.NotificationUserInfoKey.userSession] as? UserSession else { return } self.setupUserLocationServiceIfNeeded(for: userSession) } @objc private func userSessionsServiceDidRemoveUserSession(_ notification: Notification) { guard let userInfo = notification.userInfo, let userId = userInfo[UserSessionsService.NotificationUserInfoKey.userId] as? String else { return } self.tearDownUserLocationService(for: userId) } }