Added a simple migration progress indicator and animation (need timing tweaks)

Cleaned up the creation of the GRDBStorage instance
Fixed an issue where the launch screen wasn't setting it's background colour based on the system setting
Renamed the GRDBStorageError to StorageError (in preparation of legacy 'Storage' relocation)
Consolidated the two Environment classes (in Swift)
Refactored the AppSetup class to Swift
This commit is contained in:
Morgan Pretty 2022-05-30 13:04:26 +10:00
parent e2ee0e94ee
commit 26c7a5022a
45 changed files with 567 additions and 704 deletions

View File

@ -184,8 +184,6 @@
B8856D11256F112A001CE70E /* OWSAudioSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF281255B6D84007E1867 /* OWSAudioSession.swift */; }; B8856D11256F112A001CE70E /* OWSAudioSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF281255B6D84007E1867 /* OWSAudioSession.swift */; };
B8856D1A256F114D001CE70E /* ProximityMonitoringManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */; }; B8856D1A256F114D001CE70E /* ProximityMonitoringManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */; };
B8856D23256F116B001CE70E /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2EF255B6DBB007E1867 /* Weak.swift */; }; B8856D23256F116B001CE70E /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2EF255B6DBB007E1867 /* Weak.swift */; };
B8856D34256F1192001CE70E /* Environment.m in Sources */ = {isa = PBXBuildFile; fileRef = C37F5402255BA9ED002AEA92 /* Environment.m */; };
B8856D3D256F11B2001CE70E /* Environment.h in Headers */ = {isa = PBXBuildFile; fileRef = C37F53E8255BA9BB002AEA92 /* Environment.h */; settings = {ATTRIBUTES = (Public, ); }; };
B8856D60256F129B001CE70E /* OWSAlerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8856D5F256F129B001CE70E /* OWSAlerts.swift */; }; B8856D60256F129B001CE70E /* OWSAlerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8856D5F256F129B001CE70E /* OWSAlerts.swift */; };
B8856D69256F141F001CE70E /* OWSWindowManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF306255B6DBE007E1867 /* OWSWindowManager.m */; }; B8856D69256F141F001CE70E /* OWSWindowManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF306255B6DBE007E1867 /* OWSWindowManager.m */; };
B8856D72256F1421001CE70E /* OWSWindowManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; B8856D72256F1421001CE70E /* OWSWindowManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -421,8 +419,6 @@
C38EF275255B6D7A007E1867 /* OWSDatabaseMigrationRunner.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF26F255B6D79007E1867 /* OWSDatabaseMigrationRunner.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF275255B6D7A007E1867 /* OWSDatabaseMigrationRunner.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF26F255B6D79007E1867 /* OWSDatabaseMigrationRunner.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF276255B6D7A007E1867 /* OWSDatabaseMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */; }; C38EF276255B6D7A007E1867 /* OWSDatabaseMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */; };
C38EF277255B6D7A007E1867 /* OWSDatabaseMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */; settings = {ATTRIBUTES = (Public, ); }; }; C38EF277255B6D7A007E1867 /* OWSDatabaseMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF28F255B6D86007E1867 /* VersionMigrations.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF283255B6D84007E1867 /* VersionMigrations.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF292255B6D86007E1867 /* VersionMigrations.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF286255B6D85007E1867 /* VersionMigrations.m */; };
C38EF2A5255B6D93007E1867 /* Identicon+ObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2A2255B6D93007E1867 /* Identicon+ObjC.swift */; }; C38EF2A5255B6D93007E1867 /* Identicon+ObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2A2255B6D93007E1867 /* Identicon+ObjC.swift */; };
C38EF2A6255B6D93007E1867 /* PlaceholderIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */; }; C38EF2A6255B6D93007E1867 /* PlaceholderIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */; };
C38EF2A7255B6D93007E1867 /* ProfilePictureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */; }; C38EF2A7255B6D93007E1867 /* ProfilePictureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */; };
@ -680,6 +676,8 @@
FD848B9328420164000E298B /* UnicodeScalar+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD848B9228420164000E298B /* UnicodeScalar+Utilities.swift */; }; FD848B9328420164000E298B /* UnicodeScalar+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD848B9228420164000E298B /* UnicodeScalar+Utilities.swift */; };
FD848B9628422A2A000E298B /* MessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD848B86283B844B000E298B /* MessageViewModel.swift */; }; FD848B9628422A2A000E298B /* MessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD848B86283B844B000E298B /* MessageViewModel.swift */; };
FD848B9828422F1A000E298B /* Date+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD848B9728422F1A000E298B /* Date+Utilities.swift */; }; FD848B9828422F1A000E298B /* Date+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD848B9728422F1A000E298B /* Date+Utilities.swift */; };
FD848B9A28442CE6000E298B /* StorageError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD848B9928442CE6000E298B /* StorageError.swift */; };
FD848B9C284435D7000E298B /* AppSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD848B9B284435D7000E298B /* AppSetup.swift */; };
FD859F0027C4691300510D0C /* MockDataGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD859EFF27C4691300510D0C /* MockDataGenerator.swift */; }; FD859F0027C4691300510D0C /* MockDataGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD859EFF27C4691300510D0C /* MockDataGenerator.swift */; };
FD88BAD927A7439C00BBC442 /* MessageRequestsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */; }; FD88BAD927A7439C00BBC442 /* MessageRequestsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */; };
FD88BADB27A750F200BBC442 /* MessageRequestsMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */; }; FD88BADB27A750F200BBC442 /* MessageRequestsMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */; };
@ -690,8 +688,6 @@
FD9004162818B46700ABAAF6 /* JobRunnerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE77F68280F9EDA002CFC5D /* JobRunnerError.swift */; }; FD9004162818B46700ABAAF6 /* JobRunnerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE77F68280F9EDA002CFC5D /* JobRunnerError.swift */; };
FDA8EAFE280E8B78002B68E5 /* FailedMessageSendsJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDA8EAFD280E8B78002B68E5 /* FailedMessageSendsJob.swift */; }; FDA8EAFE280E8B78002B68E5 /* FailedMessageSendsJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDA8EAFD280E8B78002B68E5 /* FailedMessageSendsJob.swift */; };
FDA8EB00280E8D58002B68E5 /* FailedAttachmentDownloadsJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDA8EAFF280E8D58002B68E5 /* FailedAttachmentDownloadsJob.swift */; }; FDA8EB00280E8D58002B68E5 /* FailedAttachmentDownloadsJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDA8EAFF280E8D58002B68E5 /* FailedAttachmentDownloadsJob.swift */; };
FDA8EB09280E90FB002B68E5 /* AppSetup.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF287255B6D85007E1867 /* AppSetup.m */; };
FDA8EB0A280E9103002B68E5 /* AppSetup.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF284255B6D84007E1867 /* AppSetup.h */; settings = {ATTRIBUTES = (Public, ); }; };
FDA8EB10280F8238002B68E5 /* Codable+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDA8EB0F280F8238002B68E5 /* Codable+Utilities.swift */; }; FDA8EB10280F8238002B68E5 /* Codable+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDA8EB0F280F8238002B68E5 /* Codable+Utilities.swift */; };
FDB4BBC72838B91E00B7C95D /* LinkPreviewError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDB4BBC62838B91E00B7C95D /* LinkPreviewError.swift */; }; FDB4BBC72838B91E00B7C95D /* LinkPreviewError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDB4BBC62838B91E00B7C95D /* LinkPreviewError.swift */; };
FDB4BBC92839BEF000B7C95D /* ProfileManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDB4BBC82839BEF000B7C95D /* ProfileManagerError.swift */; }; FDB4BBC92839BEF000B7C95D /* ProfileManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDB4BBC82839BEF000B7C95D /* ProfileManagerError.swift */; };
@ -710,7 +706,7 @@
FDF0B74B28061F7A004C14C5 /* InteractionAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B74A28061F7A004C14C5 /* InteractionAttachment.swift */; }; FDF0B74B28061F7A004C14C5 /* InteractionAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B74A28061F7A004C14C5 /* InteractionAttachment.swift */; };
FDF0B74F28079E5E004C14C5 /* SendReadReceiptsJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B74E28079E5E004C14C5 /* SendReadReceiptsJob.swift */; }; FDF0B74F28079E5E004C14C5 /* SendReadReceiptsJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B74E28079E5E004C14C5 /* SendReadReceiptsJob.swift */; };
FDF0B7512807BA56004C14C5 /* NotificationsProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B7502807BA56004C14C5 /* NotificationsProtocol.swift */; }; FDF0B7512807BA56004C14C5 /* NotificationsProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B7502807BA56004C14C5 /* NotificationsProtocol.swift */; };
FDF0B7552807C4BB004C14C5 /* SSKEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B7542807C4BB004C14C5 /* SSKEnvironment.swift */; }; FDF0B7552807C4BB004C14C5 /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B7542807C4BB004C14C5 /* Environment.swift */; };
FDF0B7582807F368004C14C5 /* MessageReceiverError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B7572807F368004C14C5 /* MessageReceiverError.swift */; }; FDF0B7582807F368004C14C5 /* MessageReceiverError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B7572807F368004C14C5 /* MessageReceiverError.swift */; };
FDF0B75A2807F3A3004C14C5 /* MessageSenderError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B7592807F3A3004C14C5 /* MessageSenderError.swift */; }; FDF0B75A2807F3A3004C14C5 /* MessageSenderError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B7592807F3A3004C14C5 /* MessageSenderError.swift */; };
FDF0B75C2807F41D004C14C5 /* MessageSender+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B75B2807F41D004C14C5 /* MessageSender+Convenience.swift */; }; FDF0B75C2807F41D004C14C5 /* MessageSender+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B75B2807F41D004C14C5 /* MessageSender+Convenience.swift */; };
@ -1337,8 +1333,6 @@
C374EEEA25DA3CA70073A857 /* ConversationTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationTitleView.swift; sourceTree = "<group>"; }; C374EEEA25DA3CA70073A857 /* ConversationTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationTitleView.swift; sourceTree = "<group>"; };
C374EEF325DB31D40073A857 /* VoiceMessageRecordingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecordingView.swift; sourceTree = "<group>"; }; C374EEF325DB31D40073A857 /* VoiceMessageRecordingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecordingView.swift; sourceTree = "<group>"; };
C379DCF3256735770002D4EB /* VisibleMessage+Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+Attachment.swift"; sourceTree = "<group>"; }; C379DCF3256735770002D4EB /* VisibleMessage+Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+Attachment.swift"; sourceTree = "<group>"; };
C37F53E8255BA9BB002AEA92 /* Environment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Environment.h; sourceTree = "<group>"; };
C37F5402255BA9ED002AEA92 /* Environment.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Environment.m; sourceTree = "<group>"; };
C38D5E8C2575011E00B6A65C /* MessageSender+ClosedGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageSender+ClosedGroups.swift"; sourceTree = "<group>"; }; C38D5E8C2575011E00B6A65C /* MessageSender+ClosedGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageSender+ClosedGroups.swift"; sourceTree = "<group>"; };
C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SNProtoEnvelope+Conversion.swift"; sourceTree = "<group>"; }; C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SNProtoEnvelope+Conversion.swift"; sourceTree = "<group>"; };
C38EF224255B6D5D007E1867 /* SignalAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SignalAttachment.swift; path = "SessionMessagingKit/Sending & Receiving/Attachments/SignalAttachment.swift"; sourceTree = SOURCE_ROOT; }; C38EF224255B6D5D007E1867 /* SignalAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SignalAttachment.swift; path = "SessionMessagingKit/Sending & Receiving/Attachments/SignalAttachment.swift"; sourceTree = SOURCE_ROOT; };
@ -1364,10 +1358,6 @@
C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigration.m; path = SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigration.m; sourceTree = SOURCE_ROOT; }; C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigration.m; path = SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigration.m; sourceTree = SOURCE_ROOT; };
C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigration.h; path = SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigration.h; sourceTree = SOURCE_ROOT; }; C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigration.h; path = SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigration.h; sourceTree = SOURCE_ROOT; };
C38EF281255B6D84007E1867 /* OWSAudioSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSAudioSession.swift; path = SessionMessagingKit/Utilities/OWSAudioSession.swift; sourceTree = SOURCE_ROOT; }; C38EF281255B6D84007E1867 /* OWSAudioSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSAudioSession.swift; path = SessionMessagingKit/Utilities/OWSAudioSession.swift; sourceTree = SOURCE_ROOT; };
C38EF283255B6D84007E1867 /* VersionMigrations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VersionMigrations.h; path = SignalUtilitiesKit/Utilities/VersionMigrations.h; sourceTree = SOURCE_ROOT; };
C38EF284255B6D84007E1867 /* AppSetup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppSetup.h; path = SignalUtilitiesKit/Utilities/AppSetup.h; sourceTree = SOURCE_ROOT; };
C38EF286255B6D85007E1867 /* VersionMigrations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VersionMigrations.m; path = SignalUtilitiesKit/Utilities/VersionMigrations.m; sourceTree = SOURCE_ROOT; };
C38EF287255B6D85007E1867 /* AppSetup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppSetup.m; path = SignalUtilitiesKit/Utilities/AppSetup.m; sourceTree = SOURCE_ROOT; };
C38EF2A2255B6D93007E1867 /* Identicon+ObjC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Identicon+ObjC.swift"; path = "SignalUtilitiesKit/Profile Pictures/Identicon+ObjC.swift"; sourceTree = SOURCE_ROOT; }; C38EF2A2255B6D93007E1867 /* Identicon+ObjC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Identicon+ObjC.swift"; path = "SignalUtilitiesKit/Profile Pictures/Identicon+ObjC.swift"; sourceTree = SOURCE_ROOT; };
C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PlaceholderIcon.swift; path = "SignalUtilitiesKit/Profile Pictures/PlaceholderIcon.swift"; sourceTree = SOURCE_ROOT; }; C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PlaceholderIcon.swift; path = "SignalUtilitiesKit/Profile Pictures/PlaceholderIcon.swift"; sourceTree = SOURCE_ROOT; };
C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProfilePictureView.swift; path = "SignalUtilitiesKit/Profile Pictures/ProfilePictureView.swift"; sourceTree = SOURCE_ROOT; }; C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProfilePictureView.swift; path = "SignalUtilitiesKit/Profile Pictures/ProfilePictureView.swift"; sourceTree = SOURCE_ROOT; };
@ -1648,6 +1638,8 @@
FD848B8E283EF2A8000E298B /* UIScrollView+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+Utilities.swift"; sourceTree = "<group>"; }; FD848B8E283EF2A8000E298B /* UIScrollView+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+Utilities.swift"; sourceTree = "<group>"; };
FD848B9228420164000E298B /* UnicodeScalar+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UnicodeScalar+Utilities.swift"; sourceTree = "<group>"; }; FD848B9228420164000E298B /* UnicodeScalar+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UnicodeScalar+Utilities.swift"; sourceTree = "<group>"; };
FD848B9728422F1A000E298B /* Date+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Utilities.swift"; sourceTree = "<group>"; }; FD848B9728422F1A000E298B /* Date+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Utilities.swift"; sourceTree = "<group>"; };
FD848B9928442CE6000E298B /* StorageError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageError.swift; sourceTree = "<group>"; };
FD848B9B284435D7000E298B /* AppSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSetup.swift; sourceTree = "<group>"; };
FD859EFF27C4691300510D0C /* MockDataGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDataGenerator.swift; sourceTree = "<group>"; }; FD859EFF27C4691300510D0C /* MockDataGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDataGenerator.swift; sourceTree = "<group>"; };
FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsCell.swift; sourceTree = "<group>"; }; FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsCell.swift; sourceTree = "<group>"; };
FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsMigration.swift; sourceTree = "<group>"; }; FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsMigration.swift; sourceTree = "<group>"; };
@ -1676,7 +1668,7 @@
FDF0B74A28061F7A004C14C5 /* InteractionAttachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionAttachment.swift; sourceTree = "<group>"; }; FDF0B74A28061F7A004C14C5 /* InteractionAttachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionAttachment.swift; sourceTree = "<group>"; };
FDF0B74E28079E5E004C14C5 /* SendReadReceiptsJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendReadReceiptsJob.swift; sourceTree = "<group>"; }; FDF0B74E28079E5E004C14C5 /* SendReadReceiptsJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendReadReceiptsJob.swift; sourceTree = "<group>"; };
FDF0B7502807BA56004C14C5 /* NotificationsProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsProtocol.swift; sourceTree = "<group>"; }; FDF0B7502807BA56004C14C5 /* NotificationsProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsProtocol.swift; sourceTree = "<group>"; };
FDF0B7542807C4BB004C14C5 /* SSKEnvironment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSKEnvironment.swift; sourceTree = "<group>"; }; FDF0B7542807C4BB004C14C5 /* Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Environment.swift; sourceTree = "<group>"; };
FDF0B7572807F368004C14C5 /* MessageReceiverError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageReceiverError.swift; sourceTree = "<group>"; }; FDF0B7572807F368004C14C5 /* MessageReceiverError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageReceiverError.swift; sourceTree = "<group>"; };
FDF0B7592807F3A3004C14C5 /* MessageSenderError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSenderError.swift; sourceTree = "<group>"; }; FDF0B7592807F3A3004C14C5 /* MessageSenderError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSenderError.swift; sourceTree = "<group>"; };
FDF0B75B2807F41D004C14C5 /* MessageSender+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MessageSender+Convenience.swift"; sourceTree = "<group>"; }; FDF0B75B2807F41D004C14C5 /* MessageSender+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MessageSender+Convenience.swift"; sourceTree = "<group>"; };
@ -2125,6 +2117,7 @@
FD17D7CB27F546F500122BE0 /* Models */, FD17D7CB27F546F500122BE0 /* Models */,
FD17D7B427F51E6700122BE0 /* Types */, FD17D7B427F51E6700122BE0 /* Types */,
FD17D7BB27F51F5C00122BE0 /* Utilities */, FD17D7BB27F51F5C00122BE0 /* Utilities */,
FD848B9928442CE6000E298B /* StorageError.swift */,
FD28A4F527EAD44C00FF65E7 /* GRDBStorage.swift */, FD28A4F527EAD44C00FF65E7 /* GRDBStorage.swift */,
C33FDBAB255A581500E217F9 /* OWSFileSystem.h */, C33FDBAB255A581500E217F9 /* OWSFileSystem.h */,
C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */, C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */,
@ -2873,8 +2866,7 @@
C33FDB75255A581000E217F9 /* AppReadiness.m */, C33FDB75255A581000E217F9 /* AppReadiness.m */,
FD09799027FD499200936362 /* BoxKeyPair+Utilities.swift */, FD09799027FD499200936362 /* BoxKeyPair+Utilities.swift */,
C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */, C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */,
C37F53E8255BA9BB002AEA92 /* Environment.h */, FDF0B7542807C4BB004C14C5 /* Environment.swift */,
C37F5402255BA9ED002AEA92 /* Environment.m */,
C3BBE0C62554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift */, C3BBE0C62554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift */,
C3A71D0A2558989C0043A11F /* MessageWrapper.swift */, C3A71D0A2558989C0043A11F /* MessageWrapper.swift */,
C3A71D4E25589FF30043A11F /* NSData+messagePadding.h */, C3A71D4E25589FF30043A11F /* NSData+messagePadding.h */,
@ -2894,7 +2886,6 @@
FDB4BBC82839BEF000B7C95D /* ProfileManagerError.swift */, FDB4BBC82839BEF000B7C95D /* ProfileManagerError.swift */,
C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */, C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */,
C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */, C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */,
FDF0B7542807C4BB004C14C5 /* SSKEnvironment.swift */,
C3A3A170256E1D25004D228D /* SSKReachabilityManager.swift */, C3A3A170256E1D25004D228D /* SSKReachabilityManager.swift */,
C3ECBF7A257056B700EA7FCE /* Threading.swift */, C3ECBF7A257056B700EA7FCE /* Threading.swift */,
C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */, C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */,
@ -3032,8 +3023,7 @@
C3CA3B11255CF17200F4C6D4 /* Utilities */ = { C3CA3B11255CF17200F4C6D4 /* Utilities */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
C38EF284255B6D84007E1867 /* AppSetup.h */, FD848B9B284435D7000E298B /* AppSetup.swift */,
C38EF287255B6D85007E1867 /* AppSetup.m */,
C38EF302255B6DBE007E1867 /* OWSAnyTouchGestureRecognizer.h */, C38EF302255B6DBE007E1867 /* OWSAnyTouchGestureRecognizer.h */,
C38EF2F0255B6DBB007E1867 /* OWSAnyTouchGestureRecognizer.m */, C38EF2F0255B6DBB007E1867 /* OWSAnyTouchGestureRecognizer.m */,
FDCDB8DD2810F73B00352A0C /* Differentiable+Utilities.swift */, FDCDB8DD2810F73B00352A0C /* Differentiable+Utilities.swift */,
@ -3071,8 +3061,6 @@
C38EF2F2255B6DBC007E1867 /* Searcher.swift */, C38EF2F2255B6DBC007E1867 /* Searcher.swift */,
B8856D5F256F129B001CE70E /* OWSAlerts.swift */, B8856D5F256F129B001CE70E /* OWSAlerts.swift */,
C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */, C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */,
C38EF283255B6D84007E1867 /* VersionMigrations.h */,
C38EF286255B6D85007E1867 /* VersionMigrations.m */,
C33FDA8B255A57FD00E217F9 /* AppVersion.m */, C33FDA8B255A57FD00E217F9 /* AppVersion.m */,
C33FDB69255A580F00E217F9 /* FeatureFlags.swift */, C33FDB69255A580F00E217F9 /* FeatureFlags.swift */,
C33FDA99255A57FE00E217F9 /* OutageDetection.swift */, C33FDA99255A57FE00E217F9 /* OutageDetection.swift */,
@ -3538,7 +3526,6 @@
C33FDD7C255A582000E217F9 /* SSKAsserts.h in Headers */, C33FDD7C255A582000E217F9 /* SSKAsserts.h in Headers */,
C38EF3F6255B6DF7007E1867 /* OWSTextView.h in Headers */, C38EF3F6255B6DF7007E1867 /* OWSTextView.h in Headers */,
C38EF24C255B6D67007E1867 /* NSAttributedString+OWS.h in Headers */, C38EF24C255B6D67007E1867 /* NSAttributedString+OWS.h in Headers */,
FDA8EB0A280E9103002B68E5 /* AppSetup.h in Headers */,
C38EF32B255B6DBF007E1867 /* OWSFormat.h in Headers */, C38EF32B255B6DBF007E1867 /* OWSFormat.h in Headers */,
C33FDDB8255A582000E217F9 /* NSSet+Functional.h in Headers */, C33FDDB8255A582000E217F9 /* NSSet+Functional.h in Headers */,
C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */, C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */,
@ -3562,7 +3549,6 @@
C33FD9AF255A548A00E217F9 /* SignalUtilitiesKit.h in Headers */, C33FD9AF255A548A00E217F9 /* SignalUtilitiesKit.h in Headers */,
C33FDC50255A582000E217F9 /* OWSDispatch.h in Headers */, C33FDC50255A582000E217F9 /* OWSDispatch.h in Headers */,
C33FDD06255A582000E217F9 /* AppVersion.h in Headers */, C33FDD06255A582000E217F9 /* AppVersion.h in Headers */,
C38EF28F255B6D86007E1867 /* VersionMigrations.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -3613,7 +3599,6 @@
C32A026C25A801AF000ED5D4 /* NSData+messagePadding.h in Headers */, C32A026C25A801AF000ED5D4 /* NSData+messagePadding.h in Headers */,
B8856D72256F1421001CE70E /* OWSWindowManager.h in Headers */, B8856D72256F1421001CE70E /* OWSWindowManager.h in Headers */,
B8856CF7256F105E001CE70E /* OWSAudioPlayer.h in Headers */, B8856CF7256F105E001CE70E /* OWSAudioPlayer.h in Headers */,
B8856D3D256F11B2001CE70E /* Environment.h in Headers */,
C32C5E7E256DE023003C73A2 /* YapDatabaseTransaction+OWS.h in Headers */, C32C5E7E256DE023003C73A2 /* YapDatabaseTransaction+OWS.h in Headers */,
C32C5EA0256DE0D6003C73A2 /* OWSPrimaryStorage.h in Headers */, C32C5EA0256DE0D6003C73A2 /* OWSPrimaryStorage.h in Headers */,
B8856E33256F18D5001CE70E /* OWSStorage+Subclass.h in Headers */, B8856E33256F18D5001CE70E /* OWSStorage+Subclass.h in Headers */,
@ -4306,7 +4291,6 @@
C38EF247255B6D67007E1867 /* NSAttributedString+OWS.m in Sources */, C38EF247255B6D67007E1867 /* NSAttributedString+OWS.m in Sources */,
C33FDD49255A582000E217F9 /* ParamParser.swift in Sources */, C33FDD49255A582000E217F9 /* ParamParser.swift in Sources */,
C38EF3C5255B6DE7007E1867 /* OWSViewController+ImageEditor.swift in Sources */, C38EF3C5255B6DE7007E1867 /* OWSViewController+ImageEditor.swift in Sources */,
FDA8EB09280E90FB002B68E5 /* AppSetup.m in Sources */,
C38EF2A5255B6D93007E1867 /* Identicon+ObjC.swift in Sources */, C38EF2A5255B6D93007E1867 /* Identicon+ObjC.swift in Sources */,
C38EF273255B6D7A007E1867 /* OWSDatabaseMigrationRunner.m in Sources */, C38EF273255B6D7A007E1867 /* OWSDatabaseMigrationRunner.m in Sources */,
C38EF31A255B6DBF007E1867 /* OWSAnyTouchGestureRecognizer.m in Sources */, C38EF31A255B6DBF007E1867 /* OWSAnyTouchGestureRecognizer.m in Sources */,
@ -4384,7 +4368,6 @@
C33FDC78255A582000E217F9 /* TSConstants.m in Sources */, C33FDC78255A582000E217F9 /* TSConstants.m in Sources */,
C38EF324255B6DBF007E1867 /* Bench.swift in Sources */, C38EF324255B6DBF007E1867 /* Bench.swift in Sources */,
FDCDB8DE2810F73B00352A0C /* Differentiable+Utilities.swift in Sources */, FDCDB8DE2810F73B00352A0C /* Differentiable+Utilities.swift in Sources */,
C38EF292255B6D86007E1867 /* VersionMigrations.m in Sources */,
C38EF3F9255B6DF7007E1867 /* OWSLayerView.swift in Sources */, C38EF3F9255B6DF7007E1867 /* OWSLayerView.swift in Sources */,
C33FDD03255A582000E217F9 /* WeakTimer.swift in Sources */, C33FDD03255A582000E217F9 /* WeakTimer.swift in Sources */,
B8B3204E258C15C80020074B /* ContactsMigration.swift in Sources */, B8B3204E258C15C80020074B /* ContactsMigration.swift in Sources */,
@ -4400,6 +4383,7 @@
B8C2B2C82563685C00551B4D /* CircleView.swift in Sources */, B8C2B2C82563685C00551B4D /* CircleView.swift in Sources */,
C38EF331255B6DBF007E1867 /* UIGestureRecognizer+OWS.swift in Sources */, C38EF331255B6DBF007E1867 /* UIGestureRecognizer+OWS.swift in Sources */,
C33FDDC5255A582000E217F9 /* OWSError.m in Sources */, C33FDDC5255A582000E217F9 /* OWSError.m in Sources */,
FD848B9C284435D7000E298B /* AppSetup.swift in Sources */,
C38EF38D255B6DD2007E1867 /* AttachmentCaptionViewController.swift in Sources */, C38EF38D255B6DD2007E1867 /* AttachmentCaptionViewController.swift in Sources */,
C38EF31C255B6DBF007E1867 /* Searcher.swift in Sources */, C38EF31C255B6DBF007E1867 /* Searcher.swift in Sources */,
C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */, C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */,
@ -4501,6 +4485,7 @@
B8856DE6256F15F2001CE70E /* String+SSK.swift in Sources */, B8856DE6256F15F2001CE70E /* String+SSK.swift in Sources */,
FDF2220F281B55E6000A4995 /* QueryInterfaceRequest+Utilities.swift in Sources */, FDF2220F281B55E6000A4995 /* QueryInterfaceRequest+Utilities.swift in Sources */,
C3471ED42555386B00297E91 /* AESGCM.swift in Sources */, C3471ED42555386B00297E91 /* AESGCM.swift in Sources */,
FD848B9A28442CE6000E298B /* StorageError.swift in Sources */,
FD17D7B827F51ECA00122BE0 /* Migration.swift in Sources */, FD17D7B827F51ECA00122BE0 /* Migration.swift in Sources */,
C32C5DDB256DD9FF003C73A2 /* ContentProxy.swift in Sources */, C32C5DDB256DD9FF003C73A2 /* ContentProxy.swift in Sources */,
C3A71F892558BA9F0043A11F /* Mnemonic.swift in Sources */, C3A71F892558BA9F0043A11F /* Mnemonic.swift in Sources */,
@ -4583,12 +4568,11 @@
FD09797F27FCFBFF00936362 /* OWSAES256Key+Utilities.swift in Sources */, FD09797F27FCFBFF00936362 /* OWSAES256Key+Utilities.swift in Sources */,
FDB4BBC72838B91E00B7C95D /* LinkPreviewError.swift in Sources */, FDB4BBC72838B91E00B7C95D /* LinkPreviewError.swift in Sources */,
FD09798327FD1A1500936362 /* ClosedGroup.swift in Sources */, FD09798327FD1A1500936362 /* ClosedGroup.swift in Sources */,
B8856D34256F1192001CE70E /* Environment.m in Sources */,
B8B320B7258C30D70020074B /* HTMLMetadata.swift in Sources */, B8B320B7258C30D70020074B /* HTMLMetadata.swift in Sources */,
FD09798727FD1B7800936362 /* GroupMember.swift in Sources */, FD09798727FD1B7800936362 /* GroupMember.swift in Sources */,
FD09799127FD499200936362 /* BoxKeyPair+Utilities.swift in Sources */, FD09799127FD499200936362 /* BoxKeyPair+Utilities.swift in Sources */,
FDB4BBC92839BEF000B7C95D /* ProfileManagerError.swift in Sources */, FDB4BBC92839BEF000B7C95D /* ProfileManagerError.swift in Sources */,
FDF0B7552807C4BB004C14C5 /* SSKEnvironment.swift in Sources */, FDF0B7552807C4BB004C14C5 /* Environment.swift in Sources */,
B8856ECE256F1E58001CE70E /* OWSPreferences.m in Sources */, B8856ECE256F1E58001CE70E /* OWSPreferences.m in Sources */,
FD3E0C84283B5835002A425C /* SessionThreadViewModel.swift in Sources */, FD3E0C84283B5835002A425C /* SessionThreadViewModel.swift in Sources */,
FD09C5EC282B8F18000CE219 /* AttachmentError.swift in Sources */, FD09C5EC282B8F18000CE219 /* AttachmentError.swift in Sources */,

View File

@ -873,6 +873,7 @@ extension ConversationVC:
let interaction: Interaction = try? Interaction.fetchOne(db, id: cellViewModel.id), let interaction: Interaction = try? Interaction.fetchOne(db, id: cellViewModel.id),
let thread: SessionThread = try SessionThread.fetchOne(db, id: threadId) let thread: SessionThread = try SessionThread.fetchOne(db, id: threadId)
else { return } else { return }
try MessageSender.send( try MessageSender.send(
db, db,
interaction: interaction, interaction: interaction,

View File

@ -15,7 +15,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
var window: UIWindow? var window: UIWindow?
var backgroundSnapshotBlockerWindow: UIWindow? var backgroundSnapshotBlockerWindow: UIWindow?
var appStartupWindow: UIWindow? var appStartupWindow: UIWindow?
var poller: Poller = Poller() var hasInitialRootViewController: Bool = false
/// This needs to be a lazy variable to ensure it doesn't get initialized before it actually needs to be used
lazy var poller: Poller = {
return Poller()
}()
// MARK: - Lifecycle // MARK: - Lifecycle
@ -26,8 +31,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
AppModeManager.configure(delegate: self) AppModeManager.configure(delegate: self)
Cryptography.seedRandom() Cryptography.seedRandom()
AppVersion.sharedInstance()
AppVersion.sharedInstance() // TODO: ???
// Prevent the device from sleeping during database view async registration // Prevent the device from sleeping during database view async registration
// (e.g. long database upgrades). // (e.g. long database upgrades).
@ -35,14 +39,38 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
// This block will be cleared in storageIsReady. // This block will be cleared in storageIsReady.
DeviceSleepManager.sharedInstance.addBlock(blockObject: self) DeviceSleepManager.sharedInstance.addBlock(blockObject: self)
let mainWindow: UIWindow = UIWindow(frame: UIScreen.main.bounds)
let loadingViewController: LoadingViewController = LoadingViewController()
AppSetup.setupEnvironment( AppSetup.setupEnvironment(
appSpecificSingletonBlock: { appSpecificBlock: {
// Create AppEnvironment // Create AppEnvironment
AppEnvironment.shared.setup() AppEnvironment.shared.setup()
},
migrationCompletion: { [weak self] successful, needsConfigSync in
guard let strongSelf = self else { return }
// Note: Intentionally dispatching sync as we want to wait for these to complete before
// continuing
DispatchQueue.main.sync {
OWSScreenLockUI.sharedManager().setup(withRootWindow: mainWindow)
OWSWindowManager.shared().setup(
withRootWindow: mainWindow,
screenBlockingWindow: OWSScreenLockUI.sharedManager().screenBlockingWindow
)
OWSScreenLockUI.sharedManager().startObserving()
}
},
migrationProgressChanged: { progress, minEstimatedTotalTime in
loadingViewController.updateProgress(
progress: progress,
minEstimatedTotalTime: minEstimatedTotalTime
)
},
migrationsCompletion: { [weak self] successful, needsConfigSync in
guard let strongSelf = self else { return }
guard successful else {
return
}
Configuration.performMainSetup()
JobRunner.add(executor: SyncPushTokensJob.self, for: .syncPushTokens) JobRunner.add(executor: SyncPushTokensJob.self, for: .syncPushTokens)
// Trigger any launch-specific jobs and start the JobRunner // Trigger any launch-specific jobs and start the JobRunner
@ -56,7 +84,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
DeviceSleepManager.sharedInstance.removeBlock(blockObject: strongSelf) DeviceSleepManager.sharedInstance.removeBlock(blockObject: strongSelf)
AppVersion.sharedInstance().mainAppLaunchDidComplete() AppVersion.sharedInstance().mainAppLaunchDidComplete()
Environment.shared.audioSession.setup() Environment.shared.audioSession.setup()
SSKEnvironment.shared.reachabilityManager.setup() Environment.shared.reachabilityManager.setup()
GRDBStorage.shared.writeAsync { db in GRDBStorage.shared.writeAsync { db in
// Disable the SAE until the main app has successfully completed launch process // Disable the SAE until the main app has successfully completed launch process
@ -83,18 +111,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
} }
) )
Configuration.performMainSetup()
SNAppearance.switchToSessionAppearance() SNAppearance.switchToSessionAppearance()
// No point continuing if we are running tests // No point continuing if we are running tests
guard !CurrentAppContext().isRunningTests else { return true } guard !CurrentAppContext().isRunningTests else { return true }
let mainWindow: UIWindow = UIWindow(frame: UIScreen.main.bounds)
self.window = mainWindow self.window = mainWindow
CurrentAppContext().mainWindow = mainWindow CurrentAppContext().mainWindow = mainWindow
// Show LoadingViewController until the async database view registrations are complete. // Show LoadingViewController until the async database view registrations are complete.
mainWindow.rootViewController = LoadingViewController() mainWindow.rootViewController = loadingViewController
mainWindow.makeKeyAndVisible() mainWindow.makeKeyAndVisible()
adapt(appMode: AppModeManager.getAppModeOrSystemDefault()) adapt(appMode: AppModeManager.getAppModeOrSystemDefault())
@ -104,14 +130,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
// Setting the delegate also seems to prevent us from getting the legacy notification // Setting the delegate also seems to prevent us from getting the legacy notification
// notification callbacks upon launch e.g. 'didReceiveLocalNotification' // notification callbacks upon launch e.g. 'didReceiveLocalNotification'
UNUserNotificationCenter.current().delegate = self UNUserNotificationCenter.current().delegate = self
OWSScreenLockUI.sharedManager().setup(withRootWindow: mainWindow)
OWSWindowManager.shared().setup(
withRootWindow: mainWindow,
screenBlockingWindow: OWSScreenLockUI.sharedManager().screenBlockingWindow
)
OWSScreenLockUI.sharedManager().startObserving()
NotificationCenter.default.addObserver( NotificationCenter.default.addObserver(
self, self,
selector: #selector(registrationStateDidChange), selector: #selector(registrationStateDidChange),
@ -196,10 +215,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
private func verifyDBKeysAvailableBeforeBackgroundLaunch() { private func verifyDBKeysAvailableBeforeBackgroundLaunch() {
guard UIApplication.shared.applicationState == .background else { return } guard UIApplication.shared.applicationState == .background else { return }
let migrationHasRun: Bool = false // Ensure both databases are accessible (as long as we are supporting the YDB migration
// we should keep this check)
let databasePasswordAccessible: Bool = ( let databasePasswordAccessible: Bool = (
(migrationHasRun && GRDBStorage.isDatabasePasswordAccessible) || // GRDB password access GRDBStorage.isDatabasePasswordAccessible && // GRDB password access
OWSStorage.isDatabasePasswordAccessible() // YapDatabase password access OWSStorage.isDatabasePasswordAccessible() // YapDatabase password access
) )
@ -250,8 +269,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
} }
private func ensureRootViewController() { private func ensureRootViewController() {
// TODO: Add 'MigrationProcessingViewController' in here as well guard AppReadiness.isAppReady() && GRDBStorage.shared.isValid && !hasInitialRootViewController else {
guard self.window?.rootViewController is LoadingViewController else { return } return
}
let navController: UINavigationController = OWSNavigationController( let navController: UINavigationController = OWSNavigationController(
rootViewController: (Identity.userExists() ? rootViewController: (Identity.userExists() ?

View File

@ -57,7 +57,7 @@ import SignalUtilitiesKit
@objc @objc
public func setup() { public func setup() {
// Hang certain singletons on SSKEnvironment too. // Hang certain singletons on SSKEnvironment too.
SSKEnvironment.shared.notificationsManager.mutate { Environment.shared.notificationsManager.mutate {
$0 = notificationPresenter $0 = notificationPresenter
} }
setupLogFiles() setupLogFiles()

View File

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15705" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_1" orientation="portrait" appearance="light"/> <device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15706"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<scenes> <scenes>
@ -27,7 +28,7 @@
</constraints> </constraints>
</imageView> </imageView>
</subviews> </subviews>
<color key="backgroundColor" red="0.086274509803921567" green="0.086274509803921567" blue="0.086274509803921567" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" name="session_navigation_bar_background"/>
<constraints> <constraints>
<constraint firstItem="b92-yg-YYQ" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="ec1-lk-fbn"/> <constraint firstItem="b92-yg-YYQ" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="ec1-lk-fbn"/>
<constraint firstItem="b92-yg-YYQ" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="jLr-XH-MKf"/> <constraint firstItem="b92-yg-YYQ" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="jLr-XH-MKf"/>
@ -41,5 +42,8 @@
</scenes> </scenes>
<resources> <resources>
<image name="SessionGreen64" width="57.5" height="64"/> <image name="SessionGreen64" width="57.5" height="64"/>
<namedColor name="session_navigation_bar_background">
<color red="0.9882352941176471" green="0.9882352941176471" blue="0.9882352941176471" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
</resources> </resources>
</document> </document>

View File

@ -1,115 +1,150 @@
// // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation import UIKit
import PromiseKit import PromiseKit
import SessionUIKit
// The initial presentation is intended to be indistinguishable from the Launch Screen. // The initial presentation is intended to be indistinguishable from the Launch Screen.
// After a delay we present some "loading" UI so the user doesn't think the app is frozen. // After a delay we present some "loading" UI so the user doesn't think the app is frozen.
@objc
public class LoadingViewController: UIViewController { public class LoadingViewController: UIViewController {
/// This value specifies the minimum expected duration which needs to be hit before the loading UI needs to be show
private static let minExpectedDurationToShowLoading: TimeInterval = 5
/// This value specifies the minimum expected duration which needs to be hit before the additional "might take a few minutes"
/// label gets shown
private static let minExpectedDurationAdditionalLabel: TimeInterval = 15
private var isShowingProgress: Bool = false
// MARK: - UI
override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
private var logoView: UIImageView = {
let result: UIImageView = UIImageView(image: #imageLiteral(resourceName: "SessionGreen64"))
result.contentMode = .scaleAspectFit
result.layer.shadowColor = Colors.accent.cgColor
result.layer.shadowOffset = .zero
result.layer.shadowRadius = 3
result.layer.shadowOpacity = 0
return result
}()
private var progressBar: UIProgressView = {
let result: UIProgressView = UIProgressView(progressViewStyle: .bar)
result.clipsToBounds = true
result.progress = 0
result.tintColor = Colors.accent
result.trackTintColor = Colors.text.withAlphaComponent(0.1)
result.layer.cornerRadius = 6
var logoView: UIImageView! return result
var topLabel: UILabel! }()
var bottomLabel: UILabel!
private var topLabel: UILabel = {
let result: UILabel = UILabel()
result.font = UIFont.systemFont(ofSize: Values.mediumFontSize)
result.text = "DATABASE_VIEW_OVERLAY_TITLE".localized()
result.textColor = Colors.text
result.textAlignment = .center
result.numberOfLines = 0
result.lineBreakMode = .byWordWrapping
return result
}()
private var bottomLabel: UILabel = {
let result: UILabel = UILabel()
result.font = UIFont.systemFont(ofSize: Values.verySmallFontSize)
result.text = "DATABASE_VIEW_OVERLAY_SUBTITLE".localized()
result.textColor = Colors.text
result.textAlignment = .center
result.numberOfLines = 0
result.lineBreakMode = .byWordWrapping
result.isHidden = true
return result
}()
private lazy var labelStack: UIStackView = {
let result: UIStackView = UIStackView()
result.axis = .vertical
result.alignment = .center
result.spacing = 20
result.alpha = 0
return result
}()
// MARK: - Lifecycle
override public func loadView() { override public func loadView() {
self.view = UIView() self.view = UIView()
// Loki: Set gradient background self.view.backgroundColor = Colors.navigationBarBackground
view.backgroundColor = .clear
let gradient = Gradients.defaultBackground
view.setGradient(gradient)
self.logoView = UIImageView(image: #imageLiteral(resourceName: "SessionGreen64")) self.view.addSubview(self.logoView)
view.addSubview(logoView) self.view.addSubview(self.labelStack)
self.view.addSubview(self.bottomLabel)
self.labelStack.addArrangedSubview(self.progressBar)
self.labelStack.addArrangedSubview(self.topLabel)
logoView.autoCenterInSuperview() // Layout
logoView.autoSetDimension(.width, toSize: 64)
logoView.autoSetDimension(.height, toSize: 64) self.logoView.autoCenterInSuperview()
logoView.contentMode = .scaleAspectFit self.logoView.autoSetDimension(.width, toSize: 64)
self.logoView.autoSetDimension(.height, toSize: 64)
self.topLabel = buildLabel()
topLabel.alpha = 0 self.progressBar.set(.height, to: (self.progressBar.layer.cornerRadius * 2))
topLabel.font = UIFont.ows_dynamicTypeTitle2 self.progressBar.set(.width, to: .width, of: self.view, multiplier: 0.5)
topLabel.text = NSLocalizedString("DATABASE_VIEW_OVERLAY_TITLE", comment: "Title shown while the app is updating its database.")
self.labelStack.pin(.top, to: .bottom, of: self.logoView, withInset: 40)
self.bottomLabel = buildLabel() self.labelStack.pin(.left, to: .left, of: self.view)
bottomLabel.alpha = 0 self.labelStack.pin(.right, to: .right, of: self.view)
bottomLabel.font = UIFont.ows_dynamicTypeBody self.labelStack.setCompressionResistanceHigh()
bottomLabel.text = NSLocalizedString("DATABASE_VIEW_OVERLAY_SUBTITLE", comment: "Subtitle shown while the app is updating its database.") self.labelStack.setContentHuggingHigh()
let labelStack = UIStackView(arrangedSubviews: [topLabel, bottomLabel]) self.bottomLabel.pin(.top, to: .bottom, of: self.labelStack, withInset: 10)
labelStack.axis = .vertical self.bottomLabel.pin(.left, to: .left, of: self.view)
labelStack.alignment = .center self.bottomLabel.pin(.right, to: .right, of: self.view)
labelStack.spacing = 8 self.bottomLabel.setCompressionResistanceHigh()
view.addSubview(labelStack) self.bottomLabel.setContentHuggingHigh()
labelStack.autoPinEdge(.top, to: .bottom, of: logoView, withOffset: 20)
labelStack.autoPinLeadingToSuperviewMargin()
labelStack.autoPinTrailingToSuperviewMargin()
labelStack.setCompressionResistanceHigh()
labelStack.setContentHuggingHigh()
} }
var isShowingTopLabel = false // MARK: - Functions
var isShowingBottomLabel = false
override public func viewWillAppear(_ animated: Bool) { public func updateProgress(progress: CGFloat, minEstimatedTotalTime: TimeInterval) {
super.viewWillAppear(animated) guard minEstimatedTotalTime >= LoadingViewController.minExpectedDurationToShowLoading else { return }
// We only show the "loading" UI if it's a slow launch. Otherwise this ViewController if !self.isShowingProgress {
// should be indistinguishable from the launch screen. self.isShowingProgress = true
let kTopLabelThreshold: TimeInterval = 5 self.bottomLabel.isHidden = (
DispatchQueue.main.asyncAfter(deadline: .now() + kTopLabelThreshold) { [weak self] in minEstimatedTotalTime < LoadingViewController.minExpectedDurationAdditionalLabel
guard let strongSelf = self else { )
return
UIView.animate(withDuration: 0.3) { [weak self] in
self?.labelStack.alpha = 1
} }
guard !strongSelf.isShowingTopLabel else { UIView.animate(
return withDuration: 1.95,
} delay: 0.05,
options: [
strongSelf.isShowingTopLabel = true .curveEaseInOut,
UIView.animate(withDuration: 0.1) { .autoreverse,
strongSelf.topLabel.alpha = 1 .repeat
} ],
UIView.animate(withDuration: 0.9, delay: 2, options: [.autoreverse, .repeat, .curveEaseInOut], animations: { animations: { [weak self] in
strongSelf.topLabel.alpha = 0.2 self?.logoView.layer.shadowOpacity = 1
}, completion: nil) },
completion: nil
)
} }
let kBottomLabelThreshold: TimeInterval = 15 self.progressBar.setProgress(Float(progress), animated: true)
DispatchQueue.main.asyncAfter(deadline: .now() + kBottomLabelThreshold) { [weak self] in
guard let strongSelf = self else {
return
}
guard !strongSelf.isShowingBottomLabel else {
return
}
strongSelf.isShowingBottomLabel = true
UIView.animate(withDuration: 0.1) {
strongSelf.bottomLabel.alpha = 1
}
}
}
// MARK: Orientation
override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
// MARK:
private func buildLabel() -> UILabel {
let label = UILabel()
label.textColor = .white
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
return label
} }
} }

View File

@ -348,7 +348,7 @@ NS_ASSUME_NONNULL_BEGIN
return ScreenLockUIStateNone; return ScreenLockUIStateNone;
} }
if (Environment.shared.isRequestingPermission) { if (SMKEnvironment.shared.isRequestingPermission) {
return ScreenLockUIStateNone; return ScreenLockUIStateNone;
} }

View File

@ -486,7 +486,7 @@ public enum SMKLegacy {
let admins: [Data] = self.admins let admins: [Data] = self.admins
else { else {
SNLog("[Migration Error] Unable to decode Legacy ClosedGroupControlMessage") SNLog("[Migration Error] Unable to decode Legacy ClosedGroupControlMessage")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
return .new( return .new(
@ -504,7 +504,7 @@ public enum SMKLegacy {
case "encryptionKeyPair": case "encryptionKeyPair":
guard let wrappers: [_KeyPairWrapper] = self.wrappers else { guard let wrappers: [_KeyPairWrapper] = self.wrappers else {
SNLog("[Migration Error] Unable to decode Legacy ClosedGroupControlMessage") SNLog("[Migration Error] Unable to decode Legacy ClosedGroupControlMessage")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
return .encryptionKeyPair( return .encryptionKeyPair(
@ -515,7 +515,7 @@ public enum SMKLegacy {
let encryptedKeyPair: Data = wrapper.encryptedKeyPair let encryptedKeyPair: Data = wrapper.encryptedKeyPair
else { else {
SNLog("[Migration Error] Unable to decode Legacy ClosedGroupControlMessage") SNLog("[Migration Error] Unable to decode Legacy ClosedGroupControlMessage")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
return SessionMessagingKit.ClosedGroupControlMessage.KeyPairWrapper( return SessionMessagingKit.ClosedGroupControlMessage.KeyPairWrapper(
@ -528,7 +528,7 @@ public enum SMKLegacy {
case "nameChange": case "nameChange":
guard let name: String = self.name else { guard let name: String = self.name else {
SNLog("[Migration Error] Unable to decode Legacy ClosedGroupControlMessage") SNLog("[Migration Error] Unable to decode Legacy ClosedGroupControlMessage")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
return .nameChange( return .nameChange(
@ -538,7 +538,7 @@ public enum SMKLegacy {
case "membersAdded": case "membersAdded":
guard let members: [Data] = self.members else { guard let members: [Data] = self.members else {
SNLog("[Migration Error] Unable to decode Legacy ClosedGroupControlMessage") SNLog("[Migration Error] Unable to decode Legacy ClosedGroupControlMessage")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
return .membersAdded(members: members) return .membersAdded(members: members)
@ -546,14 +546,14 @@ public enum SMKLegacy {
case "membersRemoved": case "membersRemoved":
guard let members: [Data] = self.members else { guard let members: [Data] = self.members else {
SNLog("[Migration Error] Unable to decode Legacy ClosedGroupControlMessage") SNLog("[Migration Error] Unable to decode Legacy ClosedGroupControlMessage")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
return .membersRemoved(members: members) return .membersRemoved(members: members)
case "memberLeft": return .memberLeft case "memberLeft": return .memberLeft
case "encryptionKeyPairRequest": return .encryptionKeyPairRequest case "encryptionKeyPairRequest": return .encryptionKeyPairRequest
default: throw GRDBStorageError.migrationFailed default: throw StorageError.migrationFailed
} }
}() }()
) )
@ -592,12 +592,12 @@ public enum SMKLegacy {
case "mediaSaved": case "mediaSaved":
guard let timestamp: UInt64 = self.timestamp else { guard let timestamp: UInt64 = self.timestamp else {
SNLog("[Migration Error] Unable to decode Legacy DataExtractionNotification") SNLog("[Migration Error] Unable to decode Legacy DataExtractionNotification")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
return .mediaSaved(timestamp: timestamp) return .mediaSaved(timestamp: timestamp)
default: throw GRDBStorageError.migrationFailed default: throw StorageError.migrationFailed
} }
}() }()
) )

View File

@ -6,6 +6,8 @@ import SessionUtilitiesKit
enum _001_InitialSetupMigration: Migration { enum _001_InitialSetupMigration: Migration {
static let identifier: String = "initialSetup" static let identifier: String = "initialSetup"
static let minExpectedRunDuration: TimeInterval = 0.1
static let needsConfigSync: Bool = false
static func migrate(_ db: Database) throws { static func migrate(_ db: Database) throws {
// Define the tokenizer to be used in all the FTS tables // Define the tokenizer to be used in all the FTS tables

View File

@ -10,6 +10,8 @@ import SessionSnodeKit
/// before running the `YDBToGRDBMigration` /// before running the `YDBToGRDBMigration`
enum _002_SetupStandardJobs: Migration { enum _002_SetupStandardJobs: Migration {
static let identifier: String = "SetupStandardJobs" static let identifier: String = "SetupStandardJobs"
static let minExpectedRunDuration: TimeInterval = 0.1
static let needsConfigSync: Bool = false
static func migrate(_ db: Database) throws { static func migrate(_ db: Database) throws {
// Start by adding the jobs that don't have collections (in the jobs like these // Start by adding the jobs that don't have collections (in the jobs like these

View File

@ -11,8 +11,12 @@ import SessionSnodeKit
// ~250k messages and ~1000 threads seems to take up // ~250k messages and ~1000 threads seems to take up
enum _003_YDBToGRDBMigration: Migration { enum _003_YDBToGRDBMigration: Migration {
static let identifier: String = "YDBToGRDBMigration" static let identifier: String = "YDBToGRDBMigration"
static let minExpectedRunDuration: TimeInterval = 20
static let needsConfigSync: Bool = true
static func migrate(_ db: Database) throws { static func migrate(_ db: Database) throws {
let targetIdentifier: TargetMigrations.Identifier = .messagingKit
// MARK: - Process Contacts, Threads & Interactions // MARK: - Process Contacts, Threads & Interactions
print("RAWR [\(Date().timeIntervalSince1970)] - SessionMessagingKit migration - Start") print("RAWR [\(Date().timeIntervalSince1970)] - SessionMessagingKit migration - Start")
var shouldFailMigration: Bool = false var shouldFailMigration: Bool = false
@ -283,7 +287,7 @@ enum _003_YDBToGRDBMigration: Migration {
} }
// We can't properly throw within the 'enumerateKeysAndObjects' block so have to throw here // We can't properly throw within the 'enumerateKeysAndObjects' block so have to throw here
guard !shouldFailMigration else { throw GRDBStorageError.migrationFailed } guard !shouldFailMigration else { throw StorageError.migrationFailed }
// Insert the data into GRDB // Insert the data into GRDB
@ -411,7 +415,7 @@ enum _003_YDBToGRDBMigration: Migration {
try legacyThreads.sorted(by: { lhs, rhs in lhs.uniqueId < rhs.uniqueId }).forEach { legacyThread in try legacyThreads.sorted(by: { lhs, rhs in lhs.uniqueId < rhs.uniqueId }).forEach { legacyThread in
guard let threadId: String = legacyThreadIdToIdMap[legacyThread.uniqueId] else { guard let threadId: String = legacyThreadIdToIdMap[legacyThread.uniqueId] else {
SNLog("[Migration Error] Unable to migrate thread with no id mapping") SNLog("[Migration Error] Unable to migrate thread with no id mapping")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
let threadVariant: SessionThread.Variant let threadVariant: SessionThread.Variant
@ -464,7 +468,7 @@ enum _003_YDBToGRDBMigration: Migration {
let formationTimestamp: UInt64 = closedGroupFormation[legacyThread.uniqueId] let formationTimestamp: UInt64 = closedGroupFormation[legacyThread.uniqueId]
else { else {
SNLog("[Migration Error] Closed group missing required data") SNLog("[Migration Error] Closed group missing required data")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
try ClosedGroup( try ClosedGroup(
@ -519,7 +523,7 @@ enum _003_YDBToGRDBMigration: Migration {
if legacyThread.isOpenGroup { if legacyThread.isOpenGroup {
guard let openGroup: OpenGroupV2 = openGroupInfo[legacyThread.uniqueId] else { guard let openGroup: OpenGroupV2 = openGroupInfo[legacyThread.uniqueId] else {
SNLog("[Migration Error] Open group missing required data") SNLog("[Migration Error] Open group missing required data")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
try OpenGroup( try OpenGroup(
@ -673,7 +677,7 @@ enum _003_YDBToGRDBMigration: Migration {
default: default:
// TODO: What message types have no body? // TODO: What message types have no body?
SNLog("[Migration Error] Unsupported interaction type") SNLog("[Migration Error] Unsupported interaction type")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
// Insert the data // Insert the data
@ -727,7 +731,7 @@ enum _003_YDBToGRDBMigration: Migration {
guard let interactionId: Int64 = interaction.id else { guard let interactionId: Int64 = interaction.id else {
// TODO: Is it possible the old database has duplicates which could hit this case? // TODO: Is it possible the old database has duplicates which could hit this case?
SNLog("[Migration Error] Failed to insert interaction") SNLog("[Migration Error] Failed to insert interaction")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
// Store the interactionId in the lookup map to simplify job creation later // Store the interactionId in the lookup map to simplify job creation later
@ -874,7 +878,7 @@ enum _003_YDBToGRDBMigration: Migration {
guard linkPreview.imageAttachmentId == nil || attachments[linkPreview.imageAttachmentId ?? ""] != nil else { guard linkPreview.imageAttachmentId == nil || attachments[linkPreview.imageAttachmentId ?? ""] != nil else {
// TODO: Is it possible to hit this case if a quoted attachment hasn't been downloaded? // TODO: Is it possible to hit this case if a quoted attachment hasn't been downloaded?
SNLog("[Migration Error] Missing link preview attachment") SNLog("[Migration Error] Missing link preview attachment")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
// Setup the attachment and add it to the lookup (if it exists) // Setup the attachment and add it to the lookup (if it exists)
@ -1268,7 +1272,7 @@ enum _003_YDBToGRDBMigration: Migration {
try attachmentUploadJobs.forEach { legacyJob in try attachmentUploadJobs.forEach { legacyJob in
guard let sendJob: Job = messageSendJobLegacyMap[legacyJob.messageSendJobID], let sendJobId: Int64 = sendJob.id else { guard let sendJob: Job = messageSendJobLegacyMap[legacyJob.messageSendJobID], let sendJobId: Int64 = sendJob.id else {
SNLog("[Migration Error] attachmentUpload job missing associated MessageSendJob") SNLog("[Migration Error] attachmentUpload job missing associated MessageSendJob")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
let uploadJob: Job? = try Job( let uploadJob: Job? = try Job(
@ -1286,7 +1290,7 @@ enum _003_YDBToGRDBMigration: Migration {
// Add the dependency to the relevant MessageSendJob // Add the dependency to the relevant MessageSendJob
guard let uploadJobId: Int64 = uploadJob?.id else { guard let uploadJobId: Int64 = uploadJob?.id else {
SNLog("[Migration Error] attachmentUpload job was not created") SNLog("[Migration Error] attachmentUpload job was not created")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
try JobDependencies( try JobDependencies(
@ -1302,7 +1306,7 @@ enum _003_YDBToGRDBMigration: Migration {
try attachmentDownloadJobs.forEach { legacyJob in try attachmentDownloadJobs.forEach { legacyJob in
guard let interactionId: Int64 = legacyInteractionToIdMap[legacyJob.tsMessageID] else { guard let interactionId: Int64 = legacyInteractionToIdMap[legacyJob.tsMessageID] else {
SNLog("[Migration Error] attachmentDownload job unable to find interaction") SNLog("[Migration Error] attachmentDownload job unable to find interaction")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
guard processedAttachmentIds.contains(legacyJob.attachmentID) else { guard processedAttachmentIds.contains(legacyJob.attachmentID) else {
SNLog("[Migration Error] attachmentDownload job unable to find attachment") SNLog("[Migration Error] attachmentDownload job unable to find attachment")
@ -1441,7 +1445,7 @@ enum _003_YDBToGRDBMigration: Migration {
guard !processedAttachmentIds.contains(legacyAttachmentId) else { guard !processedAttachmentIds.contains(legacyAttachmentId) else {
guard isQuotedMessage else { guard isQuotedMessage else {
SNLog("[Migration Error] Attempted to process duplicate attachment") SNLog("[Migration Error] Attempted to process duplicate attachment")
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
return legacyAttachmentId return legacyAttachmentId

View File

@ -983,7 +983,7 @@ extension Attachment {
guard uploadedAttachment != nil else { guard uploadedAttachment != nil else {
SNLog("Couldn't update attachmentUpload job.") SNLog("Couldn't update attachmentUpload job.")
failure?(GRDBStorageError.failedToSave) failure?(StorageError.failedToSave)
return return
} }
@ -1025,7 +1025,7 @@ extension Attachment {
guard updatedAttachment != nil else { guard updatedAttachment != nil else {
SNLog("Couldn't update attachmentUpload job.") SNLog("Couldn't update attachmentUpload job.")
failure?(GRDBStorageError.failedToSave) failure?(StorageError.failedToSave)
return return
} }
@ -1049,7 +1049,7 @@ extension Attachment {
guard uploadedAttachment != nil else { guard uploadedAttachment != nil else {
SNLog("Couldn't update attachmentUpload job.") SNLog("Couldn't update attachmentUpload job.")
failure?(GRDBStorageError.failedToSave) failure?(StorageError.failedToSave)
return return
} }

View File

@ -121,7 +121,7 @@ public extension Profile {
{ {
guard let validProfileKey: OWSAES256Key = OWSAES256Key(data: profileKeyData) else { guard let validProfileKey: OWSAES256Key = OWSAES256Key(data: profileKeyData) else {
owsFailDebug("Failed to make profile key for key data") owsFailDebug("Failed to make profile key for key data")
throw GRDBStorageError.decodingFailed throw StorageError.decodingFailed
} }
profileKey = validProfileKey profileKey = validProfileKey

View File

@ -94,7 +94,7 @@ public extension DisappearingMessagesJob {
do { do {
guard let interactionId: Int64 = try? (interaction.id ?? interaction.inserted(db).id) else { guard let interactionId: Int64 = try? (interaction.id ?? interaction.inserted(db).id) else {
throw GRDBStorageError.objectNotFound throw StorageError.objectNotFound
} }
return updateNextRunIfNeeded(db, interactionIds: [interactionId], startedAtMs: startedAtMs) return updateNextRunIfNeeded(db, interactionIds: [interactionId], startedAtMs: startedAtMs)

View File

@ -211,18 +211,18 @@ extension MessageSendJob {
guard let messageType: String = try? container.decode(String.self, forKey: .messageType) else { guard let messageType: String = try? container.decode(String.self, forKey: .messageType) else {
Logger.error("Unable to decode messageSend job due to missing messageType") Logger.error("Unable to decode messageSend job due to missing messageType")
throw GRDBStorageError.decodingFailed throw StorageError.decodingFailed
} }
/// Note: This **MUST** be a `Codable.Type` rather than a `Message.Type` otherwise the decoding will result /// Note: This **MUST** be a `Codable.Type` rather than a `Message.Type` otherwise the decoding will result
/// in a `Message` object being returned rather than the desired subclass /// in a `Message` object being returned rather than the desired subclass
guard let MessageType: Codable.Type = MessageSendJob.Details.supportedMessageTypes[messageType] else { guard let MessageType: Codable.Type = MessageSendJob.Details.supportedMessageTypes[messageType] else {
Logger.error("Unable to decode messageSend job due to unsupported messageType") Logger.error("Unable to decode messageSend job due to unsupported messageType")
throw GRDBStorageError.decodingFailed throw StorageError.decodingFailed
} }
guard let message: Message = try MessageType.decoded(with: container, forKey: .message) as? Message else { guard let message: Message = try MessageType.decoded(with: container, forKey: .message) as? Message else {
Logger.error("Unable to decode messageSend job due to message conversion issue") Logger.error("Unable to decode messageSend job due to message conversion issue")
throw GRDBStorageError.decodingFailed throw StorageError.decodingFailed
} }
self = Details( self = Details(
@ -241,7 +241,7 @@ extension MessageSendJob {
guard let messageTypeString: String = maybeMessageTypeString else { guard let messageTypeString: String = maybeMessageTypeString else {
Logger.error("Unable to encode messageSend job due to unsupported messageType") Logger.error("Unable to encode messageSend job due to unsupported messageType")
throw GRDBStorageError.objectNotFound throw StorageError.objectNotFound
} }
try container.encode(destination, forKey: .destination) try container.encode(destination, forKey: .destination)

View File

@ -17,7 +17,7 @@ public extension Message {
case .closedGroup: return .closedGroup(groupPublicKey: thread.id) case .closedGroup: return .closedGroup(groupPublicKey: thread.id)
case .openGroup: case .openGroup:
guard let openGroup: OpenGroup = try thread.openGroup.fetchOne(db) else { guard let openGroup: OpenGroup = try thread.openGroup.fetchOne(db) else {
throw GRDBStorageError.objectNotFound throw StorageError.objectNotFound
} }
return .openGroupV2(room: openGroup.room, server: openGroup.server) return .openGroupV2(room: openGroup.room, server: openGroup.server)

View File

@ -494,7 +494,7 @@ extension MessageReceiver {
throw error throw error
} }
guard let interactionId: Int64 = interaction.id else { throw GRDBStorageError.failedToSave } guard let interactionId: Int64 = interaction.id else { throw StorageError.failedToSave }
// Update and recipient and read states as needed // Update and recipient and read states as needed
try updateRecipientAndReadStates( try updateRecipientAndReadStates(

View File

@ -230,9 +230,7 @@ extension MessageSender {
timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000)) timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000))
).inserted(db) ).inserted(db)
guard let interactionId: Int64 = interaction.id else { guard let interactionId: Int64 = interaction.id else { throw StorageError.objectNotSaved }
throw GRDBStorageError.objectNotSaved
}
// Send the update to the group // Send the update to the group
let closedGroupControlMessage = ClosedGroupControlMessage(kind: .nameChange(name: name)) let closedGroupControlMessage = ClosedGroupControlMessage(kind: .nameChange(name: name))
@ -305,10 +303,10 @@ extension MessageSender {
thread: SessionThread thread: SessionThread
) throws { ) throws {
guard let disappearingMessagesConfig: DisappearingMessagesConfiguration = try thread.disappearingMessagesConfiguration.fetchOne(db) else { guard let disappearingMessagesConfig: DisappearingMessagesConfiguration = try thread.disappearingMessagesConfiguration.fetchOne(db) else {
throw GRDBStorageError.objectNotFound throw StorageError.objectNotFound
} }
guard let encryptionKeyPair: ClosedGroupKeyPair = try closedGroup.fetchLatestKeyPair(db) else { guard let encryptionKeyPair: ClosedGroupKeyPair = try closedGroup.fetchLatestKeyPair(db) else {
throw GRDBStorageError.objectNotFound throw StorageError.objectNotFound
} }
let groupMemberIds: [String] = allGroupMembers let groupMemberIds: [String] = allGroupMembers
@ -332,9 +330,7 @@ extension MessageSender {
timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000)) timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000))
).inserted(db) ).inserted(db)
guard let interactionId: Int64 = interaction.id else { guard let interactionId: Int64 = interaction.id else { throw StorageError.objectNotSaved }
throw GRDBStorageError.objectNotSaved
}
// Send the update to the group // Send the update to the group
try MessageSender.send( try MessageSender.send(
@ -437,9 +433,7 @@ extension MessageSender {
timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000)) timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000))
).inserted(db) ).inserted(db)
guard let newInteractionId: Int64 = interaction.id else { guard let newInteractionId: Int64 = interaction.id else { throw StorageError.objectNotSaved }
throw GRDBStorageError.objectNotSaved
}
interactionId = newInteractionId interactionId = newInteractionId
} }
@ -505,7 +499,7 @@ extension MessageSender {
).inserted(db) ).inserted(db)
guard let interactionId: Int64 = interaction.id else { guard let interactionId: Int64 = interaction.id else {
throw GRDBStorageError.objectNotSaved throw StorageError.objectNotSaved
} }
// Send the update to the group // Send the update to the group

View File

@ -10,7 +10,7 @@ extension MessageSender {
// MARK: - Durable // MARK: - Durable
public static func send(_ db: Database, interaction: Interaction, with attachments: [SignalAttachment], in thread: SessionThread) throws { public static func send(_ db: Database, interaction: Interaction, with attachments: [SignalAttachment], in thread: SessionThread) throws {
guard let interactionId: Int64 = interaction.id else { throw GRDBStorageError.objectNotSaved } guard let interactionId: Int64 = interaction.id else { throw StorageError.objectNotSaved }
try prep(db, signalAttachments: attachments, for: interactionId) try prep(db, signalAttachments: attachments, for: interactionId)
send( send(
@ -25,7 +25,7 @@ extension MessageSender {
public static func send(_ db: Database, interaction: Interaction, in thread: SessionThread) throws { public static func send(_ db: Database, interaction: Interaction, in thread: SessionThread) throws {
// Only 'VisibleMessage' types can be sent via this method // Only 'VisibleMessage' types can be sent via this method
guard interaction.variant == .standardOutgoing else { throw MessageSenderError.invalidMessage } guard interaction.variant == .standardOutgoing else { throw MessageSenderError.invalidMessage }
guard let interactionId: Int64 = interaction.id else { throw GRDBStorageError.objectNotSaved } guard let interactionId: Int64 = interaction.id else { throw StorageError.objectNotSaved }
send( send(
db, db,
@ -64,7 +64,7 @@ extension MessageSender {
// MARK: - Non-Durable // MARK: - Non-Durable
public static func sendNonDurably(_ db: Database, interaction: Interaction, with attachments: [SignalAttachment], in thread: SessionThread) throws -> Promise<Void> { public static func sendNonDurably(_ db: Database, interaction: Interaction, with attachments: [SignalAttachment], in thread: SessionThread) throws -> Promise<Void> {
guard let interactionId: Int64 = interaction.id else { return Promise(error: GRDBStorageError.objectNotSaved) } guard let interactionId: Int64 = interaction.id else { return Promise(error: StorageError.objectNotSaved) }
try prep(db, signalAttachments: attachments, for: interactionId) try prep(db, signalAttachments: attachments, for: interactionId)
@ -80,7 +80,7 @@ extension MessageSender {
public static func sendNonDurably(_ db: Database, interaction: Interaction, in thread: SessionThread) throws -> Promise<Void> { public static func sendNonDurably(_ db: Database, interaction: Interaction, in thread: SessionThread) throws -> Promise<Void> {
// Only 'VisibleMessage' types can be sent via this method // Only 'VisibleMessage' types can be sent via this method
guard interaction.variant == .standardOutgoing else { throw MessageSenderError.invalidMessage } guard interaction.variant == .standardOutgoing else { throw MessageSenderError.invalidMessage }
guard let interactionId: Int64 = interaction.id else { throw GRDBStorageError.objectNotSaved } guard let interactionId: Int64 = interaction.id else { throw StorageError.objectNotSaved }
return sendNonDurably( return sendNonDurably(
db, db,
@ -174,9 +174,7 @@ extension MessageSender {
// If we don't have a userKeyPair yet then there is no need to sync the configuration // If we don't have a userKeyPair yet then there is no need to sync the configuration
// as the user doesn't exist yet (this will get triggered on the first launch of a // as the user doesn't exist yet (this will get triggered on the first launch of a
// fresh install due to the migrations getting run) // fresh install due to the migrations getting run)
guard Identity.userExists(db) else { guard Identity.userExists(db) else { return Promise(error: StorageError.generic) }
return Promise(error: GRDBStorageError.generic)
}
let destination: Message.Destination = Message.Destination.contact( let destination: Message.Destination = Message.Destination.contact(
publicKey: getUserHexEncodedPublicKey(db) publicKey: getUserHexEncodedPublicKey(db)
@ -188,7 +186,7 @@ extension MessageSender {
try MessageSender try MessageSender
.sendImmediate(db, message: configurationMessage, to: destination, interactionId: nil) .sendImmediate(db, message: configurationMessage, to: destination, interactionId: nil)
.done { seal.fulfill(()) } .done { seal.fulfill(()) }
.catch { _ in seal.reject(GRDBStorageError.generic) } .catch { _ in seal.reject(StorageError.generic) }
.retainUntilComplete() .retainUntilComplete()
} }
else { else {

View File

@ -782,7 +782,7 @@ public extension SessionThreadViewModel {
.defaulting(to: FTS5Pattern(matchingAnyTokenIn: searchTerm)) .defaulting(to: FTS5Pattern(matchingAnyTokenIn: searchTerm))
) )
guard let pattern: FTS5Pattern = maybePattern else { throw GRDBStorageError.invalidSearchPattern } guard let pattern: FTS5Pattern = maybePattern else { throw StorageError.invalidSearchPattern }
return pattern return pattern
} }

View File

@ -1,39 +0,0 @@
#import <Foundation/Foundation.h>
@class OWSAudioSession;
@class OWSPreferences;
@class OWSWindowManager;
@protocol OWSProximityMonitoringManager;
/**
*
* Environment is a data and data accessor class.
* It handles application-level component wiring in order to support mocks for testing.
* It also handles network configuration for testing/deployment server configurations.
*
**/
@interface Environment : NSObject
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithAudioSession:(OWSAudioSession *)audioSession
preferences:(OWSPreferences *)preferences
proximityMonitoringManager:(id<OWSProximityMonitoringManager>)proximityMonitoringManager
windowManager:(OWSWindowManager *)windowManager;
@property (nonatomic, readonly) OWSAudioSession *audioSession;
@property (nonatomic, readonly) id<OWSProximityMonitoringManager> proximityMonitoringManager;
@property (nonatomic, readonly) OWSPreferences *preferences;
@property (nonatomic, readonly) OWSWindowManager *windowManager;
// We don't want to cover the window when we request the photo library permission
@property (nonatomic, readwrite) BOOL isRequestingPermission;
@property (class, nonatomic) Environment *shared;
#ifdef DEBUG
// Should only be called by tests.
+ (void)clearSharedForTests;
#endif
@end

View File

@ -1,62 +0,0 @@
#import <Foundation/Foundation.h>
#import "OWSWindowManager.h"
#import <SessionMessagingKit/SessionMessagingKit-Swift.h>
#import "OWSPreferences.h"
static Environment *sharedEnvironment = nil;
@interface Environment ()
@property (nonatomic) OWSAudioSession *audioSession;
@property (nonatomic) OWSPreferences *preferences;
@property (nonatomic) id<OWSProximityMonitoringManager> proximityMonitoringManager;
@property (nonatomic) OWSWindowManager *windowManager;
@end
#pragma mark -
@implementation Environment
+ (Environment *)shared
{
return sharedEnvironment;
}
+ (void)setShared:(Environment *)environment
{
// The main app environment should only be set once.
//
// App extensions may be opened multiple times in the same process,
// so statics will persist.
sharedEnvironment = environment;
}
+ (void)clearSharedForTests
{
sharedEnvironment = nil;
}
- (instancetype)initWithAudioSession:(OWSAudioSession *)audioSession
preferences:(OWSPreferences *)preferences
proximityMonitoringManager:(id<OWSProximityMonitoringManager>)proximityMonitoringManager
windowManager:(OWSWindowManager *)windowManager
{
self = [super init];
if (!self) {
return self;
}
_audioSession = audioSession;
_preferences = preferences;
_proximityMonitoringManager = proximityMonitoringManager;
_windowManager = windowManager;
_isRequestingPermission = false;
return self;
}
@end

View File

@ -0,0 +1,76 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import SessionUtilitiesKit
public class Environment {
public static var shared: Environment!
public let primaryStorage: OWSPrimaryStorage
public let reachabilityManager: SSKReachabilityManager
public let audioSession: OWSAudioSession
public let preferences: OWSPreferences
public let proximityMonitoringManager: OWSProximityMonitoringManager
public let windowManager: OWSWindowManager
public var isRequestingPermission: Bool
// Note: This property is configured after Environment is created.
public let notificationsManager: Atomic<NotificationsProtocol?> = Atomic(nil)
public var isComplete: Bool {
(notificationsManager.wrappedValue != nil)
}
public var objectReadWriteConnection: YapDatabaseConnection
public var sessionStoreDBConnection: YapDatabaseConnection
public var migrationDBConnection: YapDatabaseConnection
public var analyticsDBConnection: YapDatabaseConnection
// MARK: - Initialization
public init(
primaryStorage: OWSPrimaryStorage,
reachabilityManager: SSKReachabilityManager,
audioSession: OWSAudioSession,
preferences: OWSPreferences,
proximityMonitoringManager: OWSProximityMonitoringManager,
windowManager: OWSWindowManager
) {
self.primaryStorage = primaryStorage
self.reachabilityManager = reachabilityManager
self.audioSession = audioSession
self.preferences = preferences
self.proximityMonitoringManager = proximityMonitoringManager
self.windowManager = windowManager
self.isRequestingPermission = false
self.objectReadWriteConnection = primaryStorage.newDatabaseConnection()
self.sessionStoreDBConnection = primaryStorage.newDatabaseConnection()
self.migrationDBConnection = primaryStorage.newDatabaseConnection()
self.analyticsDBConnection = primaryStorage.newDatabaseConnection()
if Environment.shared == nil {
Environment.shared = self
}
}
// MARK: - Functions
public static func clearSharedForTests() {
shared = nil
}
}
// MARK: - Objective C Support
@objc(SMKEnvironment)
class SMKEnvironment: NSObject {
@objc public static let shared: SMKEnvironment = SMKEnvironment()
@objc public var primaryStorage: OWSPrimaryStorage { Environment.shared.primaryStorage }
@objc public var audioSession: OWSAudioSession { Environment.shared.audioSession }
@objc public var windowManager: OWSWindowManager { Environment.shared.windowManager }
@objc public var isRequestingPermission: Bool { Environment.shared.isRequestingPermission }
}

View File

@ -94,7 +94,7 @@ NS_ASSUME_NONNULL_BEGIN
- (OWSAudioSession *)audioSession - (OWSAudioSession *)audioSession
{ {
return Environment.shared.audioSession; return SMKEnvironment.shared.audioSession;
} }
#pragma mark #pragma mark

View File

@ -4,6 +4,7 @@
#import "OWSWindowManager.h" #import "OWSWindowManager.h"
#import "Environment.h" #import "Environment.h"
#import <SessionMessagingKit/SessionMessagingKit-Swift.h>
#import <SessionUtilitiesKit/SessionUtilitiesKit.h> #import <SessionUtilitiesKit/SessionUtilitiesKit.h>
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@ -153,7 +154,7 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
+ (instancetype)sharedManager + (instancetype)sharedManager
{ {
return Environment.shared.windowManager; return SMKEnvironment.shared.windowManager;
} }
- (instancetype)initDefault - (instancetype)initDefault

View File

@ -1,51 +0,0 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import SessionUtilitiesKit
@objc
public class SSKEnvironment: NSObject {
@objc public let primaryStorage: OWSPrimaryStorage
public let reachabilityManager: SSKReachabilityManager
// Note: This property is configured after Environment is created.
public let notificationsManager: Atomic<NotificationsProtocol?> = Atomic(nil)
@objc public static var shared: SSKEnvironment!
public var isComplete: Bool {
(notificationsManager.wrappedValue != nil)
}
public var objectReadWriteConnection: YapDatabaseConnection
public var sessionStoreDBConnection: YapDatabaseConnection
public var migrationDBConnection: YapDatabaseConnection
public var analyticsDBConnection: YapDatabaseConnection
// MARK: - Initialization
@objc public init(
primaryStorage: OWSPrimaryStorage,
reachabilityManager: SSKReachabilityManager
) {
self.primaryStorage = primaryStorage
self.reachabilityManager = reachabilityManager
self.objectReadWriteConnection = primaryStorage.newDatabaseConnection()
self.sessionStoreDBConnection = primaryStorage.newDatabaseConnection()
self.migrationDBConnection = primaryStorage.newDatabaseConnection()
self.analyticsDBConnection = primaryStorage.newDatabaseConnection()
super.init()
if SSKEnvironment.shared == nil {
SSKEnvironment.shared = self
}
}
// MARK: - Functions
public static func clearSharedForTests() {
shared = nil
}
}

View File

@ -115,12 +115,12 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension
guard GRDBStorage.shared[.isReadyForAppExtensions] else { return completeSilenty() } guard GRDBStorage.shared[.isReadyForAppExtensions] else { return completeSilenty() }
AppSetup.setupEnvironment( AppSetup.setupEnvironment(
appSpecificSingletonBlock: { appSpecificBlock: {
SSKEnvironment.shared.notificationsManager.mutate { Environment.shared.notificationsManager.mutate {
$0 = NSENotificationPresenter() $0 = NSENotificationPresenter()
} }
}, },
migrationCompletion: { [weak self] _, needsConfigSync in migrationsCompletion: { [weak self] _, needsConfigSync in
self?.versionMigrationsDidComplete(needsConfigSync: needsConfigSync) self?.versionMigrationsDidComplete(needsConfigSync: needsConfigSync)
completion() completion()
} }

View File

@ -43,14 +43,12 @@ final class ShareVC : UINavigationController, ShareViewDelegate, AppModeManagerD
} }
AppSetup.setupEnvironment( AppSetup.setupEnvironment(
appSpecificSingletonBlock: { appSpecificBlock: {
SSKEnvironment.shared.notificationsManager.mutate { Environment.shared.notificationsManager.mutate {
$0 = NoopNotificationsManager() $0 = NoopNotificationsManager()
} }
}, },
migrationCompletion: { [weak self] _, needsConfigSync in migrationsCompletion: { [weak self] _, needsConfigSync in
AssertIsOnMainThread()
// performUpdateCheck must be invoked after Environment has been initialized because // performUpdateCheck must be invoked after Environment has been initialized because
// upgrade process may depend on Environment. // upgrade process may depend on Environment.
self?.versionMigrationsDidComplete(needsConfigSync: needsConfigSync) self?.versionMigrationsDidComplete(needsConfigSync: needsConfigSync)

View File

@ -6,6 +6,8 @@ import SessionUtilitiesKit
enum _001_InitialSetupMigration: Migration { enum _001_InitialSetupMigration: Migration {
static let identifier: String = "initialSetup" static let identifier: String = "initialSetup"
static let minExpectedRunDuration: TimeInterval = 0.1
static let needsConfigSync: Bool = false
static func migrate(_ db: Database) throws { static func migrate(_ db: Database) throws {
try db.create(table: Snode.self) { t in try db.create(table: Snode.self) { t in

View File

@ -8,6 +8,8 @@ import SessionUtilitiesKit
/// before running the `YDBToGRDBMigration` /// before running the `YDBToGRDBMigration`
enum _002_SetupStandardJobs: Migration { enum _002_SetupStandardJobs: Migration {
static let identifier: String = "SetupStandardJobs" static let identifier: String = "SetupStandardJobs"
static let minExpectedRunDuration: TimeInterval = 0.1
static let needsConfigSync: Bool = false
static func migrate(_ db: Database) throws { static func migrate(_ db: Database) throws {
try autoreleasepool { try autoreleasepool {

View File

@ -6,6 +6,8 @@ import SessionUtilitiesKit
enum _003_YDBToGRDBMigration: Migration { enum _003_YDBToGRDBMigration: Migration {
static let identifier: String = "YDBToGRDBMigration" static let identifier: String = "YDBToGRDBMigration"
static let minExpectedRunDuration: TimeInterval = 0.2
static let needsConfigSync: Bool = false
static func migrate(_ db: Database) throws { static func migrate(_ db: Database) throws {
// MARK: - OnionRequestPath, Snode Pool & Swarm // MARK: - OnionRequestPath, Snode Pool & Swarm

View File

@ -97,9 +97,9 @@ public extension UIView {
} }
@discardableResult @discardableResult
func set(_ dimension: Dimension, to otherDimension: Dimension, of view: UIView, withOffset offset: CGFloat = 0) -> NSLayoutConstraint { func set(_ dimension: Dimension, to otherDimension: Dimension, of view: UIView, withOffset offset: CGFloat = 0, multiplier: CGFloat = 1) -> NSLayoutConstraint {
translatesAutoresizingMaskIntoConstraints = false translatesAutoresizingMaskIntoConstraints = false
let otherAnchor: NSLayoutAnchor<NSLayoutDimension> = { let otherAnchor: NSLayoutDimension = {
switch otherDimension { switch otherDimension {
case .width: return view.widthAnchor case .width: return view.widthAnchor
case .height: return view.heightAnchor case .height: return view.heightAnchor
@ -107,8 +107,8 @@ public extension UIView {
}() }()
let constraint: NSLayoutConstraint = { let constraint: NSLayoutConstraint = {
switch dimension { switch dimension {
case .width: return widthAnchor.constraint(equalTo: otherAnchor, constant: offset) case .width: return widthAnchor.constraint(equalTo: otherAnchor, multiplier: multiplier, constant: offset)
case .height: return heightAnchor.constraint(equalTo: otherAnchor, constant: offset) case .height: return heightAnchor.constraint(equalTo: otherAnchor, multiplier: multiplier, constant: offset)
} }
}() }()
constraint.isActive = true constraint.isActive = true

View File

@ -5,25 +5,8 @@ import GRDB
import PromiseKit import PromiseKit
import SignalCoreKit import SignalCoreKit
public enum GRDBStorageError: Error { // TODO: Rename to `StorageError`
case generic
case migrationFailed
case invalidKeySpec
case decodingFailed
case failedToSave
case objectNotFound
case objectNotSaved
case invalidSearchPattern
}
// TODO: Protocol for storage (just need to have 'read' and 'write' methods and mock 'Database'?
// TODO: Rename to `Storage`
public final class GRDBStorage { public final class GRDBStorage {
public static var shared: GRDBStorage! // TODO: Figure out how/if we want to do this
private static let dbFileName: String = "Session.sqlite" private static let dbFileName: String = "Session.sqlite"
private static let keychainService: String = "TSKeyChainService" private static let keychainService: String = "TSKeyChainService"
private static let dbCipherKeySpecKey: String = "GRDBDatabaseCipherKeySpec" private static let dbCipherKeySpecKey: String = "GRDBDatabaseCipherKeySpec"
@ -40,14 +23,17 @@ public final class GRDBStorage {
return true return true
} }
private let dbPool: DatabasePool public static let shared: GRDBStorage = GRDBStorage()
private let migrator: DatabaseMigrator public private(set) var isValid: Bool = false
public private(set) var hasCompletedMigrations: Bool = false
private var dbPool: DatabasePool?
private var migrator: DatabaseMigrator?
private var migrationProgressUpdater: Atomic<((String, CGFloat) -> ())>?
// MARK: - Initialization // MARK: - Initialization
public init?( public init() {
migrations: [TargetMigrations]
) throws {
print("RAWR START \("\(GRDBStorage.sharedDatabaseDirectoryPath)/\(GRDBStorage.dbFileName)")") print("RAWR START \("\(GRDBStorage.sharedDatabaseDirectoryPath)/\(GRDBStorage.dbFileName)")")
GRDBStorage.deleteDatabaseFiles() // TODO: Remove this GRDBStorage.deleteDatabaseFiles() // TODO: Remove this
try! GRDBStorage.deleteDbKeys() // TODO: Remove this try! GRDBStorage.deleteDbKeys() // TODO: Remove this
@ -76,7 +62,7 @@ public final class GRDBStorage {
// using explicit BLOB syntax, e.g.: // using explicit BLOB syntax, e.g.:
// //
// x'98483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C483648101010101010101010101010101010101' // x'98483C6EB40B6C31A448C22A66DED3B5E5E8D5119CAC8327B655C8B5C483648101010101010101010101010101010101'
keySpec = try (keySpec.toHexString().data(using: .utf8) ?? { throw GRDBStorageError.invalidKeySpec }()) keySpec = try (keySpec.toHexString().data(using: .utf8) ?? { throw StorageError.invalidKeySpec }())
keySpec.insert(contentsOf: [120, 39], at: 0) // "x'" prefix keySpec.insert(contentsOf: [120, 39], at: 0) // "x'" prefix
keySpec.append(39) // "'" suffix keySpec.append(39) // "'" suffix
@ -90,40 +76,111 @@ public final class GRDBStorage {
try db.execute(sql: "PRAGMA cipher_plaintext_header_size = 32") try db.execute(sql: "PRAGMA cipher_plaintext_header_size = 32")
} }
// Create the DatabasePool to allow us to connect to the database // Create the DatabasePool to allow us to connect to the database and mark the storage as valid
dbPool = try DatabasePool( do {
path: "\(GRDBStorage.sharedDatabaseDirectoryPath)/\(GRDBStorage.dbFileName)", dbPool = try DatabasePool(
configuration: config path: "\(GRDBStorage.sharedDatabaseDirectoryPath)/\(GRDBStorage.dbFileName)",
) configuration: config
)
isValid = true
}
catch {}
}
// MARK: - Migrations
public func perform(
migrations: [TargetMigrations],
onProgressUpdate: ((CGFloat, TimeInterval) -> ())?,
onComplete: @escaping (Bool, Bool) -> ()
) {
guard isValid, let dbPool: DatabasePool = dbPool else { return }
typealias MigrationInfo = (identifier: TargetMigrations.Identifier, migrations: TargetMigrations.MigrationSet)
let sortedMigrationInfo: [MigrationInfo] = migrations
.sorted()
.reduce(into: [[MigrationInfo]]()) { result, next in
next.migrations.enumerated().forEach { index, migrationSet in
if result.count <= index {
result.append([])
}
result[index] = (result[index] + [(next.identifier, migrationSet)])
}
}
.reduce(into: []) { result, next in result.append(contentsOf: next) }
// Setup and run any required migrations // Setup and run any required migrations
migrator = { migrator = {
var migrator: DatabaseMigrator = DatabaseMigrator() var migrator: DatabaseMigrator = DatabaseMigrator()
migrations sortedMigrationInfo.forEach { migrationInfo in
.sorted() migrationInfo.migrations.forEach { migration in
.reduce(into: [[(identifier: TargetMigrations.Identifier, migrations: TargetMigrations.MigrationSet)]]()) { result, next in migrator.registerMigration(migrationInfo.identifier, migration: migration)
next.migrations.enumerated().forEach { index, migrationSet in
if result.count <= index {
result.append([])
}
result[index] = (result[index] + [(next.identifier, migrationSet)])
}
}
.compactMap { $0 }
.forEach { sortedMigrationInfo in
sortedMigrationInfo.forEach { migrationInfo in
migrationInfo.migrations.forEach { migration in
migrator.registerMigration(migrationInfo.identifier, migration: migration)
}
}
} }
}
return migrator return migrator
}() }()
try! migrator.migrate(dbPool)
GRDBStorage.shared = self // TODO: Fix this // Determine which migrations need to be performed and gather the relevant settings needed to
// inform the app of progress/states
let completedMigrations: [String] = (try? dbPool.read { db in try migrator?.completedMigrations(db) })
.defaulting(to: [])
let unperformedMigrations: [(key: String, migration: Migration.Type)] = sortedMigrationInfo
.reduce(into: []) { result, next in
next.migrations.forEach { migration in
let key: String = next.identifier.key(with: migration)
guard !completedMigrations.contains(key) else { return }
result.append((key, migration))
}
}
let migrationToDurationMap: [String: TimeInterval] = unperformedMigrations
.reduce(into: [:]) { result, next in
result[next.key] = next.migration.minExpectedRunDuration
}
let unperformedMigrationDurations: [TimeInterval] = unperformedMigrations
.map { _, migration in migration.minExpectedRunDuration }
let totalMinExpectedDuration: TimeInterval = migrationToDurationMap.values.reduce(0, +)
let needsConfigSync: Bool = unperformedMigrations
.contains(where: { _, migration in migration.needsConfigSync })
self.migrationProgressUpdater = Atomic({ targetKey, progress in
guard let migrationIndex: Int = unperformedMigrations.firstIndex(where: { key, _ in key == targetKey }) else {
return
}
let completedExpectedDuration: TimeInterval = (
(migrationIndex > 0 ? unperformedMigrationDurations[0..<migrationIndex].reduce(0, +) : 0) +
(unperformedMigrationDurations[migrationIndex] * progress)
)
let totalProgress: CGFloat = (completedExpectedDuration / totalMinExpectedDuration)
DispatchQueue.main.async {
onProgressUpdate?(totalProgress, totalMinExpectedDuration)
}
})
// If we have an unperformed migration then trigger the progress updater immediately
if let firstMigrationKey: String = unperformedMigrations.first?.key {
self.migrationProgressUpdater?.wrappedValue(firstMigrationKey, 0)
}
self.migrator?.asyncMigrate(dbPool) { [weak self] _, error in
self?.hasCompletedMigrations = true
self?.migrationProgressUpdater = nil
onComplete((error == nil), needsConfigSync)
}
}
public func update(
progress: CGFloat,
for migration: Migration.Type,
in target: TargetMigrations.Identifier
) {
GRDBStorage.shared.migrationProgressUpdater?.wrappedValue(target.key(with: migration), progress)
} }
// MARK: - Security // MARK: - Security
@ -137,7 +194,7 @@ public final class GRDBStorage {
var keySpec: Data = try getDatabaseCipherKeySpec() var keySpec: Data = try getDatabaseCipherKeySpec()
defer { keySpec.resetBytes(in: 0..<keySpec.count) } defer { keySpec.resetBytes(in: 0..<keySpec.count) }
guard keySpec.count == kSQLCipherKeySpecLength else { throw GRDBStorageError.invalidKeySpec } guard keySpec.count == kSQLCipherKeySpecLength else { throw StorageError.invalidKeySpec }
return keySpec return keySpec
} }
@ -151,7 +208,7 @@ public final class GRDBStorage {
//errSecInteractionNotAllowed //errSecInteractionNotAllowed
case (GRDBStorageError.invalidKeySpec, _): case (StorageError.invalidKeySpec, _):
// For these cases it means either the keySpec or the keychain has become corrupt so in order to // For these cases it means either the keySpec or the keychain has become corrupt so in order to
// get back to a "known good state" and behave like a new install we need to reset the storage // get back to a "known good state" and behave like a new install we need to reset the storage
// and regenerate the key // and regenerate the key
@ -227,6 +284,8 @@ public final class GRDBStorage {
// MARK: - Functions // MARK: - Functions
@discardableResult public func write<T>(updates: (Database) throws -> T?) -> T? { @discardableResult public func write<T>(updates: (Database) throws -> T?) -> T? {
guard isValid, let dbPool: DatabasePool = dbPool else { return nil }
return try? dbPool.write(updates) return try? dbPool.write(updates)
} }
@ -235,6 +294,8 @@ public final class GRDBStorage {
} }
public func writeAsync<T>(updates: @escaping (Database) throws -> T, completion: @escaping (Database, Swift.Result<T, Error>) throws -> Void) { public func writeAsync<T>(updates: @escaping (Database) throws -> T, completion: @escaping (Database, Swift.Result<T, Error>) throws -> Void) {
guard isValid, let dbPool: DatabasePool = dbPool else { return }
dbPool.asyncWrite( dbPool.asyncWrite(
updates, updates,
completion: { db, result in completion: { db, result in
@ -244,6 +305,8 @@ public final class GRDBStorage {
} }
@discardableResult public func read<T>(_ value: (Database) throws -> T?) -> T? { @discardableResult public func read<T>(_ value: (Database) throws -> T?) -> T? {
guard isValid, let dbPool: DatabasePool = dbPool else { return nil }
return try? dbPool.read(value) return try? dbPool.read(value)
} }
@ -262,7 +325,9 @@ public final class GRDBStorage {
onError: @escaping (Error) -> Void, onError: @escaping (Error) -> Void,
onChange: @escaping (Reducer.Value) -> Void onChange: @escaping (Reducer.Value) -> Void
) -> DatabaseCancellable { ) -> DatabaseCancellable {
observation.start( guard isValid, let dbPool: DatabasePool = dbPool else { return AnyDatabaseCancellable(cancel: {}) }
return observation.start(
in: dbPool, in: dbPool,
scheduling: scheduler, scheduling: scheduler,
onError: onError, onError: onError,
@ -271,6 +336,7 @@ public final class GRDBStorage {
} }
public func addObserver(_ observer: TransactionObserver?) { public func addObserver(_ observer: TransactionObserver?) {
guard isValid, let dbPool: DatabasePool = dbPool else { return }
guard let observer: TransactionObserver = observer else { return } guard let observer: TransactionObserver = observer else { return }
dbPool.add(transactionObserver: observer) dbPool.add(transactionObserver: observer)
@ -282,6 +348,8 @@ public final class GRDBStorage {
public extension GRDBStorage { public extension GRDBStorage {
// FIXME: Would be good to replace these with Swift Combine // FIXME: Would be good to replace these with Swift Combine
@discardableResult func read<T>(_ value: (Database) throws -> Promise<T>) -> Promise<T> { @discardableResult func read<T>(_ value: (Database) throws -> Promise<T>) -> Promise<T> {
guard isValid, let dbPool: DatabasePool = dbPool else { return Promise(error: StorageError.databaseInvalid) }
do { do {
return try dbPool.read(value) return try dbPool.read(value)
} }
@ -291,6 +359,8 @@ public extension GRDBStorage {
} }
@discardableResult func write<T>(updates: (Database) throws -> Promise<T>) -> Promise<T> { @discardableResult func write<T>(updates: (Database) throws -> Promise<T>) -> Promise<T> {
guard isValid, let dbPool: DatabasePool = dbPool else { return Promise(error: StorageError.databaseInvalid) }
do { do {
return try dbPool.write(updates) return try dbPool.write(updates)
} }

View File

@ -5,6 +5,8 @@ import GRDB
enum _001_InitialSetupMigration: Migration { enum _001_InitialSetupMigration: Migration {
static let identifier: String = "initialSetup" static let identifier: String = "initialSetup"
static let minExpectedRunDuration: TimeInterval = 0.1
static let needsConfigSync: Bool = false
static func migrate(_ db: Database) throws { static func migrate(_ db: Database) throws {
try db.create(table: Identity.self) { t in try db.create(table: Identity.self) { t in

View File

@ -8,6 +8,8 @@ import Curve25519Kit
/// before running the `YDBToGRDBMigration` /// before running the `YDBToGRDBMigration`
enum _002_SetupStandardJobs: Migration { enum _002_SetupStandardJobs: Migration {
static let identifier: String = "SetupStandardJobs" static let identifier: String = "SetupStandardJobs"
static let minExpectedRunDuration: TimeInterval = 0.1
static let needsConfigSync: Bool = false
static func migrate(_ db: Database) throws { static func migrate(_ db: Database) throws {
try autoreleasepool { try autoreleasepool {

View File

@ -5,6 +5,8 @@ import GRDB
enum _003_YDBToGRDBMigration: Migration { enum _003_YDBToGRDBMigration: Migration {
static let identifier: String = "YDBToGRDBMigration" static let identifier: String = "YDBToGRDBMigration"
static let minExpectedRunDuration: TimeInterval = 0.1
static let needsConfigSync: Bool = false
static func migrate(_ db: Database) throws { static func migrate(_ db: Database) throws {
// MARK: - Identity keys // MARK: - Identity keys
@ -69,7 +71,7 @@ enum _003_YDBToGRDBMigration: Migration {
return return
} }
throw GRDBStorageError.migrationFailed throw StorageError.migrationFailed
} }
print("RAWR publicKey \(userX25519KeyPair.publicKey.toHexString())") print("RAWR publicKey \(userX25519KeyPair.publicKey.toHexString())")
try autoreleasepool { try autoreleasepool {

View File

@ -0,0 +1,17 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
public enum StorageError: Error {
case generic
case databaseInvalid
case migrationFailed
case invalidKeySpec
case decodingFailed
case failedToSave
case objectNotFound
case objectNotSaved
case invalidSearchPattern
}

View File

@ -5,6 +5,8 @@ import GRDB
public protocol Migration { public protocol Migration {
static var identifier: String { get } static var identifier: String { get }
static var needsConfigSync: Bool { get }
static var minExpectedRunDuration: TimeInterval { get }
static func migrate(_ db: Database) throws static func migrate(_ db: Database) throws
} }

View File

@ -26,6 +26,10 @@ public struct TargetMigrations: Comparable {
return (lhsIndex < rhsIndex) return (lhsIndex < rhsIndex)
} }
func key(with migration: Migration.Type) -> String {
return "\(self.rawValue).\(migration.identifier)"
}
} }
public typealias MigrationSet = [Migration.Type] public typealias MigrationSet = [Migration.Type]

View File

@ -3,8 +3,6 @@ import SessionSnodeKit
extension OWSPrimaryStorage : OWSPrimaryStorageProtocol { } extension OWSPrimaryStorage : OWSPrimaryStorageProtocol { }
var isSetup: Bool = false // TODO: Remove this
@objc(SNConfiguration) @objc(SNConfiguration)
public final class Configuration : NSObject { public final class Configuration : NSObject {
@ -19,21 +17,4 @@ public final class Configuration : NSObject {
SNMessagingKit.configure(storage: Storage.shared) SNMessagingKit.configure(storage: Storage.shared)
SNSnodeKit.configure() SNSnodeKit.configure()
} }
@objc public static func performDatabaseSetup() {
if !isSetup {
isSetup = true
// TODO: Need to store this result somewhere?
// TODO: This function seems to get called multiple times
//DispatchQueue.main.once
let storage: GRDBStorage? = try? GRDBStorage(
migrations: [
SNUtilitiesKit.migrations(),
SNSnodeKit.migrations(),
SNMessagingKit.migrations()
]
)
}
}
} }

View File

@ -1,17 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
typedef void (^OWSDatabaseMigrationCompletion)(BOOL success, BOOL requiresConfigurationSync);
// This is _NOT_ a singleton and will be instantiated each time that the SAE is used.
@interface AppSetup : NSObject
+ (void)setupEnvironmentWithAppSpecificSingletonBlock:(dispatch_block_t)appSpecificSingletonBlock
migrationCompletion:(OWSDatabaseMigrationCompletion)migrationCompletion;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,93 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "AppSetup.h"
#import "Environment.h"
#import "VersionMigrations.h"
#import <SignalUtilitiesKit/OWSDatabaseMigration.h>
#import <SessionMessagingKit/OWSBackgroundTask.h>
#import <SessionMessagingKit/OWSStorage.h>
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
NS_ASSUME_NONNULL_BEGIN
@implementation AppSetup
+ (void)setupEnvironmentWithAppSpecificSingletonBlock:(dispatch_block_t)appSpecificSingletonBlock
migrationCompletion:(OWSDatabaseMigrationCompletion)migrationCompletion
{
OWSAssertDebug(appSpecificSingletonBlock);
OWSAssertDebug(migrationCompletion);
__block OWSBackgroundTask *_Nullable backgroundTask =
[OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Order matters here.
//
// All of these "singletons" should have any dependencies used in their
// initializers injected.
[[OWSBackgroundTaskManager sharedManager] observeNotifications];
OWSPrimaryStorage *primaryStorage = [[OWSPrimaryStorage alloc] initStorage];
[OWSPrimaryStorage protectFiles];
// AFNetworking (via CFNetworking) spools it's attachments to NSTemporaryDirectory().
// If you receive a media message while the device is locked, the download will fail if the temporary directory
// is NSFileProtectionComplete
BOOL success = [OWSFileSystem protectFileOrFolderAtPath:NSTemporaryDirectory()
fileProtectionType:NSFileProtectionCompleteUntilFirstUserAuthentication];
OWSAssert(success);
OWSPreferences *preferences = [OWSPreferences new];
id<SSKReachabilityManager> reachabilityManager = [SSKReachabilityManagerImpl new];
OWSAudioSession *audioSession = [OWSAudioSession new];
id<OWSProximityMonitoringManager> proximityMonitoringManager = [OWSProximityMonitoringManagerImpl new];
OWSWindowManager *windowManager = [[OWSWindowManager alloc] initDefault];
[Environment setShared:[[Environment alloc] initWithAudioSession:audioSession
preferences:preferences
proximityMonitoringManager:proximityMonitoringManager
windowManager:windowManager]];
// TODO: Add this back
// TODO: Refactor this file to Swift
[SSKEnvironment setShared:[[SSKEnvironment alloc] initWithPrimaryStorage:primaryStorage
reachabilityManager:reachabilityManager]];
appSpecificSingletonBlock();
// TODO: Add this back?
// OWSAssertDebug(SSKEnvironment.shared.isComplete);
[SNConfiguration performMainSetup]; // Must happen before the performUpdateCheck call below
// Register renamed classes.
[NSKeyedUnarchiver setClass:[OWSDatabaseMigration class] forClassName:[OWSDatabaseMigration collection]];
[OWSStorage registerExtensionsWithMigrationBlock:^() {
dispatch_async(dispatch_get_main_queue(), ^{
// Don't start database migrations until storage is ready.
[VersionMigrations performUpdateCheckWithCompletion:^(BOOL successful, BOOL needsConfigSync) {
OWSAssertIsOnMainThread();
migrationCompletion(successful, needsConfigSync);
OWSAssertDebug(backgroundTask);
backgroundTask = nil;
}];
});
}];
// Must happen after the performUpdateCheck above to ensure all legacy database migrations have run
[SNConfiguration performDatabaseSetup];
});
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,71 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import SessionMessagingKit
import SessionUtilitiesKit
import UIKit
public enum AppSetup {
private static var hasRun: Bool = false
public static func setupEnvironment(
appSpecificBlock: @escaping () -> (),
migrationProgressChanged: ((CGFloat, TimeInterval) -> ())? = nil,
migrationsCompletion: @escaping (Bool, Bool) -> ()
) {
guard !AppSetup.hasRun else { return }
AppSetup.hasRun = true
var backgroundTask: OWSBackgroundTask? = OWSBackgroundTask(labelStr: #function)
DispatchQueue.global(qos: .userInitiated).async {
// Order matters here.
//
// All of these "singletons" should have any dependencies used in their
// initializers injected.
OWSBackgroundTaskManager.shared().observeNotifications()
let primaryStorage: OWSPrimaryStorage = OWSPrimaryStorage(storage: ())
OWSPrimaryStorage.protectFiles()
// AFNetworking (via CFNetworking) spools it's attachments to NSTemporaryDirectory().
// If you receive a media message while the device is locked, the download will fail if the temporary directory
// is NSFileProtectionComplete
let success: Bool = OWSFileSystem.protectFileOrFolder(
atPath: NSTemporaryDirectory(),
fileProtectionType: .completeUntilFirstUserAuthentication
)
assert(success)
Environment.shared = Environment(
primaryStorage: primaryStorage,
reachabilityManager: SSKReachabilityManagerImpl(),
audioSession: OWSAudioSession(),
preferences: OWSPreferences(),
proximityMonitoringManager: OWSProximityMonitoringManagerImpl(),
windowManager: OWSWindowManager(default: ())
)
appSpecificBlock()
/// `performMainSetup` **MUST** run before `perform(migrations:)`
Configuration.performMainSetup()
GRDBStorage.shared.perform(
migrations: [
SNUtilitiesKit.migrations(),
SNSnodeKit.migrations(),
SNMessagingKit.migrations()
],
onProgressUpdate: migrationProgressChanged,
onComplete: { success, needsConfigSync in
DispatchQueue.main.async {
migrationsCompletion(success, needsConfigSync)
// The 'if' is only there to prevent the "variable never read" warning from showing
if backgroundTask != nil { backgroundTask = nil }
}
}
)
}
}
}

View File

@ -1,25 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
#define RECENT_CALLS_DEFAULT_KEY @"RPRecentCallsDefaultKey"
typedef void (^VersionMigrationCompletion)(BOOL success, BOOL requiresConfigurationSync);
@interface VersionMigrations : NSObject
+ (void)performUpdateCheckWithCompletion:(VersionMigrationCompletion)completion;
+ (BOOL)isVersion:(NSString *)thisVersionString
atLeast:(NSString *)openLowerBoundVersionString
andLessThan:(NSString *)closedUpperBoundVersionString;
+ (BOOL)isVersion:(NSString *)thisVersionString atLeast:(NSString *)thatVersionString;
+ (BOOL)isVersion:(NSString *)thisVersionString lessThan:(NSString *)thatVersionString;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,126 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "VersionMigrations.h"
#import "OWSDatabaseMigrationRunner.h"
#import <SessionUtilitiesKit/AppContext.h>
#import <SignalUtilitiesKit/AppVersion.h>
#import <SessionUtilitiesKit/NSUserDefaults+OWS.h>
#import <YapDatabase/YapDatabase.h>
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
NS_ASSUME_NONNULL_BEGIN
#define NEEDS_TO_REGISTER_PUSH_KEY @"Register For Push"
#define NEEDS_TO_REGISTER_ATTRIBUTES @"Register Attributes"
@implementation VersionMigrations
#pragma mark - Utility methods
+ (void)performUpdateCheckWithCompletion:(VersionMigrationCompletion)completion
{
OWSLogInfo(@"");
// performUpdateCheck must be invoked after Environment has been initialized because
// upgrade process may depend on Environment.
OWSAssertDebug(Environment.shared);
OWSAssertDebug(completion);
NSString *previousVersion = AppVersion.sharedInstance.lastAppVersion;
NSString *currentVersion = AppVersion.sharedInstance.currentAppVersion;
OWSLogInfo(@"Checking migrations. currentVersion: %@, lastRanVersion: %@", currentVersion, previousVersion);
if (!previousVersion) {
// Note: We need to run the migrations here anyway to ensure that they don't run on subsequent launches
// and result in unexpected data changes (eg. 'MessageRequestsMigration' auto-approves all threads
// if this happens on the 2nd launch then any threads created during the 1st launch which haven't
// been approved would get auto-approved, allowing the user to use contacts which haven't approved
// comms to appear as options when creating closed groups)
OWSLogInfo(@"No previous version found. Probably first launch since install - running migrations so they don't run on second launch.");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[[OWSDatabaseMigrationRunner alloc] init] runAllOutstandingWithCompletion:completion];
});
return;
}
if ([self isVersion:previousVersion atLeast:@"2.0.0" andLessThan:@"2.1.70"] && [SUKIdentity userExists]) {
[self clearVideoCache];
}
if ([self isVersion:previousVersion atLeast:@"2.0.0" andLessThan:@"2.3.0"] && [SUKIdentity userExists]) {
[self clearBloomFilterCache];
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[[OWSDatabaseMigrationRunner alloc] init] runAllOutstandingWithCompletion:completion];
});
}
+ (BOOL)isVersion:(NSString *)thisVersionString
atLeast:(NSString *)openLowerBoundVersionString
andLessThan:(NSString *)closedUpperBoundVersionString
{
return [self isVersion:thisVersionString atLeast:openLowerBoundVersionString] &&
[self isVersion:thisVersionString lessThan:closedUpperBoundVersionString];
}
+ (BOOL)isVersion:(NSString *)thisVersionString atLeast:(NSString *)thatVersionString
{
return [thisVersionString compare:thatVersionString options:NSNumericSearch] != NSOrderedAscending;
}
+ (BOOL)isVersion:(NSString *)thisVersionString lessThan:(NSString *)thatVersionString
{
return [thisVersionString compare:thatVersionString options:NSNumericSearch] == NSOrderedAscending;
}
#pragma mark Upgrading to 2.1 - Removing video cache folder
+ (void)clearVideoCache
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
basePath = [basePath stringByAppendingPathComponent:@"videos"];
NSError *error;
if ([[NSFileManager defaultManager] fileExistsAtPath:basePath]) {
[NSFileManager.defaultManager removeItemAtPath:basePath error:&error];
}
if (error) {
OWSLogError(
@"An error occured while removing the videos cache folder from old location: %@", error.debugDescription);
}
}
#pragma mark Upgrading to 2.3.0
// We removed bloom filter contact discovery. Clean up any local bloom filter data.
+ (void)clearBloomFilterCache
{
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *cachesDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *bloomFilterPath = [[cachesDir objectAtIndex:0] stringByAppendingPathComponent:@"bloomfilter"];
if ([fm fileExistsAtPath:bloomFilterPath]) {
NSError *deleteError;
if ([fm removeItemAtPath:bloomFilterPath error:&deleteError]) {
OWSLogInfo(@"Successfully removed bloom filter cache.");
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
[transaction removeAllObjectsInCollection:@"TSRecipient"];
}];
} else {
OWSLogError(@"Failed to remove bloom filter cache with error: %@", deleteError.localizedDescription);
}
} else {
OWSLogDebug(@"No bloom filter cache to remove.");
}
}
@end
NS_ASSUME_NONNULL_END