[WIP] Refactored dependency access to be more generic
This commit is contained in:
parent
6dd4c797a7
commit
c77d7ecda1
|
@ -1 +1 @@
|
|||
Subproject commit 517a61a455d31cd9363198d1b3d02f20093a5811
|
||||
Subproject commit 9b0cdcdc0cfc788b4e46c1b337ceddfbc1deee0f
|
|
@ -530,10 +530,7 @@
|
|||
FD23CE282A67755C0000B97C /* MockCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE272A67755C0000B97C /* MockCrypto.swift */; };
|
||||
FD23CE292A6775650000B97C /* MockCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE272A67755C0000B97C /* MockCrypto.swift */; };
|
||||
FD23CE2A2A6775660000B97C /* MockCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE272A67755C0000B97C /* MockCrypto.swift */; };
|
||||
FD23CE2C2A678DF80000B97C /* MockCaches.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE2B2A678DF80000B97C /* MockCaches.swift */; };
|
||||
FD23CE2D2A678E1E0000B97C /* MockCaches.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE2B2A678DF80000B97C /* MockCaches.swift */; };
|
||||
FD23CE2E2A678E1E0000B97C /* MockCaches.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE2B2A678DF80000B97C /* MockCaches.swift */; };
|
||||
FD23CE302A67B8820000B97C /* Caches.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE2F2A67B8820000B97C /* Caches.swift */; };
|
||||
FD23CE302A67B8820000B97C /* CacheInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE2F2A67B8820000B97C /* CacheInfo.swift */; };
|
||||
FD23CE332A67C4D90000B97C /* MockNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE312A67C38D0000B97C /* MockNetwork.swift */; };
|
||||
FD23CE342A67C4D90000B97C /* MockNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE312A67C38D0000B97C /* MockNetwork.swift */; };
|
||||
FD23CE352A67C4DA0000B97C /* MockNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE312A67C38D0000B97C /* MockNetwork.swift */; };
|
||||
|
@ -649,6 +646,10 @@
|
|||
FD5C7307284F103B0029977D /* MessageReceiver+MessageRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C7306284F103B0029977D /* MessageReceiver+MessageRequests.swift */; };
|
||||
FD5C7309285007920029977D /* BlindedIdLookup.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C7308285007920029977D /* BlindedIdLookup.swift */; };
|
||||
FD5D201E27B0D87C00FEA984 /* SessionId.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D201D27B0D87C00FEA984 /* SessionId.swift */; };
|
||||
FD65318A2AA025C500DFEEAA /* TestDependencies.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6531892AA025C500DFEEAA /* TestDependencies.swift */; };
|
||||
FD65318B2AA025C500DFEEAA /* TestDependencies.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6531892AA025C500DFEEAA /* TestDependencies.swift */; };
|
||||
FD65318C2AA025C500DFEEAA /* TestDependencies.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6531892AA025C500DFEEAA /* TestDependencies.swift */; };
|
||||
FD65318D2AA025C500DFEEAA /* TestDependencies.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6531892AA025C500DFEEAA /* TestDependencies.swift */; };
|
||||
FD6A7A692818BE7300035AC1 /* RetrieveDefaultOpenGroupRoomsJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6A7A682818BE7300035AC1 /* RetrieveDefaultOpenGroupRoomsJob.swift */; };
|
||||
FD6A7A6B2818C17C00035AC1 /* UpdateProfilePictureJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6A7A6A2818C17C00035AC1 /* UpdateProfilePictureJob.swift */; };
|
||||
FD6A7A6D2818C61500035AC1 /* _002_SetupStandardJobs.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6A7A6C2818C61500035AC1 /* _002_SetupStandardJobs.swift */; };
|
||||
|
@ -786,7 +787,6 @@
|
|||
FDB5DB072A981F88002C8721 /* Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC290A527D860CE005DAE71 /* Mock.swift */; };
|
||||
FDB5DB082A981F8B002C8721 /* Mocked.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0969F82A69FFE700C5C365 /* Mocked.swift */; };
|
||||
FDB5DB092A981F8D002C8721 /* MockCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE272A67755C0000B97C /* MockCrypto.swift */; };
|
||||
FDB5DB0A2A981F90002C8721 /* MockCaches.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE2B2A678DF80000B97C /* MockCaches.swift */; };
|
||||
FDB5DB0B2A981F92002C8721 /* MockGeneralCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDFD645C27F273F300808CA1 /* MockGeneralCache.swift */; };
|
||||
FDB5DB0C2A981F96002C8721 /* MockNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE312A67C38D0000B97C /* MockNetwork.swift */; };
|
||||
FDB5DB0D2A981F9D002C8721 /* MockJobRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD96F3A629DBD43D00401309 /* MockJobRunner.swift */; };
|
||||
|
@ -885,6 +885,7 @@
|
|||
FDE77F6B280FEB28002CFC5D /* ControlMessageProcessRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE77F6A280FEB28002CFC5D /* ControlMessageProcessRecord.swift */; };
|
||||
FDED2E3C282E1B5D00B2CD2A /* UICollectionView+ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDED2E3B282E1B5D00B2CD2A /* UICollectionView+ReusableView.swift */; };
|
||||
FDF01FAB2A9EBAD500CAF969 /* MessageSenderGroupsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF01FAA2A9EBAD500CAF969 /* MessageSenderGroupsSpec.swift */; };
|
||||
FDF01FAD2A9ECC4200CAF969 /* SingletonInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF01FAC2A9ECC4200CAF969 /* SingletonInfo.swift */; };
|
||||
FDF0B73C27FFD3D6004C14C5 /* LinkPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B73B27FFD3D6004C14C5 /* LinkPreview.swift */; };
|
||||
FDF0B7422804EA4F004C14C5 /* _002_SetupStandardJobs.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B7412804EA4F004C14C5 /* _002_SetupStandardJobs.swift */; };
|
||||
FDF0B7472804F0CE004C14C5 /* DisappearingMessagesJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B7462804F0CE004C14C5 /* DisappearingMessagesJob.swift */; };
|
||||
|
@ -1757,8 +1758,7 @@
|
|||
FD23CE232A675C440000B97C /* Crypto+SessionMessagingKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Crypto+SessionMessagingKit.swift"; sourceTree = "<group>"; };
|
||||
FD23CE252A676B5B0000B97C /* DependenciesSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DependenciesSpec.swift; sourceTree = "<group>"; };
|
||||
FD23CE272A67755C0000B97C /* MockCrypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCrypto.swift; sourceTree = "<group>"; };
|
||||
FD23CE2B2A678DF80000B97C /* MockCaches.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCaches.swift; sourceTree = "<group>"; };
|
||||
FD23CE2F2A67B8820000B97C /* Caches.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Caches.swift; sourceTree = "<group>"; };
|
||||
FD23CE2F2A67B8820000B97C /* CacheInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheInfo.swift; sourceTree = "<group>"; };
|
||||
FD23CE312A67C38D0000B97C /* MockNetwork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockNetwork.swift; sourceTree = "<group>"; };
|
||||
FD23EA6028ED0B260058676E /* CombineExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CombineExtensions.swift; sourceTree = "<group>"; };
|
||||
FD245C612850664300B966DD /* Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
|
||||
|
@ -1841,6 +1841,7 @@
|
|||
FD5C7308285007920029977D /* BlindedIdLookup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlindedIdLookup.swift; sourceTree = "<group>"; };
|
||||
FD5CE3442A3C5D96001A6DE3 /* DecryptExportedKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecryptExportedKey.swift; sourceTree = "<group>"; };
|
||||
FD5D201D27B0D87C00FEA984 /* SessionId.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionId.swift; sourceTree = "<group>"; };
|
||||
FD6531892AA025C500DFEEAA /* TestDependencies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestDependencies.swift; sourceTree = "<group>"; };
|
||||
FD6A7A682818BE7300035AC1 /* RetrieveDefaultOpenGroupRoomsJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RetrieveDefaultOpenGroupRoomsJob.swift; sourceTree = "<group>"; };
|
||||
FD6A7A6A2818C17C00035AC1 /* UpdateProfilePictureJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateProfilePictureJob.swift; sourceTree = "<group>"; };
|
||||
FD6A7A6C2818C61500035AC1 /* _002_SetupStandardJobs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _002_SetupStandardJobs.swift; sourceTree = "<group>"; };
|
||||
|
@ -2053,6 +2054,7 @@
|
|||
FDE77F6A280FEB28002CFC5D /* ControlMessageProcessRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlMessageProcessRecord.swift; sourceTree = "<group>"; };
|
||||
FDED2E3B282E1B5D00B2CD2A /* UICollectionView+ReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionView+ReusableView.swift"; sourceTree = "<group>"; };
|
||||
FDF01FAA2A9EBAD500CAF969 /* MessageSenderGroupsSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSenderGroupsSpec.swift; sourceTree = "<group>"; };
|
||||
FDF01FAC2A9ECC4200CAF969 /* SingletonInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingletonInfo.swift; sourceTree = "<group>"; };
|
||||
FDF0B73B27FFD3D6004C14C5 /* LinkPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkPreview.swift; sourceTree = "<group>"; };
|
||||
FDF0B73F280402C4004C14C5 /* Job.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Job.swift; sourceTree = "<group>"; };
|
||||
FDF0B7412804EA4F004C14C5 /* _002_SetupStandardJobs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _002_SetupStandardJobs.swift; sourceTree = "<group>"; };
|
||||
|
@ -4160,11 +4162,11 @@
|
|||
FDC290A527D860CE005DAE71 /* Mock.swift */,
|
||||
FD0969F82A69FFE700C5C365 /* Mocked.swift */,
|
||||
FD23CE272A67755C0000B97C /* MockCrypto.swift */,
|
||||
FD23CE2B2A678DF80000B97C /* MockCaches.swift */,
|
||||
FDFD645C27F273F300808CA1 /* MockGeneralCache.swift */,
|
||||
FD23CE312A67C38D0000B97C /* MockNetwork.swift */,
|
||||
FD96F3A629DBD43D00401309 /* MockJobRunner.swift */,
|
||||
FD83B9BD27CF2243005E1583 /* TestConstants.swift */,
|
||||
FD6531892AA025C500DFEEAA /* TestDependencies.swift */,
|
||||
FD9DD2702A72516D00ECB68E /* TestExtensions.swift */,
|
||||
FDC290A727D9B46D005DAE71 /* NimbleExtensions.swift */,
|
||||
FD078E4727E02561000769AF /* CommonMockedExtensions.swift */,
|
||||
|
@ -4496,8 +4498,9 @@
|
|||
FDF01FAE2A9ED0C800CAF969 /* Dependency Injection */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FD23CE2F2A67B8820000B97C /* Caches.swift */,
|
||||
FD23CE2F2A67B8820000B97C /* CacheInfo.swift */,
|
||||
FDC6D75F2862B3F600B04575 /* Dependencies.swift */,
|
||||
FDF01FAC2A9ECC4200CAF969 /* SingletonInfo.swift */,
|
||||
);
|
||||
path = "Dependency Injection";
|
||||
sourceTree = "<group>";
|
||||
|
@ -5982,7 +5985,7 @@
|
|||
FD23CE1F2A65269C0000B97C /* Crypto.swift in Sources */,
|
||||
B8BC00C0257D90E30032E807 /* General.swift in Sources */,
|
||||
FDF8488629405A61007DCAE5 /* Request.swift in Sources */,
|
||||
FD23CE302A67B8820000B97C /* Caches.swift in Sources */,
|
||||
FD23CE302A67B8820000B97C /* CacheInfo.swift in Sources */,
|
||||
FD17D7A127F40D2500122BE0 /* Storage.swift in Sources */,
|
||||
FD1A94FB2900D1C2000D73D3 /* PersistableRecord+Utilities.swift in Sources */,
|
||||
FD5D201E27B0D87C00FEA984 /* SessionId.swift in Sources */,
|
||||
|
@ -6022,6 +6025,7 @@
|
|||
FDF8488929405B27007DCAE5 /* Data+Utilities.swift in Sources */,
|
||||
FD09797227FAA2F500936362 /* Optional+Utilities.swift in Sources */,
|
||||
FD7162DB281B6C440060647B /* TypedTableAlias.swift in Sources */,
|
||||
FDF01FAD2A9ECC4200CAF969 /* SingletonInfo.swift in Sources */,
|
||||
FD7115F828C8151C00B47552 /* DisposableBarButtonItem.swift in Sources */,
|
||||
FD17D7E727F6A16700122BE0 /* _003_YDBToGRDBMigration.swift in Sources */,
|
||||
);
|
||||
|
@ -6233,8 +6237,6 @@
|
|||
FD245C56285065EA00B966DD /* SNProto.swift in Sources */,
|
||||
FD09798B27FD1CFE00936362 /* Capability.swift in Sources */,
|
||||
C3BBE0C72554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift in Sources */,
|
||||
FD1D732A2A85AA2000E3F410 /* Setting+Utilities.swift in Sources */,
|
||||
FD17D79C27F40B2E00122BE0 /* SMKLegacy.swift in Sources */,
|
||||
FD09798127FCFEE800936362 /* SessionThread.swift in Sources */,
|
||||
FD09C5EA282A1BB2000CE219 /* ThreadTypingIndicator.swift in Sources */,
|
||||
FDB5DADA2A95D839002C8721 /* GroupUpdateInfoChangeMessage.swift in Sources */,
|
||||
|
@ -6472,7 +6474,6 @@
|
|||
FD23CE292A6775650000B97C /* MockCrypto.swift in Sources */,
|
||||
FD23CE332A67C4D90000B97C /* MockNetwork.swift in Sources */,
|
||||
FD71161528D00D6700B47552 /* ThreadDisappearingMessagesViewModelSpec.swift in Sources */,
|
||||
FD23CE2D2A678E1E0000B97C /* MockCaches.swift in Sources */,
|
||||
FD23EA5E28ED00FD0058676E /* NimbleExtensions.swift in Sources */,
|
||||
FD23EA5F28ED00FF0058676E /* CommonMockedExtensions.swift in Sources */,
|
||||
FD23EA5D28ED00FA0058676E /* TestConstants.swift in Sources */,
|
||||
|
@ -6482,6 +6483,7 @@
|
|||
FD23EA6128ED0B260058676E /* CombineExtensions.swift in Sources */,
|
||||
7B6ACADE2A32D3A9009AFB73 /* MessageReceiverDisappearingMessagesSpec.swift in Sources */,
|
||||
FD9DD2712A72516D00ECB68E /* TestExtensions.swift in Sources */,
|
||||
FD65318A2AA025C500DFEEAA /* TestDependencies.swift in Sources */,
|
||||
FD2AAAED28ED3E1000A49611 /* MockGeneralCache.swift in Sources */,
|
||||
FDB5DB0D2A981F9D002C8721 /* MockJobRunner.swift in Sources */,
|
||||
);
|
||||
|
@ -6493,6 +6495,7 @@
|
|||
files = (
|
||||
FD2AAAF228ED57B500A49611 /* SynchronousStorage.swift in Sources */,
|
||||
FD078E4927E02576000769AF /* CommonMockedExtensions.swift in Sources */,
|
||||
FD65318D2AA025C500DFEEAA /* TestDependencies.swift in Sources */,
|
||||
FD83B9BF27CF2294005E1583 /* TestConstants.swift in Sources */,
|
||||
FDFBB7542A2023EB00CA7350 /* BencodeSpec.swift in Sources */,
|
||||
FD9DD2732A72516D00ECB68E /* TestExtensions.swift in Sources */,
|
||||
|
@ -6506,7 +6509,6 @@
|
|||
FD2AAAEE28ED3E1100A49611 /* MockGeneralCache.swift in Sources */,
|
||||
FD9B30F3293EA0BF008DEE3E /* BatchResponseSpec.swift in Sources */,
|
||||
FD37EA1528AB42CB003AE748 /* IdentitySpec.swift in Sources */,
|
||||
FD23CE2C2A678DF80000B97C /* MockCaches.swift in Sources */,
|
||||
FD0B77B229B82B7A009169BA /* ArrayUtilitiesSpec.swift in Sources */,
|
||||
FD1A94FE2900D2EA000D73D3 /* PersistableRecordUtilitiesSpec.swift in Sources */,
|
||||
FD23CE262A676B5B0000B97C /* DependenciesSpec.swift in Sources */,
|
||||
|
@ -6526,9 +6528,9 @@
|
|||
FDB5DB082A981F8B002C8721 /* Mocked.swift in Sources */,
|
||||
FDB5DB142A981FAE002C8721 /* CombineExtensions.swift in Sources */,
|
||||
FDB5DB162A9821DF002C8721 /* CommonMockedExtensions.swift in Sources */,
|
||||
FDB5DB0A2A981F90002C8721 /* MockCaches.swift in Sources */,
|
||||
FDB5DB112A981FA6002C8721 /* TestExtensions.swift in Sources */,
|
||||
FDB5DB092A981F8D002C8721 /* MockCrypto.swift in Sources */,
|
||||
FD65318C2AA025C500DFEEAA /* TestDependencies.swift in Sources */,
|
||||
FDB5DB102A981FA3002C8721 /* TestConstants.swift in Sources */,
|
||||
FDB5DB0C2A981F96002C8721 /* MockNetwork.swift in Sources */,
|
||||
FDB5DB0F2A981FA1002C8721 /* MockJobRunner.swift in Sources */,
|
||||
|
@ -6570,8 +6572,8 @@
|
|||
FD2B4AFB29429D1000AB4848 /* ConfigContacts.swift in Sources */,
|
||||
FDA1E83D29AC71A800C5C3BD /* SessionUtilSpec.swift in Sources */,
|
||||
FD83B9C027CF2294005E1583 /* TestConstants.swift in Sources */,
|
||||
FD65318B2AA025C500DFEEAA /* TestDependencies.swift in Sources */,
|
||||
FDC4389A27BA002500C60D73 /* OpenGroupAPISpec.swift in Sources */,
|
||||
FD23CE2E2A678E1E0000B97C /* MockCaches.swift in Sources */,
|
||||
FD23EA6228ED0B260058676E /* CombineExtensions.swift in Sources */,
|
||||
FDC3833B2A9344C700FFD6A2 /* ConfigGroupInfo.swift in Sources */,
|
||||
FDB5DACD2A9452F0002C8721 /* ConfigGroupMembers.swift in Sources */,
|
||||
|
|
|
@ -274,7 +274,7 @@ public final class SessionCall: CurrentCallProtocol, WebRTCSessionDelegate {
|
|||
|
||||
webRTCSession.hangUp()
|
||||
|
||||
Storage.shared.writeAsync { [weak self] db in
|
||||
Dependencies()[singleton: .storage].writeAsync { [weak self] db in
|
||||
try self?.webRTCSession.endCall(db, with: sessionId)
|
||||
}
|
||||
|
||||
|
@ -289,7 +289,7 @@ public final class SessionCall: CurrentCallProtocol, WebRTCSessionDelegate {
|
|||
let duration: TimeInterval = self.duration
|
||||
let hasStartedConnecting: Bool = self.hasStartedConnecting
|
||||
|
||||
dependencies.storage.writeAsync(
|
||||
dependencies[singleton: .storage].writeAsync(
|
||||
updates: { db in
|
||||
guard let interaction: Interaction = try? Interaction.fetchOne(db, id: callInteractionId) else {
|
||||
return
|
||||
|
@ -430,7 +430,7 @@ public final class SessionCall: CurrentCallProtocol, WebRTCSessionDelegate {
|
|||
let sessionId: String = self.sessionId
|
||||
let webRTCSession: WebRTCSession = self.webRTCSession
|
||||
|
||||
guard let thread: SessionThread = Storage.shared.read({ db in try SessionThread.fetchOne(db, id: sessionId) }) else {
|
||||
guard let thread: SessionThread = Dependencies()[singleton: .storage].read({ db in try SessionThread.fetchOne(db, id: sessionId) }) else {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ extension SessionCallManager {
|
|||
public func startCallAction() -> Bool {
|
||||
guard let call: CurrentCallProtocol = self.currentCall else { return false }
|
||||
|
||||
Storage.shared.writeAsync { db in
|
||||
Dependencies()[singleton: .storage].writeAsync { db in
|
||||
call.startSessionCall(db)
|
||||
}
|
||||
|
||||
|
|
|
@ -188,10 +188,12 @@ public final class SessionCallManager: NSObject, CallManagerProtocol {
|
|||
callUpdate.supportsDTMF = false
|
||||
}
|
||||
|
||||
public static func suspendDatabaseIfCallEndedInBackground() {
|
||||
public static func suspendDatabaseIfCallEndedInBackground(
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
if CurrentAppContext().isInBackground() {
|
||||
// Stop all jobs except for message sending and when completed suspend the database
|
||||
JobRunner.stopAndClearPendingJobs(exceptForVariant: .messageSend) {
|
||||
dependencies[singleton: .jobRunner].stopAndClearPendingJobs(exceptForVariant: .messageSend) {
|
||||
Storage.suspendDatabaseAccess()
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +202,7 @@ public final class SessionCallManager: NSObject, CallManagerProtocol {
|
|||
// MARK: - UI
|
||||
|
||||
public func showCallUIForCall(caller: String, uuid: String, mode: CallMode, interactionId: Int64?) {
|
||||
guard let call: SessionCall = Storage.shared.read({ db in SessionCall(db, for: caller, uuid: uuid, mode: mode) }) else {
|
||||
guard let call: SessionCall = Dependencies()[singleton: .storage].read({ db in SessionCall(db, for: caller, uuid: uuid, mode: mode) }) else {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ final class IncomingCallBanner: UIView, UIGestureRecognizerDelegate {
|
|||
publicKey: call.sessionId,
|
||||
threadVariant: .contact,
|
||||
customImageData: nil,
|
||||
profile: Storage.shared.read { db in Profile.fetchOrCreate(db, id: call.sessionId) },
|
||||
profile: Dependencies()[singleton: .storage].read { db in Profile.fetchOrCreate(db, id: call.sessionId) },
|
||||
additionalProfile: nil
|
||||
)
|
||||
displayNameLabel.text = call.contactName
|
||||
|
|
|
@ -102,7 +102,7 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
|
|||
|
||||
let threadId: String = self.threadId
|
||||
|
||||
Storage.shared.read { [weak self] db in
|
||||
Dependencies()[singleton: .storage].read { [weak self] db in
|
||||
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
||||
self?.userPublicKey = userPublicKey
|
||||
self?.name = try ClosedGroup
|
||||
|
@ -368,7 +368,7 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
|
|||
.map { $0.profileId }
|
||||
.asSet()
|
||||
) { [weak self] selectedUserIds in
|
||||
Storage.shared.read { [weak self] db in
|
||||
Dependencies()[singleton: .storage].read { [weak self] db in
|
||||
let selectedGroupMembers: [GroupMemberDisplayInfo] = try Profile
|
||||
.filter(selectedUserIds.contains(Profile.Columns.id))
|
||||
.fetchAll(db)
|
||||
|
@ -464,7 +464,7 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
|
|||
}
|
||||
|
||||
ModalActivityIndicatorViewController.present(fromViewController: navigationController) { _ in
|
||||
Storage.shared
|
||||
Dependencies()[singleton: .storage]
|
||||
.writePublisher { db in
|
||||
// If the user is no longer a member then leave the group
|
||||
guard !updatedMemberIds.contains(userPublicKey) else { return }
|
||||
|
|
|
@ -86,7 +86,7 @@ extension ConversationSearchController: UISearchResultsUpdating {
|
|||
let threadId: String = self.threadId
|
||||
|
||||
DispatchQueue.global(qos: .default).async { [weak self] in
|
||||
let results: [Interaction.TimestampInfo]? = Storage.shared.read { db -> [Interaction.TimestampInfo] in
|
||||
let results: [Interaction.TimestampInfo]? = Dependencies()[singleton: .storage].read { db -> [Interaction.TimestampInfo] in
|
||||
self?.resultsBar.willStartSearching(readConnection: db)
|
||||
|
||||
return try Interaction.idsForTermWithin(
|
||||
|
|
|
@ -77,7 +77,7 @@ extension ConversationVC:
|
|||
@objc func startCall(_ sender: Any?) {
|
||||
guard SessionCall.isEnabled else { return }
|
||||
guard viewModel.threadData.threadIsBlocked == false else { return }
|
||||
guard Storage.shared[.areCallsEnabled] else {
|
||||
guard Dependencies()[singleton: .storage][.areCallsEnabled] else {
|
||||
let confirmationModal: ConfirmationModal = ConfirmationModal(
|
||||
info: ConfirmationModal.Info(
|
||||
title: "modal_call_permission_request_title".localized(),
|
||||
|
@ -111,7 +111,7 @@ extension ConversationVC:
|
|||
guard AVAudioSession.sharedInstance().recordPermission == .granted else { return }
|
||||
guard self.viewModel.threadData.threadVariant == .contact else { return }
|
||||
guard AppEnvironment.shared.callManager.currentCall == nil else { return }
|
||||
guard let call: SessionCall = Storage.shared.read({ db in SessionCall(db, for: threadId, uuid: UUID().uuidString.lowercased(), mode: .offer, outgoing: true) }) else {
|
||||
guard let call: SessionCall = Dependencies()[singleton: .storage].read({ db in SessionCall(db, for: threadId, uuid: UUID().uuidString.lowercased(), mode: .offer, outgoing: true) }) else {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -240,14 +240,14 @@ extension ConversationVC:
|
|||
// MARK: - ExpandingAttachmentsButtonDelegate
|
||||
|
||||
func handleGIFButtonTapped() {
|
||||
guard Storage.shared[.isGiphyEnabled] else {
|
||||
guard Dependencies()[singleton: .storage][.isGiphyEnabled] else {
|
||||
let modal: ConfirmationModal = ConfirmationModal(
|
||||
info: ConfirmationModal.Info(
|
||||
title: "GIPHY_PERMISSION_TITLE".localized(),
|
||||
body: .text("GIPHY_PERMISSION_MESSAGE".localized()),
|
||||
confirmTitle: "continue_2".localized()
|
||||
) { [weak self] _ in
|
||||
Storage.shared.writeAsync(
|
||||
Dependencies()[singleton: .storage].writeAsync(
|
||||
updates: { db in
|
||||
db[.isGiphyEnabled] = true
|
||||
},
|
||||
|
@ -539,7 +539,7 @@ extension ConversationVC:
|
|||
let quoteThumbnailAttachment: Attachment? = optimisticData.quoteModel?.attachment?.cloneAsQuoteThumbnail()
|
||||
|
||||
// Actually send the message
|
||||
dependencies.storage
|
||||
dependencies[singleton: .storage]
|
||||
.writePublisher { [weak self] db in
|
||||
// Update the thread to be visible (if it isn't already)
|
||||
if self?.viewModel.threadData.threadShouldBeVisible == false {
|
||||
|
@ -592,12 +592,13 @@ extension ConversationVC:
|
|||
)
|
||||
|
||||
// Trigger disappear after read
|
||||
dependencies.jobRunner.upsert(
|
||||
dependencies[singleton: .jobRunner].upsert(
|
||||
db,
|
||||
job: DisappearingMessagesJob.updateNextRunIfNeeded(
|
||||
db,
|
||||
interaction: insertedInteraction,
|
||||
startedAtMs: TimeInterval(SnodeAPI.currentOffsetTimestampMs())
|
||||
startedAtMs: TimeInterval(SnodeAPI.currentOffsetTimestampMs(using: dependencies)),
|
||||
using: dependencies
|
||||
),
|
||||
canStartJob: true,
|
||||
using: dependencies
|
||||
|
@ -619,14 +620,14 @@ extension ConversationVC:
|
|||
}
|
||||
|
||||
func handleMessageSent() {
|
||||
if Storage.shared[.playNotificationSoundInForeground] {
|
||||
if Dependencies()[singleton: .storage][.playNotificationSoundInForeground] {
|
||||
let soundID = Preferences.Sound.systemSoundId(for: .messageSent, quiet: true)
|
||||
AudioServicesPlaySystemSound(soundID)
|
||||
}
|
||||
|
||||
let threadId: String = self.viewModel.threadData.threadId
|
||||
|
||||
Storage.shared.writeAsync { db in
|
||||
Dependencies()[singleton: .storage].writeAsync { db in
|
||||
TypingIndicators.didStopTyping(db, threadId: threadId, direction: .outgoing)
|
||||
|
||||
_ = try SessionThread
|
||||
|
@ -642,7 +643,7 @@ extension ConversationVC:
|
|||
body: .text("modal_link_previews_explanation".localized()),
|
||||
confirmTitle: "modal_link_previews_button_title".localized()
|
||||
) { [weak self] _ in
|
||||
Storage.shared.writeAsync { db in
|
||||
Dependencies()[singleton: .storage].writeAsync { db in
|
||||
db[.areLinkPreviewsEnabled] = true
|
||||
}
|
||||
|
||||
|
@ -675,7 +676,7 @@ extension ConversationVC:
|
|||
)
|
||||
|
||||
if needsToStartTypingIndicator {
|
||||
Storage.shared.writeAsync { db in
|
||||
Dependencies()[singleton: .storage].writeAsync { db in
|
||||
TypingIndicators.start(db, threadId: threadId, direction: .outgoing)
|
||||
}
|
||||
}
|
||||
|
@ -939,8 +940,8 @@ extension ConversationVC:
|
|||
let threadId: String = self.viewModel.threadData.threadId
|
||||
|
||||
// Retry downloading the failed attachment
|
||||
dependencies.storage.writeAsync { db in
|
||||
dependencies.jobRunner.add(
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
dependencies[singleton: .jobRunner].add(
|
||||
db,
|
||||
job: Job(
|
||||
variant: .attachmentDownload,
|
||||
|
@ -1026,7 +1027,7 @@ extension ConversationVC:
|
|||
case .textOnlyMessage:
|
||||
if let quote: Quote = cellViewModel.quote {
|
||||
// Scroll to the original quoted message
|
||||
let maybeOriginalInteractionInfo: Interaction.TimestampInfo? = Storage.shared.read { db in
|
||||
let maybeOriginalInteractionInfo: Interaction.TimestampInfo? = Dependencies()[singleton: .storage].read { db in
|
||||
try quote.originalInteraction
|
||||
.select(.id, .timestampMs)
|
||||
.asRequest(of: Interaction.TimestampInfo.self)
|
||||
|
@ -1099,7 +1100,7 @@ extension ConversationVC:
|
|||
// FIXME: Add in support for starting a thread with a 'blinded25' id
|
||||
guard SessionId.Prefix(from: sessionId) != .blinded25 else { return }
|
||||
guard SessionId.Prefix(from: sessionId) == .blinded15 else {
|
||||
Storage.shared.write { db in
|
||||
Dependencies()[singleton: .storage].write { db in
|
||||
try SessionThread
|
||||
.fetchOrCreate(db, id: sessionId, variant: .contact, shouldBeVisible: nil)
|
||||
}
|
||||
|
@ -1116,7 +1117,7 @@ extension ConversationVC:
|
|||
return
|
||||
}
|
||||
|
||||
let targetThreadId: String? = Storage.shared.write { db in
|
||||
let targetThreadId: String? = Dependencies()[singleton: .storage].write { db in
|
||||
let lookup: BlindedIdLookup = try BlindedIdLookup
|
||||
.fetchOrCreate(
|
||||
db,
|
||||
|
@ -1211,7 +1212,7 @@ extension ConversationVC:
|
|||
func removeAllReactions(_ cellViewModel: MessageViewModel, for emoji: String, using dependencies: Dependencies) {
|
||||
guard cellViewModel.threadVariant == .community else { return }
|
||||
|
||||
Storage.shared
|
||||
Dependencies()[singleton: .storage]
|
||||
.readPublisher { db -> (HTTP.PreparedRequest<OpenGroupAPI.ReactionRemoveAllResponse>, OpenGroupAPI.PendingChange) in
|
||||
guard
|
||||
let openGroup: OpenGroup = try? OpenGroup
|
||||
|
@ -1258,7 +1259,7 @@ extension ConversationVC:
|
|||
}
|
||||
.sinkUntilComplete(
|
||||
receiveCompletion: { _ in
|
||||
Storage.shared.writeAsync { db in
|
||||
Dependencies()[singleton: .storage].writeAsync { db in
|
||||
_ = try Reaction
|
||||
.filter(Reaction.Columns.interactionId == cellViewModel.id)
|
||||
.filter(Reaction.Columns.emoji == emoji)
|
||||
|
@ -1285,7 +1286,7 @@ extension ConversationVC:
|
|||
let threadVariant: SessionThread.Variant = self.viewModel.threadData.threadVariant
|
||||
let openGroupRoom: String? = self.viewModel.threadData.openGroupRoomToken
|
||||
let sentTimestamp: Int64 = SnodeAPI.currentOffsetTimestampMs()
|
||||
let recentReactionTimestamps: [Int64] = dependencies.caches[.general].recentReactionTimestamps
|
||||
let recentReactionTimestamps: [Int64] = dependencies[cache: .general].recentReactionTimestamps
|
||||
|
||||
guard
|
||||
recentReactionTimestamps.count < 20 ||
|
||||
|
@ -1303,7 +1304,7 @@ extension ConversationVC:
|
|||
return
|
||||
}
|
||||
|
||||
dependencies.caches.mutate(cache: .general) {
|
||||
dependencies.mutate(cache: .general) {
|
||||
$0.recentReactionTimestamps = Array($0.recentReactionTimestamps
|
||||
.suffix(19))
|
||||
.appending(sentTimestamp)
|
||||
|
@ -1340,7 +1341,7 @@ extension ConversationVC:
|
|||
}
|
||||
.subscribe(on: DispatchQueue.global(qos: .userInitiated), using: dependencies)
|
||||
.flatMap { pendingChange -> AnyPublisher<(MessageSender.PreparedSendData?, OpenGroupInfo?), Error> in
|
||||
dependencies.storage.writePublisher { [weak self] db -> (MessageSender.PreparedSendData?, OpenGroupInfo?) in
|
||||
dependencies[singleton: .storage].writePublisher { [weak self] db -> (MessageSender.PreparedSendData?, OpenGroupInfo?) in
|
||||
// Update the thread to be visible (if it isn't already)
|
||||
if self?.viewModel.threadData.threadShouldBeVisible == false {
|
||||
_ = try SessionThread
|
||||
|
@ -1496,7 +1497,7 @@ extension ConversationVC:
|
|||
|
||||
func handleReactionSentFailure(_ pendingReaction: Reaction?, remove: Bool) {
|
||||
guard let pendingReaction = pendingReaction else { return }
|
||||
Storage.shared.writeAsync { db in
|
||||
Dependencies()[singleton: .storage].writeAsync { db in
|
||||
// Reverse the database
|
||||
if remove {
|
||||
try pendingReaction.insert(db)
|
||||
|
@ -1547,7 +1548,7 @@ extension ConversationVC:
|
|||
|
||||
if cellViewModel.state != .failedToSync {
|
||||
sheet.addAction(UIAlertAction(title: "TXT_DELETE_TITLE".localized(), style: .destructive, handler: { _ in
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
try Interaction
|
||||
.filter(id: cellViewModel.id)
|
||||
.deleteAll(db)
|
||||
|
@ -1614,7 +1615,7 @@ extension ConversationVC:
|
|||
return presentingViewController.present(errorModal, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
Storage.shared
|
||||
Dependencies()[singleton: .storage]
|
||||
.writePublisher { db in
|
||||
OpenGroupManager.shared.add(
|
||||
db,
|
||||
|
@ -1643,7 +1644,7 @@ extension ConversationVC:
|
|||
// If there was a failure then the group will be in invalid state until
|
||||
// the next launch so remove it (the user will be left on the previous
|
||||
// screen so can re-trigger the join)
|
||||
Storage.shared.writeAsync { db in
|
||||
Dependencies()[singleton: .storage].writeAsync { db in
|
||||
OpenGroupManager.shared.delete(
|
||||
db,
|
||||
openGroupId: OpenGroup.idFor(roomToken: room, server: server),
|
||||
|
@ -1710,7 +1711,7 @@ extension ConversationVC:
|
|||
return
|
||||
}
|
||||
|
||||
dependencies.storage.writeAsync { [weak self] db in
|
||||
dependencies[singleton: .storage].writeAsync { [weak self] db in
|
||||
guard
|
||||
let threadId: String = self?.viewModel.threadData.threadId,
|
||||
let threadVariant: SessionThread.Variant = self?.viewModel.threadData.threadVariant,
|
||||
|
@ -1828,7 +1829,7 @@ extension ConversationVC:
|
|||
// Info messages and unsent messages should just trigger a local
|
||||
// deletion (they are created as side effects so we wouldn't be
|
||||
// able to delete them for all participants anyway)
|
||||
Storage.shared.writeAsync { db in
|
||||
Dependencies()[singleton: .storage].writeAsync { db in
|
||||
_ = try Interaction
|
||||
.filter(id: cellViewModel.id)
|
||||
.deleteAll(db)
|
||||
|
@ -1862,7 +1863,7 @@ extension ConversationVC:
|
|||
case .failure: break
|
||||
case .finished:
|
||||
// Delete the interaction (and associated data) from the database
|
||||
Storage.shared.writeAsync { db in
|
||||
Dependencies()[singleton: .storage].writeAsync { db in
|
||||
_ = try Interaction
|
||||
.filter(id: cellViewModel.id)
|
||||
.deleteAll(db)
|
||||
|
@ -1884,7 +1885,7 @@ extension ConversationVC:
|
|||
// Handle open group messages the old way
|
||||
case .community:
|
||||
// If it's an incoming message the user must have moderator status
|
||||
let result: (openGroupServerMessageId: Int64?, openGroup: OpenGroup?)? = Storage.shared.read { db -> (Int64?, OpenGroup?) in
|
||||
let result: (openGroupServerMessageId: Int64?, openGroup: OpenGroup?)? = dependencies[singleton: .storage].read { db -> (Int64?, OpenGroup?) in
|
||||
(
|
||||
try Interaction
|
||||
.select(.openGroupServerMessageId)
|
||||
|
@ -1910,7 +1911,7 @@ extension ConversationVC:
|
|||
guard cellViewModel.state == .sending || cellViewModel.state == .failed else { return }
|
||||
|
||||
// Retrieve any message send jobs for this interaction
|
||||
let jobs: [Job] = Storage.shared
|
||||
let jobs: [Job] = dependencies[singleton: .storage]
|
||||
.read { db in
|
||||
try? Job
|
||||
.filter(Job.Columns.variant == Job.Variant.messageSend)
|
||||
|
@ -1921,10 +1922,12 @@ extension ConversationVC:
|
|||
|
||||
// If the job is currently running then wait until it's done before triggering
|
||||
// the deletion
|
||||
let targetJob: Job? = jobs.first(where: { JobRunner.isCurrentlyRunning($0) })
|
||||
let targetJob: Job? = jobs.first(where: { job -> Bool in
|
||||
dependencies[singleton: .jobRunner].isCurrentlyRunning(job)
|
||||
})
|
||||
|
||||
guard targetJob == nil else {
|
||||
JobRunner.afterCurrentlyRunningJob(targetJob) { [weak self] result in
|
||||
dependencies[singleton: .jobRunner].afterCurrentlyRunningJob(targetJob) { [weak self] result in
|
||||
switch result {
|
||||
// If it succeeded then we'll need to delete from the server so re-run
|
||||
// this function (if we still don't have the server id for some reason
|
||||
|
@ -1934,9 +1937,9 @@ extension ConversationVC:
|
|||
// Otherwise we just need to cancel the pending job (in case it retries)
|
||||
// and delete the interaction
|
||||
default:
|
||||
JobRunner.removePendingJob(targetJob)
|
||||
dependencies[singleton: .jobRunner].removePendingJob(targetJob)
|
||||
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
_ = try Interaction
|
||||
.filter(id: cellViewModel.id)
|
||||
.deleteAll(db)
|
||||
|
@ -1948,9 +1951,9 @@ extension ConversationVC:
|
|||
|
||||
// If it's not currently running then remove any pending jobs (just to be safe) and
|
||||
// delete the interaction locally
|
||||
jobs.forEach { JobRunner.removePendingJob($0) }
|
||||
jobs.forEach { dependencies[singleton: .jobRunner].removePendingJob($0) }
|
||||
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
_ = try Interaction
|
||||
.filter(id: cellViewModel.id)
|
||||
.deleteAll(db)
|
||||
|
@ -1961,7 +1964,7 @@ extension ConversationVC:
|
|||
// Delete the message from the open group
|
||||
deleteRemotely(
|
||||
from: self,
|
||||
request: Storage.shared
|
||||
request: dependencies[singleton: .storage]
|
||||
.readPublisher { db in
|
||||
try OpenGroupAPI.preparedMessageDelete(
|
||||
db,
|
||||
|
@ -1982,7 +1985,7 @@ extension ConversationVC:
|
|||
userPublicKey :
|
||||
cellViewModel.threadId
|
||||
)
|
||||
let serverHash: String? = Storage.shared.read { db -> String? in
|
||||
let serverHash: String? = dependencies[singleton: .storage].read { db -> String? in
|
||||
try Interaction
|
||||
.select(.serverHash)
|
||||
.filter(id: cellViewModel.id)
|
||||
|
@ -1999,7 +2002,7 @@ extension ConversationVC:
|
|||
|
||||
// For incoming interactions or interactions with no serverHash just delete them locally
|
||||
guard cellViewModel.variant == .standardOutgoing, let serverHash: String = serverHash else {
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
_ = try Interaction
|
||||
.filter(id: cellViewModel.id)
|
||||
.deleteAll(db)
|
||||
|
@ -2027,7 +2030,7 @@ extension ConversationVC:
|
|||
accessibilityIdentifier: "Delete for me",
|
||||
style: .destructive
|
||||
) { [weak self] _ in
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
_ = try Interaction
|
||||
.filter(id: cellViewModel.id)
|
||||
.deleteAll(db)
|
||||
|
@ -2060,7 +2063,7 @@ extension ConversationVC:
|
|||
style: .destructive
|
||||
) { [weak self] _ in
|
||||
let completeServerDeletion = { [weak self] in
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
try MessageSender
|
||||
.send(
|
||||
db,
|
||||
|
@ -2159,7 +2162,7 @@ extension ConversationVC:
|
|||
confirmTitle: "BUTTON_OK".localized(),
|
||||
cancelStyle: .alert_text,
|
||||
onConfirm: { [weak self] _ in
|
||||
Storage.shared
|
||||
Dependencies()[singleton: .storage]
|
||||
.readPublisher { db -> HTTP.PreparedRequest<NoResponse> in
|
||||
guard let openGroup: OpenGroup = try OpenGroup.fetchOne(db, id: threadId) else {
|
||||
throw StorageError.objectNotFound
|
||||
|
@ -2215,7 +2218,7 @@ extension ConversationVC:
|
|||
confirmTitle: "BUTTON_OK".localized(),
|
||||
cancelStyle: .alert_text,
|
||||
onConfirm: { [weak self] _ in
|
||||
dependencies.storage
|
||||
dependencies[singleton: .storage]
|
||||
.readPublisher { db in
|
||||
guard let openGroup: OpenGroup = try OpenGroup.fetchOne(db, id: threadId) else {
|
||||
throw StorageError.objectNotFound
|
||||
|
@ -2407,7 +2410,7 @@ extension ConversationVC:
|
|||
let threadId: String = self.viewModel.threadData.threadId
|
||||
let threadVariant: SessionThread.Variant = self.viewModel.threadData.threadVariant
|
||||
|
||||
dependencies.storage.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
try MessageSender.send(
|
||||
db,
|
||||
message: DataExtractionNotification(
|
||||
|
@ -2477,11 +2480,11 @@ extension ConversationVC {
|
|||
// (it'll be updated with correct profile info if they accept the message request so this
|
||||
// shouldn't cause weird behaviours)
|
||||
guard
|
||||
let contact: Contact = Storage.shared.read({ db in Contact.fetchOrCreate(db, id: threadId) }),
|
||||
let contact: Contact = Dependencies()[singleton: .storage].read({ db in Contact.fetchOrCreate(db, id: threadId) }),
|
||||
!contact.isApproved
|
||||
else { return }
|
||||
|
||||
Storage.shared
|
||||
Dependencies()[singleton: .storage]
|
||||
.writePublisher { db in
|
||||
// If we aren't creating a new thread (ie. sending a message request) then send a
|
||||
// messageRequestResponse back to the sender (this allows the sender to know that
|
||||
|
|
|
@ -407,7 +407,7 @@ final class ConversationVC: BaseVC, SessionUtilRespondingViewController, Convers
|
|||
init(threadId: String, threadVariant: SessionThread.Variant, focusedInteractionInfo: Interaction.TimestampInfo? = nil) {
|
||||
self.viewModel = ConversationViewModel(threadId: threadId, threadVariant: threadVariant, focusedInteractionInfo: focusedInteractionInfo)
|
||||
|
||||
Storage.shared.addObserver(viewModel.pagedDataObserver)
|
||||
Dependencies()[singleton: .storage].addObserver(viewModel.pagedDataObserver)
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
@ -617,7 +617,7 @@ final class ConversationVC: BaseVC, SessionUtilRespondingViewController, Convers
|
|||
visibleOnly: true
|
||||
)
|
||||
{
|
||||
Storage.shared.writeAsync { db in
|
||||
Dependencies()[singleton: .storage].writeAsync { db in
|
||||
_ = try SessionThread // Intentionally use `deleteAll` here instead of `deleteOrLeave`
|
||||
.filter(id: threadId)
|
||||
.deleteAll(db)
|
||||
|
@ -652,7 +652,7 @@ final class ConversationVC: BaseVC, SessionUtilRespondingViewController, Convers
|
|||
private func startObservingChanges(didReturnFromBackground: Bool = false) {
|
||||
guard dataChangeObservable == nil else { return }
|
||||
|
||||
dataChangeObservable = Storage.shared.start(
|
||||
dataChangeObservable = Dependencies()[singleton: .storage].start(
|
||||
viewModel.observableThreadData,
|
||||
onError: { _ in },
|
||||
onChange: { [weak self] maybeThreadData in
|
||||
|
@ -665,7 +665,7 @@ final class ConversationVC: BaseVC, SessionUtilRespondingViewController, Convers
|
|||
SessionId.Prefix(from: sessionId) == .blinded15 ||
|
||||
SessionId.Prefix(from: sessionId) == .blinded25
|
||||
),
|
||||
let blindedLookup: BlindedIdLookup = Storage.shared.read({ db in
|
||||
let blindedLookup: BlindedIdLookup = Dependencies()[singleton: .storage].read({ db in
|
||||
try BlindedIdLookup
|
||||
.filter(id: sessionId)
|
||||
.fetchOne(db)
|
||||
|
@ -689,13 +689,13 @@ final class ConversationVC: BaseVC, SessionUtilRespondingViewController, Convers
|
|||
|
||||
// Stop observing changes
|
||||
self?.stopObservingChanges()
|
||||
Storage.shared.removeObserver(self?.viewModel.pagedDataObserver)
|
||||
Dependencies()[singleton: .storage].removeObserver(self?.viewModel.pagedDataObserver)
|
||||
|
||||
// Swap the observing to the updated thread
|
||||
self?.viewModel.swapToThread(updatedThreadId: unblindedId)
|
||||
|
||||
// Start observing changes again
|
||||
Storage.shared.addObserver(self?.viewModel.pagedDataObserver)
|
||||
Dependencies()[singleton: .storage].addObserver(self?.viewModel.pagedDataObserver)
|
||||
self?.startObservingChanges()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
private let initialUnreadInteractionId: Int64?
|
||||
private let markAsReadTrigger: PassthroughSubject<(SessionThreadViewModel.ReadTarget, Int64?), Never> = PassthroughSubject()
|
||||
private var markAsReadPublisher: AnyPublisher<Void, Never>?
|
||||
private let dependencies: Dependencies
|
||||
|
||||
public lazy var blockedBannerMessage: String = {
|
||||
switch self.threadData.threadVariant {
|
||||
|
@ -64,7 +65,12 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
|
||||
// MARK: - Initialization
|
||||
|
||||
init(threadId: String, threadVariant: SessionThread.Variant, focusedInteractionInfo: Interaction.TimestampInfo?) {
|
||||
init(
|
||||
threadId: String,
|
||||
threadVariant: SessionThread.Variant,
|
||||
focusedInteractionInfo: Interaction.TimestampInfo?,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
typealias InitialData = (
|
||||
currentUserPublicKey: String,
|
||||
initialUnreadInteractionInfo: Interaction.TimestampInfo?,
|
||||
|
@ -75,10 +81,10 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
blinded25Key: String?
|
||||
)
|
||||
|
||||
let initialData: InitialData? = Storage.shared.read { db -> InitialData in
|
||||
let initialData: InitialData? = dependencies[singleton: .storage].read { db -> InitialData in
|
||||
let interaction: TypedTableAlias<Interaction> = TypedTableAlias()
|
||||
let groupMember: TypedTableAlias<GroupMember> = TypedTableAlias()
|
||||
let currentUserPublicKey: String = getUserHexEncodedPublicKey(db)
|
||||
let currentUserPublicKey: String = getUserHexEncodedPublicKey(db, using: dependencies)
|
||||
|
||||
// If we have a specified 'focusedInteractionInfo' then use that, otherwise retrieve the oldest
|
||||
// unread interaction and start focused around that one
|
||||
|
@ -152,6 +158,7 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
currentUserBlinded25PublicKeyForThisThread: initialData?.blinded25Key
|
||||
)
|
||||
self.pagedDataObserver = nil
|
||||
self.dependencies = dependencies
|
||||
|
||||
// Note: Since this references self we need to finish initializing before setting it, we
|
||||
// also want to skip the initial query and trigger it async so that the push animation
|
||||
|
@ -161,7 +168,8 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
for: threadId,
|
||||
userPublicKey: (initialData?.currentUserPublicKey ?? getUserHexEncodedPublicKey()),
|
||||
blinded15PublicKey: initialData?.blinded15Key,
|
||||
blinded25PublicKey: initialData?.blinded25Key
|
||||
blinded25PublicKey: initialData?.blinded25Key,
|
||||
using: dependencies
|
||||
)
|
||||
|
||||
// Run the initial query on a background thread so we don't block the push transition
|
||||
|
@ -252,7 +260,8 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
for threadId: String,
|
||||
userPublicKey: String,
|
||||
blinded15PublicKey: String?,
|
||||
blinded25PublicKey: String?
|
||||
blinded25PublicKey: String?,
|
||||
using dependencies: Dependencies
|
||||
) -> PagedDatabaseObserver<Interaction, MessageViewModel> {
|
||||
return PagedDatabaseObserver(
|
||||
pagedTable: Interaction.self,
|
||||
|
@ -365,7 +374,8 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -633,12 +643,15 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
|
||||
// MARK: - Mentions
|
||||
|
||||
public func mentions(for query: String = "") -> [MentionInfo] {
|
||||
public func mentions(
|
||||
for query: String = "",
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) -> [MentionInfo] {
|
||||
let threadData: SessionThreadViewModel = self.threadData
|
||||
|
||||
return Storage.shared
|
||||
return dependencies[singleton: .storage]
|
||||
.read { db -> [MentionInfo] in
|
||||
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
||||
let userPublicKey: String = getUserHexEncodedPublicKey(db, using: dependencies)
|
||||
let pattern: FTS5Pattern? = try? SessionThreadViewModel.pattern(db, searchTerm: query, forTable: Profile.self)
|
||||
let capabilities: Set<Capability.Variant> = (threadData.threadVariant != .community ?
|
||||
nil :
|
||||
|
@ -670,9 +683,12 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
|
||||
// MARK: - Functions
|
||||
|
||||
public func updateDraft(to draft: String) {
|
||||
public func updateDraft(
|
||||
to draft: String,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
let threadId: String = self.threadId
|
||||
let currentDraft: String = Storage.shared
|
||||
let currentDraft: String = dependencies[singleton: .storage]
|
||||
.read { db in
|
||||
try SessionThread
|
||||
.select(.messageDraft)
|
||||
|
@ -685,7 +701,7 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
// Only write the updated draft to the database if it's changed (avoid unnecessary writes)
|
||||
guard draft != currentDraft else { return }
|
||||
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
try SessionThread
|
||||
.filter(id: threadId)
|
||||
.updateAll(db, SessionThread.Columns.messageDraft.set(to: draft))
|
||||
|
@ -741,7 +757,7 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
markAsReadTrigger.send((target, timestampMs))
|
||||
}
|
||||
|
||||
public func swapToThread(updatedThreadId: String) {
|
||||
public func swapToThread(updatedThreadId: String, using dependencies: Dependencies = Dependencies()) {
|
||||
let oldestMessageId: Int64? = self.interactionData
|
||||
.filter { $0.model == .messages }
|
||||
.first?
|
||||
|
@ -755,7 +771,8 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
for: updatedThreadId,
|
||||
userPublicKey: getUserHexEncodedPublicKey(),
|
||||
blinded15PublicKey: nil,
|
||||
blinded25PublicKey: nil
|
||||
blinded25PublicKey: nil,
|
||||
using: dependencies
|
||||
)
|
||||
|
||||
// Try load everything up to the initial visible message, fallback to just the initial page of messages
|
||||
|
@ -766,12 +783,12 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
public func trustContact() {
|
||||
public func trustContact(using dependencies: Dependencies = Dependencies()) {
|
||||
guard self.threadData.threadVariant == .contact else { return }
|
||||
|
||||
let threadId: String = self.threadId
|
||||
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
try Contact
|
||||
.filter(id: threadId)
|
||||
.updateAll(db, Contact.Columns.isTrusted.set(to: true))
|
||||
|
@ -782,7 +799,7 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
.stateInfo(authorId: threadId, state: .pendingDownload)
|
||||
.fetchAll(db)
|
||||
.forEach { attachmentDownloadInfo in
|
||||
JobRunner.add(
|
||||
dependencies[singleton: .jobRunner].add(
|
||||
db,
|
||||
job: Job(
|
||||
variant: .attachmentDownload,
|
||||
|
@ -791,18 +808,20 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
details: AttachmentDownloadJob.Details(
|
||||
attachmentId: attachmentDownloadInfo.attachmentId
|
||||
)
|
||||
)
|
||||
),
|
||||
canStartJob: true,
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func unblockContact() {
|
||||
public func unblockContact(using dependencies: Dependencies = Dependencies()) {
|
||||
guard self.threadData.threadVariant == .contact else { return }
|
||||
|
||||
let threadId: String = self.threadId
|
||||
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
try Contact
|
||||
.filter(id: threadId)
|
||||
.updateAllAndConfig(db, Contact.Columns.isBlocked.set(to: false))
|
||||
|
@ -1025,7 +1044,7 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
|
|||
.firstIndex(where: { $0.id == interactionId }),
|
||||
currentIndex < (messageSection.elements.count - 1),
|
||||
messageSection.elements[currentIndex + 1].cellType == .audio,
|
||||
Storage.shared[.shouldAutoPlayConsecutiveAudioMessages] == true
|
||||
dependencies[singleton: .storage][.shouldAutoPlayConsecutiveAudioMessages] == true
|
||||
else { return }
|
||||
|
||||
let nextItem: MessageViewModel = messageSection.elements[currentIndex + 1]
|
||||
|
|
|
@ -75,7 +75,7 @@ class EmojiPickerCollectionView: UICollectionView {
|
|||
tapGestureRecognizer.delegate = self
|
||||
|
||||
// Fetch the emoji data from the database
|
||||
let maybeEmojiData: (recent: [EmojiWithSkinTones], allGrouped: [Emoji.Category: [EmojiWithSkinTones]])? = Storage.shared.read { db in
|
||||
let maybeEmojiData: (recent: [EmojiWithSkinTones], allGrouped: [Emoji.Category: [EmojiWithSkinTones]])? = Dependencies()[singleton: .storage].read { db in
|
||||
// Some emoji have two different code points but identical appearances. Let's remove them!
|
||||
// If we normalize to a different emoji than the one currently in our array, we want to drop
|
||||
// the non-normalized variant if the normalized variant already exists. Otherwise, map to the
|
||||
|
@ -188,7 +188,7 @@ class EmojiPickerCollectionView: UICollectionView {
|
|||
currentSkinTonePicker?.dismiss()
|
||||
currentSkinTonePicker = EmojiSkinTonePicker.present(referenceView: cell, emoji: emoji) { [weak self] emoji in
|
||||
if let emoji: EmojiWithSkinTones = emoji {
|
||||
Storage.shared.writeAsync { db in
|
||||
Dependencies()[singleton: .storage].writeAsync { db in
|
||||
emoji.baseEmoji?.setPreferredSkinTones(
|
||||
db,
|
||||
preferredSkinTonePermutation: emoji.skinTones
|
||||
|
|
|
@ -282,14 +282,16 @@ final class InputView: UIView, InputViewButtonDelegate, InputTextViewDelegate, M
|
|||
quoteView.pin(.bottom, to: .bottom, of: additionalContentContainer, withInset: -6)
|
||||
}
|
||||
|
||||
private func autoGenerateLinkPreviewIfPossible() {
|
||||
private func autoGenerateLinkPreviewIfPossible(
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
// Don't allow link previews on 'none' or 'textOnly' input
|
||||
guard enabledMessageTypes == .all else { return }
|
||||
|
||||
// Suggest that the user enable link previews if they haven't already and we haven't
|
||||
// told them about link previews yet
|
||||
let text = inputTextView.text!
|
||||
let areLinkPreviewsEnabled: Bool = Storage.shared[.areLinkPreviewsEnabled]
|
||||
let areLinkPreviewsEnabled: Bool = dependencies[singleton: .storage][.areLinkPreviewsEnabled]
|
||||
|
||||
if
|
||||
!LinkPreview.allPreviewUrls(forMessageBodyText: text).isEmpty &&
|
||||
|
|
|
@ -141,7 +141,7 @@ final class CallMessageCell: MessageCell {
|
|||
|
||||
let shouldShowInfoIcon: Bool = (
|
||||
messageInfo.state == .permissionDenied &&
|
||||
!Storage.shared[.areCallsEnabled]
|
||||
!Dependencies()[singleton: .storage][.areCallsEnabled]
|
||||
)
|
||||
infoImageViewWidthConstraint.constant = (shouldShowInfoIcon ? CallMessageCell.iconSize : 0)
|
||||
infoImageViewHeightConstraint.constant = (shouldShowInfoIcon ? CallMessageCell.iconSize : 0)
|
||||
|
@ -177,7 +177,7 @@ final class CallMessageCell: MessageCell {
|
|||
else { return }
|
||||
|
||||
// Should only be tappable if the info icon is visible
|
||||
guard messageInfo.state == .permissionDenied && !Storage.shared[.areCallsEnabled] else { return }
|
||||
guard messageInfo.state == .permissionDenied && !Dependencies()[singleton: .storage][.areCallsEnabled] else { return }
|
||||
|
||||
self.delegate?.handleItemTapped(cellViewModel, gestureRecognizer: gestureRecognizer)
|
||||
}
|
||||
|
|
|
@ -483,7 +483,7 @@ class ThreadDisappearingMessagesSettingsViewModel: SessionTableViewModel<ThreadD
|
|||
|
||||
guard self.config != updatedConfig else { return }
|
||||
|
||||
dependencies.storage.writeAsync(using: dependencies) { db in
|
||||
dependencies[singleton: .storage].writeAsync(using: dependencies) { db in
|
||||
_ = try updatedConfig.saved(db)
|
||||
|
||||
_ = try Interaction
|
||||
|
@ -523,7 +523,7 @@ class ThreadDisappearingMessagesSettingsViewModel: SessionTableViewModel<ThreadD
|
|||
}
|
||||
|
||||
// Contacts & legacy closed groups need to update the SessionUtil
|
||||
dependencies.storage.writeAsync(using: dependencies) { db in
|
||||
dependencies[singleton: .storage].writeAsync(using: dependencies) { db in
|
||||
switch threadVariant {
|
||||
case .contact:
|
||||
try SessionUtil
|
||||
|
|
|
@ -72,7 +72,7 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
|
|||
self.didTriggerSearch = didTriggerSearch
|
||||
self.oldDisplayName = (threadVariant != .contact ?
|
||||
nil :
|
||||
dependencies.storage.read { db in
|
||||
dependencies[singleton: .storage].read { db in
|
||||
try Profile
|
||||
.filter(id: threadId)
|
||||
.select(.nickname)
|
||||
|
@ -151,7 +151,7 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
|
|||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
self?.oldDisplayName = (updatedNickname.isEmpty ? nil : editedDisplayName)
|
||||
|
||||
dependencies.storage.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
try Profile
|
||||
.filter(id: threadId)
|
||||
.updateAllAndConfig(
|
||||
|
@ -532,7 +532,7 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
|
|||
cancelStyle: .alert_text
|
||||
),
|
||||
onTap: {
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try SessionThread.deleteOrLeave(
|
||||
db,
|
||||
threadId: threadId,
|
||||
|
@ -596,7 +596,7 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
|
|||
onTap: {
|
||||
let newValue: Bool = !(threadViewModel.threadOnlyNotifyForMentions == true)
|
||||
|
||||
dependencies.storage.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
try SessionThread
|
||||
.filter(id: threadId)
|
||||
.updateAll(
|
||||
|
@ -635,7 +635,7 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
|
|||
label: "Mute notifications"
|
||||
),
|
||||
onTap: {
|
||||
dependencies.storage.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
let currentValue: TimeInterval? = try SessionThread
|
||||
.filter(id: threadId)
|
||||
.select(.mutedUntilTimestamp)
|
||||
|
@ -719,7 +719,7 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
|
|||
}
|
||||
.removeDuplicates()
|
||||
.handleEvents(didFail: { SNLog("[ThreadSettingsViewModel] Observation failed with error: \($0)") })
|
||||
.publisher(in: dependencies.storage, scheduling: dependencies.scheduler)
|
||||
.publisher(in: dependencies[singleton: .storage], scheduling: dependencies[singleton: .scheduler])
|
||||
.mapToSessionTableViewData(for: self)
|
||||
|
||||
// MARK: - Functions
|
||||
|
@ -764,7 +764,7 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
|
|||
publicKey: publicKey
|
||||
)
|
||||
|
||||
dependencies.storage.writeAsync { [dependencies] db in
|
||||
dependencies[singleton: .storage].writeAsync { [dependencies] db in
|
||||
try selectedUsers.forEach { userId in
|
||||
let thread: SessionThread = try SessionThread
|
||||
.fetchOrCreate(db, id: userId, variant: .contact, shouldBeVisible: nil)
|
||||
|
@ -810,7 +810,7 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
|
|||
) {
|
||||
guard oldBlockedState != isBlocked else { return }
|
||||
|
||||
dependencies.storage.writeAsync(
|
||||
dependencies[singleton: .storage].writeAsync(
|
||||
updates: { db in
|
||||
try Contact
|
||||
.filter(id: threadId)
|
||||
|
|
|
@ -32,7 +32,7 @@ class GlobalSearchViewController: BaseVC, SessionUtilRespondingViewController, U
|
|||
// MARK: - Variables
|
||||
|
||||
private lazy var defaultSearchResults: [SectionModel] = {
|
||||
let result: SessionThreadViewModel? = Storage.shared.read { db -> SessionThreadViewModel? in
|
||||
let result: SessionThreadViewModel? = Dependencies()[singleton: .storage].read { db -> SessionThreadViewModel? in
|
||||
try SessionThreadViewModel
|
||||
.noteToSelfOnlyQuery(userPublicKey: getUserHexEncodedPublicKey(db))
|
||||
.fetchOne(db)
|
||||
|
@ -160,7 +160,11 @@ class GlobalSearchViewController: BaseVC, SessionUtilRespondingViewController, U
|
|||
}
|
||||
}
|
||||
|
||||
private func updateSearchResults(searchText rawSearchText: String, force: Bool = false) {
|
||||
private func updateSearchResults(
|
||||
searchText rawSearchText: String,
|
||||
force: Bool = false,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
let searchText = rawSearchText.stripped
|
||||
|
||||
guard searchText.count > 0 else {
|
||||
|
@ -178,7 +182,7 @@ class GlobalSearchViewController: BaseVC, SessionUtilRespondingViewController, U
|
|||
DispatchQueue.global(qos: .default).async { [weak self] in
|
||||
self?.readConnection.wrappedValue?.interrupt()
|
||||
|
||||
let result: Result<[SectionModel], Error>? = Storage.shared.read { db -> Result<[SectionModel], Error> in
|
||||
let result: Result<[SectionModel], Error>? = dependencies[singleton: .storage].read { db -> Result<[SectionModel], Error> in
|
||||
self?.readConnection.mutate { $0 = db }
|
||||
|
||||
do {
|
||||
|
@ -308,7 +312,13 @@ extension GlobalSearchViewController {
|
|||
}
|
||||
}
|
||||
|
||||
private func show(threadId: String, threadVariant: SessionThread.Variant, focusedInteractionInfo: Interaction.TimestampInfo? = nil, animated: Bool = true) {
|
||||
private func show(
|
||||
threadId: String,
|
||||
threadVariant: SessionThread.Variant,
|
||||
focusedInteractionInfo: Interaction.TimestampInfo? = nil,
|
||||
animated: Bool = true,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
guard Thread.isMainThread else {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.show(threadId: threadId, threadVariant: threadVariant, focusedInteractionInfo: focusedInteractionInfo, animated: animated)
|
||||
|
@ -319,7 +329,7 @@ extension GlobalSearchViewController {
|
|||
// If it's a one-to-one thread then make sure the thread exists before pushing to it (in case the
|
||||
// contact has been hidden)
|
||||
if threadVariant == .contact {
|
||||
Storage.shared.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try SessionThread.fetchOrCreate(
|
||||
db,
|
||||
id: threadId,
|
||||
|
|
|
@ -29,7 +29,7 @@ final class HomeVC: BaseVC, SessionUtilRespondingViewController, UITableViewData
|
|||
// MARK: - Intialization
|
||||
|
||||
init() {
|
||||
Storage.shared.addObserver(viewModel.pagedDataObserver)
|
||||
Dependencies()[singleton: .storage].addObserver(viewModel.pagedDataObserver)
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
@ -282,7 +282,7 @@ final class HomeVC: BaseVC, SessionUtilRespondingViewController, UITableViewData
|
|||
|
||||
// Start polling if needed (i.e. if the user just created or restored their Session ID)
|
||||
if Identity.userExists(), let appDelegate: AppDelegate = UIApplication.shared.delegate as? AppDelegate {
|
||||
appDelegate.startPollersIfNeeded()
|
||||
appDelegate.startPollersIfNeeded(using: Dependencies())
|
||||
}
|
||||
|
||||
// Onion request path countries cache
|
||||
|
@ -333,7 +333,7 @@ final class HomeVC: BaseVC, SessionUtilRespondingViewController, UITableViewData
|
|||
runAndClearInitialChangeCallback = nil
|
||||
}
|
||||
|
||||
dataChangeObservable = Storage.shared.start(
|
||||
dataChangeObservable = Dependencies()[singleton: .storage].start(
|
||||
viewModel.observableState,
|
||||
onError: { _ in },
|
||||
onChange: { [weak self] state in
|
||||
|
|
|
@ -31,18 +31,20 @@ public class HomeViewModel {
|
|||
|
||||
// MARK: - Initialization
|
||||
|
||||
init() {
|
||||
init(
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
typealias InitialData = (
|
||||
showViewedSeedBanner: Bool,
|
||||
hasHiddenMessageRequests: Bool,
|
||||
profile: Profile
|
||||
)
|
||||
|
||||
let initialData: InitialData? = Storage.shared.read { db -> InitialData in
|
||||
let initialData: InitialData? = dependencies[singleton: .storage].read { db -> InitialData in
|
||||
(
|
||||
!db[.hasViewedSeed],
|
||||
db[.hasHiddenMessageRequests],
|
||||
Profile.fetchOrCreateCurrentUser(db)
|
||||
Profile.fetchOrCreateCurrentUser(db, using: dependencies)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -217,7 +219,8 @@ public class HomeViewModel {
|
|||
)
|
||||
|
||||
self?.hasReceivedInitialThreadData = true
|
||||
}
|
||||
},
|
||||
using: dependencies
|
||||
)
|
||||
|
||||
// Run the initial query on a background thread so we don't block the main thread
|
||||
|
|
|
@ -24,7 +24,7 @@ class MessageRequestsViewController: BaseVC, SessionUtilRespondingViewController
|
|||
// MARK: - Intialization
|
||||
|
||||
init() {
|
||||
Storage.shared.addObserver(viewModel.pagedDataObserver)
|
||||
Dependencies()[singleton: .storage].addObserver(viewModel.pagedDataObserver)
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
|
|
@ -188,7 +188,7 @@ public class MessageRequestsViewModel {
|
|||
groupThreadIds: [String]
|
||||
) {
|
||||
// Clear the requests
|
||||
Storage.shared.write { db in
|
||||
Dependencies()[singleton: .storage].write { db in
|
||||
// Remove the one-to-one requests
|
||||
try SessionThread.deleteOrLeave(
|
||||
db,
|
||||
|
|
|
@ -31,7 +31,7 @@ public class DocumentTileViewController: UIViewController, UITableViewDelegate,
|
|||
|
||||
init(viewModel: MediaGalleryViewModel) {
|
||||
self.viewModel = viewModel
|
||||
Storage.shared.addObserver(viewModel.pagedDataObserver)
|
||||
Dependencies()[singleton: .storage].addObserver(viewModel.pagedDataObserver)
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
|
|
@ -399,7 +399,7 @@ public class MediaGalleryViewModel {
|
|||
|
||||
// Note: It's possible we already have cached album data for this interaction
|
||||
// but to avoid displaying stale data we re-fetch from the database anyway
|
||||
let maybeAlbumInfo: AlbumInfo? = Storage.shared.read { db -> AlbumInfo in
|
||||
let maybeAlbumInfo: AlbumInfo? = Dependencies()[singleton: .storage].read { db -> AlbumInfo in
|
||||
let attachment: TypedTableAlias<Attachment> = TypedTableAlias()
|
||||
let interaction: TypedTableAlias<Interaction> = TypedTableAlias()
|
||||
let interactionAttachment: TypedTableAlias<InteractionAttachment> = TypedTableAlias()
|
||||
|
|
|
@ -393,7 +393,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
|
|||
guard dataChangeObservable == nil else { return }
|
||||
|
||||
// Start observing for data changes
|
||||
dataChangeObservable = Storage.shared.start(
|
||||
dataChangeObservable = Dependencies()[singleton: .storage].start(
|
||||
viewModel.observableAlbumData,
|
||||
onError: { _ in },
|
||||
onChange: { [weak self] albumData in
|
||||
|
@ -545,7 +545,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
|
|||
let threadId: String = self.viewModel.threadId
|
||||
let threadVariant: SessionThread.Variant = self.viewModel.threadVariant
|
||||
|
||||
Storage.shared.write { db in
|
||||
Dependencies()[singleton: .storage].write { db in
|
||||
try MessageSender.send(
|
||||
db,
|
||||
message: DataExtractionNotification(
|
||||
|
@ -571,13 +571,13 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
|
|||
title: "delete_message_for_me".localized(),
|
||||
style: .destructive
|
||||
) { _ in
|
||||
Storage.shared.writeAsync { db in
|
||||
Dependencies()[singleton: .storage].writeAsync { db in
|
||||
_ = try Attachment
|
||||
.filter(id: itemToDelete.attachment.id)
|
||||
.deleteAll(db)
|
||||
|
||||
// Add the garbage collection job to delete orphaned attachment files
|
||||
JobRunner.add(
|
||||
Dependencies()[singleton: .jobRunner].add(
|
||||
db,
|
||||
job: Job(
|
||||
variant: .garbageCollection,
|
||||
|
@ -585,7 +585,9 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
|
|||
details: GarbageCollectionJob.Details(
|
||||
typesToCollect: [.orphanedAttachmentFiles]
|
||||
)
|
||||
)
|
||||
),
|
||||
canStartJob: true,
|
||||
using: Dependencies()
|
||||
)
|
||||
|
||||
// Delete any interactions which had all of their attachments removed
|
||||
|
@ -891,7 +893,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
|
|||
let name: String = {
|
||||
switch targetItem.interactionVariant {
|
||||
case .standardIncoming:
|
||||
return Storage.shared
|
||||
return Dependencies()[singleton: .storage]
|
||||
.read { db in
|
||||
Profile.displayName(
|
||||
db,
|
||||
|
|
|
@ -39,7 +39,7 @@ public class MediaTileViewController: UIViewController, UICollectionViewDataSour
|
|||
|
||||
init(viewModel: MediaGalleryViewModel) {
|
||||
self.viewModel = viewModel
|
||||
Storage.shared.addObserver(viewModel.pagedDataObserver)
|
||||
Dependencies()[singleton: .storage].addObserver(viewModel.pagedDataObserver)
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
@ -691,7 +691,7 @@ public class MediaTileViewController: UIViewController, UICollectionViewDataSour
|
|||
}()
|
||||
|
||||
let deleteAction = UIAlertAction(title: confirmationTitle, style: .destructive) { [weak self] _ in
|
||||
Storage.shared.writeAsync { db in
|
||||
Dependencies()[singleton: .storage].writeAsync { db in
|
||||
let interactionIds: Set<Int64> = items
|
||||
.map { $0.interactionId }
|
||||
.asSet()
|
||||
|
@ -701,7 +701,7 @@ public class MediaTileViewController: UIViewController, UICollectionViewDataSour
|
|||
.deleteAll(db)
|
||||
|
||||
// Add the garbage collection job to delete orphaned attachment files
|
||||
JobRunner.add(
|
||||
Dependencies()[singleton: .jobRunner].add(
|
||||
db,
|
||||
job: Job(
|
||||
variant: .garbageCollection,
|
||||
|
@ -709,7 +709,9 @@ public class MediaTileViewController: UIViewController, UICollectionViewDataSour
|
|||
details: GarbageCollectionJob.Details(
|
||||
typesToCollect: [.orphanedAttachmentFiles]
|
||||
)
|
||||
)
|
||||
),
|
||||
canStartJob: true,
|
||||
using: Dependencies()
|
||||
)
|
||||
|
||||
// Delete any interactions which had all of their attachments removed
|
||||
|
|
|
@ -35,6 +35,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
SetCurrentAppContext(MainAppContext())
|
||||
verifyDBKeysAvailableBeforeBackgroundLaunch()
|
||||
|
||||
// Called via the OS so create a default 'Dependencies' instance
|
||||
let dependencies: Dependencies = Dependencies()
|
||||
Cryptography.seedRandom()
|
||||
AppVersion.sharedInstance()
|
||||
AppEnvironment.shared.pushRegistrationManager.createVoipRegistryIfNecessary()
|
||||
|
@ -74,7 +76,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
if case .failure(let error) = result {
|
||||
DispatchQueue.main.async {
|
||||
self?.initialLaunchFailed = true
|
||||
self?.showFailedStartupAlert(calledFrom: .finishLaunching, error: .databaseError(error))
|
||||
self?.showFailedStartupAlert(
|
||||
calledFrom: .finishLaunching,
|
||||
error: .databaseError(error),
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -84,7 +90,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
/// **Note:** Need to do this after the db migrations because theme preferences are stored in the database and
|
||||
/// we don't want to access it until after the migrations run
|
||||
ThemeManager.mainWindow = mainWindow
|
||||
self?.completePostMigrationSetup(calledFrom: .finishLaunching, needsConfigSync: needsConfigSync)
|
||||
self?.completePostMigrationSetup(
|
||||
calledFrom: .finishLaunching,
|
||||
needsConfigSync: needsConfigSync,
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -135,14 +145,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
/// Apple's documentation on the matter)
|
||||
UNUserNotificationCenter.current().delegate = self
|
||||
|
||||
Storage.resumeDatabaseAccess()
|
||||
// Called via the OS so create a default 'Dependencies' instance
|
||||
let dependencies: Dependencies = Dependencies()
|
||||
Storage.resumeDatabaseAccess(using: dependencies)
|
||||
|
||||
// Reset the 'startTime' (since it would be invalid from the last launch)
|
||||
startTime = CACurrentMediaTime()
|
||||
|
||||
// If we've already completed migrations at least once this launch then check
|
||||
// to see if any "delayed" migrations now need to run
|
||||
if Storage.shared.hasCompletedMigrations {
|
||||
if dependencies[singleton: .storage].hasCompletedMigrations {
|
||||
SNLog("Checking for pending migrations")
|
||||
let initialLaunchFailed: Bool = self.initialLaunchFailed
|
||||
|
||||
|
@ -169,7 +181,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
DispatchQueue.main.async {
|
||||
self?.showFailedStartupAlert(
|
||||
calledFrom: .enterForeground(initialLaunchFailed: initialLaunchFailed),
|
||||
error: .databaseError(error)
|
||||
error: .databaseError(error),
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
return
|
||||
|
@ -177,9 +190,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
|
||||
self?.completePostMigrationSetup(
|
||||
calledFrom: .enterForeground(initialLaunchFailed: initialLaunchFailed),
|
||||
needsConfigSync: needsConfigSync
|
||||
needsConfigSync: needsConfigSync,
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
},
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -190,12 +205,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
|
||||
DDLog.flushLog()
|
||||
|
||||
// Called via the OS so create a default 'Dependencies' instance
|
||||
let dependencies: Dependencies = Dependencies()
|
||||
|
||||
// NOTE: Fix an edge case where user taps on the callkit notification
|
||||
// but answers the call on another device
|
||||
stopPollers(shouldStopUserPoller: !self.hasCallOngoing())
|
||||
stopPollers(shouldStopUserPoller: !self.hasCallOngoing(), using: dependencies)
|
||||
|
||||
// Stop all jobs except for message sending and when completed suspend the database
|
||||
JobRunner.stopAndClearPendingJobs(exceptForVariant: .messageSend) {
|
||||
dependencies[singleton: .jobRunner].stopAndClearPendingJobs(exceptForVariant: .messageSend) {
|
||||
if !self.hasCallOngoing() {
|
||||
Storage.suspendDatabaseAccess()
|
||||
}
|
||||
|
@ -215,12 +233,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
guard !SNUtilitiesKit.isRunningTests else { return }
|
||||
|
||||
// Called via the OS so create a default 'Dependencies' instance
|
||||
let dependencies: Dependencies = Dependencies()
|
||||
UserDefaults.sharedLokiProject?[.isMainAppActive] = true
|
||||
|
||||
ensureRootViewController(calledFrom: .didBecomeActive)
|
||||
ensureRootViewController(calledFrom: .didBecomeActive, using: dependencies)
|
||||
|
||||
AppReadiness.runNowOrWhenAppDidBecomeReady { [weak self] in
|
||||
self?.handleActivation()
|
||||
self?.handleActivation(using: dependencies)
|
||||
|
||||
/// Clear all notifications whenever we become active once the app is ready
|
||||
///
|
||||
|
@ -229,7 +249,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
/// within the `runNowOrWhenAppDidBecomeReady` callback and dispatch to the next run loop to ensure it runs after
|
||||
/// the notification has actually been handled
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.clearAllNotificationsAndRestoreBadgeCount()
|
||||
self?.clearAllNotificationsAndRestoreBadgeCount(using: dependencies)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,13 +332,17 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
|
||||
// MARK: - App Readiness
|
||||
|
||||
private func completePostMigrationSetup(calledFrom lifecycleMethod: LifecycleMethod, needsConfigSync: Bool) {
|
||||
private func completePostMigrationSetup(
|
||||
calledFrom lifecycleMethod: LifecycleMethod,
|
||||
needsConfigSync: Bool,
|
||||
using dependencies: Dependencies
|
||||
) {
|
||||
SNLog("Migrations completed, performing setup and ensuring rootViewController")
|
||||
Configuration.performMainSetup()
|
||||
JobRunner.setExecutor(SyncPushTokensJob.self, for: .syncPushTokens)
|
||||
Configuration.performMainSetup(using: dependencies)
|
||||
dependencies[singleton: .jobRunner].setExecutor(SyncPushTokensJob.self, for: .syncPushTokens)
|
||||
|
||||
// Setup the UI if needed, then trigger any post-UI setup actions
|
||||
self.ensureRootViewController(calledFrom: lifecycleMethod) { [weak self] success in
|
||||
self.ensureRootViewController(calledFrom: lifecycleMethod, using: dependencies) { [weak self] success in
|
||||
// If we didn't successfully ensure the rootViewController then don't continue as
|
||||
// the user is in an invalid state (and should have already been shown a modal)
|
||||
guard success else { return }
|
||||
|
@ -326,12 +350,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
SNLog("RootViewController ready, readying remaining processes")
|
||||
self?.initialLaunchFailed = false
|
||||
|
||||
/// Trigger any launch-specific jobs and start the JobRunner with `JobRunner.appDidFinishLaunching()` some
|
||||
/// Trigger any launch-specific jobs and start the JobRunner with `jobRunner.appDidFinishLaunching(using:)` some
|
||||
/// of these jobs (eg. DisappearingMessages job) can impact the interactions which get fetched to display on the home
|
||||
/// screen, if the PagedDatabaseObserver hasn't been setup yet then the home screen can show stale (ie. deleted)
|
||||
/// interactions incorrectly
|
||||
if lifecycleMethod == .finishLaunching {
|
||||
JobRunner.appDidFinishLaunching()
|
||||
dependencies[singleton: .jobRunner].appDidFinishLaunching(using: dependencies)
|
||||
}
|
||||
|
||||
/// Flag that the app is ready via `AppReadiness.setAppIsReady()`
|
||||
|
@ -341,7 +365,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
///
|
||||
/// **Note:** This this does much more than set a flag - it will also run all deferred blocks (including the JobRunner
|
||||
/// `appDidBecomeActive` method hence why it **must** also come after calling
|
||||
/// `JobRunner.appDidFinishLaunching()`)
|
||||
/// `jobRunner.appDidFinishLaunching(using:)`)
|
||||
AppReadiness.setAppIsReady()
|
||||
|
||||
/// Remove the sleep blocking once the startup is done (needs to run on the main thread and sleeping while
|
||||
|
@ -352,7 +376,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
AppVersion.sharedInstance().mainAppLaunchDidComplete()
|
||||
|
||||
/// App won't be ready for extensions and no need to enqueue a config sync unless we successfully completed startup
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
// Increment the launch count (guaranteed to change which results in the write actually
|
||||
// doing something and outputting and error if the DB is suspended)
|
||||
db[.activeCounter] = ((db[.activeCounter] ?? 0) + 1)
|
||||
|
@ -391,6 +415,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
calledFrom lifecycleMethod: LifecycleMethod,
|
||||
error: StartupError,
|
||||
animated: Bool = true,
|
||||
using dependencies: Dependencies,
|
||||
presentationCompletion: (() -> ())? = nil
|
||||
) {
|
||||
/// This **must** be a standard `UIAlertController` instead of a `ConfirmationModal` because we may not
|
||||
|
@ -408,7 +433,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
// the app)
|
||||
guard self?.hasInitialRootViewController == false else { return }
|
||||
|
||||
self?.showFailedStartupAlert(calledFrom: lifecycleMethod, error: error)
|
||||
self?.showFailedStartupAlert(calledFrom: lifecycleMethod, error: error, using: dependencies)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -439,13 +464,22 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
switch result {
|
||||
case .failure:
|
||||
DispatchQueue.main.async {
|
||||
self?.showFailedStartupAlert(calledFrom: lifecycleMethod, error: .failedToRestore)
|
||||
self?.showFailedStartupAlert(
|
||||
calledFrom: lifecycleMethod,
|
||||
error: .failedToRestore,
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
|
||||
case .success:
|
||||
self?.completePostMigrationSetup(calledFrom: lifecycleMethod, needsConfigSync: needsConfigSync)
|
||||
self?.completePostMigrationSetup(
|
||||
calledFrom: lifecycleMethod,
|
||||
needsConfigSync: needsConfigSync,
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
using: dependencies
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -498,19 +532,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
}
|
||||
}
|
||||
|
||||
private func handleActivation() {
|
||||
private func handleActivation(using dependencies: Dependencies = Dependencies()) {
|
||||
/// There is a _fun_ behaviour here where if the user launches the app, sends it to the background at the right time and then
|
||||
/// opens it again the `AppReadiness` closures can be triggered before `applicationDidBecomeActive` has been
|
||||
/// called again - this can result in odd behaviours so hold off on running this logic until it's properly called again
|
||||
guard
|
||||
Identity.userExists() &&
|
||||
Identity.userExists(using: dependencies) &&
|
||||
UserDefaults.sharedLokiProject?[.isMainAppActive] == true
|
||||
else { return }
|
||||
|
||||
enableBackgroundRefreshIfNecessary()
|
||||
JobRunner.appDidBecomeActive()
|
||||
dependencies[singleton: .jobRunner].appDidBecomeActive(using: dependencies)
|
||||
|
||||
startPollersIfNeeded()
|
||||
startPollersIfNeeded(using: dependencies)
|
||||
|
||||
if CurrentAppContext().isMainApp {
|
||||
handleAppActivatedWithOngoingCallIfNeeded()
|
||||
|
@ -519,13 +553,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
|
||||
private func ensureRootViewController(
|
||||
calledFrom lifecycleMethod: LifecycleMethod,
|
||||
using dependencies: Dependencies,
|
||||
onComplete: @escaping ((Bool) -> ()) = { _ in }
|
||||
) {
|
||||
let hasInitialRootViewController: Bool = self.hasInitialRootViewController
|
||||
|
||||
// Always call the completion block and indicate whether we successfully created the UI
|
||||
guard
|
||||
Storage.shared.isValid &&
|
||||
dependencies[singleton: .storage].isValid &&
|
||||
(
|
||||
AppReadiness.isAppReady() ||
|
||||
lifecycleMethod == .finishLaunching ||
|
||||
|
@ -541,7 +576,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
repeats: false
|
||||
) { [weak self] timer in
|
||||
timer.invalidate()
|
||||
self?.showFailedStartupAlert(calledFrom: lifecycleMethod, error: .startupTimeout)
|
||||
self?.showFailedStartupAlert(
|
||||
calledFrom: lifecycleMethod,
|
||||
error: .startupTimeout,
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
|
||||
// All logic which needs to run after the 'rootViewController' is created
|
||||
|
@ -577,7 +616,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
case is UIAlertController, is ConfirmationModal:
|
||||
/// If the viewController we were presenting happened to be the "failed startup" modal then we can dismiss it
|
||||
/// automatically (while this seems redundant it's less jarring for the user than just instantly having it disappear)
|
||||
self?.showFailedStartupAlert(calledFrom: lifecycleMethod, error: .startupTimeout, animated: false) {
|
||||
self?.showFailedStartupAlert(
|
||||
calledFrom: lifecycleMethod,
|
||||
error: .startupTimeout,
|
||||
animated: false,
|
||||
using: dependencies
|
||||
) {
|
||||
self?.window?.rootViewController?.dismiss(animated: true)
|
||||
}
|
||||
|
||||
|
@ -642,7 +686,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
#endif
|
||||
}
|
||||
|
||||
private func clearAllNotificationsAndRestoreBadgeCount() {
|
||||
private func clearAllNotificationsAndRestoreBadgeCount(using dependencies: Dependencies = Dependencies()) {
|
||||
AppReadiness.runNowOrWhenAppDidBecomeReady {
|
||||
AppEnvironment.shared.notificationPresenter.clearAllNotifications()
|
||||
|
||||
|
@ -652,9 +696,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
/// read pools (up to a few seconds), since this read is blocking we want to dispatch it to run async to ensure
|
||||
/// we don't block user interaction while it's running
|
||||
DispatchQueue.global(qos: .default).async {
|
||||
let unreadCount: Int = Storage.shared
|
||||
let unreadCount: Int = dependencies[singleton: .storage]
|
||||
.read { db in
|
||||
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
||||
let userPublicKey: String = getUserHexEncodedPublicKey(db, using: dependencies)
|
||||
let thread: TypedTableAlias<SessionThread> = TypedTableAlias()
|
||||
|
||||
return try Interaction
|
||||
|
@ -766,28 +810,34 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
|||
|
||||
// MARK: - Polling
|
||||
|
||||
public func startPollersIfNeeded(shouldStartGroupPollers: Bool = true) {
|
||||
guard Identity.userExists() else { return }
|
||||
public func startPollersIfNeeded(
|
||||
shouldStartGroupPollers: Bool = true,
|
||||
using dependencies: Dependencies
|
||||
) {
|
||||
guard Identity.userExists(using: dependencies) else { return }
|
||||
|
||||
/// There is a fun issue where if you launch without any valid paths then the pollers are guaranteed to fail their first poll due to
|
||||
/// trying and failing to build paths without having the `SnodeAPI.snodePool` populated, by waiting for the
|
||||
/// `JobRunner.blockingQueue` to complete we can have more confidence that paths won't fail to build incorrectly
|
||||
JobRunner.afterBlockingQueue { [weak self] in
|
||||
/// `jobRunner.blockingQueue` to complete we can have more confidence that paths won't fail to build incorrectly
|
||||
dependencies[singleton: .jobRunner].afterBlockingQueue { [weak self] in
|
||||
self?.poller.start()
|
||||
|
||||
guard shouldStartGroupPollers else { return }
|
||||
|
||||
ClosedGroupPoller.shared.start()
|
||||
dependencies[singleton: .closedGroupPoller].start(using: dependencies)
|
||||
OpenGroupManager.shared.startPolling()
|
||||
}
|
||||
}
|
||||
|
||||
public func stopPollers(shouldStopUserPoller: Bool = true) {
|
||||
public func stopPollers(
|
||||
shouldStopUserPoller: Bool = true,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
if shouldStopUserPoller {
|
||||
poller.stopAllPollers()
|
||||
}
|
||||
|
||||
ClosedGroupPoller.shared.stopAllPollers()
|
||||
|
||||
dependencies[singleton: .closedGroupPoller].stopAllPollers()
|
||||
OpenGroupManager.shared.stopPolling()
|
||||
}
|
||||
|
||||
|
|
|
@ -40,9 +40,10 @@ public struct SessionApp {
|
|||
variant: SessionThread.Variant,
|
||||
action: ConversationViewModel.Action = .none,
|
||||
dismissing presentingViewController: UIViewController?,
|
||||
animated: Bool
|
||||
animated: Bool,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
let threadInfo: (threadExists: Bool, isMessageRequest: Bool)? = Storage.shared.read { db in
|
||||
let threadInfo: (threadExists: Bool, isMessageRequest: Bool)? = dependencies[singleton: .storage].read { db in
|
||||
let isMessageRequest: Bool = {
|
||||
switch variant {
|
||||
case .contact:
|
||||
|
@ -50,7 +51,7 @@ public struct SessionApp {
|
|||
.isMessageRequest(
|
||||
id: threadId,
|
||||
variant: .contact,
|
||||
currentUserPublicKey: getUserHexEncodedPublicKey(db),
|
||||
currentUserPublicKey: getUserHexEncodedPublicKey(db, using: dependencies),
|
||||
shouldBeVisible: nil,
|
||||
contactIsApproved: (try? Contact
|
||||
.filter(id: threadId)
|
||||
|
@ -86,7 +87,7 @@ public struct SessionApp {
|
|||
/// should do it on a background thread just in case something is keeping the DBWrite thread busy as in the past this could cause the app to hang
|
||||
guard threadInfo?.threadExists == true else {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
Storage.shared.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try SessionThread.fetchOrCreate(db, id: threadId, variant: variant, shouldBeVisible: nil)
|
||||
}
|
||||
|
||||
|
|
|
@ -512,7 +512,7 @@ public class NotificationPresenter: NotificationsProtocol {
|
|||
|
||||
private func checkIfShouldPlaySound(applicationState: UIApplication.State) -> Bool {
|
||||
guard applicationState == .active else { return true }
|
||||
guard Storage.shared[.playNotificationSoundInForeground] else { return false }
|
||||
guard Dependencies()[singleton: .storage][.playNotificationSoundInForeground] else { return false }
|
||||
|
||||
let nowMs: UInt64 = UInt64(floor(Date().timeIntervalSince1970 * 1000))
|
||||
let recentThreshold = nowMs - UInt64(kAudioNotificationsThrottleInterval * Double(kSecondInMs))
|
||||
|
@ -544,7 +544,7 @@ class NotificationActionHandler {
|
|||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
guard Storage.shared.read({ db in try SessionThread.exists(db, id: threadId) }) == true else {
|
||||
guard Dependencies()[singleton: .storage].read({ db in try SessionThread.exists(db, id: threadId) }) == true else {
|
||||
return Fail(error: NotificationError.failDebug("unable to find thread with id: \(threadId)"))
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
@ -563,12 +563,12 @@ class NotificationActionHandler {
|
|||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
guard let thread: SessionThread = Storage.shared.read({ db in try SessionThread.fetchOne(db, id: threadId) }) else {
|
||||
guard let thread: SessionThread = dependencies[singleton: .storage].read({ db in try SessionThread.fetchOne(db, id: threadId) }) else {
|
||||
return Fail<Void, Error>(error: NotificationError.failDebug("unable to find thread with id: \(threadId)"))
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
return dependencies.storage
|
||||
return dependencies[singleton: .storage]
|
||||
.writePublisher { db in
|
||||
let interaction: Interaction = try Interaction(
|
||||
threadId: threadId,
|
||||
|
@ -607,7 +607,7 @@ class NotificationActionHandler {
|
|||
switch result {
|
||||
case .finished: break
|
||||
case .failure:
|
||||
Storage.shared.read { [weak self] db in
|
||||
dependencies[singleton: .storage].read { [weak self] db in
|
||||
self?.notificationPresenter.notifyForFailedSend(
|
||||
db,
|
||||
in: thread,
|
||||
|
@ -651,7 +651,7 @@ class NotificationActionHandler {
|
|||
threadId: String,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) -> AnyPublisher<Void, Error> {
|
||||
return dependencies.storage
|
||||
return dependencies[singleton: .storage]
|
||||
.writePublisher { db in
|
||||
guard
|
||||
let threadVariant: SessionThread.Variant = try SessionThread
|
||||
|
|
|
@ -286,11 +286,13 @@ public enum PushRegistrationError: Error {
|
|||
return
|
||||
}
|
||||
|
||||
// Called via the OS so create a default 'Dependencies' instance
|
||||
let dependencies: Dependencies = Dependencies()
|
||||
Storage.resumeDatabaseAccess()
|
||||
|
||||
let maybeCall: SessionCall? = Storage.shared.write { db in
|
||||
let maybeCall: SessionCall? = dependencies[singleton: .storage].write { db in
|
||||
let messageInfo: CallMessage.MessageInfo = CallMessage.MessageInfo(
|
||||
state: (caller == getUserHexEncodedPublicKey(db) ?
|
||||
state: (caller == getUserHexEncodedPublicKey(db, using: dependencies) ?
|
||||
.outgoing :
|
||||
.incoming
|
||||
)
|
||||
|
@ -327,7 +329,7 @@ public enum PushRegistrationError: Error {
|
|||
}
|
||||
|
||||
// NOTE: Just start 1-1 poller so that it won't wait for polling group messages
|
||||
(UIApplication.shared.delegate as? AppDelegate)?.startPollersIfNeeded(shouldStartGroupPollers: false)
|
||||
(UIApplication.shared.delegate as? AppDelegate)?.startPollersIfNeeded(shouldStartGroupPollers: false, using: dependencies)
|
||||
|
||||
call.reportIncomingCallIfNeeded { error in
|
||||
if let error = error {
|
||||
|
|
|
@ -37,7 +37,7 @@ public enum SyncPushTokensJob: JobExecutor {
|
|||
// If the job is running and 'Fast Mode' is disabled then we should try to unregister the existing
|
||||
// token
|
||||
guard isUsingFullAPNs else {
|
||||
Just(dependencies.storage[.lastRecordedPushToken])
|
||||
Just(dependencies[singleton: .storage][.lastRecordedPushToken])
|
||||
.setFailureType(to: Error.self)
|
||||
.flatMap { lastRecordedPushToken -> AnyPublisher<Void, Error> in
|
||||
// Tell the device to unregister for remote notifications (essentially try to invalidate
|
||||
|
@ -46,7 +46,7 @@ public enum SyncPushTokensJob: JobExecutor {
|
|||
DispatchQueue.main.sync { UIApplication.shared.unregisterForRemoteNotifications() }
|
||||
|
||||
// Clear the old token
|
||||
dependencies.storage.write(using: dependencies) { db in
|
||||
dependencies[singleton: .storage].write(using: dependencies) { db in
|
||||
db[.lastRecordedPushToken] = nil
|
||||
}
|
||||
|
||||
|
@ -102,9 +102,9 @@ public enum SyncPushTokensJob: JobExecutor {
|
|||
case .finished:
|
||||
Logger.warn("Recording push tokens locally. pushToken: \(redact(pushToken)), voipToken: \(redact(voipToken))")
|
||||
SNLog("[SyncPushTokensJob] Completed")
|
||||
dependencies.standardUserDefaults[.lastPushNotificationSync] = dependencies.dateNow
|
||||
dependencies[singleton: .standardUserDefaults][.lastPushNotificationSync] = dependencies.dateNow
|
||||
|
||||
dependencies.storage.write(using: dependencies) { db in
|
||||
dependencies[singleton: .storage].write(using: dependencies) { db in
|
||||
db[.lastRecordedPushToken] = pushToken
|
||||
db[.lastRecordedVoipToken] = voipToken
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ enum Onboarding {
|
|||
.map { _ -> String? in
|
||||
guard requestId == profileNameRetrievalIdentifier.wrappedValue else { return nil }
|
||||
|
||||
return Storage.shared.read { db in
|
||||
return dependencies[singleton: .storage].read { db in
|
||||
try Profile
|
||||
.filter(id: userPublicKey)
|
||||
.select(.name)
|
||||
|
@ -89,7 +89,7 @@ enum Onboarding {
|
|||
SessionUtil.clearMemoryState(using: dependencies)
|
||||
|
||||
// Clear any data which gets set during Onboarding
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
db[.hasViewedSeed] = false
|
||||
|
||||
try SessionThread.deleteAll(db)
|
||||
|
@ -104,7 +104,7 @@ enum Onboarding {
|
|||
profileNameRetrievalIdentifier.mutate { $0 = nil }
|
||||
profileNameRetrievalPublisher.mutate { $0 = nil }
|
||||
|
||||
dependencies.standardUserDefaults[.hasSyncedInitialConfiguration] = false
|
||||
dependencies[singleton: .standardUserDefaults][.hasSyncedInitialConfiguration] = false
|
||||
}
|
||||
|
||||
func preregister(
|
||||
|
@ -116,7 +116,7 @@ enum Onboarding {
|
|||
let x25519PublicKey = x25519KeyPair.hexEncodedPublicKey
|
||||
|
||||
// Store the user identity information
|
||||
Storage.shared.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try Identity.store(
|
||||
db,
|
||||
seed: seed,
|
||||
|
@ -166,7 +166,7 @@ enum Onboarding {
|
|||
// home screen a configuration sync is triggered (yes, the logic is a
|
||||
// bit weird). This is needed so that if the user registers and
|
||||
// immediately links a device, there'll be a configuration in their swarm.
|
||||
dependencies.standardUserDefaults[.hasSyncedInitialConfiguration] = (self == .register)
|
||||
dependencies[singleton: .standardUserDefaults][.hasSyncedInitialConfiguration] = (self == .register)
|
||||
|
||||
// Only continue if this isn't a new account
|
||||
guard self != .register else { return }
|
||||
|
@ -182,7 +182,7 @@ enum Onboarding {
|
|||
// what the user set in the display name step with whatever we find in their
|
||||
// swarm (otherwise the user could enter a display name and have it immediately
|
||||
// overwritten due to the config request running slow)
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try Profile
|
||||
.filter(id: getUserHexEncodedPublicKey(db))
|
||||
.updateAllAndConfig(
|
||||
|
|
|
@ -155,7 +155,7 @@ final class PNModeVC: BaseVC, OptionViewDelegate {
|
|||
|
||||
// Check if we already have a profile name (ie. profile retrieval completed while waiting on
|
||||
// this screen)
|
||||
let existingProfileName: String? = Storage.shared
|
||||
let existingProfileName: String? = Dependencies()[singleton: .storage]
|
||||
.read { db in
|
||||
try Profile
|
||||
.filter(id: getUserHexEncodedPublicKey(db))
|
||||
|
|
|
@ -6,11 +6,11 @@ import SessionUtilitiesKit
|
|||
import SignalUtilitiesKit
|
||||
|
||||
final class SeedVC: BaseVC {
|
||||
public static func mnemonic() throws -> String {
|
||||
let dbIsValid: Bool = Storage.shared.isValid
|
||||
let dbIsSuspendedUnsafe: Bool = Storage.shared.isSuspendedUnsafe
|
||||
public static func mnemonic(using dependencies: Dependencies = Dependencies()) throws -> String {
|
||||
let dbIsValid: Bool = dependencies[singleton: .storage].isValid
|
||||
let dbIsSuspendedUnsafe: Bool = dependencies[singleton: .storage].isSuspendedUnsafe
|
||||
|
||||
if let hexEncodedSeed: String = Identity.fetchHexEncodedSeed() {
|
||||
if let hexEncodedSeed: String = Identity.fetchHexEncodedSeed(using: dependencies) {
|
||||
return Mnemonic.encode(hexEncodedString: hexEncodedSeed)
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ final class SeedVC: BaseVC {
|
|||
|
||||
// Set up mnemonic label
|
||||
mnemonicLabel.text = redactedMnemonic
|
||||
let mnemonicLabelGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(revealMnemonic))
|
||||
let mnemonicLabelGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(revealMnemonicTapped))
|
||||
mnemonicLabel.addGestureRecognizer(mnemonicLabelGestureRecognizer)
|
||||
mnemonicLabel.isUserInteractionEnabled = true
|
||||
mnemonicLabel.isEnabled = true
|
||||
|
@ -151,7 +151,7 @@ final class SeedVC: BaseVC {
|
|||
callToActionLabel.themeTextColor = .textSecondary
|
||||
callToActionLabel.textAlignment = .center
|
||||
|
||||
let callToActionLabelGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(revealMnemonic))
|
||||
let callToActionLabelGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(revealMnemonicTapped))
|
||||
callToActionLabel.addGestureRecognizer(callToActionLabelGestureRecognizer)
|
||||
callToActionLabel.isUserInteractionEnabled = true
|
||||
callToActionLabel.isEnabled = true
|
||||
|
@ -222,7 +222,9 @@ final class SeedVC: BaseVC {
|
|||
dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@objc private func revealMnemonic() {
|
||||
@objc private func revealMnemonicTapped() { revealMnemonic() }
|
||||
|
||||
private func revealMnemonic(using dependencies: Dependencies = Dependencies()) {
|
||||
UIView.transition(with: mnemonicLabel, duration: 0.25, options: .transitionCrossDissolve, animations: {
|
||||
self.mnemonicLabel.text = self.mnemonic
|
||||
self.mnemonicLabel.themeTextColor = .textPrimary
|
||||
|
@ -246,7 +248,7 @@ final class SeedVC: BaseVC {
|
|||
}, completion: nil)
|
||||
seedReminderView.setProgress(1, animated: true)
|
||||
|
||||
Storage.shared.writeAsync { db in db[.hasViewedSeed] = true }
|
||||
dependencies[singleton: .storage].writeAsync { db in db[.hasViewedSeed] = true }
|
||||
}
|
||||
|
||||
@objc private func copyMnemonic() {
|
||||
|
|
|
@ -163,20 +163,28 @@ final class JoinOpenGroupVC: BaseVC, UIPageViewControllerDataSource, UIPageViewC
|
|||
joinOpenGroup(roomToken: room, server: server, publicKey: publicKey, shouldOpenCommunity: true, onError: onError)
|
||||
}
|
||||
|
||||
fileprivate func joinOpenGroup(roomToken: String, server: String, publicKey: String, shouldOpenCommunity: Bool, onError: (() -> ())?) {
|
||||
fileprivate func joinOpenGroup(
|
||||
roomToken: String,
|
||||
server: String,
|
||||
publicKey: String,
|
||||
shouldOpenCommunity: Bool,
|
||||
using dependencies: Dependencies = Dependencies(),
|
||||
onError: (() -> ())?
|
||||
) {
|
||||
guard !isJoining, let navigationController: UINavigationController = navigationController else { return }
|
||||
|
||||
isJoining = true
|
||||
|
||||
ModalActivityIndicatorViewController.present(fromViewController: navigationController, canCancel: false) { [weak self] _ in
|
||||
Storage.shared
|
||||
dependencies[singleton: .storage]
|
||||
.writePublisher { db in
|
||||
OpenGroupManager.shared.add(
|
||||
db,
|
||||
roomToken: roomToken,
|
||||
server: server,
|
||||
publicKey: publicKey,
|
||||
calledFromConfigHandling: false
|
||||
calledFromConfigHandling: false,
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
.flatMap { successfullyAddedGroup in
|
||||
|
@ -185,7 +193,8 @@ final class JoinOpenGroupVC: BaseVC, UIPageViewControllerDataSource, UIPageViewC
|
|||
roomToken: roomToken,
|
||||
server: server,
|
||||
publicKey: publicKey,
|
||||
calledFromConfigHandling: false
|
||||
calledFromConfigHandling: false,
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
.subscribe(on: DispatchQueue.global(qos: .userInitiated))
|
||||
|
@ -197,7 +206,7 @@ final class JoinOpenGroupVC: BaseVC, UIPageViewControllerDataSource, UIPageViewC
|
|||
// If there was a failure then the group will be in invalid state until
|
||||
// the next launch so remove it (the user will be left on the previous
|
||||
// screen so can re-trigger the join)
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
OpenGroupManager.shared.delete(
|
||||
db,
|
||||
openGroupId: OpenGroup.idFor(roomToken: roomToken, server: server),
|
||||
|
|
|
@ -5,6 +5,7 @@ import Reachability
|
|||
import SessionUIKit
|
||||
import SessionSnodeKit
|
||||
import SessionMessagingKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
final class PathStatusView: UIView {
|
||||
enum Size {
|
||||
|
@ -45,10 +46,15 @@ final class PathStatusView: UIView {
|
|||
// MARK: - Initialization
|
||||
|
||||
private let size: Size
|
||||
private let dependencies: Dependencies
|
||||
private let reachability: Reachability? = Environment.shared?.reachabilityManager.reachability
|
||||
|
||||
init(size: Size = .small) {
|
||||
init(
|
||||
size: Size = .small,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
self.size = size
|
||||
self.dependencies = dependencies
|
||||
|
||||
super.init(frame: .zero)
|
||||
|
||||
|
@ -58,6 +64,7 @@ final class PathStatusView: UIView {
|
|||
|
||||
required init?(coder: NSCoder) {
|
||||
self.size = .small
|
||||
self.dependencies = Dependencies()
|
||||
|
||||
super.init(coder: coder)
|
||||
|
||||
|
@ -77,7 +84,7 @@ final class PathStatusView: UIView {
|
|||
self.set(.width, to: self.size.pointSize)
|
||||
self.set(.height, to: self.size.pointSize)
|
||||
|
||||
switch (reachability?.isReachable(), OnionRequestAPI.paths.isEmpty) {
|
||||
switch (reachability?.isReachable(), dependencies[cache: .onionRequestAPI].paths.isEmpty) {
|
||||
case (.some(false), _), (nil, _): setStatus(to: .error)
|
||||
case (.some(true), true): setStatus(to: .connecting)
|
||||
case (.some(true), false): setStatus(to: .connected)
|
||||
|
@ -153,6 +160,6 @@ final class PathStatusView: UIView {
|
|||
return
|
||||
}
|
||||
|
||||
setStatus(to: (!OnionRequestAPI.paths.isEmpty ? .connected : .connecting))
|
||||
setStatus(to: (!dependencies[cache: .onionRequestAPI].paths.isEmpty ? .connected : .connecting))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import NVActivityIndicatorView
|
|||
import SessionMessagingKit
|
||||
import SessionUIKit
|
||||
import SessionSnodeKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
final class PathVC: BaseVC {
|
||||
public static let dotSize: CGFloat = 8
|
||||
|
@ -135,7 +136,7 @@ final class PathVC: BaseVC {
|
|||
private func update() {
|
||||
pathStackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
|
||||
|
||||
guard let pathToDisplay: [Snode] = OnionRequestAPI.paths.first else {
|
||||
guard let pathToDisplay: [Snode] = Dependencies()[cache: .onionRequestAPI].paths.first else {
|
||||
spinner.startAnimating()
|
||||
|
||||
UIView.animate(withDuration: 0.25) {
|
||||
|
@ -338,7 +339,7 @@ private final class LineView: UIView {
|
|||
}
|
||||
}
|
||||
|
||||
switch (reachability?.isReachable(), OnionRequestAPI.paths.isEmpty) {
|
||||
switch (reachability?.isReachable(), Dependencies()[cache: .onionRequestAPI].paths.isEmpty) {
|
||||
case (.some(false), _), (nil, _): setStatus(to: .error)
|
||||
case (.some(true), true): setStatus(to: .connecting)
|
||||
case (.some(true), false): setStatus(to: .connected)
|
||||
|
@ -420,6 +421,6 @@ private final class LineView: UIView {
|
|||
return
|
||||
}
|
||||
|
||||
setStatus(to: (!OnionRequestAPI.paths.isEmpty ? .connected : .connecting))
|
||||
setStatus(to: (!Dependencies()[cache: .onionRequestAPI].paths.isEmpty ? .connected : .connecting))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,7 +173,7 @@ class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsView
|
|||
].flatMap { $0 }
|
||||
}
|
||||
|
||||
private func unblockTapped() {
|
||||
private func unblockTapped(using dependencies: Dependencies = Dependencies()) {
|
||||
guard !selectedContactIdsSubject.value.isEmpty else { return }
|
||||
|
||||
let contactIds: Set<String> = selectedContactIdsSubject.value
|
||||
|
@ -244,7 +244,7 @@ class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsView
|
|||
cancelStyle: .alert_text
|
||||
) { [weak self] _ in
|
||||
// Unblock the contacts
|
||||
Storage.shared.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
_ = try Contact
|
||||
.filter(ids: contactIds)
|
||||
.updateAllAndConfig(db, Contact.Columns.isBlocked.set(to: false))
|
||||
|
|
|
@ -31,6 +31,18 @@ class ConversationSettingsViewModel: SessionTableViewModel<NoNav, ConversationSe
|
|||
}
|
||||
}
|
||||
|
||||
private let dependencies: Dependencies
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
init(
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
self.dependencies = dependencies
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
// MARK: - Content
|
||||
|
||||
private struct State: Equatable {
|
||||
|
@ -58,9 +70,9 @@ class ConversationSettingsViewModel: SessionTableViewModel<NoNav, ConversationSe
|
|||
}
|
||||
.removeDuplicates()
|
||||
.handleEvents(didFail: { SNLog("[ConversationSettingsViewModel] Observation failed with error: \($0)") })
|
||||
.publisher(in: Storage.shared)
|
||||
.publisher(in: dependencies[singleton: .storage], scheduling: dependencies[singleton: .scheduler])
|
||||
.withPrevious()
|
||||
.map { (previous: State?, current: State) -> [SectionModel] in
|
||||
.map { [dependencies] (previous: State?, current: State) -> [SectionModel] in
|
||||
return [
|
||||
SectionModel(
|
||||
model: .messageTrimming,
|
||||
|
@ -77,7 +89,7 @@ class ConversationSettingsViewModel: SessionTableViewModel<NoNav, ConversationSe
|
|||
)
|
||||
),
|
||||
onTap: {
|
||||
Storage.shared.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
db[.trimOpenGroupMessagesOlderThanSixMonths] = !db[.trimOpenGroupMessagesOlderThanSixMonths]
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +111,7 @@ class ConversationSettingsViewModel: SessionTableViewModel<NoNav, ConversationSe
|
|||
)
|
||||
),
|
||||
onTap: {
|
||||
Storage.shared.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
db[.shouldAutoPlayConsecutiveAudioMessages] = !db[.shouldAutoPlayConsecutiveAudioMessages]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,16 @@ class HelpViewModel: SessionTableViewModel<NoNav, HelpViewModel.Section, HelpVie
|
|||
var style: SessionTableSectionStyle { .padding }
|
||||
}
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
private let dependencies: Dependencies
|
||||
|
||||
init(using dependencies: Dependencies = Dependencies()) {
|
||||
self.dependencies = dependencies
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
// MARK: - Content
|
||||
|
||||
override var title: String { "HELP_TITLE".localized() }
|
||||
|
@ -169,7 +179,7 @@ class HelpViewModel: SessionTableViewModel<NoNav, HelpViewModel.Section, HelpVie
|
|||
}
|
||||
.removeDuplicates()
|
||||
.handleEvents(didFail: { SNLog("[HelpViewModel] Observation failed with error: \($0)") })
|
||||
.publisher(in: Storage.shared)
|
||||
.publisher(in: dependencies[singleton: .storage], scheduling: dependencies[singleton: .scheduler])
|
||||
.mapToSessionTableViewData(for: self)
|
||||
|
||||
// MARK: - Functions
|
||||
|
@ -242,7 +252,7 @@ class HelpViewModel: SessionTableViewModel<NoNav, HelpViewModel.Section, HelpVie
|
|||
),
|
||||
confirmTitle: "Export",
|
||||
dismissOnConfirm: false,
|
||||
onConfirm: { [weak self] modal in
|
||||
onConfirm: { [weak self, dependencies] modal in
|
||||
modal.dismiss(animated: true) {
|
||||
guard let password: String = self?.databaseKeyEncryptionPassword, password.count >= 6 else {
|
||||
self?.transitionToScreen(
|
||||
|
@ -258,7 +268,7 @@ class HelpViewModel: SessionTableViewModel<NoNav, HelpViewModel.Section, HelpVie
|
|||
}
|
||||
|
||||
do {
|
||||
let exportInfo = try Storage.shared.exportInfo(password: password)
|
||||
let exportInfo = try dependencies[singleton: .storage].exportInfo(password: password)
|
||||
let shareVC = UIActivityViewController(
|
||||
activityItems: [
|
||||
URL(fileURLWithPath: exportInfo.dbPath),
|
||||
|
|
|
@ -8,17 +8,14 @@ import SessionMessagingKit
|
|||
import SessionUtilitiesKit
|
||||
|
||||
class NotificationContentViewModel: SessionTableViewModel<NoNav, NotificationSettingsViewModel.Section, Preferences.NotificationPreviewType> {
|
||||
private let storage: Storage
|
||||
private let scheduler: ValueObservationScheduler
|
||||
private let dependencies: Dependencies
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
init(
|
||||
storage: Storage = Storage.shared,
|
||||
scheduling scheduler: ValueObservationScheduler = Storage.defaultPublisherScheduler
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
self.storage = storage
|
||||
self.scheduler = scheduler
|
||||
self.dependencies = dependencies
|
||||
}
|
||||
|
||||
// MARK: - Section
|
||||
|
@ -41,7 +38,7 @@ class NotificationContentViewModel: SessionTableViewModel<NoNav, NotificationSet
|
|||
/// fetch (after the ones in `ValueConcurrentObserver.asyncStart`/`ValueConcurrentObserver.syncStart`)
|
||||
/// just in case the database has changed between the two reads - unfortunately it doesn't look like there is a way to prevent this
|
||||
private lazy var _observableTableData: ObservableData = ValueObservation
|
||||
.trackingConstantRegion { [storage] db -> [SectionModel] in
|
||||
.trackingConstantRegion { [dependencies] db -> [SectionModel] in
|
||||
let currentSelection: Preferences.NotificationPreviewType? = db[.preferencesNotificationPreviewType]
|
||||
.defaulting(to: .defaultPreviewType)
|
||||
|
||||
|
@ -57,7 +54,7 @@ class NotificationContentViewModel: SessionTableViewModel<NoNav, NotificationSet
|
|||
isSelected: { (currentSelection == previewType) }
|
||||
),
|
||||
onTap: { [weak self] in
|
||||
storage.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
db[.preferencesNotificationPreviewType] = previewType
|
||||
}
|
||||
|
||||
|
@ -70,6 +67,6 @@ class NotificationContentViewModel: SessionTableViewModel<NoNav, NotificationSet
|
|||
}
|
||||
.removeDuplicates()
|
||||
.handleEvents(didFail: { SNLog("[NotificationContentViewModel] Observation failed with error: \($0)") })
|
||||
.publisher(in: storage, scheduling: scheduler)
|
||||
.publisher(in: dependencies[singleton: .storage], scheduling: dependencies[singleton: .scheduler])
|
||||
.mapToSessionTableViewData(for: self)
|
||||
}
|
||||
|
|
|
@ -39,6 +39,18 @@ class NotificationSettingsViewModel: SessionTableViewModel<NoNav, NotificationSe
|
|||
case content
|
||||
}
|
||||
|
||||
private let dependencies: Dependencies
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
init(
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
self.dependencies = dependencies
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
// MARK: - Content
|
||||
|
||||
private struct State: Equatable {
|
||||
|
@ -72,7 +84,7 @@ class NotificationSettingsViewModel: SessionTableViewModel<NoNav, NotificationSe
|
|||
}
|
||||
.removeDuplicates()
|
||||
.handleEvents(didFail: { SNLog("[NotificationSettingsViewModel] Observation failed with error: \($0)") })
|
||||
.publisher(in: Storage.shared)
|
||||
.publisher(in: dependencies[singleton: .storage], scheduling: dependencies[singleton: .scheduler])
|
||||
.manualRefreshFrom(forcedRefresh)
|
||||
.map { dbState -> State in
|
||||
State(
|
||||
|
@ -83,7 +95,7 @@ class NotificationSettingsViewModel: SessionTableViewModel<NoNav, NotificationSe
|
|||
)
|
||||
}
|
||||
.withPrevious()
|
||||
.map { (previous: State?, current: State) -> [SectionModel] in
|
||||
.map { [dependencies] (previous: State?, current: State) -> [SectionModel] in
|
||||
return [
|
||||
SectionModel(
|
||||
model: .strategy,
|
||||
|
@ -154,7 +166,7 @@ class NotificationSettingsViewModel: SessionTableViewModel<NoNav, NotificationSe
|
|||
)
|
||||
),
|
||||
onTap: {
|
||||
Storage.shared.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
db[.playNotificationSoundInForeground] = !db[.playNotificationSoundInForeground]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,14 +22,21 @@ class NotificationSoundViewModel: SessionTableViewModel<NotificationSoundViewMod
|
|||
|
||||
// FIXME: Remove `threadId` once we ditch the per-thread notification sound
|
||||
private let threadId: String?
|
||||
private let dependencies: Dependencies
|
||||
private var audioPlayer: OWSAudioPlayer?
|
||||
private var storedSelection: Preferences.Sound?
|
||||
private var currentSelection: CurrentValueSubject<Preferences.Sound?, Never> = CurrentValueSubject(nil)
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
init(threadId: String? = nil) {
|
||||
init(
|
||||
threadId: String? = nil,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
self.threadId = threadId
|
||||
self.dependencies = dependencies
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
@ -147,7 +154,7 @@ class NotificationSoundViewModel: SessionTableViewModel<NotificationSoundViewMod
|
|||
}
|
||||
.removeDuplicates()
|
||||
.handleEvents(didFail: { SNLog("[NotificationSoundViewModel] Observation failed with error: \($0)") })
|
||||
.publisher(in: Storage.shared)
|
||||
.publisher(in: dependencies[singleton: .storage], scheduling: dependencies[singleton: .scheduler])
|
||||
.mapToSessionTableViewData(for: self)
|
||||
|
||||
// MARK: - Functions
|
||||
|
@ -157,7 +164,7 @@ class NotificationSoundViewModel: SessionTableViewModel<NotificationSoundViewMod
|
|||
|
||||
let threadId: String? = self.threadId
|
||||
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
guard let threadId: String = threadId else {
|
||||
db[.defaultNotificationSound] = currentSelection
|
||||
return
|
||||
|
|
|
@ -172,7 +172,7 @@ final class NukeDataModal: Modal {
|
|||
.present(fromViewController: presentedViewController, canCancel: false) { [weak self] _ in
|
||||
Publishers
|
||||
.MergeMany(
|
||||
Storage.shared
|
||||
dependencies[singleton: .storage]
|
||||
.read { db -> [(String, HTTP.PreparedRequest<OpenGroupAPI.DeleteInboxResponse>)] in
|
||||
return try OpenGroup
|
||||
.filter(OpenGroup.Columns.isActive == true)
|
||||
|
@ -268,7 +268,7 @@ final class NukeDataModal: Modal {
|
|||
///
|
||||
/// **Note:** This is file as long as this process kills the app, if it doesn't then we need an alternate mechanism to flag that
|
||||
/// the `JobRunner` is allowed to start it's queues again
|
||||
JobRunner.stopAndClearPendingJobs()
|
||||
dependencies[singleton: .jobRunner].stopAndClearPendingJobs()
|
||||
|
||||
// Clear the app badge and notifications
|
||||
AppEnvironment.shared.notificationPresenter.clearAllNotifications()
|
||||
|
@ -278,7 +278,7 @@ final class NukeDataModal: Modal {
|
|||
UserDefaults.removeAll()
|
||||
|
||||
// Remove the cached key so it gets re-cached on next access
|
||||
dependencies.caches.mutate(cache: .general) {
|
||||
dependencies.mutate(cache: .general) {
|
||||
$0.encodedPublicKey = nil
|
||||
$0.recentReactionTimestamps = []
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
|
|||
}
|
||||
.removeDuplicates()
|
||||
.handleEvents(didFail: { SNLog("[PrivacySettingsViewModel] Observation failed with error: \($0)") })
|
||||
.publisher(in: dependencies.storage)
|
||||
.publisher(in: dependencies[singleton: .storage], scheduling: dependencies[singleton: .scheduler])
|
||||
.withPrevious()
|
||||
.map { [dependencies] (previous: State?, current: State) -> [SectionModel] in
|
||||
return [
|
||||
|
@ -148,7 +148,7 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
|
|||
return
|
||||
}
|
||||
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try db.setAndUpdateConfig(
|
||||
.isScreenLockEnabled,
|
||||
to: !db[.isScreenLockEnabled],
|
||||
|
@ -174,7 +174,7 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
|
|||
)
|
||||
),
|
||||
onTap: { [weak self] in
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try db.setAndUpdateConfig(
|
||||
.checkForCommunityMessageRequests,
|
||||
to: !db[.checkForCommunityMessageRequests],
|
||||
|
@ -200,7 +200,7 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
|
|||
)
|
||||
),
|
||||
onTap: {
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try db.setAndUpdateConfig(
|
||||
.areReadReceiptsEnabled,
|
||||
to: !db[.areReadReceiptsEnabled],
|
||||
|
@ -258,7 +258,7 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
|
|||
)
|
||||
),
|
||||
onTap: {
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try db.setAndUpdateConfig(
|
||||
.typingIndicatorsEnabled,
|
||||
to: !db[.typingIndicatorsEnabled],
|
||||
|
@ -284,7 +284,7 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
|
|||
)
|
||||
),
|
||||
onTap: {
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try db.setAndUpdateConfig(
|
||||
.areLinkPreviewsEnabled,
|
||||
to: !db[.areLinkPreviewsEnabled],
|
||||
|
@ -322,7 +322,7 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
|
|||
onConfirm: { _ in Permissions.requestMicrophonePermissionIfNeeded() }
|
||||
),
|
||||
onTap: {
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try db.setAndUpdateConfig(
|
||||
.areCallsEnabled,
|
||||
to: !db[.areCallsEnabled],
|
||||
|
|
|
@ -122,7 +122,7 @@ final class SeedModal: Modal {
|
|||
mnemonicLabel.pin(to: mnemonicLabelContainer, withInset: isIPhone6OrSmaller ? 4 : Values.smallSpacing)
|
||||
|
||||
// Mark seed as viewed
|
||||
Storage.shared.writeAsync { db in db[.hasViewedSeed] = true }
|
||||
Dependencies()[singleton: .storage].writeAsync { db in db[.hasViewedSeed] = true }
|
||||
}
|
||||
|
||||
// MARK: - Interaction
|
||||
|
|
|
@ -69,6 +69,7 @@ class SettingsViewModel: SessionTableViewModel<SettingsViewModel.NavButton, Sett
|
|||
// MARK: - Variables
|
||||
|
||||
private let userSessionId: String
|
||||
private let dependencies: Dependencies
|
||||
private lazy var imagePickerHandler: ImagePickerHandler = ImagePickerHandler(
|
||||
onTransition: { [weak self] in self?.transitionToScreen($0, transitionType: $1) },
|
||||
onImageDataPicked: { [weak self] resultImageData in
|
||||
|
@ -87,9 +88,12 @@ class SettingsViewModel: SessionTableViewModel<SettingsViewModel.NavButton, Sett
|
|||
|
||||
// MARK: - Initialization
|
||||
|
||||
override init() {
|
||||
self.userSessionId = getUserHexEncodedPublicKey()
|
||||
self.oldDisplayName = Profile.fetchOrCreateCurrentUser().name
|
||||
init(
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
self.userSessionId = getUserHexEncodedPublicKey(using: dependencies)
|
||||
self.oldDisplayName = Profile.fetchOrCreateCurrentUser(using: dependencies).name
|
||||
self.dependencies = dependencies
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
@ -482,7 +486,7 @@ class SettingsViewModel: SessionTableViewModel<SettingsViewModel.NavButton, Sett
|
|||
}
|
||||
.removeDuplicates()
|
||||
.handleEvents(didFail: { SNLog("[SettingsViewModel] Observation failed with error: \($0)") })
|
||||
.publisher(in: Storage.shared)
|
||||
.publisher(in: dependencies[singleton: .storage], scheduling: dependencies[singleton: .scheduler])
|
||||
.mapToSessionTableViewData(for: self)
|
||||
|
||||
public override var footerView: AnyPublisher<UIView?, Never> {
|
||||
|
|
|
@ -167,7 +167,7 @@ class ScreenLockUI {
|
|||
// It's not safe to access OWSScreenLock.isScreenLockEnabled
|
||||
// until the app is ready.
|
||||
AppReadiness.runNowOrWhenAppWillBecomeReady { [weak self] in
|
||||
self?.isScreenLockLocked = Storage.shared[.isScreenLockEnabled]
|
||||
self?.isScreenLockLocked = Dependencies()[singleton: .storage][.isScreenLockEnabled]
|
||||
self?.ensureUI()
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ class ScreenLockUI {
|
|||
Logger.verbose("tryToActivateScreenLockUponBecomingActive NO 0")
|
||||
return
|
||||
}
|
||||
guard Storage.shared[.isScreenLockEnabled] else {
|
||||
guard Dependencies()[singleton: .storage][.isScreenLockEnabled] else {
|
||||
// Screen lock is not enabled.
|
||||
Logger.verbose("tryToActivateScreenLockUponBecomingActive NO 1")
|
||||
return;
|
||||
|
@ -372,7 +372,7 @@ class ScreenLockUI {
|
|||
return;
|
||||
}
|
||||
|
||||
self.isScreenLockLocked = Storage.shared[.isScreenLockEnabled]
|
||||
self.isScreenLockLocked = Dependencies()[singleton: .storage][.isScreenLockEnabled]
|
||||
|
||||
// NOTE: this notifications fires _before_ applicationDidBecomeActive,
|
||||
// which is desirable. Don't assume that though; call ensureUI
|
||||
|
|
|
@ -93,7 +93,7 @@ class SessionTableViewController<NavItemId: Equatable, Section: SessionTableSect
|
|||
init(viewModel: SessionTableViewModel<NavItemId, Section, SettingItem>) {
|
||||
self.viewModel = viewModel
|
||||
|
||||
Storage.shared.addObserver(viewModel.pagedDataObserver)
|
||||
Dependencies()[singleton: .storage].addObserver(viewModel.pagedDataObserver)
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ public final class BackgroundPoller {
|
|||
[pollForMessages(using: dependencies)]
|
||||
.appending(contentsOf: pollForClosedGroupMessages(using: dependencies))
|
||||
.appending(
|
||||
contentsOf: Storage.shared
|
||||
contentsOf: dependencies[singleton: .storage]
|
||||
.read { db in
|
||||
/// The default room promise creates an OpenGroup with an empty `roomToken` value, we
|
||||
/// don't want to start a poller for this as the user hasn't actually joined a room
|
||||
|
@ -95,7 +95,7 @@ public final class BackgroundPoller {
|
|||
) -> [AnyPublisher<Void, Error>] {
|
||||
// Fetch all closed groups (excluding any don't contain the current user as a
|
||||
// GroupMemeber as the user is no longer a member of those)
|
||||
return Storage.shared
|
||||
return dependencies[singleton: .storage]
|
||||
.read { db in
|
||||
try ClosedGroup
|
||||
.select(.threadId)
|
||||
|
|
|
@ -63,7 +63,7 @@ final class IP2Country {
|
|||
}
|
||||
|
||||
@discardableResult func populateCacheIfNeeded() -> Bool {
|
||||
guard let pathToDisplay: [Snode] = OnionRequestAPI.paths.first else { return false }
|
||||
guard let pathToDisplay: [Snode] = Dependencies()[cache: .onionRequestAPI].paths.first else { return false }
|
||||
|
||||
countryNamesCache.mutate { [weak self] cache in
|
||||
pathToDisplay.forEach { snode in
|
||||
|
|
|
@ -48,7 +48,8 @@ public extension UIContextualAction {
|
|||
indexPath: IndexPath,
|
||||
tableView: UITableView,
|
||||
threadViewModel: SessionThreadViewModel,
|
||||
viewController: UIViewController?
|
||||
viewController: UIViewController?,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) -> [UIContextualAction]? {
|
||||
guard !actions.isEmpty else { return nil }
|
||||
|
||||
|
@ -128,7 +129,9 @@ public extension UIContextualAction {
|
|||
) { _, _, completionHandler in
|
||||
switch threadViewModel.threadId {
|
||||
case SessionThreadViewModel.messageRequestsSectionId:
|
||||
Storage.shared.write { db in db[.hasHiddenMessageRequests] = true }
|
||||
dependencies[singleton: .storage].write { db in
|
||||
db[.hasHiddenMessageRequests] = true
|
||||
}
|
||||
completionHandler(true)
|
||||
|
||||
default:
|
||||
|
@ -159,7 +162,7 @@ public extension UIContextualAction {
|
|||
cancelStyle: .alert_text,
|
||||
dismissOnConfirm: true,
|
||||
onConfirm: { _ in
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
try SessionThread.deleteOrLeave(
|
||||
db,
|
||||
threadId: threadViewModel.threadId,
|
||||
|
@ -207,7 +210,7 @@ public extension UIContextualAction {
|
|||
|
||||
// Delay the change to give the cell "unswipe" animation some time to complete
|
||||
DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + unswipeAnimationDelay) {
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
try SessionThread
|
||||
.filter(id: threadViewModel.threadId)
|
||||
.updateAllAndConfig(
|
||||
|
@ -247,7 +250,7 @@ public extension UIContextualAction {
|
|||
|
||||
// Delay the change to give the cell "unswipe" animation some time to complete
|
||||
DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + unswipeAnimationDelay) {
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
let currentValue: TimeInterval? = try SessionThread
|
||||
.filter(id: threadViewModel.threadId)
|
||||
.select(.mutedUntilTimestamp)
|
||||
|
@ -308,7 +311,7 @@ public extension UIContextualAction {
|
|||
|
||||
// Delay the change to give the cell "unswipe" animation some time to complete
|
||||
DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + unswipeAnimationDelay) {
|
||||
Storage.shared
|
||||
dependencies[singleton: .storage]
|
||||
.writePublisher { db in
|
||||
// Create the contact if it doesn't exist
|
||||
try Contact
|
||||
|
@ -412,7 +415,7 @@ public extension UIContextualAction {
|
|||
cancelStyle: .alert_text,
|
||||
dismissOnConfirm: true,
|
||||
onConfirm: { _ in
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
try SessionThread.deleteOrLeave(
|
||||
db,
|
||||
threadId: threadViewModel.threadId,
|
||||
|
@ -510,7 +513,7 @@ public extension UIContextualAction {
|
|||
cancelStyle: .alert_text,
|
||||
dismissOnConfirm: true,
|
||||
onConfirm: { _ in
|
||||
Storage.shared.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
try SessionThread.deleteOrLeave(
|
||||
db,
|
||||
threadId: threadViewModel.threadId,
|
||||
|
|
|
@ -176,7 +176,7 @@ public final class WebRTCSession : NSObject, RTCPeerConnectionDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
dependencies.storage
|
||||
dependencies[singleton: .storage]
|
||||
.writePublisher { db in
|
||||
try MessageSender
|
||||
.preparedSendData(
|
||||
|
@ -220,7 +220,7 @@ public final class WebRTCSession : NSObject, RTCPeerConnectionDelegate {
|
|||
let uuid: String = self.uuid
|
||||
let mediaConstraints: RTCMediaConstraints = mediaConstraints(false)
|
||||
|
||||
return dependencies.storage
|
||||
return dependencies[singleton: .storage]
|
||||
.readPublisher { db -> SessionThread in
|
||||
guard let thread: SessionThread = try? SessionThread.fetchOne(db, id: sessionId) else {
|
||||
throw WebRTCSessionError.noThread
|
||||
|
@ -247,7 +247,7 @@ public final class WebRTCSession : NSObject, RTCPeerConnectionDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
dependencies.storage
|
||||
dependencies[singleton: .storage]
|
||||
.writePublisher { db in
|
||||
try MessageSender
|
||||
.preparedSendData(
|
||||
|
@ -300,7 +300,7 @@ public final class WebRTCSession : NSObject, RTCPeerConnectionDelegate {
|
|||
// Empty the queue
|
||||
self.queuedICECandidates.removeAll()
|
||||
|
||||
dependencies.storage
|
||||
dependencies[singleton: .storage]
|
||||
.writePublisher { db in
|
||||
guard let thread: SessionThread = try SessionThread.fetchOne(db, id: contactSessionId) else {
|
||||
throw WebRTCSessionError.noThread
|
||||
|
|
|
@ -40,24 +40,30 @@ public enum SNMessagingKit: MigratableTarget { // Just to make the external API
|
|||
)
|
||||
}
|
||||
|
||||
public static func configure() {
|
||||
public static func configure(using dependencies: Dependencies) {
|
||||
// Configure the job executors
|
||||
JobRunner.setExecutor(DisappearingMessagesJob.self, for: .disappearingMessages)
|
||||
JobRunner.setExecutor(FailedMessageSendsJob.self, for: .failedMessageSends)
|
||||
JobRunner.setExecutor(FailedAttachmentDownloadsJob.self, for: .failedAttachmentDownloads)
|
||||
JobRunner.setExecutor(UpdateProfilePictureJob.self, for: .updateProfilePicture)
|
||||
JobRunner.setExecutor(RetrieveDefaultOpenGroupRoomsJob.self, for: .retrieveDefaultOpenGroupRooms)
|
||||
JobRunner.setExecutor(GarbageCollectionJob.self, for: .garbageCollection)
|
||||
JobRunner.setExecutor(MessageSendJob.self, for: .messageSend)
|
||||
JobRunner.setExecutor(MessageReceiveJob.self, for: .messageReceive)
|
||||
JobRunner.setExecutor(NotifyPushServerJob.self, for: .notifyPushServer)
|
||||
JobRunner.setExecutor(SendReadReceiptsJob.self, for: .sendReadReceipts)
|
||||
JobRunner.setExecutor(AttachmentUploadJob.self, for: .attachmentUpload)
|
||||
JobRunner.setExecutor(GroupLeavingJob.self, for: .groupLeaving)
|
||||
JobRunner.setExecutor(AttachmentDownloadJob.self, for: .attachmentDownload)
|
||||
JobRunner.setExecutor(ConfigurationSyncJob.self, for: .configurationSync)
|
||||
JobRunner.setExecutor(ConfigMessageReceiveJob.self, for: .configMessageReceive)
|
||||
JobRunner.setExecutor(ExpirationUpdateJob.self, for: .expirationUpdate)
|
||||
JobRunner.setExecutor(GetExpirationJob.self, for: .getExpiration)
|
||||
let executors: [Job.Variant: JobExecutor.Type] = [
|
||||
.disappearingMessages: DisappearingMessagesJob.self,
|
||||
.failedMessageSends: FailedMessageSendsJob.self,
|
||||
.failedAttachmentDownloads: FailedAttachmentDownloadsJob.self,
|
||||
.updateProfilePicture: UpdateProfilePictureJob.self,
|
||||
.retrieveDefaultOpenGroupRooms: RetrieveDefaultOpenGroupRoomsJob.self,
|
||||
.garbageCollection: GarbageCollectionJob.self,
|
||||
.messageSend: MessageSendJob.self,
|
||||
.messageReceive: MessageReceiveJob.self,
|
||||
.notifyPushServer: NotifyPushServerJob.self,
|
||||
.sendReadReceipts: SendReadReceiptsJob.self,
|
||||
.attachmentUpload: AttachmentUploadJob.self,
|
||||
.groupLeaving: GroupLeavingJob.self,
|
||||
.attachmentDownload: AttachmentDownloadJob.self,
|
||||
.configurationSync: ConfigurationSyncJob.self,
|
||||
.configMessageReceive: ConfigMessageReceiveJob.self,
|
||||
.expirationUpdate: ExpirationUpdateJob.self,
|
||||
.getExpiration: GetExpirationJob.self
|
||||
]
|
||||
|
||||
executors.forEach { variant, executor in
|
||||
dependencies[singleton: .jobRunner].setExecutor(executor, for: variant)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -378,6 +378,6 @@ enum _001_InitialSetupMigration: Migration {
|
|||
t.column(.timestampMs, .integer).notNull()
|
||||
}
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,6 @@ enum _002_SetupStandardJobs: Migration {
|
|||
).migrationSafeInserted(db)
|
||||
}
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ enum _003_YDBToGRDBMigration: Migration {
|
|||
guard
|
||||
!SNUtilitiesKit.isRunningTests &&
|
||||
Identity.userExists(db)
|
||||
else { return Storage.update(progress: 1, for: self, in: target) }
|
||||
else { return Storage.update(progress: 1, for: self, in: target, using: dependencies) }
|
||||
|
||||
SNLogNotTests("[Migration Error] Attempted to perform legacy migation")
|
||||
throw StorageError.migrationNoLongerSupported
|
||||
|
|
|
@ -13,6 +13,6 @@ enum _004_RemoveLegacyYDB: Migration {
|
|||
static let minExpectedRunDuration: TimeInterval = 0.1
|
||||
|
||||
static func migrate(_ db: Database, using dependencies: Dependencies) throws {
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,6 @@ enum _005_FixDeletedMessageReadState: Migration {
|
|||
)
|
||||
.updateAll(db, Interaction.Columns.wasRead.set(to: true))
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,6 @@ enum _006_FixHiddenModAdminSupport: Migration {
|
|||
_ = try OpenGroup
|
||||
.updateAll(db, OpenGroup.Columns.infoUpdates.set(to: 0))
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,6 @@ enum _007_HomeQueryOptimisationIndexes: Migration {
|
|||
]
|
||||
)
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,6 @@ enum _008_EmojiReacts: Migration {
|
|||
t.uniqueKey([.interactionId, .emoji, .authorId])
|
||||
}
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,6 @@ enum _009_OpenGroupPermission: Migration {
|
|||
_ = try OpenGroup
|
||||
.updateAll(db, OpenGroup.Columns.infoUpdates.set(to: 0))
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,6 @@ enum _010_AddThreadIdToFTS: Migration {
|
|||
t.column(Interaction.Columns.threadId.name)
|
||||
}
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,6 @@ enum _011_AddPendingReadReceipts: Migration {
|
|||
t.primaryKey([.threadId, .interactionTimestampMs])
|
||||
}
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,6 @@ enum _012_AddFTSIfNeeded: Migration {
|
|||
}
|
||||
}
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -243,6 +243,6 @@ enum _013_SessionUtilChanges: Migration {
|
|||
}
|
||||
}
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ enum _014_GenerateInitialUserConfigDumps: Migration {
|
|||
static func migrate(_ db: Database, using dependencies: Dependencies) throws {
|
||||
// If we have no ed25519 key then there is no need to create cached dump data
|
||||
guard Identity.fetchUserEd25519KeyPair(db) != nil else {
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ enum _014_GenerateInitialUserConfigDumps: Migration {
|
|||
|
||||
// MARK: - UserProfile Config Dump
|
||||
|
||||
try dependencies.caches[.sessionUtil]
|
||||
try dependencies[cache: .sessionUtil]
|
||||
.config(for: .userProfile, publicKey: userPublicKey)
|
||||
.mutate { config in
|
||||
try SessionUtil.update(
|
||||
|
@ -64,7 +64,7 @@ enum _014_GenerateInitialUserConfigDumps: Migration {
|
|||
|
||||
// MARK: - Contact Config Dump
|
||||
|
||||
try dependencies.caches[.sessionUtil]
|
||||
try dependencies[cache: .sessionUtil]
|
||||
.config(for: .contacts, publicKey: userPublicKey)
|
||||
.mutate { config in
|
||||
// Exclude Note to Self, community, group and outgoing blinded message requests
|
||||
|
@ -130,7 +130,7 @@ enum _014_GenerateInitialUserConfigDumps: Migration {
|
|||
|
||||
// MARK: - ConvoInfoVolatile Config Dump
|
||||
|
||||
try dependencies.caches[.sessionUtil]
|
||||
try dependencies[cache: .sessionUtil]
|
||||
.config(for: .convoInfoVolatile, publicKey: userPublicKey)
|
||||
.mutate { config in
|
||||
let volatileThreadInfo: [SessionUtil.VolatileThreadInfo] = SessionUtil.VolatileThreadInfo
|
||||
|
@ -155,7 +155,7 @@ enum _014_GenerateInitialUserConfigDumps: Migration {
|
|||
|
||||
// MARK: - UserGroups Config Dump
|
||||
|
||||
try dependencies.caches[.sessionUtil]
|
||||
try dependencies[cache: .sessionUtil]
|
||||
.config(for: .userGroups, publicKey: userPublicKey)
|
||||
.mutate { config in
|
||||
let legacyGroupData: [SessionUtil.LegacyGroupInfo] = try SessionUtil.LegacyGroupInfo.fetchAll(db)
|
||||
|
@ -200,7 +200,7 @@ enum _014_GenerateInitialUserConfigDumps: Migration {
|
|||
ConfigurationSyncJob.enqueue(db, publicKey: userPublicKey)
|
||||
}
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
|
||||
struct ContactInfo: FetchableRecord, Decodable, ColumnExpressible {
|
||||
|
|
|
@ -26,7 +26,7 @@ enum _015_BlockCommunityMessageRequests: Migration {
|
|||
Identity.userExists(db),
|
||||
(try Setting.exists(db, id: Setting.BoolKey.checkForCommunityMessageRequests.rawValue)) == false
|
||||
{
|
||||
let rawBlindedMessageRequestValue: Int32 = try dependencies.caches[.sessionUtil]
|
||||
let rawBlindedMessageRequestValue: Int32 = try dependencies[cache: .sessionUtil]
|
||||
.config(for: .userProfile, publicKey: getUserHexEncodedPublicKey(db))
|
||||
.wrappedValue
|
||||
.map { config -> Int32 in try SessionUtil.rawBlindedMessageRequestValue(in: config) }
|
||||
|
@ -39,6 +39,6 @@ enum _015_BlockCommunityMessageRequests: Migration {
|
|||
)
|
||||
}
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ enum _016_DisappearingMessagesConfiguration: Migration {
|
|||
// If there isn't already a user account then we can just finish here (there will be no
|
||||
// threads/configs to update and the configs won't be setup which would cause this to crash
|
||||
guard Identity.userExists(db) else {
|
||||
return Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
return Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
|
||||
// Convenience function to set the disappearing messages type per conversation
|
||||
|
@ -78,7 +78,7 @@ enum _016_DisappearingMessagesConfiguration: Migration {
|
|||
_ = try SessionUtil.updatingDisappearingConfigsOneToOne(db, contactUpdate, using: dependencies)
|
||||
_ = try SessionUtil.batchUpdate(db, disappearingConfigs: legacyGroupUpdate, using: dependencies)
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ enum _017_GroupsRebuildChanges: Migration {
|
|||
.defaults(to: true)
|
||||
}
|
||||
|
||||
Storage.update(progress: 1, for: self, in: target) // In case this is the last migration
|
||||
Storage.update(progress: 1, for: self, in: target, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1071,7 +1071,7 @@ extension Attachment {
|
|||
|
||||
let attachmentId: String = self.id
|
||||
|
||||
return dependencies.storage
|
||||
return dependencies[singleton: .storage]
|
||||
.writePublisher { db -> (HTTP.PreparedRequest<FileUploadResponse>?, String?, Data?, Data?) in
|
||||
// If the attachment is a downloaded attachment, check if it came from
|
||||
// the server and if so just succeed immediately (no use re-uploading
|
||||
|
@ -1165,7 +1165,7 @@ extension Attachment {
|
|||
///
|
||||
/// **Note:** We **MUST** use the `.with` function here to ensure the `isValid` flag is
|
||||
/// updated correctly
|
||||
dependencies.storage
|
||||
dependencies[singleton: .storage]
|
||||
.writePublisher { db in
|
||||
try self
|
||||
.with(
|
||||
|
@ -1189,7 +1189,7 @@ extension Attachment {
|
|||
switch result {
|
||||
case .finished: break
|
||||
case .failure:
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try Attachment
|
||||
.filter(id: attachmentId)
|
||||
.updateAll(db, Attachment.Columns.state.set(to: Attachment.State.failedUpload))
|
||||
|
|
|
@ -94,7 +94,7 @@ public extension BlindedIdLookup {
|
|||
// If we we given a sessionId then validate it is correct and if so save it
|
||||
if
|
||||
let sessionId: String = sessionId,
|
||||
dependencies.crypto.verify(
|
||||
dependencies[singleton: .crypto].verify(
|
||||
.sessionId(
|
||||
sessionId,
|
||||
matchesBlindedId: blindedId,
|
||||
|
@ -118,7 +118,7 @@ public extension BlindedIdLookup {
|
|||
|
||||
while let contact: Contact = try contactsThatApprovedMeCursor.next() {
|
||||
guard
|
||||
dependencies.crypto.verify(
|
||||
dependencies[singleton: .crypto].verify(
|
||||
.sessionId(
|
||||
contact.id,
|
||||
matchesBlindedId: blindedId,
|
||||
|
@ -160,7 +160,7 @@ public extension BlindedIdLookup {
|
|||
while let otherLookup: BlindedIdLookup = try blindedIdLookupCursor.next() {
|
||||
guard
|
||||
let sessionId: String = otherLookup.sessionId,
|
||||
dependencies.crypto.verify(
|
||||
dependencies[singleton: .crypto].verify(
|
||||
.sessionId(
|
||||
sessionId,
|
||||
matchesBlindedId: blindedId,
|
||||
|
|
|
@ -195,12 +195,13 @@ public extension ClosedGroup {
|
|||
) throws {
|
||||
guard !threadIds.isEmpty else { return }
|
||||
guard let db: Database = db else {
|
||||
Storage.shared.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try ClosedGroup.removeKeysAndUnsubscribe(
|
||||
db,
|
||||
threadIds: threadIds,
|
||||
removeGroupData: removeGroupData,
|
||||
calledFromConfigHandling: calledFromConfigHandling
|
||||
calledFromConfigHandling: calledFromConfigHandling,
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
return
|
||||
|
@ -210,7 +211,7 @@ public extension ClosedGroup {
|
|||
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
||||
|
||||
threadIds.forEach { threadId in
|
||||
ClosedGroupPoller.shared.stopPolling(for: threadId)
|
||||
dependencies[singleton: .closedGroupPoller].stopPolling(for: threadId)
|
||||
|
||||
try? PushNotificationAPI
|
||||
.preparedUnsubscribeFromLegacyGroup(
|
||||
|
|
|
@ -456,9 +456,11 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu
|
|||
|
||||
// Start the disappearing messages timer if needed
|
||||
if self.expiresStartedAtMs != nil {
|
||||
JobRunner.upsert(
|
||||
Dependencies()[singleton: .jobRunner].upsert(
|
||||
db,
|
||||
job: DisappearingMessagesJob.updateNextRunIfNeeded(db)
|
||||
job: DisappearingMessagesJob.updateNextRunIfNeeded(db),
|
||||
canStartJob: true,
|
||||
using: Dependencies()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -544,14 +546,16 @@ public extension Interaction {
|
|||
// Add the 'DisappearingMessagesJob' if needed - this will update any expiring
|
||||
// messages `expiresStartedAtMs` values in local database, and create seperate
|
||||
// jobs updating message expiration
|
||||
JobRunner.upsert(
|
||||
dependencies[singleton: .jobRunner].upsert(
|
||||
db,
|
||||
job: DisappearingMessagesJob.updateNextRunIfNeeded(
|
||||
db,
|
||||
interactionIds: interactionInfo.map { $0.id },
|
||||
startedAtMs: TimeInterval(SnodeAPI.currentOffsetTimestampMs()),
|
||||
threadId: threadId
|
||||
threadId: threadId,
|
||||
using: dependencies
|
||||
),
|
||||
canStartJob: true,
|
||||
using: dependencies
|
||||
)
|
||||
|
||||
|
@ -584,15 +588,17 @@ public extension Interaction {
|
|||
// If we want to send read receipts and it's a contact thread then try to add the
|
||||
// 'SendReadReceiptsJob' for and unread messages that weren't outgoing
|
||||
if trySendReadReceipt && threadVariant == .contact {
|
||||
JobRunner.upsert(
|
||||
dependencies[singleton: .jobRunner].upsert(
|
||||
db,
|
||||
job: SendReadReceiptsJob.createOrUpdateIfNeeded(
|
||||
db,
|
||||
threadId: threadId,
|
||||
interactionIds: interactionInfo
|
||||
.filter { !$0.wasRead && $0.variant != .standardOutgoing }
|
||||
.map { $0.id }
|
||||
.map { $0.id },
|
||||
using: dependencies
|
||||
),
|
||||
canStartJob: true,
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
|
@ -871,7 +877,7 @@ public extension Interaction {
|
|||
if let openGroup: OpenGroup = try? OpenGroup.fetchOne(db, id: threadId) {
|
||||
if
|
||||
let userEd25519KeyPair: KeyPair = Identity.fetchUserEd25519KeyPair(db),
|
||||
let blindedKeyPair: KeyPair = dependencies.crypto.generate(
|
||||
let blindedKeyPair: KeyPair = dependencies[singleton: .crypto].generate(
|
||||
.blindedKeyPair(serverPublicKey: openGroup.publicKey, edKeyPair: userEd25519KeyPair, using: dependencies)
|
||||
)
|
||||
{
|
||||
|
|
|
@ -211,8 +211,12 @@ public extension LinkPreview {
|
|||
|
||||
private static var previewUrlCache: Atomic<NSCache<NSString, NSString>> = Atomic(NSCache())
|
||||
|
||||
static func previewUrl(for body: String?, selectedRange: NSRange? = nil) -> String? {
|
||||
guard Storage.shared[.areLinkPreviewsEnabled] else { return nil }
|
||||
static func previewUrl(
|
||||
for body: String?,
|
||||
selectedRange: NSRange? = nil,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) -> String? {
|
||||
guard dependencies[singleton: .storage][.areLinkPreviewsEnabled] else { return nil }
|
||||
guard let body: String = body else { return nil }
|
||||
|
||||
if let cachedUrl = previewUrlCache.wrappedValue.object(forKey: body as NSString) as String? {
|
||||
|
@ -284,20 +288,27 @@ public extension LinkPreview {
|
|||
}
|
||||
}
|
||||
|
||||
private static func setCachedLinkPreview(_ linkPreviewDraft: LinkPreviewDraft, forPreviewUrl previewUrl: String) {
|
||||
private static func setCachedLinkPreview(
|
||||
_ linkPreviewDraft: LinkPreviewDraft,
|
||||
forPreviewUrl previewUrl: String,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
assert(previewUrl == linkPreviewDraft.urlString)
|
||||
|
||||
// Exit early if link previews are not enabled in order to avoid
|
||||
// tainting the cache.
|
||||
guard Storage.shared[.areLinkPreviewsEnabled] else { return }
|
||||
guard dependencies[singleton: .storage][.areLinkPreviewsEnabled] else { return }
|
||||
|
||||
serialQueue.sync {
|
||||
linkPreviewDraftCache = linkPreviewDraft
|
||||
}
|
||||
}
|
||||
|
||||
static func tryToBuildPreviewInfo(previewUrl: String?) -> AnyPublisher<LinkPreviewDraft, Error> {
|
||||
guard Storage.shared[.areLinkPreviewsEnabled] else {
|
||||
static func tryToBuildPreviewInfo(
|
||||
previewUrl: String?,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) -> AnyPublisher<LinkPreviewDraft, Error> {
|
||||
guard dependencies[singleton: .storage][.areLinkPreviewsEnabled] else {
|
||||
return Fail(error: LinkPreviewError.featureDisabled)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
|
|
@ -213,8 +213,12 @@ public extension Profile {
|
|||
)
|
||||
}
|
||||
|
||||
static func fetchAllContactProfiles(excluding: Set<String> = [], excludeCurrentUser: Bool = true) -> [Profile] {
|
||||
return Storage.shared
|
||||
static func fetchAllContactProfiles(
|
||||
excluding: Set<String> = [],
|
||||
excludeCurrentUser: Bool = true,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) -> [Profile] {
|
||||
return dependencies[singleton: .storage]
|
||||
.read { db in
|
||||
// Sort the contacts by their displayName value
|
||||
try Profile
|
||||
|
@ -228,10 +232,24 @@ public extension Profile {
|
|||
.defaulting(to: [])
|
||||
}
|
||||
|
||||
static func displayName(_ db: Database? = nil, id: ID, threadVariant: SessionThread.Variant = .contact, customFallback: String? = nil) -> String {
|
||||
static func displayName(
|
||||
_ db: Database? = nil,
|
||||
id: ID,
|
||||
threadVariant: SessionThread.Variant = .contact,
|
||||
customFallback: String? = nil,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) -> String {
|
||||
guard let db: Database = db else {
|
||||
return Storage.shared
|
||||
.read { db in displayName(db, id: id, threadVariant: threadVariant, customFallback: customFallback) }
|
||||
return dependencies[singleton: .storage]
|
||||
.read { db in
|
||||
displayName(
|
||||
db,
|
||||
id: id,
|
||||
threadVariant: threadVariant,
|
||||
customFallback: customFallback,
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
.defaulting(to: (customFallback ?? id))
|
||||
}
|
||||
|
||||
|
@ -241,9 +259,16 @@ public extension Profile {
|
|||
return (existingDisplayName ?? (customFallback ?? id))
|
||||
}
|
||||
|
||||
static func displayNameNoFallback(_ db: Database? = nil, id: ID, threadVariant: SessionThread.Variant = .contact) -> String? {
|
||||
static func displayNameNoFallback(
|
||||
_ db: Database? = nil,
|
||||
id: ID,
|
||||
threadVariant: SessionThread.Variant = .contact,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) -> String? {
|
||||
guard let db: Database = db else {
|
||||
return Storage.shared.read { db in displayNameNoFallback(db, id: id, threadVariant: threadVariant) }
|
||||
return dependencies[singleton: .storage].read { db in
|
||||
displayNameNoFallback(db, id: id, threadVariant: threadVariant, using: dependencies)
|
||||
}
|
||||
}
|
||||
|
||||
return (try? Profile.fetchOne(db, id: id))?
|
||||
|
@ -278,7 +303,7 @@ public extension Profile {
|
|||
let userPublicKey: String = getUserHexEncodedPublicKey(db, using: dependencies)
|
||||
|
||||
guard let db: Database = db else {
|
||||
return dependencies.storage
|
||||
return dependencies[singleton: .storage]
|
||||
.read { db in fetchOrCreateCurrentUser(db, using: dependencies) }
|
||||
.defaulting(to: defaultFor(userPublicKey))
|
||||
}
|
||||
|
|
|
@ -548,7 +548,7 @@ public extension SessionThread {
|
|||
) -> String? {
|
||||
guard threadVariant == .community else { return nil }
|
||||
guard let db: Database = db else {
|
||||
return dependencies.storage.read { db in
|
||||
return dependencies[singleton: .storage].read { db in
|
||||
getUserHexEncodedBlindedKey(
|
||||
db,
|
||||
threadId: threadId,
|
||||
|
@ -584,7 +584,7 @@ public extension SessionThread {
|
|||
|
||||
guard capabilities.isEmpty || capabilities.contains(.blind) else { return nil }
|
||||
|
||||
let blindedKeyPair: KeyPair? = dependencies.crypto.generate(
|
||||
let blindedKeyPair: KeyPair? = dependencies[singleton: .crypto].generate(
|
||||
.blindedKeyPair(serverPublicKey: openGroupInfo.publicKey, edKeyPair: userEdKeyPair, using: dependencies)
|
||||
)
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ public enum AttachmentDownloadJob: JobExecutor {
|
|||
let threadId: String = job.threadId,
|
||||
let detailsData: Data = job.details,
|
||||
let details: Details = try? JSONDecoder().decode(Details.self, from: detailsData),
|
||||
let attachment: Attachment = Storage.shared
|
||||
let attachment: Attachment = dependencies[singleton: .storage]
|
||||
.read({ db in try Attachment.fetchOne(db, id: details.attachmentId) })
|
||||
else {
|
||||
failure(job, JobRunnerError.missingRequiredDetails, true, dependencies)
|
||||
|
@ -42,7 +42,7 @@ public enum AttachmentDownloadJob: JobExecutor {
|
|||
// the same attachment multiple times at the same time (it also adds a "clean up" mechanism
|
||||
// if an attachment ends up stuck in a "downloading" state incorrectly
|
||||
guard attachment.state != .downloading else {
|
||||
let otherCurrentJobAttachmentIds: Set<String> = dependencies.jobRunner
|
||||
let otherCurrentJobAttachmentIds: Set<String> = dependencies[singleton: .jobRunner]
|
||||
.jobInfoFor(state: .running, variant: .attachmentDownload)
|
||||
.filter { key, _ in key != job.id }
|
||||
.values
|
||||
|
@ -58,7 +58,7 @@ public enum AttachmentDownloadJob: JobExecutor {
|
|||
// then we should update the state of the attachment to be failed to avoid having attachments
|
||||
// appear in an endlessly downloading state
|
||||
if !otherCurrentJobAttachmentIds.contains(attachment.id) {
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
_ = try Attachment
|
||||
.filter(id: attachment.id)
|
||||
.updateAll(db, Attachment.Columns.state.set(to: Attachment.State.failedDownload))
|
||||
|
@ -76,7 +76,7 @@ public enum AttachmentDownloadJob: JobExecutor {
|
|||
}
|
||||
|
||||
// Update to the 'downloading' state (no need to update the 'attachment' instance)
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try Attachment
|
||||
.filter(id: attachment.id)
|
||||
.updateAll(db, Attachment.Columns.state.set(to: Attachment.State.downloading))
|
||||
|
@ -94,7 +94,7 @@ public enum AttachmentDownloadJob: JobExecutor {
|
|||
let fileId: String = Attachment.fileId(for: downloadUrl)
|
||||
else { throw AttachmentDownloadError.invalidUrl }
|
||||
|
||||
return Storage.shared
|
||||
return dependencies[singleton: .storage]
|
||||
.readPublisher { db -> HTTP.PreparedRequest<Data>? in
|
||||
try OpenGroup.fetchOne(db, id: threadId)
|
||||
.map { openGroup in
|
||||
|
@ -164,7 +164,7 @@ public enum AttachmentDownloadJob: JobExecutor {
|
|||
///
|
||||
/// **Note:** We **MUST** use the `'with()` function here as it will update the
|
||||
/// `isValid` and `duration` values based on the downloaded data and the state
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
_ = try attachment
|
||||
.with(
|
||||
state: .downloaded,
|
||||
|
@ -209,7 +209,7 @@ public enum AttachmentDownloadJob: JobExecutor {
|
|||
///
|
||||
/// **Note:** We **MUST** use the `'with()` function here as it will update the
|
||||
/// `isValid` and `duration` values based on the downloaded data and the state
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
_ = try Attachment
|
||||
.filter(id: attachment.id)
|
||||
.updateAll(db, Attachment.Columns.state.set(to: targetState))
|
||||
|
|
|
@ -24,7 +24,7 @@ public enum AttachmentUploadJob: JobExecutor {
|
|||
let interactionId: Int64 = job.interactionId,
|
||||
let detailsData: Data = job.details,
|
||||
let details: Details = try? JSONDecoder().decode(Details.self, from: detailsData),
|
||||
let (attachment, openGroup): (Attachment, OpenGroup?) = dependencies.storage.read({ db in
|
||||
let (attachment, openGroup): (Attachment, OpenGroup?) = dependencies[singleton: .storage].read({ db in
|
||||
guard let attachment: Attachment = try Attachment.fetchOne(db, id: details.attachmentId) else {
|
||||
return nil
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ public enum AttachmentUploadJob: JobExecutor {
|
|||
|
||||
// If the original interaction no longer exists then don't bother uploading the attachment (ie. the
|
||||
// message was deleted before it even got sent)
|
||||
guard dependencies.storage.read({ db in try Interaction.exists(db, id: interactionId) }) == true else {
|
||||
guard dependencies[singleton: .storage].read({ db in try Interaction.exists(db, id: interactionId) }) == true else {
|
||||
SNLog("[AttachmentUploadJob] Failed due to missing interaction")
|
||||
return failure(job, StorageError.objectNotFound, true, dependencies)
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ public enum AttachmentUploadJob: JobExecutor {
|
|||
// If this upload is related to sending a message then trigger the 'handleMessageWillSend' logic
|
||||
// as if this is a retry the logic wouldn't run until after the upload has completed resulting in
|
||||
// a potentially incorrect delivery status
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
guard
|
||||
let sendJob: Job = try Job.fetchOne(db, id: details.messageSendJobId),
|
||||
let sendJobDetails: Data = sendJob.details,
|
||||
|
@ -82,7 +82,7 @@ public enum AttachmentUploadJob: JobExecutor {
|
|||
// If this upload is related to sending a message then trigger the
|
||||
// 'handleFailedMessageSend' logic as we want to ensure the message
|
||||
// has the correct delivery status
|
||||
dependencies.storage.read { db in
|
||||
dependencies[singleton: .storage].read { db in
|
||||
guard
|
||||
let sendJob: Job = try Job.fetchOne(db, id: details.messageSendJobId),
|
||||
let sendJobDetails: Data = sendJob.details,
|
||||
|
|
|
@ -25,7 +25,7 @@ public enum ConfigMessageReceiveJob: JobExecutor {
|
|||
let removeDependencyOnMessageReceiveJobs: () -> () = {
|
||||
guard let jobId: Int64 = job.id else { return }
|
||||
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try JobDependencies
|
||||
.filter(JobDependencies.Columns.dependantId == jobId)
|
||||
.joining(
|
||||
|
@ -55,7 +55,7 @@ public enum ConfigMessageReceiveJob: JobExecutor {
|
|||
let sharedConfigMessages: [SharedConfigMessage] = details.messages
|
||||
.compactMap { $0.message as? SharedConfigMessage }
|
||||
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
// Send any SharedConfigMessages to the SessionUtil to handle it
|
||||
do {
|
||||
try SessionUtil.handleConfigMessages(
|
||||
|
|
|
@ -30,8 +30,7 @@ public enum ConfigurationSyncJob: JobExecutor {
|
|||
// between the jobs we just continue to defer the subsequent job while the first one is running in
|
||||
// order to prevent multiple configurationSync jobs with the same target from running at the same time
|
||||
guard
|
||||
dependencies
|
||||
.jobRunner
|
||||
dependencies[singleton: .jobRunner]
|
||||
.jobInfoFor(state: .running, variant: .configurationSync)
|
||||
.filter({ key, info in
|
||||
key != job.id && // Exclude this job
|
||||
|
@ -41,7 +40,7 @@ public enum ConfigurationSyncJob: JobExecutor {
|
|||
else {
|
||||
// Defer the job to run 'maxRunFrequency' from when this one ran (if we don't it'll try start
|
||||
// it again immediately which is pointless)
|
||||
let updatedJob: Job? = dependencies.storage.write { db in
|
||||
let updatedJob: Job? = dependencies[singleton: .storage].write { db in
|
||||
try job
|
||||
.with(nextRunTimestamp: dependencies.dateNow.timeIntervalSince1970 + maxRunFrequency)
|
||||
.saved(db)
|
||||
|
@ -56,7 +55,7 @@ public enum ConfigurationSyncJob: JobExecutor {
|
|||
// fresh install due to the migrations getting run)
|
||||
guard
|
||||
let publicKey: String = job.threadId,
|
||||
let pendingConfigChanges: [SessionUtil.OutgoingConfResult] = dependencies.storage
|
||||
let pendingConfigChanges: [SessionUtil.OutgoingConfResult] = dependencies[singleton: .storage]
|
||||
.read(using: dependencies, { db in
|
||||
try SessionUtil.pendingChanges(db, publicKey: publicKey, using: dependencies)
|
||||
})
|
||||
|
@ -73,7 +72,7 @@ public enum ConfigurationSyncJob: JobExecutor {
|
|||
}
|
||||
|
||||
// Identify the destination and merge all obsolete hashes into a single set
|
||||
let destination: Message.Destination = (publicKey == getUserHexEncodedPublicKey() ?
|
||||
let destination: Message.Destination = (publicKey == getUserHexEncodedPublicKey(using: dependencies) ?
|
||||
Message.Destination.contact(publicKey: publicKey) :
|
||||
Message.Destination.closedGroup(groupPublicKey: publicKey)
|
||||
)
|
||||
|
@ -84,7 +83,7 @@ public enum ConfigurationSyncJob: JobExecutor {
|
|||
let jobStartTimestamp: TimeInterval = dependencies.dateNow.timeIntervalSince1970
|
||||
SNLog("[ConfigurationSyncJob] For \(publicKey) started with \(pendingConfigChanges.count) change\(pendingConfigChanges.count == 1 ? "" : "s")")
|
||||
|
||||
dependencies.storage
|
||||
dependencies[singleton: .storage]
|
||||
.readPublisher { db in
|
||||
try pendingConfigChanges.map { change -> MessageSender.PreparedSendData in
|
||||
try MessageSender.preparedSendData(
|
||||
|
@ -152,7 +151,7 @@ public enum ConfigurationSyncJob: JobExecutor {
|
|||
var shouldFinishCurrentJob: Bool = false
|
||||
|
||||
// Lastly we need to save the updated dumps to the database
|
||||
let updatedJob: Job? = dependencies.storage.write { db in
|
||||
let updatedJob: Job? = dependencies[singleton: .storage].write { db in
|
||||
// Save the updated dumps to the database
|
||||
try configDumps.forEach { try $0.save(db) }
|
||||
|
||||
|
@ -173,7 +172,7 @@ public enum ConfigurationSyncJob: JobExecutor {
|
|||
{
|
||||
// If the next job isn't currently running then delay it's start time
|
||||
// until the 'nextRunTimestamp'
|
||||
if !dependencies.jobRunner.isCurrentlyRunning(existingJob) {
|
||||
if !dependencies[singleton: .jobRunner].isCurrentlyRunning(existingJob) {
|
||||
_ = try existingJob
|
||||
.with(nextRunTimestamp: nextRunTimestamp)
|
||||
.saved(db)
|
||||
|
@ -204,7 +203,7 @@ public extension ConfigurationSyncJob {
|
|||
dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
// Upsert a config sync job if needed
|
||||
dependencies.jobRunner.upsert(
|
||||
dependencies[singleton: .jobRunner].upsert(
|
||||
db,
|
||||
job: ConfigurationSyncJob.createIfNeeded(db, publicKey: publicKey, using: dependencies),
|
||||
canStartJob: true,
|
||||
|
@ -222,7 +221,7 @@ public extension ConfigurationSyncJob {
|
|||
///
|
||||
/// **Note:** Jobs with different `threadId` values can run concurrently
|
||||
guard
|
||||
dependencies.jobRunner
|
||||
dependencies[singleton: .jobRunner]
|
||||
.jobInfoFor(state: .running, variant: .configurationSync)
|
||||
.filter({ _, info in info.threadId == publicKey })
|
||||
.isEmpty,
|
||||
|
|
|
@ -24,7 +24,7 @@ public enum DisappearingMessagesJob: JobExecutor {
|
|||
var backgroundTask: OWSBackgroundTask? = OWSBackgroundTask(label: #function)
|
||||
var numDeleted: Int = -1
|
||||
|
||||
let updatedJob: Job? = Storage.shared.write { db in
|
||||
let updatedJob: Job? = dependencies[singleton: .storage].write { db in
|
||||
numDeleted = try Interaction
|
||||
.filter(Interaction.Columns.expiresStartedAtMs != nil)
|
||||
.filter((Interaction.Columns.expiresStartedAtMs + (Interaction.Columns.expiresInSeconds * 1000)) <= timestampNowMs)
|
||||
|
@ -79,7 +79,12 @@ public extension DisappearingMessagesJob {
|
|||
.saved(db)
|
||||
}
|
||||
|
||||
static func updateNextRunIfNeeded(_ db: Database, lastReadTimestampMs: Int64, threadId: String) {
|
||||
static func updateNextRunIfNeeded(
|
||||
_ db: Database,
|
||||
lastReadTimestampMs: Int64,
|
||||
threadId: String,
|
||||
using dependencies: Dependencies
|
||||
) {
|
||||
struct ExpirationInfo: Codable, Hashable, FetchableRecord {
|
||||
let expiresInSeconds: TimeInterval
|
||||
let serverHash: String
|
||||
|
@ -105,7 +110,7 @@ public extension DisappearingMessagesJob {
|
|||
|
||||
let startedAtTimestampMs: Double = Double(SnodeAPI.currentOffsetTimestampMs())
|
||||
|
||||
JobRunner.add(
|
||||
dependencies[singleton: .jobRunner].add(
|
||||
db,
|
||||
job: Job(
|
||||
variant: .getExpiration,
|
||||
|
@ -115,11 +120,19 @@ public extension DisappearingMessagesJob {
|
|||
expirationInfo: expirationInfo,
|
||||
startedAtTimestampMs: startedAtTimestampMs
|
||||
)
|
||||
)
|
||||
),
|
||||
canStartJob: true,
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
|
||||
@discardableResult static func updateNextRunIfNeeded(_ db: Database, interactionIds: [Int64], startedAtMs: Double, threadId: String) -> Job? {
|
||||
@discardableResult static func updateNextRunIfNeeded(
|
||||
_ db: Database,
|
||||
interactionIds: [Int64],
|
||||
startedAtMs: Double,
|
||||
threadId: String,
|
||||
using dependencies: Dependencies
|
||||
) -> Job? {
|
||||
struct ExpirationInfo: Codable, Hashable, FetchableRecord {
|
||||
let id: Int64
|
||||
let expiresInSeconds: TimeInterval
|
||||
|
@ -159,7 +172,7 @@ public extension DisappearingMessagesJob {
|
|||
|
||||
interactionExpirationInfosByExpiresInSeconds.forEach { expiresInSeconds, expirationInfos in
|
||||
let expirationTimestampMs: Int64 = Int64(startedAtMs + expiresInSeconds * 1000)
|
||||
JobRunner.add(
|
||||
dependencies[singleton: .jobRunner].add(
|
||||
db,
|
||||
job: Job(
|
||||
variant: .expirationUpdate,
|
||||
|
@ -169,14 +182,21 @@ public extension DisappearingMessagesJob {
|
|||
serverHashes: expirationInfos.map { $0.serverHash },
|
||||
expirationTimestampMs: expirationTimestampMs
|
||||
)
|
||||
)
|
||||
),
|
||||
canStartJob: true,
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
|
||||
return updateNextRunIfNeeded(db)
|
||||
}
|
||||
|
||||
@discardableResult static func updateNextRunIfNeeded(_ db: Database, interaction: Interaction, startedAtMs: Double) -> Job? {
|
||||
@discardableResult static func updateNextRunIfNeeded(
|
||||
_ db: Database,
|
||||
interaction: Interaction,
|
||||
startedAtMs: Double,
|
||||
using dependencies: Dependencies
|
||||
) -> Job? {
|
||||
guard interaction.isExpiringMessage else { return nil }
|
||||
|
||||
// Don't clobber if multiple actions simultaneously triggered expiration
|
||||
|
@ -189,7 +209,13 @@ public extension DisappearingMessagesJob {
|
|||
throw StorageError.objectNotFound
|
||||
}
|
||||
|
||||
return updateNextRunIfNeeded(db, interactionIds: [interactionId], startedAtMs: startedAtMs, threadId: interaction.threadId)
|
||||
return updateNextRunIfNeeded(
|
||||
db,
|
||||
interactionIds: [interactionId],
|
||||
startedAtMs: startedAtMs,
|
||||
threadId: interaction.threadId,
|
||||
using: dependencies
|
||||
)
|
||||
}
|
||||
catch {
|
||||
SNLog("[DisappearingMessagesJob] Failed to update the expiring messages timer on an interaction")
|
||||
|
|
|
@ -62,7 +62,7 @@ public enum ExpirationUpdateJob: JobExecutor {
|
|||
receiveValue: { unchangedMessages in
|
||||
guard !unchangedMessages.isEmpty else { return }
|
||||
|
||||
dependencies.storage.writeAsync(using: dependencies) { db in
|
||||
dependencies[singleton: .storage].writeAsync(using: dependencies) { db in
|
||||
try unchangedMessages.forEach { updatedExpiry, hashes in
|
||||
try hashes.forEach { hash in
|
||||
guard
|
||||
|
|
|
@ -21,7 +21,7 @@ public enum FailedAttachmentDownloadsJob: JobExecutor {
|
|||
var changeCount: Int = -1
|
||||
|
||||
// Update all 'sending' message states to 'failed'
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
changeCount = try Attachment
|
||||
.filter(Attachment.Columns.state == Attachment.State.downloading)
|
||||
.updateAll(db, Attachment.Columns.state.set(to: Attachment.State.failedDownload))
|
||||
|
|
|
@ -21,7 +21,7 @@ public enum FailedMessageSendsJob: JobExecutor {
|
|||
var attachmentChangeCount: Int = -1
|
||||
|
||||
// Update all 'sending' message states to 'failed'
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
let sendChangeCount: Int = try RecipientState
|
||||
.filter(RecipientState.Columns.state == RecipientState.State.sending)
|
||||
.updateAll(db, RecipientState.Columns.state.set(to: RecipientState.State.failed))
|
||||
|
|
|
@ -40,7 +40,7 @@ public enum GarbageCollectionJob: JobExecutor {
|
|||
/// app at about the same time every day will trigger the garbage collection) - since this runs when the app becomes active we
|
||||
/// want to prevent it running to frequently (the app becomes active if a system alert, the notification center or the control panel
|
||||
/// are shown)
|
||||
let lastGarbageCollection: Date = dependencies.standardUserDefaults[.lastGarbageCollection]
|
||||
let lastGarbageCollection: Date = dependencies[singleton: .standardUserDefaults][.lastGarbageCollection]
|
||||
.defaulting(to: Date.distantPast)
|
||||
let finalTypesToCollect: Set<Types> = {
|
||||
guard
|
||||
|
@ -58,7 +58,7 @@ public enum GarbageCollectionJob: JobExecutor {
|
|||
return typesToCollect.asSet()
|
||||
}()
|
||||
|
||||
dependencies.storage.writeAsync(
|
||||
dependencies[singleton: .storage].writeAsync(
|
||||
updates: { db in
|
||||
/// Remove any typing indicators
|
||||
if finalTypesToCollect.contains(.threadTypingIndicators) {
|
||||
|
@ -345,7 +345,7 @@ public enum GarbageCollectionJob: JobExecutor {
|
|||
let profileAvatarFilenames: Set<String>
|
||||
}
|
||||
|
||||
let maybeFileInfo: FileInfo? = Storage.shared.read { db -> FileInfo in
|
||||
let maybeFileInfo: FileInfo? = dependencies[singleton: .storage].read { db -> FileInfo in
|
||||
var attachmentLocalRelativePaths: Set<String> = []
|
||||
var profileAvatarFilenames: Set<String> = []
|
||||
|
||||
|
@ -461,7 +461,7 @@ public enum GarbageCollectionJob: JobExecutor {
|
|||
// If we did a full collection then update the 'lastGarbageCollection' date to
|
||||
// prevent a full collection from running again in the next 23 hours
|
||||
if job.behaviour == .recurringOnActive && dependencies.dateNow.timeIntervalSince(lastGarbageCollection) > (23 * 60 * 60) {
|
||||
dependencies.standardUserDefaults[.lastGarbageCollection] = dependencies.dateNow
|
||||
dependencies[singleton: .standardUserDefaults][.lastGarbageCollection] = dependencies.dateNow
|
||||
}
|
||||
|
||||
success(job, false, dependencies)
|
||||
|
|
|
@ -29,7 +29,7 @@ public enum GetExpirationJob: JobExecutor {
|
|||
return
|
||||
}
|
||||
|
||||
let expirationInfo: [String: TimeInterval] = dependencies.storage
|
||||
let expirationInfo: [String: TimeInterval] = dependencies[singleton: .storage]
|
||||
.read(using: dependencies) { db -> [String: TimeInterval] in
|
||||
details
|
||||
.expirationInfo
|
||||
|
@ -75,7 +75,7 @@ public enum GetExpirationJob: JobExecutor {
|
|||
let hashesToUseDefault: Set<String> = Set(expirationInfo.keys)
|
||||
.subtracting(serverSpecifiedExpirationStartTimesMs.keys)
|
||||
|
||||
dependencies.storage.write(using: dependencies) { db in
|
||||
dependencies[singleton: .storage].write(using: dependencies) { db in
|
||||
try serverSpecifiedExpirationStartTimesMs.forEach { hash, expiresStartedAtMs in
|
||||
try Interaction
|
||||
.filter(Interaction.Columns.serverHash == hash)
|
||||
|
@ -93,7 +93,7 @@ public enum GetExpirationJob: JobExecutor {
|
|||
Interaction.Columns.expiresStartedAtMs.set(to: details.startedAtTimestampMs)
|
||||
)
|
||||
|
||||
dependencies.jobRunner
|
||||
dependencies[singleton: .jobRunner]
|
||||
.upsert(
|
||||
db,
|
||||
job: DisappearingMessagesJob.updateNextRunIfNeeded(db),
|
||||
|
@ -103,7 +103,7 @@ public enum GetExpirationJob: JobExecutor {
|
|||
}
|
||||
|
||||
guard hashesToUseDefault.isEmpty else {
|
||||
let updatedJob: Job? = dependencies.storage.write(using: dependencies) { db in
|
||||
let updatedJob: Job? = dependencies[singleton: .storage].write(using: dependencies) { db in
|
||||
try job
|
||||
.with(nextRunTimestamp: dependencies.dateNow.timeIntervalSince1970 + minRunFrequency)
|
||||
.saved(db)
|
||||
|
|
|
@ -22,7 +22,7 @@ public enum GroupInviteMemberJob: JobExecutor {
|
|||
guard
|
||||
let threadId: String = job.threadId,
|
||||
let detailsData: Data = job.details,
|
||||
let currentInfo: (groupName: String, adminProfile: Profile) = dependencies.storage.read({ db in
|
||||
let currentInfo: (groupName: String, adminProfile: Profile) = dependencies[singleton: .storage].read({ db in
|
||||
let maybeGroupName: String? = try ClosedGroup
|
||||
.filter(id: threadId)
|
||||
.select(.name)
|
||||
|
|
|
@ -32,7 +32,7 @@ public enum GroupLeavingJob: JobExecutor {
|
|||
|
||||
let destination: Message.Destination = .closedGroup(groupPublicKey: threadId)
|
||||
|
||||
dependencies.storage
|
||||
dependencies[singleton: .storage]
|
||||
.writePublisher { db in
|
||||
guard (try? SessionThread.exists(db, id: threadId)) == true else {
|
||||
SNLog("[GroupLeavingJob] Failed due to non-existent group conversation")
|
||||
|
@ -72,7 +72,7 @@ public enum GroupLeavingJob: JobExecutor {
|
|||
]
|
||||
|
||||
// Handle the appropriate response
|
||||
dependencies.storage.writeAsync { db in
|
||||
dependencies[singleton: .storage].writeAsync { db in
|
||||
// If it failed due to one of these errors then clear out any associated data (as somehow
|
||||
// the 'SessionThread' exists but not the data required to send the 'MEMBER_LEFT' message
|
||||
// which would leave the user in a state where they can't leave the group)
|
||||
|
|
|
@ -51,7 +51,7 @@ public enum MessageReceiveJob: JobExecutor {
|
|||
}
|
||||
}
|
||||
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
for (messageInfo, protoContent) in messageData {
|
||||
do {
|
||||
try MessageReceiver.handle(
|
||||
|
|
|
@ -52,7 +52,7 @@ public enum MessageSendJob: JobExecutor {
|
|||
// Retrieve the current attachment state
|
||||
typealias AttachmentState = (error: Error?, pendingUploadAttachmentIds: [String], preparedFileIds: [String])
|
||||
|
||||
let attachmentState: AttachmentState = dependencies.storage
|
||||
let attachmentState: AttachmentState = dependencies[singleton: .storage]
|
||||
.read { db in
|
||||
// If the original interaction no longer exists then don't bother sending the message (ie. the
|
||||
// message was deleted before it even got sent)
|
||||
|
@ -113,11 +113,11 @@ public enum MessageSendJob: JobExecutor {
|
|||
/// If we have any pending (or failed) attachment uploads then we should create jobs for them and insert them into the
|
||||
/// queue before the current job and defer it (this will mean the current job will re-run after these inserted jobs complete)
|
||||
guard attachmentState.pendingUploadAttachmentIds.isEmpty else {
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try attachmentState.pendingUploadAttachmentIds
|
||||
.filter { attachmentId in
|
||||
// Don't add a new job if there is one already in the queue
|
||||
!dependencies.jobRunner.hasJob(
|
||||
!dependencies[singleton: .jobRunner].hasJob(
|
||||
of: .attachmentUpload,
|
||||
with: AttachmentUploadJob.Details(
|
||||
messageSendJobId: jobId,
|
||||
|
@ -126,7 +126,7 @@ public enum MessageSendJob: JobExecutor {
|
|||
)
|
||||
}
|
||||
.compactMap { attachmentId -> (jobId: Int64, job: Job)? in
|
||||
dependencies.jobRunner
|
||||
dependencies[singleton: .jobRunner]
|
||||
.insert(
|
||||
db,
|
||||
job: Job(
|
||||
|
@ -167,7 +167,7 @@ public enum MessageSendJob: JobExecutor {
|
|||
///
|
||||
/// **Note:** No need to upload attachments as part of this process as the above logic splits that out into it's own job
|
||||
/// so we shouldn't get here until attachments have already been uploaded
|
||||
dependencies.storage
|
||||
dependencies[singleton: .storage]
|
||||
.writePublisher { db in
|
||||
try MessageSender.preparedSendData(
|
||||
db,
|
||||
|
@ -207,7 +207,7 @@ public enum MessageSendJob: JobExecutor {
|
|||
if details.message is VisibleMessage {
|
||||
guard
|
||||
let interactionId: Int64 = job.interactionId,
|
||||
dependencies.storage.read({ db in try Interaction.exists(db, id: interactionId) }) == true
|
||||
dependencies[singleton: .storage].read({ db in try Interaction.exists(db, id: interactionId) }) == true
|
||||
else {
|
||||
// The message has been deleted so permanently fail the job
|
||||
return failure(job, error, true, dependencies)
|
||||
|
|
|
@ -27,7 +27,7 @@ public enum NotifyPushServerJob: JobExecutor {
|
|||
return failure(job, JobRunnerError.missingRequiredDetails, true, dependencies)
|
||||
}
|
||||
|
||||
dependencies.storage
|
||||
dependencies[singleton: .storage]
|
||||
.readPublisher(using: dependencies) { db in
|
||||
try PushNotificationAPI.preparedLegacyNotify(
|
||||
recipient: details.message.recipient,
|
||||
|
|
|
@ -27,7 +27,7 @@ public enum RetrieveDefaultOpenGroupRoomsJob: JobExecutor {
|
|||
// in the database so we need to create a dummy one to retrieve the default room data
|
||||
let defaultGroupId: String = OpenGroup.idFor(roomToken: "", server: OpenGroupAPI.defaultServer)
|
||||
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
guard try OpenGroup.exists(db, id: defaultGroupId) == false else { return }
|
||||
|
||||
_ = try OpenGroup(
|
||||
|
|
|
@ -34,7 +34,7 @@ public enum SendReadReceiptsJob: JobExecutor {
|
|||
return success(job, true, dependencies)
|
||||
}
|
||||
|
||||
dependencies.storage
|
||||
dependencies[singleton: .storage]
|
||||
.writePublisher { db in
|
||||
try MessageSender.preparedSendData(
|
||||
db,
|
||||
|
@ -61,7 +61,7 @@ public enum SendReadReceiptsJob: JobExecutor {
|
|||
var shouldFinishCurrentJob: Bool = false
|
||||
let nextRunTimestamp: TimeInterval = (dependencies.dateNow.timeIntervalSince1970 + maxRunFrequency)
|
||||
|
||||
let updatedJob: Job? = Storage.shared.write { db in
|
||||
let updatedJob: Job? = dependencies[singleton: .storage].write { db in
|
||||
// If another 'sendReadReceipts' job was scheduled then update that one
|
||||
// to run at 'nextRunTimestamp' and make the current job stop
|
||||
if
|
||||
|
@ -70,7 +70,7 @@ public enum SendReadReceiptsJob: JobExecutor {
|
|||
.filter(Job.Columns.variant == Job.Variant.sendReadReceipts)
|
||||
.filter(Job.Columns.threadId == threadId)
|
||||
.fetchOne(db),
|
||||
!JobRunner.isCurrentlyRunning(existingJob)
|
||||
!dependencies[singleton: .jobRunner].isCurrentlyRunning(existingJob)
|
||||
{
|
||||
_ = try existingJob
|
||||
.with(nextRunTimestamp: nextRunTimestamp)
|
||||
|
@ -110,7 +110,12 @@ public extension SendReadReceiptsJob {
|
|||
///
|
||||
/// **Note:** This method assumes that the provided `interactionIds` are valid and won't filter out any invalid ids so
|
||||
/// ensure that is done correctly beforehand
|
||||
@discardableResult static func createOrUpdateIfNeeded(_ db: Database, threadId: String, interactionIds: [Int64]) -> Job? {
|
||||
@discardableResult static func createOrUpdateIfNeeded(
|
||||
_ db: Database,
|
||||
threadId: String,
|
||||
interactionIds: [Int64],
|
||||
using dependencies: Dependencies
|
||||
) -> Job? {
|
||||
guard db[.areReadReceiptsEnabled] == true else { return nil }
|
||||
guard !interactionIds.isEmpty else { return nil }
|
||||
|
||||
|
@ -132,7 +137,7 @@ public extension SendReadReceiptsJob {
|
|||
.filter(Job.Columns.variant == Job.Variant.sendReadReceipts)
|
||||
.filter(Job.Columns.threadId == threadId)
|
||||
.fetchOne(db),
|
||||
!JobRunner.isCurrentlyRunning(existingJob),
|
||||
!dependencies[singleton: .jobRunner].isCurrentlyRunning(existingJob),
|
||||
let existingDetailsData: Data = existingJob.details,
|
||||
let existingDetails: Details = try? JSONDecoder().decode(Details.self, from: existingDetailsData)
|
||||
{
|
||||
|
|
|
@ -24,13 +24,13 @@ public enum UpdateProfilePictureJob: JobExecutor {
|
|||
|
||||
// Only re-upload the profile picture if enough time has passed since the last upload
|
||||
guard
|
||||
let lastProfilePictureUpload: Date = dependencies.standardUserDefaults[.lastProfilePictureUpload],
|
||||
let lastProfilePictureUpload: Date = dependencies[singleton: .standardUserDefaults][.lastProfilePictureUpload],
|
||||
dependencies.dateNow.timeIntervalSince(lastProfilePictureUpload) > (14 * 24 * 60 * 60)
|
||||
else {
|
||||
// Reset the `nextRunTimestamp` value just in case the last run failed so we don't get stuck
|
||||
// in a loop endlessly deferring the job
|
||||
if let jobId: Int64 = job.id {
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
try Job
|
||||
.filter(id: jobId)
|
||||
.updateAll(db, Job.Columns.nextRunTimestamp.set(to: 0))
|
||||
|
|
|
@ -50,8 +50,7 @@ public extension Message {
|
|||
|
||||
return .contact(publicKey: threadId)
|
||||
|
||||
case .legacyGroup, .group:
|
||||
return .closedGroup(groupPublicKey: threadId)
|
||||
case .legacyGroup, .group: return .closedGroup(groupPublicKey: threadId)
|
||||
|
||||
case .community:
|
||||
guard let openGroup: OpenGroup = try OpenGroup.fetchOne(db, id: threadId) else {
|
||||
|
|
|
@ -59,11 +59,11 @@ public extension Crypto.Action {
|
|||
id: "encryptAeadXChaCha20",
|
||||
args: [message, secretKey, nonce, additionalData]
|
||||
) {
|
||||
guard secretKey.count == dependencies.crypto.size(.aeadXChaCha20KeyBytes) else { return nil }
|
||||
guard secretKey.count == dependencies[singleton: .crypto].size(.aeadXChaCha20KeyBytes) else { return nil }
|
||||
|
||||
var authenticatedCipherText = Bytes(
|
||||
repeating: 0,
|
||||
count: message.count + dependencies.crypto.size(.aeadXChaCha20ABytes)
|
||||
count: message.count + dependencies[singleton: .crypto].size(.aeadXChaCha20ABytes)
|
||||
)
|
||||
var authenticatedCipherTextLen: UInt64 = 0
|
||||
|
||||
|
@ -132,7 +132,7 @@ public extension Crypto.Action {
|
|||
|
||||
guard
|
||||
!serverPubKeyData.isEmpty,
|
||||
let serverPublicKeyHashBytes: Bytes = try? dependencies.crypto.perform(
|
||||
let serverPublicKeyHashBytes: Bytes = try? dependencies[singleton: .crypto].perform(
|
||||
.hash(message: [UInt8](serverPubKeyData), outputLength: 64)
|
||||
)
|
||||
else { return nil }
|
||||
|
@ -290,11 +290,11 @@ public extension Crypto.Action {
|
|||
args: [secretKey, otherBlindedPublicKey, kA, kB]
|
||||
) {
|
||||
let aBytes: Bytes = generatePrivateKeyScalar(secretKey: secretKey)
|
||||
let combinedKeyBytes: Bytes = try dependencies.crypto.perform(
|
||||
let combinedKeyBytes: Bytes = try dependencies[singleton: .crypto].perform(
|
||||
.combineKeys(lhsKeyBytes: aBytes, rhsKeyBytes: otherBlindedPublicKey)
|
||||
)
|
||||
|
||||
return try dependencies.crypto.perform(
|
||||
return try dependencies[singleton: .crypto].perform(
|
||||
.hash(message: (combinedKeyBytes + kA + kB), outputLength: 32)
|
||||
)
|
||||
}
|
||||
|
@ -315,7 +315,7 @@ public extension Crypto.KeyPairType {
|
|||
guard
|
||||
edKeyPair.publicKey.count == Crypto.Action.publicKeyLength,
|
||||
edKeyPair.secretKey.count == Crypto.Action.secretKeyLength,
|
||||
let kBytes: Bytes = try? dependencies.crypto.perform(
|
||||
let kBytes: Bytes = try? dependencies[singleton: .crypto].perform(
|
||||
.generateBlindingFactor(serverPublicKey: serverPublicKey, using: dependencies)
|
||||
)
|
||||
else { return nil }
|
||||
|
@ -371,7 +371,7 @@ public extension Crypto.Verification {
|
|||
blindedId.prefix == .blinded15 ||
|
||||
blindedId.prefix == .blinded25
|
||||
),
|
||||
let kBytes: Bytes = try? dependencies.crypto.perform(
|
||||
let kBytes: Bytes = try? dependencies[singleton: .crypto].perform(
|
||||
.generateBlindingFactor(serverPublicKey: serverPublicKey, using: dependencies)
|
||||
)
|
||||
else { return false }
|
||||
|
@ -385,7 +385,7 @@ public extension Crypto.Verification {
|
|||
|
||||
/// Blind the positive public key
|
||||
guard
|
||||
let pk1: Bytes = try? dependencies.crypto.perform(
|
||||
let pk1: Bytes = try? dependencies[singleton: .crypto].perform(
|
||||
.combineKeys(lhsKeyBytes: kBytes, rhsKeyBytes: xEd25519Key.bytes)
|
||||
)
|
||||
else { return false }
|
||||
|
|
|
@ -79,7 +79,7 @@ extension OpenGroupAPI.Message {
|
|||
switch SessionId.Prefix(from: sender) {
|
||||
case .blinded15, .blinded25:
|
||||
guard
|
||||
dependencies.crypto.verify(
|
||||
dependencies[singleton: .crypto].verify(
|
||||
.signature(message: data.bytes, publicKey: publicKey.bytes, signature: signature.bytes)
|
||||
)
|
||||
else {
|
||||
|
@ -89,7 +89,7 @@ extension OpenGroupAPI.Message {
|
|||
|
||||
case .standard, .unblinded:
|
||||
guard
|
||||
dependencies.crypto.verify(
|
||||
dependencies[singleton: .crypto].verify(
|
||||
.signatureEd25519(signature, publicKey: publicKey, data: data)
|
||||
)
|
||||
else {
|
||||
|
|
|
@ -1300,10 +1300,10 @@ public enum OpenGroupAPI {
|
|||
// If we have no capabilities or if the server supports blinded keys then sign using the blinded key
|
||||
if forceBlinded || capabilities.isEmpty || capabilities.contains(.blind) {
|
||||
guard
|
||||
let blindedKeyPair: KeyPair = dependencies.crypto.generate(
|
||||
let blindedKeyPair: KeyPair = dependencies[singleton: .crypto].generate(
|
||||
.blindedKeyPair(serverPublicKey: serverPublicKey, edKeyPair: userEdKeyPair, using: dependencies)
|
||||
),
|
||||
let signatureResult: Bytes = try? dependencies.crypto.perform(
|
||||
let signatureResult: Bytes = try? dependencies[singleton: .crypto].perform(
|
||||
.sogsSignature(message: messageBytes, secretKey: userEdKeyPair.secretKey, blindedSecretKey: blindedKeyPair.secretKey, blindedPublicKey: blindedKeyPair.publicKey)
|
||||
)
|
||||
else { throw OpenGroupAPIError.signingFailed }
|
||||
|
@ -1318,7 +1318,7 @@ public enum OpenGroupAPI {
|
|||
switch signingType {
|
||||
case .unblinded:
|
||||
guard
|
||||
let signatureResult: Bytes = try? dependencies.crypto.perform(
|
||||
let signatureResult: Bytes = try? dependencies[singleton: .crypto].perform(
|
||||
.signature(message: messageBytes, secretKey: userEdKeyPair.secretKey)
|
||||
)
|
||||
else { throw OpenGroupAPIError.signingFailed }
|
||||
|
@ -1332,7 +1332,7 @@ public enum OpenGroupAPI {
|
|||
default:
|
||||
guard
|
||||
let userKeyPair: KeyPair = Identity.fetchUserKeyPair(db),
|
||||
let signatureResult: Bytes = try? dependencies.crypto.perform(
|
||||
let signatureResult: Bytes = try? dependencies[singleton: .crypto].perform(
|
||||
.signEd25519(data: messageBytes, keyPair: userKeyPair)
|
||||
)
|
||||
else { throw OpenGroupAPIError.signingFailed }
|
||||
|
@ -1368,7 +1368,7 @@ public enum OpenGroupAPI {
|
|||
|
||||
guard
|
||||
!serverPublicKeyData.isEmpty,
|
||||
let nonce: Data = (try? dependencies.crypto.perform(.generateNonce16())).map({ Data($0) }),
|
||||
let nonce: Data = (try? dependencies[singleton: .crypto].perform(.generateNonce16())).map({ Data($0) }),
|
||||
let timestampBytes: Bytes = "\(timestamp)".data(using: .ascii)?.bytes
|
||||
else { throw OpenGroupAPIError.signingFailed }
|
||||
|
||||
|
@ -1376,7 +1376,7 @@ public enum OpenGroupAPI {
|
|||
let bodyHash: Bytes? = {
|
||||
guard let body: Data = preparedRequest.request.httpBody else { return nil }
|
||||
|
||||
return try? dependencies.crypto.perform(.hash(message: body.bytes, outputLength: 64))
|
||||
return try? dependencies[singleton: .crypto].perform(.hash(message: body.bytes, outputLength: 64))
|
||||
}()
|
||||
|
||||
/// Generate the signature message
|
||||
|
|
|
@ -22,9 +22,9 @@ public final class OpenGroupManager {
|
|||
// Run on the 'workQueue' to ensure any 'Atomic' access doesn't block the main thread
|
||||
// on startup
|
||||
OpenGroupAPI.workQueue.async(using: dependencies) {
|
||||
guard !dependencies.caches[.openGroupManager].isPolling else { return }
|
||||
guard !dependencies[cache: .openGroupManager].isPolling else { return }
|
||||
|
||||
let servers: Set<String> = dependencies.storage
|
||||
let servers: Set<String> = dependencies[singleton: .storage]
|
||||
.read { db in
|
||||
// The default room promise creates an OpenGroup with an empty `roomToken` value,
|
||||
// we don't want to start a poller for this as the user hasn't actually joined a room
|
||||
|
@ -39,7 +39,7 @@ public final class OpenGroupManager {
|
|||
.defaulting(to: [])
|
||||
|
||||
// Update the cache state and re-create all of the pollers
|
||||
dependencies.caches.mutate(cache: .openGroupManager) { cache in
|
||||
dependencies.mutate(cache: .openGroupManager) { cache in
|
||||
cache.isPolling = true
|
||||
cache.pollers = servers
|
||||
.reduce(into: [:]) { result, server in
|
||||
|
@ -49,13 +49,13 @@ public final class OpenGroupManager {
|
|||
}
|
||||
|
||||
// Now that the pollers have been created actually start them
|
||||
dependencies.caches[.openGroupManager].pollers
|
||||
dependencies[cache: .openGroupManager].pollers
|
||||
.forEach { _, poller in poller.startIfNeeded(using: dependencies) }
|
||||
}
|
||||
}
|
||||
|
||||
public func stopPolling(using dependencies: Dependencies = Dependencies()) {
|
||||
dependencies.caches.mutate(cache: .openGroupManager) {
|
||||
dependencies.mutate(cache: .openGroupManager) {
|
||||
$0.pollers.forEach { _, openGroupPoller in openGroupPoller.stop() }
|
||||
$0.pollers.removeAll()
|
||||
$0.isPolling = false
|
||||
|
@ -140,7 +140,7 @@ public final class OpenGroupManager {
|
|||
}
|
||||
|
||||
// First check if there is no poller for the specified server
|
||||
if Set(dependencies.caches[.openGroupManager].pollers.keys).intersection(serverOptions).isEmpty {
|
||||
if Set(dependencies[cache: .openGroupManager].pollers.keys).intersection(serverOptions).isEmpty {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -250,7 +250,7 @@ public final class OpenGroupManager {
|
|||
return OpenGroupAPI.defaultServer
|
||||
}()
|
||||
|
||||
return dependencies.storage
|
||||
return dependencies[singleton: .storage]
|
||||
.readPublisher { db in
|
||||
try OpenGroupAPI
|
||||
.preparedCapabilitiesAndRoom(
|
||||
|
@ -263,7 +263,7 @@ public final class OpenGroupManager {
|
|||
.flatMap { $0.send(using: dependencies) }
|
||||
.flatMap { info, response -> Future<Void, Error> in
|
||||
Future<Void, Error> { resolver in
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
// Add the new open group to libSession
|
||||
if !calledFromConfigHandling {
|
||||
try SessionUtil.add(
|
||||
|
@ -336,9 +336,9 @@ public final class OpenGroupManager {
|
|||
.defaulting(to: 1)
|
||||
|
||||
if numActiveRooms == 1, let server: String = server?.lowercased() {
|
||||
let poller = dependencies.caches[.openGroupManager].pollers[server]
|
||||
let poller = dependencies[cache: .openGroupManager].pollers[server]
|
||||
poller?.stop()
|
||||
dependencies.caches.mutate(cache: .openGroupManager) { $0.pollers[server] = nil }
|
||||
dependencies.mutate(cache: .openGroupManager) { $0.pollers[server] = nil }
|
||||
}
|
||||
|
||||
// Remove all the data (everything should cascade delete)
|
||||
|
@ -504,13 +504,13 @@ public final class OpenGroupManager {
|
|||
// above transaction
|
||||
OpenGroupAPI.workQueue.async(using: dependencies) {
|
||||
// Start the poller if needed
|
||||
if dependencies.caches[.openGroupManager].pollers[server.lowercased()] == nil {
|
||||
dependencies.caches.mutate(cache: .openGroupManager) {
|
||||
if dependencies[cache: .openGroupManager].pollers[server.lowercased()] == nil {
|
||||
dependencies.mutate(cache: .openGroupManager) {
|
||||
$0.pollers[server.lowercased()]?.stop()
|
||||
$0.pollers[server.lowercased()] = OpenGroupAPI.Poller(for: server.lowercased())
|
||||
}
|
||||
|
||||
dependencies.caches[.openGroupManager].pollers[server.lowercased()]?
|
||||
dependencies[cache: .openGroupManager].pollers[server.lowercased()]?
|
||||
.startIfNeeded(using: dependencies)
|
||||
}
|
||||
|
||||
|
@ -541,7 +541,7 @@ public final class OpenGroupManager {
|
|||
}
|
||||
},
|
||||
receiveValue: { data in
|
||||
dependencies.storage.write(using: dependencies) { db in
|
||||
dependencies[singleton: .storage].write(using: dependencies) { db in
|
||||
_ = try OpenGroup
|
||||
.filter(id: threadId)
|
||||
.updateAll(db, OpenGroup.Columns.imageData.set(to: data))
|
||||
|
@ -640,7 +640,7 @@ public final class OpenGroupManager {
|
|||
db,
|
||||
openGroupId: openGroup.id,
|
||||
message: message,
|
||||
associatedPendingChanges: dependencies.caches[.openGroupManager].pendingChanges
|
||||
associatedPendingChanges: dependencies[cache: .openGroupManager].pendingChanges
|
||||
.filter {
|
||||
guard $0.server == server && $0.room == roomToken && $0.changeType == .reaction else {
|
||||
return false
|
||||
|
@ -687,7 +687,7 @@ public final class OpenGroupManager {
|
|||
.updateAll(db, OpenGroup.Columns.sequenceNumber.set(to: largestValidSeqNo))
|
||||
|
||||
// Update pendingChange cache based on the `largestValidSeqNo` value
|
||||
dependencies.caches.mutate(cache: .openGroupManager) {
|
||||
dependencies.mutate(cache: .openGroupManager) {
|
||||
$0.pendingChanges = $0.pendingChanges
|
||||
.filter { $0.seqNo == nil || $0.seqNo! > largestValidSeqNo }
|
||||
}
|
||||
|
@ -838,7 +838,7 @@ public final class OpenGroupManager {
|
|||
)
|
||||
)
|
||||
|
||||
dependencies.caches.mutate(cache: .openGroupManager) {
|
||||
dependencies.mutate(cache: .openGroupManager) {
|
||||
$0.pendingChanges.append(pendingChange)
|
||||
}
|
||||
|
||||
|
@ -850,7 +850,7 @@ public final class OpenGroupManager {
|
|||
seqNo: Int64?,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
dependencies.caches.mutate(cache: .openGroupManager) {
|
||||
dependencies.mutate(cache: .openGroupManager) {
|
||||
if let index = $0.pendingChanges.firstIndex(of: pendingChange) {
|
||||
$0.pendingChanges[index].seqNo = seqNo
|
||||
}
|
||||
|
@ -861,7 +861,7 @@ public final class OpenGroupManager {
|
|||
_ pendingChange: OpenGroupAPI.PendingChange,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) {
|
||||
dependencies.caches.mutate(cache: .openGroupManager) {
|
||||
dependencies.mutate(cache: .openGroupManager) {
|
||||
if let index = $0.pendingChanges.firstIndex(of: pendingChange) {
|
||||
$0.pendingChanges.remove(at: index)
|
||||
}
|
||||
|
@ -877,7 +877,7 @@ public final class OpenGroupManager {
|
|||
) -> Bool {
|
||||
guard let server: String = server else { return false }
|
||||
guard let db: Database = db else {
|
||||
return dependencies.storage
|
||||
return dependencies[singleton: .storage]
|
||||
.read { db in doesOpenGroupSupport(db, capability: capability, on: server, using: dependencies) }
|
||||
.defaulting(to: false)
|
||||
}
|
||||
|
@ -905,7 +905,7 @@ public final class OpenGroupManager {
|
|||
let groupId: String = OpenGroup.idFor(roomToken: roomToken, server: server)
|
||||
let targetRoles: [GroupMember.Role] = [.moderator, .admin]
|
||||
|
||||
return dependencies.storage
|
||||
return dependencies[singleton: .storage]
|
||||
.read { db -> Bool in
|
||||
let isDirectModOrAdmin: Bool = GroupMember
|
||||
.filter(GroupMember.Columns.groupId == groupId)
|
||||
|
@ -946,7 +946,7 @@ public final class OpenGroupManager {
|
|||
.filter(id: groupId)
|
||||
.asRequest(of: String.self)
|
||||
.fetchOne(db),
|
||||
let blindedKeyPair: KeyPair = dependencies.crypto.generate(
|
||||
let blindedKeyPair: KeyPair = dependencies[singleton: .crypto].generate(
|
||||
.blindedKeyPair(
|
||||
serverPublicKey: openGroupPublicKey,
|
||||
edKeyPair: userEdKeyPair,
|
||||
|
@ -989,12 +989,12 @@ public final class OpenGroupManager {
|
|||
using dependencies: Dependencies = Dependencies()
|
||||
) -> AnyPublisher<[DefaultRoomInfo], Error> {
|
||||
// Note: If we already have a 'defaultRoomsPromise' then there is no need to get it again
|
||||
if let existingPublisher: AnyPublisher<[DefaultRoomInfo], Error> = dependencies.caches[.openGroupManager].defaultRoomsPublisher {
|
||||
if let existingPublisher: AnyPublisher<[DefaultRoomInfo], Error> = dependencies[cache: .openGroupManager].defaultRoomsPublisher {
|
||||
return existingPublisher
|
||||
}
|
||||
|
||||
// Try to retrieve the default rooms 8 times
|
||||
let publisher: AnyPublisher<[DefaultRoomInfo], Error> = dependencies.storage
|
||||
let publisher: AnyPublisher<[DefaultRoomInfo], Error> = dependencies[singleton: .storage]
|
||||
.readPublisher { db -> HTTP.PreparedRequest<OpenGroupAPI.CapabilitiesAndRoomsResponse> in
|
||||
try OpenGroupAPI.preparedCapabilitiesAndRooms(
|
||||
db,
|
||||
|
@ -1007,7 +1007,7 @@ public final class OpenGroupManager {
|
|||
.receive(on: OpenGroupAPI.workQueue, using: dependencies)
|
||||
.retry(8, using: dependencies)
|
||||
.map { info, response -> [DefaultRoomInfo]? in
|
||||
dependencies.storage.write { db -> [DefaultRoomInfo] in
|
||||
dependencies[singleton: .storage].write { db -> [DefaultRoomInfo] in
|
||||
// Store the capabilities first
|
||||
OpenGroupManager.handleCapabilities(
|
||||
db,
|
||||
|
@ -1070,7 +1070,7 @@ public final class OpenGroupManager {
|
|||
switch result {
|
||||
case .finished: break
|
||||
case .failure:
|
||||
dependencies.caches.mutate(cache: .openGroupManager) { cache in
|
||||
dependencies.mutate(cache: .openGroupManager) { cache in
|
||||
cache.defaultRoomsPublisher = nil
|
||||
}
|
||||
}
|
||||
|
@ -1079,7 +1079,7 @@ public final class OpenGroupManager {
|
|||
.shareReplay(1)
|
||||
.eraseToAnyPublisher()
|
||||
|
||||
dependencies.caches.mutate(cache: .openGroupManager) { cache in
|
||||
dependencies.mutate(cache: .openGroupManager) { cache in
|
||||
cache.defaultRoomsPublisher = publisher
|
||||
}
|
||||
|
||||
|
@ -1106,7 +1106,7 @@ public final class OpenGroupManager {
|
|||
// don't double up on fetch requests by storing the existing request as a promise if
|
||||
// there is one.
|
||||
let threadId: String = OpenGroup.idFor(roomToken: roomToken, server: server)
|
||||
let lastOpenGroupImageUpdate: Date? = dependencies.standardUserDefaults[.lastOpenGroupImageUpdate]
|
||||
let lastOpenGroupImageUpdate: Date? = dependencies[singleton: .standardUserDefaults][.lastOpenGroupImageUpdate]
|
||||
let now: Date = dependencies.dateNow
|
||||
let timeSinceLastUpdate: TimeInterval = (lastOpenGroupImageUpdate.map { now.timeIntervalSince($0) } ?? .greatestFiniteMagnitude)
|
||||
let updateInterval: TimeInterval = (7 * 24 * 60 * 60)
|
||||
|
@ -1121,7 +1121,7 @@ public final class OpenGroupManager {
|
|||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
if let publisher: AnyPublisher<Data, Error> = dependencies.caches[.openGroupManager].groupImagePublishers[threadId] {
|
||||
if let publisher: AnyPublisher<Data, Error> = dependencies[cache: .openGroupManager].groupImagePublishers[threadId] {
|
||||
return publisher
|
||||
}
|
||||
|
||||
|
@ -1130,7 +1130,7 @@ public final class OpenGroupManager {
|
|||
Future { resolver in
|
||||
DispatchQueue.global(qos: .background).async(using: dependencies) {
|
||||
// Hold on to the publisher until it has completed at least once
|
||||
dependencies.storage
|
||||
dependencies[singleton: .storage]
|
||||
.readPublisher { db -> (Data?, HTTP.PreparedRequest<Data>?) in
|
||||
if canUseExistingImage {
|
||||
let maybeExistingData: Data? = try? OpenGroup
|
||||
|
@ -1182,12 +1182,12 @@ public final class OpenGroupManager {
|
|||
},
|
||||
receiveValue: { imageData in
|
||||
if server.lowercased() == OpenGroupAPI.defaultServer {
|
||||
dependencies.storage.write { db in
|
||||
dependencies[singleton: .storage].write { db in
|
||||
_ = try OpenGroup
|
||||
.filter(id: threadId)
|
||||
.updateAll(db, OpenGroup.Columns.imageData.set(to: imageData))
|
||||
}
|
||||
dependencies.standardUserDefaults[.lastOpenGroupImageUpdate] = now
|
||||
dependencies[singleton: .standardUserDefaults][.lastOpenGroupImageUpdate] = now
|
||||
}
|
||||
|
||||
resolver(Result.success(imageData))
|
||||
|
@ -1205,7 +1205,7 @@ public final class OpenGroupManager {
|
|||
.subscribe(on: DispatchQueue.global(qos: .background), using: dependencies)
|
||||
.sinkUntilComplete()
|
||||
|
||||
dependencies.caches.mutate(cache: .openGroupManager) { cache in
|
||||
dependencies.mutate(cache: .openGroupManager) { cache in
|
||||
cache.groupImagePublishers[threadId] = publisher
|
||||
}
|
||||
|
||||
|
@ -1233,7 +1233,7 @@ public extension OpenGroupManager {
|
|||
return storedTimeSinceLastOpen
|
||||
}
|
||||
|
||||
guard let lastOpen: Date = dependencies.standardUserDefaults[.lastOpen] else {
|
||||
guard let lastOpen: Date = dependencies[singleton: .standardUserDefaults][.lastOpen] else {
|
||||
_timeSinceLastOpen = .greatestFiniteMagnitude
|
||||
return .greatestFiniteMagnitude
|
||||
}
|
||||
|
@ -1248,7 +1248,7 @@ public extension OpenGroupManager {
|
|||
|
||||
public extension Cache {
|
||||
static let openGroupManager: CacheInfo.Config<OGMCacheType, OGMImmutableCacheType> = CacheInfo.create(
|
||||
createInstance: { OpenGroupManager.Cache() },
|
||||
createInstance: { _ in OpenGroupManager.Cache() },
|
||||
mutableInstance: { $0 },
|
||||
immutableInstance: { $0 }
|
||||
)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue