diff --git a/Session/Conversations/ConversationViewModel.swift b/Session/Conversations/ConversationViewModel.swift index f822f7096..010865127 100644 --- a/Session/Conversations/ConversationViewModel.swift +++ b/Session/Conversations/ConversationViewModel.swift @@ -396,11 +396,11 @@ public class ConversationViewModel: OWSAudioPlayerDelegate { /// write queue when it isn't needed, in order to do this we: /// /// - Don't bother marking anything as read if there are no unread interactions (we can rely on the - /// `threadData.threadUnreadCount` to always be accurate) + /// `threadData.threadHasUnreadMessagesOfAnyKind` to always be accurate) /// - Don't bother marking anything as read if this was called with the same `interactionId` that we /// previously marked as read (ie. when scrolling and the last message hasn't changed) guard - (self.threadData.threadUnreadCount ?? 0) > 0, + self.threadData.threadHasUnreadMessagesOfAnyKind == true, let targetInteractionId: Int64 = (interactionId ?? self.threadData.interactionId), self.lastInteractionIdMarkedAsRead != targetInteractionId else { return } diff --git a/SessionMessagingKit/Database/Models/Interaction.swift b/SessionMessagingKit/Database/Models/Interaction.swift index 172f6f271..3ec5c31ac 100644 --- a/SessionMessagingKit/Database/Models/Interaction.swift +++ b/SessionMessagingKit/Database/Models/Interaction.swift @@ -102,11 +102,11 @@ public struct Interaction: Codable, Identifiable, Equatable, FetchableRecord, Mu switch self { case .standardIncoming: return true case .infoCall: return true + case .infoDisappearingMessagesUpdate, .infoScreenshotNotification, .infoMediaSavedNotification: return true // Won't be count as unread messages case .standardOutgoing, .standardIncomingDeleted: return false case .infoClosedGroupCreated, .infoClosedGroupUpdated, .infoClosedGroupCurrentUserLeft, - .infoDisappearingMessagesUpdate, .infoScreenshotNotification, .infoMediaSavedNotification, .infoMessageRequestAccepted: return false } @@ -559,23 +559,11 @@ public extension Interaction { .asRequest(of: Int64.self) .fetchAll(db) - let disappearingInteractionQuery = Interaction - .filter(Interaction.Columns.threadId == threadId) - .filter(Interaction.Columns.timestampMs <= interactionInfo.timestampMs) - .filter(Interaction.Columns.wasRead == true) - .filter(Interaction.Columns.expiresInSeconds != nil) - .filter(Interaction.Columns.expiresStartedAtMs == nil) - - let disappearingInteractionIds: [Int64] = try disappearingInteractionQuery - .select(.id) - .asRequest(of: Int64.self) - .fetchAll(db) - // If there are no other interactions to mark as read then just schedule the jobs // for this interaction (need to ensure the disapeparing messages run for sync'ed // outgoing messages which will always have 'wasRead' as false) guard !interactionIdsToMarkAsRead.isEmpty else { - scheduleJobs(interactionIds: [interactionId].appending(contentsOf: disappearingInteractionIds)) + scheduleJobs(interactionIds: [interactionId]) return } @@ -583,7 +571,7 @@ public extension Interaction { try interactionQuery.updateAll(db, Columns.wasRead.set(to: true)) // Retrieve the interaction ids we want to update - scheduleJobs(interactionIds: interactionIdsToMarkAsRead.appending(contentsOf: disappearingInteractionIds)) + scheduleJobs(interactionIds: interactionIdsToMarkAsRead) } /// This method flags sent messages as read for the specified recipients diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index 51ca714c2..39a64106d 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -356,9 +356,8 @@ public enum MessageReceiver { lastChangeTimestampMs: protoLastChangeTimestampMs ) - let expireInSeconds: TimeInterval? = (remoteConfig.isEnabled && message.openGroupServerMessageId == nil) ? remoteConfig.durationSeconds : nil - let expiresStartedAtMs: Double? = (remoteConfig.isEnabled && remoteConfig.type == .disappearAfterSend) ? Double(message.sentTimestamp ?? 0) : nil - + _ = try remoteConfig.save(db) + _ = try Interaction( serverHash: nil, // Intentionally null so sync messages are seen as duplicates threadId: threadId, @@ -371,12 +370,8 @@ public enum MessageReceiver { ), isPreviousOff: !localConfig.isEnabled ), - timestampMs: protoLastChangeTimestampMs, - expiresInSeconds: expireInSeconds, - expiresStartedAtMs: expiresStartedAtMs + timestampMs: protoLastChangeTimestampMs ).inserted(db) - - try remoteConfig.save(db) } internal static func updateProfileIfNeeded( diff --git a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift index aff2aa54f..51ff3aaec 100644 --- a/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift +++ b/SessionMessagingKit/Shared Models/SessionThreadViewModel.swift @@ -32,6 +32,7 @@ public struct SessionThreadViewModel: FetchableRecordWithRowId, Decodable, Equat public static let threadContactIsTypingKey: SQL = SQL(stringLiteral: CodingKeys.threadContactIsTyping.stringValue) public static let threadUnreadCountKey: SQL = SQL(stringLiteral: CodingKeys.threadUnreadCount.stringValue) public static let threadUnreadMentionCountKey: SQL = SQL(stringLiteral: CodingKeys.threadUnreadMentionCount.stringValue) + public static let threadHasUnreadMessagesOfAnyKindKey: SQL = SQL(stringLiteral: CodingKeys.threadHasUnreadMessagesOfAnyKind.stringValue) public static let disappearingMessagesConfigurationKey: SQL = SQL(stringLiteral: CodingKeys.disappearingMessagesConfiguration.stringValue) public static let contactProfileKey: SQL = SQL(stringLiteral: CodingKeys.contactProfile.stringValue) public static let closedGroupNameKey: SQL = SQL(stringLiteral: CodingKeys.closedGroupName.stringValue) @@ -63,6 +64,7 @@ public struct SessionThreadViewModel: FetchableRecordWithRowId, Decodable, Equat public static let threadUnreadCountString: String = CodingKeys.threadUnreadCount.stringValue public static let threadUnreadMentionCountString: String = CodingKeys.threadUnreadMentionCount.stringValue + public static let threadHasUnreadMessagesOfAnyKindString: String = CodingKeys.threadHasUnreadMessagesOfAnyKind.stringValue public static let closedGroupUserCountString: String = CodingKeys.closedGroupUserCount.stringValue public static let openGroupUserCountString: String = CodingKeys.openGroupUserCount.stringValue public static let disappearingMessagesConfigurationString: String = CodingKeys.disappearingMessagesConfiguration.stringValue @@ -98,6 +100,7 @@ public struct SessionThreadViewModel: FetchableRecordWithRowId, Decodable, Equat public let threadContactIsTyping: Bool? public let threadUnreadCount: UInt? public let threadUnreadMentionCount: UInt? + public let threadHasUnreadMessagesOfAnyKind: Bool? public var canWrite: Bool { switch threadVariant { @@ -246,6 +249,7 @@ public extension SessionThreadViewModel { contactProfile: Profile? = nil, currentUserIsClosedGroupMember: Bool? = nil, unreadCount: UInt = 0, + hasUnreadMessagesOfAnyKind: Bool = false, disappearingMessagesConfiguration: DisappearingMessagesConfiguration? = nil ) { self.rowId = -1 @@ -267,6 +271,7 @@ public extension SessionThreadViewModel { self.threadContactIsTyping = nil self.threadUnreadCount = unreadCount self.threadUnreadMentionCount = nil + self.threadHasUnreadMessagesOfAnyKind = hasUnreadMessagesOfAnyKind // Thread display info @@ -333,6 +338,7 @@ public extension SessionThreadViewModel { threadContactIsTyping: self.threadContactIsTyping, threadUnreadCount: self.threadUnreadCount, threadUnreadMentionCount: self.threadUnreadMentionCount, + threadHasUnreadMessagesOfAnyKind: self.threadHasUnreadMessagesOfAnyKind, disappearingMessagesConfiguration: self.disappearingMessagesConfiguration, contactProfile: self.contactProfile, closedGroupProfileFront: self.closedGroupProfileFront, @@ -388,6 +394,7 @@ public extension SessionThreadViewModel { threadContactIsTyping: self.threadContactIsTyping, threadUnreadCount: self.threadUnreadCount, threadUnreadMentionCount: self.threadUnreadMentionCount, + threadHasUnreadMessagesOfAnyKind: self.threadHasUnreadMessagesOfAnyKind, disappearingMessagesConfiguration: self.disappearingMessagesConfiguration, contactProfile: self.contactProfile, closedGroupProfileFront: self.closedGroupProfileFront, @@ -472,7 +479,7 @@ public extension SessionThreadViewModel { /// parse and might throw /// /// Explicitly set default values for the fields ignored for search results - let numColumnsBeforeProfiles: Int = 12 + let numColumnsBeforeProfiles: Int = 13 let numColumnsBetweenProfilesAndAttachmentInfo: Int = 11 // The attachment info columns will be combined let request: SQLRequest = """ @@ -491,6 +498,7 @@ public extension SessionThreadViewModel { (\(typingIndicator[.threadId]) IS NOT NULL) AS \(ViewModel.threadContactIsTypingKey), \(Interaction.self).\(ViewModel.threadUnreadCountKey), \(Interaction.self).\(ViewModel.threadUnreadMentionCountKey), + \(Interaction.self).\(ViewModel.threadHasUnreadMessagesOfAnyKindKey), \(ViewModel.contactProfileKey).*, \(ViewModel.closedGroupProfileFrontKey).*, @@ -537,8 +545,9 @@ public extension SessionThreadViewModel { \(interaction[.authorId]), \(interaction[.linkPreviewUrl]), - SUM(\(interaction[.wasRead]) = false) AS \(ViewModel.threadUnreadCountKey), - SUM(\(interaction[.wasRead]) = false AND \(interaction[.hasMention]) = true) AS \(ViewModel.threadUnreadMentionCountKey) + SUM(\(interaction[.wasRead]) = false AND \(interaction[.variant]) IN (\(Interaction.Variant.standardIncoming), \(Interaction.Variant.infoCall))) AS \(ViewModel.threadUnreadCountKey), + SUM(\(interaction[.wasRead]) = false AND \(interaction[.hasMention]) = true) AS \(ViewModel.threadUnreadMentionCountKey), + (SUM(\(interaction[.wasRead]) = false) > 0) AS \(ViewModel.threadHasUnreadMessagesOfAnyKindKey) FROM \(Interaction.self) WHERE \(SQL("\(interaction[.variant]) != \(Interaction.Variant.standardIncomingDeleted)")) @@ -733,7 +742,7 @@ public extension SessionThreadViewModel { /// parse and might throw /// /// Explicitly set default values for the fields ignored for search results - let numColumnsBeforeProfiles: Int = 14 + let numColumnsBeforeProfiles: Int = 15 let request: SQLRequest = """ SELECT \(thread.alias[Column.rowID]) AS \(ViewModel.rowIdKey), @@ -760,6 +769,7 @@ public extension SessionThreadViewModel { \(thread[.messageDraft]) AS \(ViewModel.threadMessageDraftKey), \(Interaction.self).\(ViewModel.threadUnreadCountKey), + \(Interaction.self).\(ViewModel.threadHasUnreadMessagesOfAnyKindKey), \(ViewModel.disappearingMessagesConfigurationKey).*, @@ -788,7 +798,8 @@ public extension SessionThreadViewModel { \(interaction[.threadId]), MAX(\(interaction[.timestampMs])), - SUM(\(interaction[.wasRead]) = false) AS \(ViewModel.threadUnreadCountKey) + SUM(\(interaction[.wasRead]) = false AND \(interaction[.variant]) IN (\(Interaction.Variant.standardIncoming), \(Interaction.Variant.infoCall))) AS \(ViewModel.threadUnreadCountKey), + (SUM(\(interaction[.wasRead]) = false) > 0) AS \(ViewModel.threadHasUnreadMessagesOfAnyKindKey) FROM \(Interaction.self) WHERE \(SQL("\(interaction[.threadId]) = \(threadId)"))