Merge remote-tracking branch 'upstream/dev' into fix/rework-recipient-state

pull/1047/head
Morgan Pretty 7 months ago
commit 7f069263e2

@ -927,7 +927,33 @@ extension ConversationVC:
dismissOnConfirm: false // Custom dismissal logic
) { [weak self] _ in
dependencies.storage.writeAsync { db in
try messageDisappearingConfig.save(db)
let userPublicKey: String = getUserHexEncodedPublicKey(db, using: dependencies)
let currentTimestampMs: Int64 = SnodeAPI.currentOffsetTimestampMs()
let interactionId = try messageDisappearingConfig
.saved(db)
.insertControlMessage(
db,
threadVariant: cellViewModel.threadVariant,
authorId: userPublicKey,
timestampMs: currentTimestampMs,
serverHash: nil,
serverExpirationTimestamp: nil
)
let expirationTimerUpdateMessage: ExpirationTimerUpdate = ExpirationTimerUpdate()
.with(sentTimestamp: UInt64(currentTimestampMs))
.with(messageDisappearingConfig)
try MessageSender.send(
db,
message: expirationTimerUpdateMessage,
interactionId: interactionId,
threadId: cellViewModel.threadId,
threadVariant: cellViewModel.threadVariant,
using: dependencies
)
try LibSession
.update(
db,

@ -535,9 +535,8 @@ class ThreadSettingsViewModel: SessionTableViewModel, NavigationItemSource, Navi
dependencies.storage.write { db in
try SessionThread.deleteOrLeave(
db,
type: .leaveGroupAsync,
threadId: threadViewModel.threadId,
threadVariant: threadViewModel.threadVariant,
groupLeaveType: .standard,
calledFromConfigHandling: false
)
}

@ -204,22 +204,20 @@ class MessageRequestsViewModel: SessionTableViewModel, NavigatableStateHolder, O
// Remove the one-to-one requests
try SessionThread.deleteOrLeave(
db,
type: .hideContactConversationAndDeleteContent,
threadIds: threadInfo
.filter { _, variant in variant == .contact }
.map { id, _ in id },
threadVariant: .contact,
groupLeaveType: .silent,
calledFromConfigHandling: false
)
// Remove the group requests
try SessionThread.deleteOrLeave(
db,
type: .deleteGroupAndContent,
threadIds: threadInfo
.filter { _, variant in variant == .legacyGroup || variant == .group }
.map { id, _ in id },
threadVariant: .group,
groupLeaveType: .silent,
calledFromConfigHandling: false
)
}

@ -148,7 +148,7 @@ struct EnterAccountIdScreen: View {
)
) {
ZStack {
Text("\("messageNewDescriptionMobile".localized())\(Image(systemName: "questionmark.circle"))")
(Text("messageNewDescriptionMobile".localized()) + Text(Image(systemName: "questionmark.circle")))
.font(.system(size: Values.verySmallFontSize))
.foregroundColor(themeColor: .textSecondary)
.multilineTextAlignment(.center)

@ -140,9 +140,8 @@ public extension UIContextualAction {
Storage.shared.writeAsync { db in
try SessionThread.deleteOrLeave(
db,
type: .hideContactConversationAndDeleteContent,
threadId: threadViewModel.threadId,
threadVariant: threadViewModel.threadVariant,
groupLeaveType: .silent,
calledFromConfigHandling: false
)
}
@ -187,9 +186,8 @@ public extension UIContextualAction {
Storage.shared.writeAsync { db in
try SessionThread.deleteOrLeave(
db,
type: .hideContactConversationAndDeleteContent,
threadId: threadViewModel.threadId,
threadVariant: threadViewModel.threadVariant,
groupLeaveType: .silent,
calledFromConfigHandling: false
)
}
@ -345,9 +343,8 @@ public extension UIContextualAction {
if threadIsMessageRequest {
try SessionThread.deleteOrLeave(
db,
type: .hideContactConversationAndDeleteContent,
threadId: threadViewModel.threadId,
threadVariant: .contact,
groupLeaveType: .silent,
calledFromConfigHandling: false
)
}
@ -429,13 +426,19 @@ public extension UIContextualAction {
cancelStyle: .alert_text,
dismissOnConfirm: true,
onConfirm: { _ in
let deletionType: SessionThread.DeletionType = {
switch threadViewModel.threadVariant {
case .legacyGroup, .group: return .leaveGroupAsync
default: return .deleteCommunityAndContent
}
}()
Storage.shared.writeAsync { db in
do {
try SessionThread.deleteOrLeave(
db,
type: deletionType,
threadId: threadViewModel.threadId,
threadVariant: threadViewModel.threadVariant,
groupLeaveType: .standard,
calledFromConfigHandling: false
)
} catch {
@ -532,12 +535,23 @@ public extension UIContextualAction {
cancelStyle: .alert_text,
dismissOnConfirm: true,
onConfirm: { _ in
let deletionType: SessionThread.DeletionType = {
switch (threadViewModel.threadVariant, isMessageRequest) {
case (.community, _): return .deleteCommunityAndContent
case (.group, true): return .deleteGroupAndContent
case (.group, _), (.legacyGroup, _):
return .leaveGroupAsync
case (.contact, _):
return .hideContactConversationAndDeleteContent
}
}()
Storage.shared.writeAsync { db in
try SessionThread.deleteOrLeave(
db,
type: deletionType,
threadId: threadViewModel.threadId,
threadVariant: threadViewModel.threadVariant,
groupLeaveType: (isMessageRequest ? .silent : .forced),
calledFromConfigHandling: false
)
}

@ -111,12 +111,6 @@ public extension ClosedGroup {
// MARK: - Convenience
public extension ClosedGroup {
enum LeaveType {
case standard
case silent
case forced
}
static func removeKeysAndUnsubscribe(
_ db: Database? = nil,
threadId: String,

@ -276,35 +276,44 @@ public extension SessionThread {
)
""")
}
}
// MARK: - Deletion
public extension SessionThread {
enum DeletionType {
case hideContactConversationAndDeleteContent
case deleteContactConversationAndContact
case leaveGroupAsync
case deleteGroupAndContent
case deleteCommunityAndContent
}
static func deleteOrLeave(
_ db: Database,
type: SessionThread.DeletionType,
threadId: String,
threadVariant: Variant,
groupLeaveType: ClosedGroup.LeaveType,
calledFromConfigHandling: Bool
) throws {
try deleteOrLeave(
db,
type: type,
threadIds: [threadId],
threadVariant: threadVariant,
groupLeaveType: groupLeaveType,
calledFromConfigHandling: calledFromConfigHandling
)
}
static func deleteOrLeave(
_ db: Database,
type: SessionThread.DeletionType,
threadIds: [String],
threadVariant: Variant,
groupLeaveType: ClosedGroup.LeaveType,
calledFromConfigHandling: Bool
) throws {
let currentUserPublicKey: String = getUserHexEncodedPublicKey(db)
let remainingThreadIds: Set<String> = threadIds.asSet().removing(currentUserPublicKey)
switch (threadVariant, groupLeaveType) {
case (.contact, .standard), (.contact, .silent):
switch type {
case .hideContactConversationAndDeleteContent:
// Clear any interactions for the deleted thread
_ = try Interaction
.filter(threadIds.contains(Interaction.Columns.threadId))
@ -334,28 +343,26 @@ public extension SessionThread {
SessionThread.Columns.shouldBeVisible.set(to: false)
)
case (.contact, .forced):
case .deleteContactConversationAndContact:
// If this wasn't called from config handling then we need to hide the conversation
if !calledFromConfigHandling {
try LibSession
.remove(db, contactIds: Array(remainingThreadIds))
try LibSession.remove(db, contactIds: Array(remainingThreadIds))
}
_ = try SessionThread
.filter(ids: remainingThreadIds)
.deleteAll(db)
case (.legacyGroup, .standard), (.group, .standard):
case .leaveGroupAsync:
try threadIds.forEach { threadId in
try MessageSender
.leave(
db,
groupPublicKey: threadId,
deleteThread: true
)
try MessageSender.leave(
db,
groupPublicKey: threadId,
deleteThread: true
)
}
case (.legacyGroup, .silent), (.legacyGroup, .forced), (.group, .forced), (.group, .silent):
case .deleteGroupAndContent:
try ClosedGroup.removeKeysAndUnsubscribe(
db,
threadIds: threadIds,
@ -363,7 +370,7 @@ public extension SessionThread {
calledFromConfigHandling: calledFromConfigHandling
)
case (.community, _):
case .deleteCommunityAndContent:
threadIds.forEach { threadId in
OpenGroupManager.shared.delete(
db,
@ -530,8 +537,8 @@ public extension SessionThread {
profile: Profile? = nil
) -> String {
switch variant {
case .legacyGroup, .group: return (closedGroupName ?? "Unknown Group")
case .community: return (openGroupName ?? "Unknown Community")
case .legacyGroup, .group: return (closedGroupName ?? "groupUnknown".localized())
case .community: return (openGroupName ?? "communityUnknown".localized())
case .contact:
guard !isNoteToSelf else { return "noteToSelf".localized() }
guard let profile: Profile = profile else {

@ -248,9 +248,8 @@ internal extension LibSession {
try SessionThread
.deleteOrLeave(
db,
type: .deleteContactConversationAndContact,
threadIds: combinedIds,
threadVariant: .contact,
groupLeaveType: .forced,
calledFromConfigHandling: true
)

@ -177,14 +177,12 @@ internal extension LibSession {
if !communityIdsToRemove.isEmpty {
LibSession.kickFromConversationUIIfNeeded(removedThreadIds: Array(communityIdsToRemove))
try SessionThread
.deleteOrLeave(
db,
threadIds: Array(communityIdsToRemove),
threadVariant: .community,
groupLeaveType: .forced,
calledFromConfigHandling: true
)
try SessionThread.deleteOrLeave(
db,
type: .deleteCommunityAndContent,
threadIds: Array(communityIdsToRemove),
calledFromConfigHandling: true
)
}
// MARK: -- Handle Legacy Group Changes
@ -370,9 +368,8 @@ internal extension LibSession {
try SessionThread
.deleteOrLeave(
db,
type: .deleteGroupAndContent,
threadIds: Array(legacyGroupIdsToRemove),
threadVariant: .legacyGroup,
groupLeaveType: .forced,
calledFromConfigHandling: true
)
}

@ -105,14 +105,12 @@ internal extension LibSession {
// `deleteOrLeave` behaviour (for 'Note to Self' this will leave the conversation
// but remove the associated interactions)
if !LibSession.shouldBeVisible(priority: targetPriority) {
try SessionThread
.deleteOrLeave(
db,
threadId: userPublicKey,
threadVariant: .contact,
groupLeaveType: .silent,
calledFromConfigHandling: true
)
try SessionThread.deleteOrLeave(
db,
type: .hideContactConversationAndDeleteContent,
threadId: userPublicKey,
calledFromConfigHandling: true
)
}
}

@ -5,7 +5,37 @@ import GRDB
import SessionUtilitiesKit
public final class ExpirationTimerUpdate: ControlMessage {
private enum CodingKeys: String, CodingKey {
case syncTarget
}
public var syncTarget: String?
public override var isSelfSendValid: Bool { true }
public init(syncTarget: String? = nil) {
super.init()
self.syncTarget = syncTarget
}
// MARK: - Codable
required init(from decoder: Decoder) throws {
try super.init(from: decoder)
let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
syncTarget = try? container.decode(String.self, forKey: .syncTarget)
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container: KeyedEncodingContainer<CodingKeys> = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(syncTarget, forKey: .syncTarget)
}
// MARK: - Proto Conversion
@ -15,12 +45,15 @@ public final class ExpirationTimerUpdate: ControlMessage {
let isExpirationTimerUpdate = (dataMessageProto.flags & UInt32(SNProtoDataMessage.SNProtoDataMessageFlags.expirationTimerUpdate.rawValue)) != 0
guard isExpirationTimerUpdate else { return nil }
return ExpirationTimerUpdate()
return ExpirationTimerUpdate(
syncTarget: dataMessageProto.syncTarget
)
}
public override func toProto(_ db: Database, threadId: String) -> SNProtoContent? {
let dataMessageProto = SNProtoDataMessage.builder()
dataMessageProto.setFlags(UInt32(SNProtoDataMessage.SNProtoDataMessageFlags.expirationTimerUpdate.rawValue))
if let syncTarget = syncTarget { dataMessageProto.setSyncTarget(syncTarget) }
let contentProto = SNProtoContent.builder()
// DisappearingMessagesConfiguration
@ -39,7 +72,9 @@ public final class ExpirationTimerUpdate: ControlMessage {
public var description: String {
"""
ExpirationTimerUpdate()
ExpirationTimerUpdate(
syncTarget: \(syncTarget ?? "null"),
)
"""
}
}

@ -269,6 +269,7 @@ public extension Message {
static func shouldSync(message: Message) -> Bool {
switch message {
case is VisibleMessage: return true
case is ExpirationTimerUpdate: return true
case is UnsendRequest: return true
case let controlMessage as ClosedGroupControlMessage:
@ -295,6 +296,7 @@ public extension Message {
switch message {
case let message as VisibleMessage: maybeSyncTarget = message.syncTarget
case let message as ExpirationTimerUpdate: maybeSyncTarget = message.syncTarget
default: maybeSyncTarget = nil
}

@ -796,7 +796,12 @@ public final class OpenGroupManager {
let syncTarget: String = (lookup.sessionId ?? message.recipient)
switch messageInfo.variant {
case .visibleMessage: (messageInfo.message as? VisibleMessage)?.syncTarget = syncTarget
case .visibleMessage:
(messageInfo.message as? VisibleMessage)?.syncTarget = syncTarget
case .expirationTimerUpdate:
(messageInfo.message as? ExpirationTimerUpdate)?.syncTarget = syncTarget
default: break
}
}

@ -104,9 +104,8 @@ extension MessageReceiver {
_ = try SessionThread
.deleteOrLeave(
db,
type: .deleteContactConversationAndContact, // Blinded contact isn't synced anyway
threadId: blindedIdLookup.blindedId,
threadVariant: .contact,
groupLeaveType: .forced,
calledFromConfigHandling: false
)
}

@ -108,6 +108,7 @@ public enum MessageReceiver {
threadIdGenerator = { message in
switch message {
case let message as VisibleMessage: return (message.syncTarget ?? sender)
case let message as ExpirationTimerUpdate: return (message.syncTarget ?? sender)
default: return sender
}
}

@ -1117,6 +1117,7 @@ public final class MessageSender {
Message.shouldSync(message: message)
{
if let message = message as? VisibleMessage { message.syncTarget = publicKey }
if let message = message as? ExpirationTimerUpdate { message.syncTarget = publicKey }
dependencies.jobRunner.add(
db,

Loading…
Cancel
Save