mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Cleanup following the AppMediator introduction (#2723)
- stop using multiple background task, the appCoordinator sync one is enough for the whole app - move the AppMeditor to the MainActor - expose the WindowManager through the AppMediator - hide sensitive WindowManager API behind a different protocol - remove the now unnecessary `BackgroundTaskService`
This commit is contained in:
@@ -20,7 +20,7 @@ import MatrixRustSDK
|
||||
import SwiftUI
|
||||
import Version
|
||||
|
||||
class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDelegate, NotificationManagerDelegate, WindowManagerDelegate {
|
||||
class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDelegate, NotificationManagerDelegate, SecureWindowManagerDelegate {
|
||||
private let stateMachine: AppCoordinatorStateMachine
|
||||
private let navigationRootCoordinator: NavigationRootCoordinator
|
||||
private let userSessionStore: UserSessionStoreProtocol
|
||||
@@ -29,7 +29,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
private let appDelegate: AppDelegate
|
||||
|
||||
/// Common background task to continue long-running tasks in the background.
|
||||
private var backgroundTask: BackgroundTaskProtocol?
|
||||
private var backgroundTask: UIBackgroundTaskIdentifier?
|
||||
|
||||
private var isSuspended = false
|
||||
|
||||
@@ -50,15 +50,12 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
private var appLockSetupFlowCoordinator: AppLockSetupFlowCoordinator?
|
||||
private var userSessionFlowCoordinator: UserSessionFlowCoordinator?
|
||||
private var softLogoutCoordinator: SoftLogoutScreenCoordinator?
|
||||
|
||||
private let backgroundTaskService: BackgroundTaskServiceProtocol
|
||||
|
||||
private var appDelegateObserver: AnyCancellable?
|
||||
private var userSessionObserver: AnyCancellable?
|
||||
private var clientProxyObserver: AnyCancellable?
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
let windowManager: WindowManagerProtocol
|
||||
let windowManager: SecureWindowManagerProtocol
|
||||
let notificationManager: NotificationManagerProtocol
|
||||
|
||||
private let appRouteURLParser: AppRouteURLParser
|
||||
@@ -103,12 +100,9 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
|
||||
navigationRootCoordinator.setRootCoordinator(SplashScreenCoordinator())
|
||||
|
||||
backgroundTaskService = UIKitBackgroundTaskService(appMediator: appMediator)
|
||||
|
||||
let keychainController = KeychainController(service: .sessions,
|
||||
accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier)
|
||||
userSessionStore = UserSessionStore(keychainController: keychainController,
|
||||
backgroundTaskService: backgroundTaskService)
|
||||
userSessionStore = UserSessionStore(keychainController: keychainController)
|
||||
|
||||
let appLockService = AppLockService(keychainController: keychainController, appSettings: appSettings)
|
||||
let appLockNavigationCoordinator = NavigationRootCoordinator()
|
||||
@@ -227,7 +221,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
|
||||
// MARK: - WindowManagerDelegate
|
||||
|
||||
func windowManagerDidConfigureWindows(_ windowManager: WindowManagerProtocol) {
|
||||
func windowManagerDidConfigureWindows(_ windowManager: SecureWindowManagerProtocol) {
|
||||
windowManager.alternateWindow.rootViewController = UIHostingController(rootView: appLockFlowCoordinator.toPresentable())
|
||||
ServiceLocator.shared.userIndicatorController.window = windowManager.overlayWindow
|
||||
}
|
||||
@@ -413,8 +407,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
appMediator: appMediator,
|
||||
appSettings: appSettings,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
orientationManager: windowManager)
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
authenticationFlowCoordinator?.delegate = self
|
||||
|
||||
authenticationFlowCoordinator?.start()
|
||||
@@ -469,7 +462,6 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
|
||||
let userSessionFlowCoordinator = UserSessionFlowCoordinator(userSession: userSession,
|
||||
navigationRootCoordinator: navigationRootCoordinator,
|
||||
windowManager: windowManager,
|
||||
appLockService: appLockFlowCoordinator.appLockService,
|
||||
bugReportService: ServiceLocator.shared.bugReportService,
|
||||
roomTimelineControllerFactory: RoomTimelineControllerFactory(),
|
||||
@@ -770,14 +762,16 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
guard backgroundTask == nil else {
|
||||
return
|
||||
}
|
||||
|
||||
backgroundTask = backgroundTaskService.startBackgroundTask(withName: "SuspendApp: \(UUID().uuidString)") { [weak self] in
|
||||
|
||||
backgroundTask = appMediator.beginBackgroundTask { [weak self] in
|
||||
guard let self else { return }
|
||||
|
||||
stopSync()
|
||||
|
||||
backgroundTask?.stop()
|
||||
backgroundTask = nil
|
||||
if let backgroundTask {
|
||||
appMediator.endBackgroundTask(backgroundTask)
|
||||
self.backgroundTask = nil
|
||||
}
|
||||
}
|
||||
|
||||
isSuspended = true
|
||||
@@ -791,8 +785,10 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
private func applicationDidBecomeActive() {
|
||||
MXLog.info("Application did become active")
|
||||
|
||||
backgroundTask?.stop()
|
||||
backgroundTask = nil
|
||||
if let backgroundTask {
|
||||
appMediator.endBackgroundTask(backgroundTask)
|
||||
self.backgroundTask = nil
|
||||
}
|
||||
|
||||
if isSuspended {
|
||||
startSync()
|
||||
|
||||
@@ -17,6 +17,6 @@
|
||||
import Foundation
|
||||
|
||||
protocol AppCoordinatorProtocol: CoordinatorProtocol {
|
||||
var windowManager: WindowManagerProtocol { get }
|
||||
var windowManager: SecureWindowManagerProtocol { get }
|
||||
@discardableResult func handleDeepLink(_ url: URL, isExternalURL: Bool) -> Bool
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import UIKit
|
||||
|
||||
class AppMediator: AppMediatorProtocol {
|
||||
private let windowManager: WindowManagerProtocol
|
||||
let windowManager: WindowManagerProtocol
|
||||
|
||||
init(windowManager: WindowManagerProtocol) {
|
||||
self.windowManager = windowManager
|
||||
@@ -28,7 +28,6 @@ class AppMediator: AppMediatorProtocol {
|
||||
UIApplication.shared
|
||||
}
|
||||
|
||||
@MainActor
|
||||
var appState: UIApplication.State {
|
||||
switch application.applicationState {
|
||||
case .active:
|
||||
@@ -42,12 +41,8 @@ class AppMediator: AppMediatorProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
var backgroundTimeRemaining: TimeInterval {
|
||||
application.backgroundTimeRemaining
|
||||
}
|
||||
|
||||
func beginBackgroundTask(withName taskName: String?, expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier {
|
||||
application.beginBackgroundTask(withName: taskName, expirationHandler: handler)
|
||||
func beginBackgroundTask(expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier {
|
||||
application.beginBackgroundTask(expirationHandler: handler)
|
||||
}
|
||||
|
||||
func endBackgroundTask(_ identifier: UIBackgroundTaskIdentifier) {
|
||||
|
||||
@@ -18,12 +18,13 @@ import Foundation
|
||||
import UIKit
|
||||
|
||||
// sourcery: AutoMockable
|
||||
@MainActor
|
||||
protocol AppMediatorProtocol {
|
||||
var windowManager: WindowManagerProtocol { get }
|
||||
|
||||
var appState: UIApplication.State { get }
|
||||
|
||||
var backgroundTimeRemaining: TimeInterval { get }
|
||||
|
||||
func beginBackgroundTask(withName taskName: String?, expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier
|
||||
func beginBackgroundTask(expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier
|
||||
|
||||
func endBackgroundTask(_ identifier: UIBackgroundTaskIdentifier)
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import SwiftUI
|
||||
///
|
||||
/// We don't support multiple scenes right now, so the implementation is pretty basic.
|
||||
class SceneDelegate: NSObject, UIWindowSceneDelegate {
|
||||
weak static var windowManager: WindowManagerProtocol!
|
||||
weak static var windowManager: SecureWindowManagerProtocol!
|
||||
|
||||
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
|
||||
guard let windowScene = scene as? UIWindowScene else { return }
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
class WindowManager: WindowManagerProtocol {
|
||||
class WindowManager: SecureWindowManagerProtocol {
|
||||
private let appDelegate: AppDelegate
|
||||
weak var windowScene: UIWindowScene?
|
||||
weak var delegate: WindowManagerDelegate?
|
||||
weak var delegate: SecureWindowManagerDelegate?
|
||||
|
||||
private(set) var mainWindow: UIWindow!
|
||||
private(set) var overlayWindow: UIWindow!
|
||||
|
||||
@@ -16,18 +16,29 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
protocol WindowManagerDelegate: AnyObject {
|
||||
protocol SecureWindowManagerDelegate: AnyObject {
|
||||
/// The window manager has configured its windows.
|
||||
func windowManagerDidConfigureWindows(_ windowManager: WindowManagerProtocol)
|
||||
func windowManagerDidConfigureWindows(_ windowManager: SecureWindowManagerProtocol)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
protocol SecureWindowManagerProtocol: WindowManagerProtocol {
|
||||
var delegate: SecureWindowManagerDelegate? { get set }
|
||||
|
||||
/// Configures the window manager to operate on the supplied scene.
|
||||
func configure(with windowScene: UIWindowScene)
|
||||
|
||||
/// Shows the main and overlay window combo, hiding the alternate window.
|
||||
func switchToMain()
|
||||
|
||||
/// Shows the alternate window, hiding the main and overlay combo.
|
||||
func switchToAlternate()
|
||||
}
|
||||
|
||||
/// A window manager that supports switching between a main app window with an overlay and
|
||||
/// an alternate window to switch contexts whilst also preserving the main view hierarchy.
|
||||
/// Heavily inspired by https://www.fivestars.blog/articles/swiftui-windows/
|
||||
protocol WindowManagerProtocol: AnyObject, OrientationManagerProtocol {
|
||||
var delegate: WindowManagerDelegate? { get set }
|
||||
|
||||
/// The app's main window (we only support a single scene).
|
||||
var mainWindow: UIWindow! { get }
|
||||
/// Presented on top of the main window, to display e.g. user indicators.
|
||||
@@ -40,15 +51,6 @@ protocol WindowManagerProtocol: AnyObject, OrientationManagerProtocol {
|
||||
/// All the windows being managed
|
||||
var windows: [UIWindow] { get }
|
||||
|
||||
/// Configures the window manager to operate on the supplied scene.
|
||||
func configure(with windowScene: UIWindowScene)
|
||||
|
||||
/// Shows the main and overlay window combo, hiding the alternate window.
|
||||
func switchToMain()
|
||||
|
||||
/// Shows the alternate window, hiding the main and overlay combo.
|
||||
func switchToAlternate()
|
||||
|
||||
/// Makes the global search window key. Used to get automatic text field focus.
|
||||
func showGlobalSearch()
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol {
|
||||
private let appSettings: AppSettings
|
||||
private let analytics: AnalyticsService
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
private let orientationManager: OrientationManagerProtocol
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
@@ -48,8 +47,7 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol {
|
||||
appMediator: AppMediatorProtocol,
|
||||
appSettings: AppSettings,
|
||||
analytics: AnalyticsService,
|
||||
userIndicatorController: UserIndicatorControllerProtocol,
|
||||
orientationManager: WindowManagerProtocol) {
|
||||
userIndicatorController: UserIndicatorControllerProtocol) {
|
||||
self.authenticationService = authenticationService
|
||||
self.bugReportService = bugReportService
|
||||
self.navigationRootCoordinator = navigationRootCoordinator
|
||||
@@ -57,7 +55,6 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol {
|
||||
self.appSettings = appSettings
|
||||
self.analytics = analytics
|
||||
self.userIndicatorController = userIndicatorController
|
||||
self.orientationManager = orientationManager
|
||||
|
||||
navigationStackCoordinator = NavigationStackCoordinator()
|
||||
}
|
||||
@@ -110,7 +107,7 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
private func startQRCodeLogin() {
|
||||
let coordinator = QRCodeLoginScreenCoordinator(parameters: .init(qrCodeLoginService: QRCodeLoginService(),
|
||||
orientationManager: orientationManager,
|
||||
orientationManager: appMediator.windowManager,
|
||||
appMediator: appMediator))
|
||||
coordinator.actionsPublisher.sink { [weak self] action in
|
||||
guard let self else {
|
||||
|
||||
@@ -50,7 +50,6 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
private let appSettings: AppSettings
|
||||
private let analytics: AnalyticsService
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
private let orientationManager: OrientationManagerProtocol
|
||||
|
||||
private var roomProxy: RoomProxyProtocol!
|
||||
|
||||
@@ -81,8 +80,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
appMediator: AppMediatorProtocol,
|
||||
appSettings: AppSettings,
|
||||
analytics: AnalyticsService,
|
||||
userIndicatorController: UserIndicatorControllerProtocol,
|
||||
orientationManager: OrientationManagerProtocol) async {
|
||||
userIndicatorController: UserIndicatorControllerProtocol) async {
|
||||
self.roomID = roomID
|
||||
self.userSession = userSession
|
||||
self.isChildFlow = isChildFlow
|
||||
@@ -93,7 +91,6 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
self.appSettings = appSettings
|
||||
self.analytics = analytics
|
||||
self.userIndicatorController = userIndicatorController
|
||||
self.orientationManager = orientationManager
|
||||
|
||||
setupStateMachine()
|
||||
|
||||
@@ -695,7 +692,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
mediaProvider: userSession.mediaProvider,
|
||||
navigationStackCoordinator: stackCoordinator,
|
||||
userIndicatorController: userIndicatorController,
|
||||
orientationManager: orientationManager)
|
||||
orientationManager: appMediator.windowManager)
|
||||
let roomDetailsEditCoordinator = RoomDetailsEditScreenCoordinator(parameters: roomDetailsEditParameters)
|
||||
|
||||
roomDetailsEditCoordinator.actions.sink { [weak self] action in
|
||||
@@ -752,7 +749,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
let mediaPickerCoordinator = MediaPickerScreenCoordinator(userIndicatorController: userIndicatorController,
|
||||
source: source,
|
||||
orientationManager: orientationManager) { [weak self] action in
|
||||
orientationManager: appMediator.windowManager) { [weak self] action in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@@ -1239,8 +1236,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
appMediator: appMediator,
|
||||
appSettings: appSettings,
|
||||
analytics: analytics,
|
||||
userIndicatorController: userIndicatorController,
|
||||
orientationManager: orientationManager)
|
||||
userIndicatorController: userIndicatorController)
|
||||
coordinator.actions.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
private let userSession: UserSessionProtocol
|
||||
private let navigationRootCoordinator: NavigationRootCoordinator
|
||||
private let navigationSplitCoordinator: NavigationSplitCoordinator
|
||||
private let windowManager: WindowManagerProtocol
|
||||
private let bugReportService: BugReportServiceProtocol
|
||||
private let appMediator: AppMediatorProtocol
|
||||
private let appSettings: AppSettings
|
||||
@@ -68,7 +67,6 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
init(userSession: UserSessionProtocol,
|
||||
navigationRootCoordinator: NavigationRootCoordinator,
|
||||
windowManager: WindowManagerProtocol,
|
||||
appLockService: AppLockServiceProtocol,
|
||||
bugReportService: BugReportServiceProtocol,
|
||||
roomTimelineControllerFactory: RoomTimelineControllerFactoryProtocol,
|
||||
@@ -80,7 +78,6 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
stateMachine = UserSessionFlowCoordinatorStateMachine()
|
||||
self.userSession = userSession
|
||||
self.navigationRootCoordinator = navigationRootCoordinator
|
||||
self.windowManager = windowManager
|
||||
self.bugReportService = bugReportService
|
||||
self.roomTimelineControllerFactory = roomTimelineControllerFactory
|
||||
self.appMediator = appMediator
|
||||
@@ -96,7 +93,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
navigationSplitCoordinator.setSidebarCoordinator(sidebarNavigationStackCoordinator)
|
||||
|
||||
settingsFlowCoordinator = SettingsFlowCoordinator(parameters: .init(userSession: userSession,
|
||||
windowManager: windowManager,
|
||||
windowManager: appMediator.windowManager,
|
||||
appLockService: appLockService,
|
||||
bugReportService: bugReportService,
|
||||
notificationSettings: userSession.clientProxy.notificationSettings,
|
||||
@@ -427,8 +424,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
appMediator: appMediator,
|
||||
appSettings: appSettings,
|
||||
analytics: analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
orientationManager: windowManager)
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
|
||||
coordinator.actions.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
@@ -480,7 +476,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
let startChatNavigationStackCoordinator = NavigationStackCoordinator()
|
||||
|
||||
let userDiscoveryService = UserDiscoveryService(clientProxy: userSession.clientProxy)
|
||||
let parameters = StartChatScreenCoordinatorParameters(orientationManager: windowManager,
|
||||
let parameters = StartChatScreenCoordinatorParameters(orientationManager: appMediator.windowManager,
|
||||
userSession: userSession,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
navigationStackCoordinator: startChatNavigationStackCoordinator,
|
||||
@@ -609,14 +605,14 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
let hostingController = UIHostingController(rootView: coordinator.toPresentable())
|
||||
hostingController.view.backgroundColor = .clear
|
||||
windowManager.globalSearchWindow.rootViewController = hostingController
|
||||
appMediator.windowManager.globalSearchWindow.rootViewController = hostingController
|
||||
|
||||
windowManager.showGlobalSearch()
|
||||
appMediator.windowManager.showGlobalSearch()
|
||||
}
|
||||
|
||||
private func dismissGlobalSearch() {
|
||||
windowManager.globalSearchWindow.rootViewController = nil
|
||||
windowManager.hideGlobalSearch()
|
||||
appMediator.windowManager.globalSearchWindow.rootViewController = nil
|
||||
appMediator.windowManager.hideGlobalSearch()
|
||||
|
||||
globalSearchScreenCoordinator = nil
|
||||
}
|
||||
|
||||
@@ -18,44 +18,11 @@ import UIKit
|
||||
|
||||
extension AppMediatorMock {
|
||||
static var `default`: AppMediatorProtocol {
|
||||
AppMediatorMock(withState: .active,
|
||||
backgroundTimeRemaining: 10,
|
||||
allowTasks: true)
|
||||
}
|
||||
|
||||
static var mockBroken: AppMediatorProtocol {
|
||||
AppMediatorMock(withState: .inactive,
|
||||
backgroundTimeRemaining: 0,
|
||||
allowTasks: false)
|
||||
}
|
||||
|
||||
static var mockAboutToSuspend: AppMediatorProtocol {
|
||||
AppMediatorMock(withState: .background,
|
||||
backgroundTimeRemaining: 2,
|
||||
allowTasks: false)
|
||||
}
|
||||
|
||||
private static var bgTaskIdentifier = 0
|
||||
|
||||
convenience init(withState applicationState: UIApplication.State,
|
||||
backgroundTimeRemaining: TimeInterval,
|
||||
allowTasks: Bool) {
|
||||
self.init()
|
||||
let mock = AppMediatorMock()
|
||||
|
||||
underlyingAppState = applicationState
|
||||
underlyingBackgroundTimeRemaining = backgroundTimeRemaining
|
||||
mock.underlyingAppState = .active
|
||||
mock.underlyingWindowManager = WindowManagerMock()
|
||||
|
||||
beginBackgroundTaskWithNameExpirationHandlerClosure = { _, handler in
|
||||
guard allowTasks else {
|
||||
return .invalid
|
||||
}
|
||||
Self.bgTaskIdentifier += 1
|
||||
|
||||
let identifier = UIBackgroundTaskIdentifier(rawValue: Self.bgTaskIdentifier)
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
||||
handler?()
|
||||
}
|
||||
return identifier
|
||||
}
|
||||
return mock
|
||||
}
|
||||
}
|
||||
|
||||
@@ -748,28 +748,28 @@ class AppLockServiceMock: AppLockServiceProtocol {
|
||||
}
|
||||
}
|
||||
class AppMediatorMock: AppMediatorProtocol {
|
||||
var windowManager: WindowManagerProtocol {
|
||||
get { return underlyingWindowManager }
|
||||
set(value) { underlyingWindowManager = value }
|
||||
}
|
||||
var underlyingWindowManager: WindowManagerProtocol!
|
||||
var appState: UIApplication.State {
|
||||
get { return underlyingAppState }
|
||||
set(value) { underlyingAppState = value }
|
||||
}
|
||||
var underlyingAppState: UIApplication.State!
|
||||
var backgroundTimeRemaining: TimeInterval {
|
||||
get { return underlyingBackgroundTimeRemaining }
|
||||
set(value) { underlyingBackgroundTimeRemaining = value }
|
||||
}
|
||||
var underlyingBackgroundTimeRemaining: TimeInterval!
|
||||
|
||||
//MARK: - beginBackgroundTask
|
||||
|
||||
var beginBackgroundTaskWithNameExpirationHandlerUnderlyingCallsCount = 0
|
||||
var beginBackgroundTaskWithNameExpirationHandlerCallsCount: Int {
|
||||
var beginBackgroundTaskExpirationHandlerUnderlyingCallsCount = 0
|
||||
var beginBackgroundTaskExpirationHandlerCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return beginBackgroundTaskWithNameExpirationHandlerUnderlyingCallsCount
|
||||
return beginBackgroundTaskExpirationHandlerUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = beginBackgroundTaskWithNameExpirationHandlerUnderlyingCallsCount
|
||||
returnValue = beginBackgroundTaskExpirationHandlerUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
@@ -777,27 +777,27 @@ class AppMediatorMock: AppMediatorProtocol {
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
beginBackgroundTaskWithNameExpirationHandlerUnderlyingCallsCount = newValue
|
||||
beginBackgroundTaskExpirationHandlerUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
beginBackgroundTaskWithNameExpirationHandlerUnderlyingCallsCount = newValue
|
||||
beginBackgroundTaskExpirationHandlerUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var beginBackgroundTaskWithNameExpirationHandlerCalled: Bool {
|
||||
return beginBackgroundTaskWithNameExpirationHandlerCallsCount > 0
|
||||
var beginBackgroundTaskExpirationHandlerCalled: Bool {
|
||||
return beginBackgroundTaskExpirationHandlerCallsCount > 0
|
||||
}
|
||||
|
||||
var beginBackgroundTaskWithNameExpirationHandlerUnderlyingReturnValue: UIBackgroundTaskIdentifier!
|
||||
var beginBackgroundTaskWithNameExpirationHandlerReturnValue: UIBackgroundTaskIdentifier! {
|
||||
var beginBackgroundTaskExpirationHandlerUnderlyingReturnValue: UIBackgroundTaskIdentifier!
|
||||
var beginBackgroundTaskExpirationHandlerReturnValue: UIBackgroundTaskIdentifier! {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return beginBackgroundTaskWithNameExpirationHandlerUnderlyingReturnValue
|
||||
return beginBackgroundTaskExpirationHandlerUnderlyingReturnValue
|
||||
} else {
|
||||
var returnValue: UIBackgroundTaskIdentifier? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = beginBackgroundTaskWithNameExpirationHandlerUnderlyingReturnValue
|
||||
returnValue = beginBackgroundTaskExpirationHandlerUnderlyingReturnValue
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
@@ -805,22 +805,22 @@ class AppMediatorMock: AppMediatorProtocol {
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
beginBackgroundTaskWithNameExpirationHandlerUnderlyingReturnValue = newValue
|
||||
beginBackgroundTaskExpirationHandlerUnderlyingReturnValue = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
beginBackgroundTaskWithNameExpirationHandlerUnderlyingReturnValue = newValue
|
||||
beginBackgroundTaskExpirationHandlerUnderlyingReturnValue = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var beginBackgroundTaskWithNameExpirationHandlerClosure: ((String?, (() -> Void)?) -> UIBackgroundTaskIdentifier)?
|
||||
var beginBackgroundTaskExpirationHandlerClosure: (((() -> Void)?) -> UIBackgroundTaskIdentifier)?
|
||||
|
||||
func beginBackgroundTask(withName taskName: String?, expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier {
|
||||
beginBackgroundTaskWithNameExpirationHandlerCallsCount += 1
|
||||
if let beginBackgroundTaskWithNameExpirationHandlerClosure = beginBackgroundTaskWithNameExpirationHandlerClosure {
|
||||
return beginBackgroundTaskWithNameExpirationHandlerClosure(taskName, handler)
|
||||
func beginBackgroundTask(expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier {
|
||||
beginBackgroundTaskExpirationHandlerCallsCount += 1
|
||||
if let beginBackgroundTaskExpirationHandlerClosure = beginBackgroundTaskExpirationHandlerClosure {
|
||||
return beginBackgroundTaskExpirationHandlerClosure(handler)
|
||||
} else {
|
||||
return beginBackgroundTaskWithNameExpirationHandlerReturnValue
|
||||
return beginBackgroundTaskExpirationHandlerReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - endBackgroundTask
|
||||
@@ -12976,122 +12976,12 @@ class VoiceMessageRecorderMock: VoiceMessageRecorderProtocol {
|
||||
}
|
||||
}
|
||||
class WindowManagerMock: WindowManagerProtocol {
|
||||
weak var delegate: WindowManagerDelegate?
|
||||
var mainWindow: UIWindow!
|
||||
var overlayWindow: UIWindow!
|
||||
var globalSearchWindow: UIWindow!
|
||||
var alternateWindow: UIWindow!
|
||||
var windows: [UIWindow] = []
|
||||
|
||||
//MARK: - configure
|
||||
|
||||
var configureWithUnderlyingCallsCount = 0
|
||||
var configureWithCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return configureWithUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = configureWithUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
configureWithUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
configureWithUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var configureWithCalled: Bool {
|
||||
return configureWithCallsCount > 0
|
||||
}
|
||||
var configureWithReceivedWindowScene: UIWindowScene?
|
||||
var configureWithReceivedInvocations: [UIWindowScene] = []
|
||||
var configureWithClosure: ((UIWindowScene) -> Void)?
|
||||
|
||||
func configure(with windowScene: UIWindowScene) {
|
||||
configureWithCallsCount += 1
|
||||
configureWithReceivedWindowScene = windowScene
|
||||
configureWithReceivedInvocations.append(windowScene)
|
||||
configureWithClosure?(windowScene)
|
||||
}
|
||||
//MARK: - switchToMain
|
||||
|
||||
var switchToMainUnderlyingCallsCount = 0
|
||||
var switchToMainCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return switchToMainUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = switchToMainUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
switchToMainUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
switchToMainUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var switchToMainCalled: Bool {
|
||||
return switchToMainCallsCount > 0
|
||||
}
|
||||
var switchToMainClosure: (() -> Void)?
|
||||
|
||||
func switchToMain() {
|
||||
switchToMainCallsCount += 1
|
||||
switchToMainClosure?()
|
||||
}
|
||||
//MARK: - switchToAlternate
|
||||
|
||||
var switchToAlternateUnderlyingCallsCount = 0
|
||||
var switchToAlternateCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return switchToAlternateUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = switchToAlternateUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
switchToAlternateUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
switchToAlternateUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var switchToAlternateCalled: Bool {
|
||||
return switchToAlternateCallsCount > 0
|
||||
}
|
||||
var switchToAlternateClosure: (() -> Void)?
|
||||
|
||||
func switchToAlternate() {
|
||||
switchToAlternateCallsCount += 1
|
||||
switchToAlternateClosure?()
|
||||
}
|
||||
//MARK: - showGlobalSearch
|
||||
|
||||
var showGlobalSearchUnderlyingCallsCount = 0
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
typealias BackgroundTaskExpirationHandler = (BackgroundTaskProtocol) -> Void
|
||||
|
||||
/// BackgroundTaskProtocol is the protocol describing a background task regardless of the platform used.
|
||||
protocol BackgroundTaskProtocol: AnyObject {
|
||||
/// Name of the background task for debug.
|
||||
var name: String { get }
|
||||
|
||||
/// `true` if the background task is currently running.
|
||||
var isRunning: Bool { get }
|
||||
|
||||
/// Flag indicating the background task is reusable. If reusable, `name` is the key to distinguish background tasks.
|
||||
var isReusable: Bool { get }
|
||||
|
||||
/// Method to be called when a task reused one more time. Should only be valid for reusable tasks.
|
||||
func reuse()
|
||||
|
||||
/// Stop the background task. Cannot be started anymore. For reusable tasks, should be called same number of times `reuse` called.
|
||||
func stop()
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
@MainActor
|
||||
protocol BackgroundTaskServiceProtocol {
|
||||
func startBackgroundTask(withName name: String,
|
||||
isReusable: Bool,
|
||||
expirationHandler: (() -> Void)?) -> BackgroundTaskProtocol?
|
||||
}
|
||||
|
||||
extension BackgroundTaskServiceProtocol {
|
||||
func startBackgroundTask(withName name: String) -> BackgroundTaskProtocol? {
|
||||
startBackgroundTask(withName: name,
|
||||
expirationHandler: nil)
|
||||
}
|
||||
|
||||
func startBackgroundTask(withName name: String,
|
||||
isReusable: Bool) -> BackgroundTaskProtocol? {
|
||||
startBackgroundTask(withName: name,
|
||||
isReusable: isReusable,
|
||||
expirationHandler: nil)
|
||||
}
|
||||
|
||||
func startBackgroundTask(withName name: String,
|
||||
expirationHandler: (() -> Void)?) -> BackgroundTaskProtocol? {
|
||||
startBackgroundTask(withName: name,
|
||||
isReusable: false,
|
||||
expirationHandler: expirationHandler)
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
import UIKit
|
||||
|
||||
class UIKitBackgroundTask: BackgroundTaskProtocol {
|
||||
let name: String
|
||||
var isRunning: Bool {
|
||||
identifier != .invalid
|
||||
}
|
||||
|
||||
let isReusable: Bool
|
||||
let expirationHandler: BackgroundTaskExpirationHandler?
|
||||
var elapsedTime: TimeInterval {
|
||||
Date().timeIntervalSince(startDate) * 1000
|
||||
}
|
||||
|
||||
private let appMediator: AppMediatorProtocol
|
||||
private var identifier: UIBackgroundTaskIdentifier = .invalid
|
||||
private var useCounter = 0
|
||||
private let startDate = Date()
|
||||
|
||||
init?(name: String,
|
||||
isReusable: Bool,
|
||||
appMediator: AppMediatorProtocol,
|
||||
expirationHandler: BackgroundTaskExpirationHandler?) {
|
||||
self.name = name
|
||||
self.isReusable = isReusable
|
||||
self.appMediator = appMediator
|
||||
self.expirationHandler = expirationHandler
|
||||
|
||||
identifier = appMediator.beginBackgroundTask(withName: name) { [weak self] in
|
||||
guard let self else { return }
|
||||
self.stop()
|
||||
self.expirationHandler?(self)
|
||||
}
|
||||
|
||||
if identifier == .invalid {
|
||||
MXLog.error("Do not start background task: \(name), as OS declined")
|
||||
expirationHandler?(self)
|
||||
return nil
|
||||
}
|
||||
|
||||
if isReusable {
|
||||
reuse()
|
||||
}
|
||||
|
||||
MXLog.verbose("Start background task #\(identifier.rawValue) - \(name)")
|
||||
}
|
||||
|
||||
func reuse() {
|
||||
guard isReusable else {
|
||||
return
|
||||
}
|
||||
useCounter += 1
|
||||
}
|
||||
|
||||
func stop() {
|
||||
if isReusable {
|
||||
useCounter -= 1
|
||||
if useCounter <= 0 {
|
||||
endTask()
|
||||
}
|
||||
} else {
|
||||
endTask()
|
||||
}
|
||||
}
|
||||
|
||||
private func endTask() {
|
||||
if identifier != .invalid {
|
||||
MXLog.verbose("End background task #\(identifier.rawValue) - \(name) after \(readableElapsedTime)")
|
||||
|
||||
appMediator.endBackgroundTask(identifier)
|
||||
identifier = .invalid
|
||||
}
|
||||
}
|
||||
|
||||
private var readableElapsedTime: String {
|
||||
String(format: "%.3fms", elapsedTime)
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
import UIKit
|
||||
|
||||
/// /// UIKitBackgroundTaskService is a concrete implementation of BackgroundTaskServiceProtocol using a given `ApplicationProtocol` instance.
|
||||
class UIKitBackgroundTaskService: BackgroundTaskServiceProtocol {
|
||||
private let appMediator: AppMediatorProtocol
|
||||
private var reusableTasks = NSMapTable<NSString, UIKitBackgroundTask>(keyOptions: .strongMemory, valueOptions: .weakMemory)
|
||||
|
||||
init(appMediator: AppMediatorProtocol) {
|
||||
self.appMediator = appMediator
|
||||
}
|
||||
|
||||
func startBackgroundTask(withName name: String,
|
||||
isReusable: Bool,
|
||||
expirationHandler: (() -> Void)?) -> BackgroundTaskProtocol? {
|
||||
if shouldAvoidStartingNewTasks() {
|
||||
MXLog.error("Do not start background task: \(name), as not enough time exists")
|
||||
// call expiration handler immediately
|
||||
expirationHandler?()
|
||||
return nil
|
||||
}
|
||||
var created = false
|
||||
var result: BackgroundTaskProtocol?
|
||||
|
||||
if isReusable {
|
||||
if let oldTask = reusableTasks.object(forKey: name as NSString), oldTask.isRunning {
|
||||
oldTask.reuse()
|
||||
result = oldTask
|
||||
} else {
|
||||
if let newTask = UIKitBackgroundTask(name: name,
|
||||
isReusable: isReusable,
|
||||
appMediator: appMediator,
|
||||
expirationHandler: { [weak self] task in
|
||||
guard let self else { return }
|
||||
self.reusableTasks.removeObject(forKey: task.name as NSString)
|
||||
expirationHandler?()
|
||||
}) {
|
||||
created = true
|
||||
reusableTasks.setObject(newTask, forKey: name as NSString)
|
||||
result = newTask
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let newTask = UIKitBackgroundTask(name: name,
|
||||
isReusable: isReusable,
|
||||
appMediator: appMediator,
|
||||
expirationHandler: { _ in
|
||||
expirationHandler?()
|
||||
}) {
|
||||
result = newTask
|
||||
created = true
|
||||
}
|
||||
}
|
||||
|
||||
let appState = appMediator.appState
|
||||
let remainingTime = readableBackgroundTimeRemaining(appMediator.backgroundTimeRemaining)
|
||||
|
||||
MXLog.verbose("Background task \(name) \(created ? "started" : "reused") with app state: \(appState) and estimated background time remaining: \(remainingTime)")
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private func readableBackgroundTimeRemaining(_ backgroundTimeRemaining: TimeInterval) -> String {
|
||||
if backgroundTimeRemaining == .greatestFiniteMagnitude {
|
||||
return "undetermined"
|
||||
} else {
|
||||
return String(format: "%.0f seconds", backgroundTimeRemaining)
|
||||
}
|
||||
}
|
||||
|
||||
private func shouldAvoidStartingNewTasks() -> Bool {
|
||||
if appMediator.appState == .background,
|
||||
appMediator.backgroundTimeRemaining < .backgroundTimeRemainingThresholdToStartTasks {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private extension TimeInterval {
|
||||
static let backgroundTimeRemainingThresholdToStartTasks: TimeInterval = 5
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import MatrixRustSDK
|
||||
|
||||
class ClientProxy: ClientProxyProtocol {
|
||||
private let client: ClientProtocol
|
||||
private let backgroundTaskService: BackgroundTaskServiceProtocol
|
||||
private let appSettings: AppSettings
|
||||
private let networkMonitor: NetworkMonitorProtocol
|
||||
|
||||
@@ -122,11 +121,9 @@ class ClientProxy: ClientProxyProtocol {
|
||||
}
|
||||
|
||||
init(client: ClientProtocol,
|
||||
backgroundTaskService: BackgroundTaskServiceProtocol,
|
||||
appSettings: AppSettings,
|
||||
networkMonitor: NetworkMonitorProtocol) async {
|
||||
self.client = client
|
||||
self.backgroundTaskService = backgroundTaskService
|
||||
self.appSettings = appSettings
|
||||
self.networkMonitor = networkMonitor
|
||||
|
||||
@@ -134,8 +131,7 @@ class ClientProxy: ClientProxyProtocol {
|
||||
|
||||
mediaLoader = MediaLoader(client: client)
|
||||
|
||||
notificationSettings = NotificationSettingsProxy(notificationSettings: client.getNotificationSettings(),
|
||||
backgroundTaskService: backgroundTaskService)
|
||||
notificationSettings = NotificationSettingsProxy(notificationSettings: client.getNotificationSettings())
|
||||
|
||||
secureBackupController = SecureBackupController(encryption: client.encryption())
|
||||
|
||||
@@ -425,8 +421,7 @@ class ClientProxy: ClientProxyProtocol {
|
||||
|
||||
if let roomListItem, let room {
|
||||
return await RoomProxy(roomListItem: roomListItem,
|
||||
room: room,
|
||||
backgroundTaskService: backgroundTaskService)
|
||||
room: room)
|
||||
}
|
||||
|
||||
// Else wait for the visible rooms list to go into fully loaded
|
||||
@@ -453,8 +448,7 @@ class ClientProxy: ClientProxyProtocol {
|
||||
}
|
||||
|
||||
return await RoomProxy(roomListItem: roomListItem,
|
||||
room: room,
|
||||
backgroundTaskService: backgroundTaskService)
|
||||
room: room)
|
||||
}
|
||||
|
||||
func roomPreviewForIdentifier(_ identifier: String) async -> Result<RoomPreviewDetails, ClientProxyError> {
|
||||
|
||||
@@ -20,14 +20,11 @@ import UIKit
|
||||
struct MediaProvider: MediaProviderProtocol {
|
||||
private let mediaLoader: MediaLoaderProtocol
|
||||
private let imageCache: Kingfisher.ImageCache
|
||||
private let backgroundTaskService: BackgroundTaskServiceProtocol?
|
||||
|
||||
init(mediaLoader: MediaLoaderProtocol,
|
||||
imageCache: Kingfisher.ImageCache,
|
||||
backgroundTaskService: BackgroundTaskServiceProtocol?) {
|
||||
imageCache: Kingfisher.ImageCache) {
|
||||
self.mediaLoader = mediaLoader
|
||||
self.imageCache = imageCache
|
||||
self.backgroundTaskService = backgroundTaskService
|
||||
}
|
||||
|
||||
// MARK: Images
|
||||
@@ -45,11 +42,6 @@ struct MediaProvider: MediaProviderProtocol {
|
||||
return .success(image)
|
||||
}
|
||||
|
||||
let loadImageBgTask = await backgroundTaskService?.startBackgroundTask(withName: "LoadImage: \(source.url.hashValue)")
|
||||
defer {
|
||||
loadImageBgTask?.stop()
|
||||
}
|
||||
|
||||
let cacheKey = cacheKeyForURL(source.url, size: size)
|
||||
|
||||
if case let .success(cacheResult) = await imageCache.retrieveImage(forKey: cacheKey),
|
||||
@@ -92,9 +84,6 @@ struct MediaProvider: MediaProviderProtocol {
|
||||
// MARK: Files
|
||||
|
||||
func loadFileFromSource(_ source: MediaSourceProxy, body: String?) async -> Result<MediaFileHandleProxy, MediaProviderError> {
|
||||
let loadFileBgTask = await backgroundTaskService?.startBackgroundTask(withName: "LoadFile: \(source.url.hashValue)")
|
||||
defer { loadFileBgTask?.stop() }
|
||||
|
||||
do {
|
||||
let file = try await mediaLoader.loadMediaFileForSource(source, body: body)
|
||||
return .success(file)
|
||||
|
||||
@@ -36,13 +36,11 @@ private final class WeakNotificationSettingsProxy: NotificationSettingsDelegate
|
||||
|
||||
final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
private(set) var notificationSettings: MatrixRustSDK.NotificationSettingsProtocol
|
||||
private let backgroundTaskService: BackgroundTaskServiceProtocol?
|
||||
|
||||
let callbacks = PassthroughSubject<NotificationSettingsProxyCallback, Never>()
|
||||
|
||||
init(notificationSettings: MatrixRustSDK.NotificationSettingsProtocol, backgroundTaskService: BackgroundTaskServiceProtocol?) {
|
||||
init(notificationSettings: MatrixRustSDK.NotificationSettingsProtocol) {
|
||||
self.notificationSettings = notificationSettings
|
||||
self.backgroundTaskService = backgroundTaskService
|
||||
notificationSettings.setDelegate(delegate: WeakNotificationSettingsProxy(proxy: self))
|
||||
}
|
||||
|
||||
@@ -52,9 +50,6 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
}
|
||||
|
||||
func setNotificationMode(roomId: String, mode: RoomNotificationModeProxy) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setNotificationMode")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.setRoomNotificationMode(roomId: roomId, mode: mode.roomNotificationMode)
|
||||
await updatedSettings()
|
||||
}
|
||||
@@ -70,9 +65,6 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
}
|
||||
|
||||
func setDefaultRoomNotificationMode(isEncrypted: Bool, isOneToOne: Bool, mode: RoomNotificationModeProxy) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setDefaultRoomNotificationMode")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
do {
|
||||
try await notificationSettings.setDefaultRoomNotificationMode(isEncrypted: isEncrypted, isOneToOne: isOneToOne, mode: mode.roomNotificationMode)
|
||||
} catch NotificationSettingsError.RuleNotFound(let ruleId) {
|
||||
@@ -86,17 +78,11 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
}
|
||||
|
||||
func restoreDefaultNotificationMode(roomId: String) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "restoreDefaultNotificationMode")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.restoreDefaultRoomNotificationMode(roomId: roomId)
|
||||
await updatedSettings()
|
||||
}
|
||||
|
||||
func unmuteRoom(roomId: String, isEncrypted: Bool, isOneToOne: Bool) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "unmuteRoom")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.unmuteRoom(roomId: roomId, isEncrypted: isEncrypted, isOneToOne: isOneToOne)
|
||||
await updatedSettings()
|
||||
}
|
||||
@@ -106,9 +92,6 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
}
|
||||
|
||||
func setRoomMentionEnabled(enabled: Bool) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setRoomMentionEnabled")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.setRoomMentionEnabled(enabled: enabled)
|
||||
await updatedSettings()
|
||||
}
|
||||
@@ -118,9 +101,6 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
}
|
||||
|
||||
func setCallEnabled(enabled: Bool) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setCallEnabled")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.setCallEnabled(enabled: enabled)
|
||||
await updatedSettings()
|
||||
}
|
||||
@@ -130,9 +110,6 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
|
||||
}
|
||||
|
||||
func setInviteForMeEnabled(enabled: Bool) async throws {
|
||||
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setInviteForMeEnabled")
|
||||
defer { backgroundTask?.stop() }
|
||||
|
||||
try await notificationSettings.setInviteForMeEnabled(enabled: enabled)
|
||||
await updatedSettings()
|
||||
}
|
||||
|
||||
@@ -26,13 +26,9 @@ class RoomProxy: RoomProxyProtocol {
|
||||
private let roomListItem: RoomListItemProtocol
|
||||
private let room: RoomProtocol
|
||||
let timeline: TimelineProxyProtocol
|
||||
private let backgroundTaskService: BackgroundTaskServiceProtocol
|
||||
private let backgroundTaskName = "SendRoomEvent"
|
||||
|
||||
private let userInitiatedDispatchQueue = DispatchQueue(label: "io.element.elementx.roomproxy.user_initiated", qos: .userInitiated)
|
||||
|
||||
private var sendMessageBackgroundTask: BackgroundTaskProtocol?
|
||||
|
||||
// periphery:ignore - required for instance retention in the rust codebase
|
||||
private var roomInfoObservationToken: TaskHandle?
|
||||
// periphery:ignore - required for instance retention in the rust codebase
|
||||
@@ -60,13 +56,12 @@ class RoomProxy: RoomProxyProtocol {
|
||||
}
|
||||
|
||||
init?(roomListItem: RoomListItemProtocol,
|
||||
room: RoomProtocol,
|
||||
backgroundTaskService: BackgroundTaskServiceProtocol) async {
|
||||
room: RoomProtocol) async {
|
||||
self.roomListItem = roomListItem
|
||||
self.room = room
|
||||
self.backgroundTaskService = backgroundTaskService
|
||||
|
||||
do {
|
||||
timeline = try await TimelineProxy(timeline: room.timeline(), backgroundTaskService: backgroundTaskService)
|
||||
timeline = try await TimelineProxy(timeline: room.timeline())
|
||||
} catch {
|
||||
MXLog.error("Failed creating timeline with error: \(error)")
|
||||
return nil
|
||||
@@ -165,12 +160,7 @@ class RoomProxy: RoomProxyProtocol {
|
||||
}
|
||||
|
||||
func redact(_ eventID: String) async -> Result<Void, RoomProxyError> {
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
return await Task.dispatch(on: userInitiatedDispatchQueue) {
|
||||
await Task.dispatch(on: userInitiatedDispatchQueue) {
|
||||
do {
|
||||
try self.room.redact(eventId: eventID, reason: nil)
|
||||
return .success(())
|
||||
@@ -180,14 +170,9 @@ class RoomProxy: RoomProxyProtocol {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func reportContent(_ eventID: String, reason: String?) async -> Result<Void, RoomProxyError> {
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
return await Task.dispatch(on: userInitiatedDispatchQueue) {
|
||||
await Task.dispatch(on: userInitiatedDispatchQueue) {
|
||||
do {
|
||||
try self.room.reportContent(eventId: eventID, score: nil, reason: reason)
|
||||
return .success(())
|
||||
@@ -226,11 +211,6 @@ class RoomProxy: RoomProxyProtocol {
|
||||
return .success(member)
|
||||
}
|
||||
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
do {
|
||||
let member = try await room.member(userId: userID)
|
||||
return .success(RoomMemberProxy(member: member))
|
||||
@@ -239,14 +219,9 @@ class RoomProxy: RoomProxyProtocol {
|
||||
return .failure(.sdkError(error))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func leaveRoom() async -> Result<Void, RoomProxyError> {
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
return await Task.dispatch(on: .global()) {
|
||||
await Task.dispatch(on: .global()) {
|
||||
do {
|
||||
try self.room.leave()
|
||||
return .success(())
|
||||
|
||||
@@ -20,10 +20,7 @@ import MatrixRustSDK
|
||||
|
||||
final class TimelineProxy: TimelineProxyProtocol {
|
||||
private let timeline: Timeline
|
||||
private var sendMessageBackgroundTask: BackgroundTaskProtocol?
|
||||
private let backgroundTaskService: BackgroundTaskServiceProtocol
|
||||
|
||||
private let backgroundTaskName = "SendRoomEvent"
|
||||
private let lowPriorityDispatchQueue = DispatchQueue(label: "io.element.elementx.roomproxy.low_priority", qos: .utility)
|
||||
private let messageSendingDispatchQueue = DispatchQueue(label: "io.element.elementx.roomproxy.message_sending", qos: .userInitiated)
|
||||
private let userInitiatedDispatchQueue = DispatchQueue(label: "io.element.elementx.roomproxy.user_initiated", qos: .userInitiated)
|
||||
@@ -54,9 +51,8 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
roomTimelineObservationToken?.cancel()
|
||||
}
|
||||
|
||||
init(timeline: Timeline, backgroundTaskService: BackgroundTaskServiceProtocol) {
|
||||
init(timeline: Timeline) {
|
||||
self.timeline = timeline
|
||||
self.backgroundTaskService = backgroundTaskService
|
||||
}
|
||||
|
||||
func subscribeForUpdates() async {
|
||||
@@ -84,11 +80,6 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
func cancelSend(transactionID: String) async {
|
||||
MXLog.info("Cancelling sending for transaction ID: \(transactionID)")
|
||||
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
return await Task.dispatch(on: messageSendingDispatchQueue) {
|
||||
self.timeline.cancelSend(txnId: transactionID)
|
||||
MXLog.info("Finished cancelling sending for transaction ID: \(transactionID)")
|
||||
@@ -101,11 +92,6 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
|
||||
MXLog.info("Editing message with original event ID: \(eventID)")
|
||||
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
let messageContent = buildMessageContentFor(message,
|
||||
html: html,
|
||||
intentionalMentions: intentionalMentions.toRustMentions())
|
||||
@@ -198,11 +184,6 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
func retrySend(transactionID: String) async {
|
||||
MXLog.info("Retrying sending for transactionID: \(transactionID)")
|
||||
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
return await Task.dispatch(on: messageSendingDispatchQueue) {
|
||||
self.timeline.retrySend(txnId: transactionID)
|
||||
MXLog.info("Finished retrying sending for transactionID: \(transactionID)")
|
||||
@@ -215,11 +196,6 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineProxyError> {
|
||||
MXLog.info("Sending audio")
|
||||
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
let handle = timeline.sendAudio(url: url.path(percentEncoded: false), audioInfo: audioInfo, caption: nil, formattedCaption: nil, progressWatcher: UploadProgressListener { progress in
|
||||
progressSubject?.send(progress)
|
||||
})
|
||||
@@ -245,11 +221,6 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineProxyError> {
|
||||
MXLog.info("Sending file")
|
||||
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
let handle = timeline.sendFile(url: url.path(percentEncoded: false), fileInfo: fileInfo, progressWatcher: UploadProgressListener { progress in
|
||||
progressSubject?.send(progress)
|
||||
})
|
||||
@@ -276,11 +247,6 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineProxyError> {
|
||||
MXLog.info("Sending image")
|
||||
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
let handle = timeline.sendImage(url: url.path(percentEncoded: false), thumbnailUrl: thumbnailURL.path(percentEncoded: false), imageInfo: imageInfo, caption: nil, formattedCaption: nil, progressWatcher: UploadProgressListener { progress in
|
||||
progressSubject?.send(progress)
|
||||
})
|
||||
@@ -307,11 +273,6 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
assetType: AssetType?) async -> Result<Void, TimelineProxyError> {
|
||||
MXLog.info("Sending location")
|
||||
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
return await Task.dispatch(on: messageSendingDispatchQueue) {
|
||||
self.timeline.sendLocation(body: body,
|
||||
geoUri: geoURI.string,
|
||||
@@ -334,11 +295,6 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineProxyError> {
|
||||
MXLog.info("Sending video")
|
||||
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
let handle = timeline.sendVideo(url: url.path(percentEncoded: false), thumbnailUrl: thumbnailURL.path(percentEncoded: false), videoInfo: videoInfo, caption: nil, formattedCaption: nil, progressWatcher: UploadProgressListener { progress in
|
||||
progressSubject?.send(progress)
|
||||
})
|
||||
@@ -365,11 +321,6 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineProxyError> {
|
||||
MXLog.info("Sending voice message")
|
||||
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
let handle = timeline.sendVoiceMessage(url: url.path(percentEncoded: false), audioInfo: audioInfo, waveform: waveform, caption: nil, formattedCaption: nil, progressWatcher: UploadProgressListener { progress in
|
||||
progressSubject?.send(progress)
|
||||
})
|
||||
@@ -399,11 +350,6 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
MXLog.info("Sending message")
|
||||
}
|
||||
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
let messageContent = buildMessageContentFor(message,
|
||||
html: html,
|
||||
intentionalMentions: intentionalMentions.toRustMentions())
|
||||
@@ -436,12 +382,7 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
|
||||
func sendMessageEventContent(_ messageContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError> {
|
||||
MXLog.info("Sending message content")
|
||||
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
|
||||
return await Task.dispatch(on: messageSendingDispatchQueue) {
|
||||
self.timeline.send(msg: messageContent)
|
||||
|
||||
@@ -456,11 +397,6 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
func sendReadReceipt(for eventID: String, type: ReceiptType) async -> Result<Void, TimelineProxyError> {
|
||||
MXLog.verbose("Sending read receipt for eventID: \(eventID)")
|
||||
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
return await Task.dispatch(on: lowPriorityDispatchQueue) {
|
||||
do {
|
||||
try self.timeline.sendReadReceipt(receiptType: type, eventId: eventID)
|
||||
@@ -476,11 +412,6 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
func toggleReaction(_ reaction: String, to eventID: String) async -> Result<Void, TimelineProxyError> {
|
||||
MXLog.info("Toggling reaction for eventID: \(eventID)")
|
||||
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
sendMessageBackgroundTask?.stop()
|
||||
}
|
||||
|
||||
return await Task.dispatch(on: userInitiatedDispatchQueue) {
|
||||
do {
|
||||
try self.timeline.toggleReaction(eventId: eventID, key: reaction)
|
||||
|
||||
@@ -20,7 +20,6 @@ import MatrixRustSDK
|
||||
|
||||
class UserSessionStore: UserSessionStoreProtocol {
|
||||
private let keychainController: KeychainControllerProtocol
|
||||
private let backgroundTaskService: BackgroundTaskServiceProtocol
|
||||
private let matrixSDKStateKey = "matrix-sdk-state"
|
||||
|
||||
/// Whether or not there are sessions in the store.
|
||||
@@ -33,9 +32,8 @@ class UserSessionStore: UserSessionStoreProtocol {
|
||||
|
||||
var clientSessionDelegate: ClientSessionDelegate { keychainController }
|
||||
|
||||
init(keychainController: KeychainControllerProtocol, backgroundTaskService: BackgroundTaskServiceProtocol) {
|
||||
init(keychainController: KeychainControllerProtocol) {
|
||||
self.keychainController = keychainController
|
||||
self.backgroundTaskService = backgroundTaskService
|
||||
baseDirectory = .sessionsBaseDirectory
|
||||
MXLog.info("Setup base directory at: \(baseDirectory)")
|
||||
}
|
||||
@@ -100,11 +98,9 @@ class UserSessionStore: UserSessionStoreProtocol {
|
||||
|
||||
private func buildUserSessionWithClient(_ clientProxy: ClientProxyProtocol) -> UserSessionProtocol {
|
||||
let mediaProvider = MediaProvider(mediaLoader: clientProxy,
|
||||
imageCache: .onlyInMemory,
|
||||
backgroundTaskService: backgroundTaskService)
|
||||
imageCache: .onlyInMemory)
|
||||
|
||||
let voiceMessageMediaManager = VoiceMessageMediaManager(mediaProvider: mediaProvider,
|
||||
backgroundTaskService: backgroundTaskService)
|
||||
let voiceMessageMediaManager = VoiceMessageMediaManager(mediaProvider: mediaProvider)
|
||||
|
||||
return UserSession(clientProxy: clientProxy,
|
||||
mediaProvider: mediaProvider,
|
||||
@@ -150,7 +146,6 @@ class UserSessionStore: UserSessionStoreProtocol {
|
||||
|
||||
private func setupProxyForClient(_ client: Client) async -> ClientProxyProtocol {
|
||||
await ClientProxy(client: client,
|
||||
backgroundTaskService: backgroundTaskService,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
networkMonitor: ServiceLocator.shared.networkMonitor)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ class VoiceMessageMediaManager: VoiceMessageMediaManagerProtocol {
|
||||
private let voiceMessageCache: VoiceMessageCacheProtocol
|
||||
private let audioConverter: AudioConverterProtocol
|
||||
|
||||
private let backgroundTaskService: BackgroundTaskServiceProtocol?
|
||||
private let processingQueue: DispatchQueue
|
||||
private var conversionRequests = [MediaSourceProxy: VoiceMessageConversionRequest]()
|
||||
|
||||
@@ -39,13 +38,11 @@ class VoiceMessageMediaManager: VoiceMessageMediaManagerProtocol {
|
||||
init(mediaProvider: MediaProviderProtocol,
|
||||
voiceMessageCache: VoiceMessageCacheProtocol = VoiceMessageCache(),
|
||||
audioConverter: AudioConverterProtocol = AudioConverter(),
|
||||
processingQueue: DispatchQueue = .global(),
|
||||
backgroundTaskService: BackgroundTaskServiceProtocol?) {
|
||||
processingQueue: DispatchQueue = .global()) {
|
||||
self.mediaProvider = mediaProvider
|
||||
self.voiceMessageCache = voiceMessageCache
|
||||
self.audioConverter = audioConverter
|
||||
self.processingQueue = processingQueue
|
||||
self.backgroundTaskService = backgroundTaskService
|
||||
}
|
||||
|
||||
deinit {
|
||||
@@ -53,9 +50,6 @@ class VoiceMessageMediaManager: VoiceMessageMediaManagerProtocol {
|
||||
}
|
||||
|
||||
func loadVoiceMessageFromSource(_ source: MediaSourceProxy, body: String?) async throws -> URL {
|
||||
let loadFileBgTask = await backgroundTaskService?.startBackgroundTask(withName: "LoadFile: \(source.url.hashValue)")
|
||||
defer { loadFileBgTask?.stop() }
|
||||
|
||||
guard let mimeType = source.mimeType, mimeType.starts(with: supportedVoiceMessageMimeType) else {
|
||||
throw VoiceMessageMediaManagerError.unsupportedMimeTye
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import MatrixRustSDK
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
class UITestsAppCoordinator: AppCoordinatorProtocol, WindowManagerDelegate {
|
||||
class UITestsAppCoordinator: AppCoordinatorProtocol, SecureWindowManagerDelegate {
|
||||
private let navigationRootCoordinator: NavigationRootCoordinator
|
||||
|
||||
// periphery:ignore - retaining purpose
|
||||
@@ -28,7 +28,7 @@ class UITestsAppCoordinator: AppCoordinatorProtocol, WindowManagerDelegate {
|
||||
// periphery:ignore - retaining purpose
|
||||
private var alternateWindowMockScreen: MockScreen?
|
||||
|
||||
let windowManager: WindowManagerProtocol
|
||||
let windowManager: SecureWindowManagerProtocol
|
||||
|
||||
init(appDelegate: AppDelegate) {
|
||||
windowManager = WindowManager(appDelegate: appDelegate)
|
||||
@@ -70,7 +70,7 @@ class UITestsAppCoordinator: AppCoordinatorProtocol, WindowManagerDelegate {
|
||||
fatalError("Not implemented.")
|
||||
}
|
||||
|
||||
func windowManagerDidConfigureWindows(_ windowManager: WindowManagerProtocol) {
|
||||
func windowManagerDidConfigureWindows(_ windowManager: SecureWindowManagerProtocol) {
|
||||
ServiceLocator.shared.userIndicatorController.window = windowManager.overlayWindow
|
||||
|
||||
// Set up the alternate window for the App Lock flow coordinator tests.
|
||||
@@ -92,14 +92,14 @@ class UITestsAppCoordinator: AppCoordinatorProtocol, WindowManagerDelegate {
|
||||
@MainActor
|
||||
class MockScreen: Identifiable {
|
||||
let id: UITestsScreenIdentifier
|
||||
let windowManager: WindowManagerProtocol
|
||||
let windowManager: SecureWindowManagerProtocol
|
||||
let navigationRootCoordinator: NavigationRootCoordinator
|
||||
|
||||
private var retainedState = [Any]()
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
init(id: UITestsScreenIdentifier,
|
||||
windowManager: WindowManagerProtocol,
|
||||
windowManager: SecureWindowManagerProtocol,
|
||||
navigationRootCoordinator: NavigationRootCoordinator) {
|
||||
self.id = id
|
||||
self.windowManager = windowManager
|
||||
@@ -129,8 +129,7 @@ class MockScreen: Identifiable {
|
||||
appMediator: AppMediatorMock.default,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
analytics: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
orientationManager: windowManager)
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
flowCoordinator.start()
|
||||
retainedState.append(flowCoordinator)
|
||||
return nil
|
||||
@@ -468,7 +467,6 @@ class MockScreen: Identifiable {
|
||||
|
||||
let flowCoordinator = UserSessionFlowCoordinator(userSession: MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider(), voiceMessageMediaManager: VoiceMessageMediaManagerMock()),
|
||||
navigationRootCoordinator: navigationRootCoordinator,
|
||||
windowManager: windowManager,
|
||||
appLockService: AppLockService(keychainController: KeychainControllerMock(),
|
||||
appSettings: ServiceLocator.shared.settings),
|
||||
bugReportService: BugReportServiceMock(),
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import SwiftUI
|
||||
|
||||
class UnitTestsAppCoordinator: AppCoordinatorProtocol {
|
||||
let windowManager: WindowManagerProtocol
|
||||
let windowManager: SecureWindowManagerProtocol
|
||||
|
||||
init(appDelegate: AppDelegate) {
|
||||
windowManager = WindowManager(appDelegate: appDelegate)
|
||||
|
||||
Reference in New Issue
Block a user