diff --git a/Riot/Modules/LocationSharing/UserLocationServiceProvider.swift b/Riot/Modules/LocationSharing/UserLocationServiceProvider.swift new file mode 100644 index 000000000..007e745e2 --- /dev/null +++ b/Riot/Modules/LocationSharing/UserLocationServiceProvider.swift @@ -0,0 +1,140 @@ +// +// 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 BuildSettings.liveLocationSharingEnabled 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) + } +}