diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 1cdcc7965..c568bb312 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -644,6 +644,7 @@ FD245C6B2850667400B966DD /* VisibleMessage+Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5B12554AF9800555489 /* VisibleMessage+Profile.swift */; }; FD245C6C2850669200B966DD /* MessageReceiveJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352A31225574F5200338F3E /* MessageReceiveJob.swift */; }; FD245C6D285066A400B966DD /* NotifyPushServerJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352A32E2557549C00338F3E /* NotifyPushServerJob.swift */; }; + FD37EA0D28AB2A45003AE748 /* _005_FixDeletedMessageReadState.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD37EA0C28AB2A45003AE748 /* _005_FixDeletedMessageReadState.swift */; }; FD3AABE928306BBD00E5099A /* ThreadPickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3AABE828306BBD00E5099A /* ThreadPickerViewModel.swift */; }; FD3C905C27E3FBEF00CD579F /* BatchRequestInfoSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3C905B27E3FBEF00CD579F /* BatchRequestInfoSpec.swift */; }; FD3C906027E410F700CD579F /* FileUploadResponseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3C905F27E410F700CD579F /* FileUploadResponseSpec.swift */; }; @@ -1683,6 +1684,7 @@ FD245C612850664300B966DD /* Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; FD28A4F327EA79F800FF65E7 /* BlockListUIUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockListUIUtils.swift; sourceTree = ""; }; FD28A4F527EAD44C00FF65E7 /* Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = ""; }; + FD37EA0C28AB2A45003AE748 /* _005_FixDeletedMessageReadState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _005_FixDeletedMessageReadState.swift; sourceTree = ""; }; FD3AABE828306BBD00E5099A /* ThreadPickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadPickerViewModel.swift; sourceTree = ""; }; FD3C905B27E3FBEF00CD579F /* BatchRequestInfoSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchRequestInfoSpec.swift; sourceTree = ""; }; FD3C905F27E410F700CD579F /* FileUploadResponseSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileUploadResponseSpec.swift; sourceTree = ""; }; @@ -3454,6 +3456,7 @@ FDF0B7412804EA4F004C14C5 /* _002_SetupStandardJobs.swift */, FD17D79827F40AB800122BE0 /* _003_YDBToGRDBMigration.swift */, FDF40CDD2897A1BC006A0CC4 /* _004_RemoveLegacyYDB.swift */, + FD37EA0C28AB2A45003AE748 /* _005_FixDeletedMessageReadState.swift */, ); path = Migrations; sourceTree = ""; @@ -5191,6 +5194,7 @@ FD716E682850318E00C96BF4 /* CallMode.swift in Sources */, FD09799527FE7B8E00936362 /* Interaction.swift in Sources */, FD5C72FF284F0F120029977D /* MessageReceiver+ConfigurationMessages.swift in Sources */, + FD37EA0D28AB2A45003AE748 /* _005_FixDeletedMessageReadState.swift in Sources */, FDC4380927B31D4E00C60D73 /* OpenGroupAPIError.swift in Sources */, FDC4382027B36ADC00C60D73 /* SOGSEndpoint.swift in Sources */, FDC438C927BB706500C60D73 /* SendDirectMessageRequest.swift in Sources */, diff --git a/Session/Meta/AppDelegate.swift b/Session/Meta/AppDelegate.swift index fca92e62e..3bbff0213 100644 --- a/Session/Meta/AppDelegate.swift +++ b/Session/Meta/AppDelegate.swift @@ -435,6 +435,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD return try Interaction .filter(Interaction.Columns.wasRead == false) + .filter( + // Exclude outgoing and deleted messages from the count + Interaction.Columns.variant != Interaction.Variant.standardOutgoing && + Interaction.Columns.variant != Interaction.Variant.standardIncomingDeleted + ) .filter( // Only count mentions if 'onlyNotifyForMentions' is set thread[.onlyNotifyForMentions] == false || diff --git a/SessionMessagingKit/Configuration.swift b/SessionMessagingKit/Configuration.swift index 22a726c2e..928133641 100644 --- a/SessionMessagingKit/Configuration.swift +++ b/SessionMessagingKit/Configuration.swift @@ -15,6 +15,9 @@ public enum SNMessagingKit { // Just to make the external API nice ], [ _004_RemoveLegacyYDB.self + ], + [ + _005_FixDeletedMessageReadState.self ] ] ) diff --git a/SessionMessagingKit/Database/Migrations/_005_FixDeletedMessageReadState.swift b/SessionMessagingKit/Database/Migrations/_005_FixDeletedMessageReadState.swift new file mode 100644 index 000000000..65e68507c --- /dev/null +++ b/SessionMessagingKit/Database/Migrations/_005_FixDeletedMessageReadState.swift @@ -0,0 +1,25 @@ +// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. + +import Foundation +import GRDB +import SessionUtilitiesKit + +/// This migration fixes a bug where certain message variants could incorrectly be counted as unread messages +enum _005_FixDeletedMessageReadState: Migration { + static let target: TargetMigrations.Identifier = .messagingKit + static let identifier: String = "FixDeletedMessageReadState" + static let needsConfigSync: Bool = false + static let minExpectedRunDuration: TimeInterval = 0.1 + + static func migrate(_ db: Database) throws { + _ = try Interaction + .filter( + Interaction.Columns.variant == Interaction.Variant.standardIncomingDeleted || + Interaction.Columns.variant == Interaction.Variant.standardOutgoing || + Interaction.Columns.variant == Interaction.Variant.infoDisappearingMessagesUpdate + ) + .updateAll(db, Interaction.Columns.wasRead.set(to: true)) + + Storage.update(progress: 1, for: self, in: target) // In case this is the last migration + } +} diff --git a/SessionMessagingKit/Database/Models/DisappearingMessageConfiguration.swift b/SessionMessagingKit/Database/Models/DisappearingMessageConfiguration.swift index 6d4b1cfbc..689162b2f 100644 --- a/SessionMessagingKit/Database/Models/DisappearingMessageConfiguration.swift +++ b/SessionMessagingKit/Database/Models/DisappearingMessageConfiguration.swift @@ -208,7 +208,7 @@ public class SMKDisappearingMessagesConfiguration: NSObject { body: config.messageInfoString(with: nil), timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000)) ) - .saved(db) + .inserted(db) try MessageSender.send( db, diff --git a/SessionMessagingKit/Database/Models/Interaction.swift b/SessionMessagingKit/Database/Models/Interaction.swift index 238816699..d94708b0d 100644 --- a/SessionMessagingKit/Database/Models/Interaction.swift +++ b/SessionMessagingKit/Database/Models/Interaction.swift @@ -262,7 +262,7 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu self.body = body self.timestampMs = timestampMs self.receivedAtTimestampMs = receivedAtTimestampMs - self.wasRead = wasRead + self.wasRead = (wasRead && variant.canBeUnread) self.hasMention = hasMention self.expiresInSeconds = expiresInSeconds self.expiresStartedAtMs = expiresStartedAtMs @@ -304,7 +304,7 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu default: return timestampMs } }() - self.wasRead = wasRead + self.wasRead = (wasRead && variant.canBeUnread) self.hasMention = hasMention self.expiresInSeconds = expiresInSeconds self.expiresStartedAtMs = expiresStartedAtMs @@ -497,8 +497,6 @@ public extension Interaction { .filter(Interaction.Columns.threadId == threadId) .filter(Interaction.Columns.timestampMs <= interactionInfo.timestampMs) .filter(Interaction.Columns.wasRead == false) - // The `wasRead` flag doesn't apply to `standardOutgoing` or `standardIncomingDeleted` - .filter(Columns.variant != Variant.standardOutgoing && Columns.variant != Variant.standardIncomingDeleted) let interactionIdsToMarkAsRead: [Int64] = try interactionQuery .select(.id) .asRequest(of: Int64.self) @@ -600,7 +598,7 @@ public extension Interaction { body: nil, timestampMs: timestampMs, receivedAtTimestampMs: receivedAtTimestampMs, - wasRead: wasRead, + wasRead: (wasRead && Variant.standardIncomingDeleted.canBeUnread), hasMention: hasMention, expiresInSeconds: expiresInSeconds, expiresStartedAtMs: expiresStartedAtMs, diff --git a/SessionMessagingKit/Database/Models/OpenGroup.swift b/SessionMessagingKit/Database/Models/OpenGroup.swift index b9a879e07..d2aae5f69 100644 --- a/SessionMessagingKit/Database/Models/OpenGroup.swift +++ b/SessionMessagingKit/Database/Models/OpenGroup.swift @@ -241,7 +241,7 @@ public class SMKOpenGroup: NSObject { .fetchOne(db), linkPreviewUrl: urlString ) - .saved(db) + .inserted(db) try MessageSender.send( db, diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Calls.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Calls.swift index de74c53f7..8dc60c126 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Calls.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Calls.swift @@ -193,6 +193,7 @@ extension MessageReceiver { ) ) .inserted(db) + try MessageSender .sendNonDurably( db, diff --git a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift index bb78b6940..58e07f7e5 100644 --- a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift +++ b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift @@ -346,6 +346,8 @@ public extension SessionThreadViewModel { // MARK: --SessionThreadViewModel public extension SessionThreadViewModel { + /// **Note:** This query **will not** include deleted incoming messages in it's unread count (they should never be marked as unread + /// but including this warning just in case there is a discrepancy) static func baseQuery( userPublicKey: String, filterSQL: SQL, @@ -610,6 +612,8 @@ public extension SessionThreadViewModel { // MARK: - ConversationVC public extension SessionThreadViewModel { + /// **Note:** This query **will** include deleted incoming messages in it's unread count (they should never be marked as unread + /// but including this warning just in case there is a discrepancy) static func conversationQuery(threadId: String, userPublicKey: String) -> AdaptedFetchRequest> { let thread: TypedTableAlias = TypedTableAlias() let contact: TypedTableAlias = TypedTableAlias()