From bd04775cbf094f29968d6198784d0cc2227235a0 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 3 May 2021 15:13:18 +1000 Subject: [PATCH 01/11] Implement open group invitations UI --- Session.xcodeproj/project.pbxproj | 8 ++ .../OpenGroupInvitationView.swift | 78 +++++++++++++++++++ .../Message Cells/VisibleMessageCell.swift | 8 +- .../File Server/FileServerAPIV2.swift | 2 + SessionMessagingKit/Jobs/Job.swift | 2 +- .../ConfigurationMessage.swift | 10 +-- .../ExpirationTimerUpdate.swift | 2 +- .../Signal/TSIncomingMessage+Conversion.swift | 4 +- .../Messages/Signal/TSIncomingMessage.h | 4 +- .../Messages/Signal/TSIncomingMessage.m | 6 +- .../Messages/Signal/TSInfoMessage.m | 4 +- .../Messages/Signal/TSMessage.h | 6 +- .../Messages/Signal/TSMessage.m | 4 + .../Signal/TSOutgoingMessage+Conversion.swift | 4 +- .../Messages/Signal/TSOutgoingMessage.h | 4 +- .../Messages/Signal/TSOutgoingMessage.m | 14 +++- .../VisibleMessage+LinkPreview.swift | 4 +- .../VisibleMessage+OpenGroupInvitation.swift | 43 ++++++++++ .../VisibleMessage+Profile.swift | 4 +- .../VisibleMessage+Quote.swift | 6 +- .../Visible Messages/VisibleMessage.swift | 15 ++-- .../Sending & Receiving/MessageReceiver.swift | 32 ++++---- .../Sending & Receiving/MessageSender.swift | 6 +- .../Pollers/ClosedGroupPoller.swift | 2 +- .../Pollers/OpenGroupPoller.swift | 2 +- .../Sending & Receiving/Pollers/Poller.swift | 2 +- 26 files changed, 221 insertions(+), 55 deletions(-) create mode 100644 Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift create mode 100644 SessionMessagingKit/Messages/Visible Messages/VisibleMessage+OpenGroupInvitation.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 687fe8f63..6cc48e38b 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -268,6 +268,8 @@ B8D64FCB25BA78A90029CFC0 /* SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; }; B8D84EA325DF745A005A043E /* LinkPreviewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D84EA225DF745A005A043E /* LinkPreviewState.swift */; }; B8D84ECF25E3108A005A043E /* ExpandingAttachmentsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D84ECE25E3108A005A043E /* ExpandingAttachmentsButton.swift */; }; + B8EB20EE2640F28000773E52 /* VisibleMessage+OpenGroupInvitation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8EB20ED2640F28000773E52 /* VisibleMessage+OpenGroupInvitation.swift */; }; + B8EB20F02640F7F000773E52 /* OpenGroupInvitationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8EB20EF2640F7F000773E52 /* OpenGroupInvitationView.swift */; }; B8F5F52925EC4F8A003BF8D4 /* BlockListUIUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B8F5F52825EC4F8A003BF8D4 /* BlockListUIUtils.m */; }; B8F5F54E25EC50A5003BF8D4 /* BlockListUIUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = B8F5F52725EC4F6A003BF8D4 /* BlockListUIUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; B8F5F56525EC8453003BF8D4 /* Notification+Contacts.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F5F56425EC8453003BF8D4 /* Notification+Contacts.swift */; }; @@ -1252,6 +1254,8 @@ B8D8F1BC25661C6F0092EF10 /* Storage+OnionRequests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+OnionRequests.swift"; sourceTree = ""; }; B8D8F1EF256621180092EF10 /* MessageSender+Convenience.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "MessageSender+Convenience.swift"; path = "../../SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift"; sourceTree = ""; }; B8EB20E6263F7E4B00773E52 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; + B8EB20ED2640F28000773E52 /* VisibleMessage+OpenGroupInvitation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+OpenGroupInvitation.swift"; sourceTree = ""; }; + B8EB20EF2640F7F000773E52 /* OpenGroupInvitationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupInvitationView.swift; sourceTree = ""; }; B8F5F52725EC4F6A003BF8D4 /* BlockListUIUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BlockListUIUtils.h; sourceTree = ""; }; B8F5F52825EC4F8A003BF8D4 /* BlockListUIUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BlockListUIUtils.m; sourceTree = ""; }; B8F5F56425EC8453003BF8D4 /* Notification+Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+Contacts.swift"; sourceTree = ""; }; @@ -2110,6 +2114,7 @@ B8569AE225CBB19A00DBA3DB /* DocumentView.swift */, B849789525D4A2F500D0D0B3 /* LinkPreviewView.swift */, B8D84EA225DF745A005A043E /* LinkPreviewState.swift */, + B8EB20EF2640F7F000773E52 /* OpenGroupInvitationView.swift */, ); path = "Content Views"; sourceTree = ""; @@ -2380,6 +2385,7 @@ C3C2A75E2553A3C500C340D1 /* VisibleMessage+LinkPreview.swift */, C3C2A7672553A3D900C340D1 /* VisibleMessage+Contact.swift */, C300A5B12554AF9800555489 /* VisibleMessage+Profile.swift */, + B8EB20ED2640F28000773E52 /* VisibleMessage+OpenGroupInvitation.swift */, ); path = "Visible Messages"; sourceTree = ""; @@ -4732,6 +4738,7 @@ C3C2A7852553AAF300C340D1 /* SessionProtos.pb.swift in Sources */, B8566C63256F55930045A0B9 /* OWSLinkPreview+Conversion.swift in Sources */, C32C5B3F256DC1DF003C73A2 /* TSQuotedMessage+Conversion.swift in Sources */, + B8EB20EE2640F28000773E52 /* VisibleMessage+OpenGroupInvitation.swift in Sources */, C3C2A7712553A41E00C340D1 /* ControlMessage.swift in Sources */, C32C5D19256DD493003C73A2 /* OWSLinkPreview.swift in Sources */, C32C5CF0256DD3E4003C73A2 /* Storage+Shared.swift in Sources */, @@ -4971,6 +4978,7 @@ 45E5A6991F61E6DE001E4A8A /* MarqueeLabel.swift in Sources */, C302093E25DCBF08001F572D /* MentionSelectionView.swift in Sources */, C328251F25CA3A900062D0A7 /* QuoteView.swift in Sources */, + B8EB20F02640F7F000773E52 /* OpenGroupInvitationView.swift in Sources */, B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */, C328254025CA55880062D0A7 /* ContextMenuVC.swift in Sources */, 3427C64320F500E000EEC730 /* OWSMessageTimerView.m in Sources */, diff --git a/Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift b/Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift new file mode 100644 index 000000000..30b5d56fa --- /dev/null +++ b/Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift @@ -0,0 +1,78 @@ + +final class OpenGroupInvitationView : UIView { + private let name: String + private let rawURL: String + private let textColor: UIColor + + private lazy var url: String = { + if let range = rawURL.range(of: "?public_key=") { + return String(rawURL[.. Profile? { + notImplemented() + } + + public func toProto() -> SNProtoDataMessage? { + notImplemented() + } + + // MARK: Description + public override var description: String { + """ + OpenGroupInvitation( + name: \(name ?? "null"), + url: \(url ?? "null") + ) + """ + } + } +} diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Profile.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Profile.swift index 71bec53c3..d9e82f7e5 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Profile.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Profile.swift @@ -62,8 +62,8 @@ public extension VisibleMessage { public override var description: String { """ Profile( - displayName: \(displayName ?? "null") - profileKey: \(profileKey?.description ?? "null") + displayName: \(displayName ?? "null"), + profileKey: \(profileKey?.description ?? "null"), profilePictureURL: \(profilePictureURL ?? "null") ) """ diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift index 2f818fdcd..2a0f9bf93 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift @@ -88,9 +88,9 @@ public extension VisibleMessage { public override var description: String { """ Quote( - timestamp: \(timestamp?.description ?? "null") - publicKey: \(publicKey ?? "null") - text: \(text ?? "null") + timestamp: \(timestamp?.description ?? "null"), + publicKey: \(publicKey ?? "null"), + text: \(text ?? "null"), attachmentID: \(attachmentID ?? "null") ) """ diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift index 9e6e4e020..a8d856382 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift @@ -12,6 +12,7 @@ public final class VisibleMessage : Message { @objc public var linkPreview: LinkPreview? @objc public var contact: Contact? @objc public var profile: Profile? + @objc public var openGroupInvitation: OpenGroupInvitation? public override var isSelfSendValid: Bool { true } @@ -22,6 +23,7 @@ public final class VisibleMessage : Message { public override var isValid: Bool { guard super.isValid else { return false } if !attachmentIDs.isEmpty { return true } + if openGroupInvitation != nil { return true } if let text = text?.trimmingCharacters(in: .whitespacesAndNewlines), !text.isEmpty { return true } return false } @@ -36,6 +38,7 @@ public final class VisibleMessage : Message { if let linkPreview = coder.decodeObject(forKey: "linkPreview") as! LinkPreview? { self.linkPreview = linkPreview } // TODO: Contact if let profile = coder.decodeObject(forKey: "profile") as! Profile? { self.profile = profile } + if let openGroupInvitation = coder.decodeObject(forKey: "openGroupInvitation") as! OpenGroupInvitation? { self.openGroupInvitation = openGroupInvitation } } public override func encode(with coder: NSCoder) { @@ -47,6 +50,7 @@ public final class VisibleMessage : Message { coder.encode(linkPreview, forKey: "linkPreview") // TODO: Contact coder.encode(profile, forKey: "profile") + coder.encode(openGroupInvitation, forKey: "openGroupInvitation") } // MARK: Proto Conversion @@ -128,12 +132,13 @@ public final class VisibleMessage : Message { public override var description: String { """ VisibleMessage( - text: \(text ?? "null") - attachmentIDs: \(attachmentIDs) - quote: \(quote?.description ?? "null") - linkPreview: \(linkPreview?.description ?? "null") - contact: \(contact?.description ?? "null") + text: \(text ?? "null"), + attachmentIDs: \(attachmentIDs), + quote: \(quote?.description ?? "null"), + linkPreview: \(linkPreview?.description ?? "null"), + contact: \(contact?.description ?? "null"), profile: \(profile?.description ?? "null") + "openGroupInvitation": \(openGroupInvitation?.description ?? "null") ) """ } diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index 3547681f3..cf724fe9f 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -92,22 +92,22 @@ public enum MessageReceiver { } groupPublicKey = envelope.source try decrypt() - -// do { -// try decrypt() -// } catch { -// do { -// let now = Date() -// // Don't spam encryption key pair requests -// let shouldRequestEncryptionKeyPair = given(lastEncryptionKeyPairRequest[groupPublicKey!]) { now.timeIntervalSince($0) > 30 } ?? true -// if shouldRequestEncryptionKeyPair { -// try MessageSender.requestEncryptionKeyPair(for: groupPublicKey!, using: transaction as! YapDatabaseReadWriteTransaction) -// lastEncryptionKeyPairRequest[groupPublicKey!] = now -// } -// } -// throw error // Throw the * decryption * error and not the error generated by requestEncryptionKeyPair (if it generated one) -// } - + /* + do { + try decrypt() + } catch { + do { + let now = Date() + // Don't spam encryption key pair requests + let shouldRequestEncryptionKeyPair = given(lastEncryptionKeyPairRequest[groupPublicKey!]) { now.timeIntervalSince($0) > 30 } ?? true + if shouldRequestEncryptionKeyPair { + try MessageSender.requestEncryptionKeyPair(for: groupPublicKey!, using: transaction as! YapDatabaseReadWriteTransaction) + lastEncryptionKeyPairRequest[groupPublicKey!] = now + } + } + throw error // Throw the * decryption * error and not the error generated by requestEncryptionKeyPair (if it generated one) + } + */ default: throw Error.unknownEnvelopeType } } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index fe737b2ef..eb7be10e8 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -9,7 +9,6 @@ public final class MessageSender : NSObject { public enum Error : LocalizedError { case invalidMessage case protoConversionFailed - case proofOfWorkCalculationFailed case noUserX25519KeyPair case noUserED25519KeyPair case signingFailed @@ -22,7 +21,7 @@ public final class MessageSender : NSObject { internal var isRetryable: Bool { switch self { - case .invalidMessage, .protoConversionFailed, .proofOfWorkCalculationFailed, .invalidClosedGroupUpdate, .signingFailed, .encryptionFailed: return false + case .invalidMessage, .protoConversionFailed, .invalidClosedGroupUpdate, .signingFailed, .encryptionFailed: return false default: return true } } @@ -31,7 +30,6 @@ public final class MessageSender : NSObject { switch self { case .invalidMessage: return "Invalid message." case .protoConversionFailed: return "Couldn't convert message to proto." - case .proofOfWorkCalculationFailed: return "Proof of work calculation failed." case .noUserX25519KeyPair: return "Couldn't find user X25519 key pair." case .noUserED25519KeyPair: return "Couldn't find user ED25519 key pair." case .signingFailed: return "Couldn't sign message." @@ -48,8 +46,6 @@ public final class MessageSender : NSObject { // MARK: Initialization private override init() { } - public static let shared = MessageSender() // FIXME: Remove once requestSenderKey is static - // MARK: Preparation public static func prep(_ signalAttachments: [SignalAttachment], for message: VisibleMessage, using transaction: YapDatabaseReadWriteTransaction) { guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift index 89283dd03..111d57152 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift @@ -7,7 +7,7 @@ public final class ClosedGroupPoller : NSObject { private var timer: Timer? // MARK: Settings - private static let pollInterval: TimeInterval = 2 + private static let pollInterval: TimeInterval = 3 // MARK: Error private enum Error : LocalizedError { diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift index 2a1c5286e..4dfc780a0 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift @@ -18,7 +18,7 @@ public final class OpenGroupPoller : NSObject { } // MARK: Settings - private let pollForNewMessagesInterval: TimeInterval = 4 + private let pollForNewMessagesInterval: TimeInterval = 8 private let pollForDeletedMessagesInterval: TimeInterval = 30 private let pollForModeratorsInterval: TimeInterval = 10 * 60 diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift index 6c338c0c4..85da45a78 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift @@ -9,7 +9,7 @@ public final class Poller : NSObject { private var pollCount = 0 // MARK: Settings - private static let pollInterval: TimeInterval = 1 + private static let pollInterval: TimeInterval = 1.5 private static let retryInterval: TimeInterval = 0.25 /// After polling a given snode this many times we always switch to a new one. /// From 2f1e2a141b8386b315dc75cef69831187367e11b Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Tue, 4 May 2021 14:39:06 +1000 Subject: [PATCH 02/11] Localize new string --- .../Message Cells/Content Views/OpenGroupInvitationView.swift | 2 +- Session/Meta/Translations/de.lproj/Localizable.strings | 1 + Session/Meta/Translations/en.lproj/Localizable.strings | 1 + Session/Meta/Translations/es.lproj/Localizable.strings | 1 + Session/Meta/Translations/fa.lproj/Localizable.strings | 1 + Session/Meta/Translations/fr.lproj/Localizable.strings | 1 + Session/Meta/Translations/id-ID.lproj/Localizable.strings | 1 + Session/Meta/Translations/it.lproj/Localizable.strings | 1 + Session/Meta/Translations/ja.lproj/Localizable.strings | 1 + Session/Meta/Translations/nl.lproj/Localizable.strings | 1 + Session/Meta/Translations/pl.lproj/Localizable.strings | 1 + Session/Meta/Translations/pt_BR.lproj/Localizable.strings | 1 + Session/Meta/Translations/ru.lproj/Localizable.strings | 1 + Session/Meta/Translations/sk.lproj/Localizable.strings | 1 + Session/Meta/Translations/vi-VN.lproj/Localizable.strings | 1 + Session/Meta/Translations/zh_CN.lproj/Localizable.strings | 1 + 16 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift b/Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift index 30b5d56fa..bd328fe8d 100644 --- a/Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift +++ b/Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift @@ -43,7 +43,7 @@ final class OpenGroupInvitationView : UIView { // Subtitle let subtitleLabel = UILabel() subtitleLabel.lineBreakMode = .byTruncatingTail - subtitleLabel.text = "Open group invitation" + subtitleLabel.text = NSLocalizedString("view_open_group_invitation_description", comment: "") subtitleLabel.textColor = textColor subtitleLabel.font = .systemFont(ofSize: Values.smallFontSize) // URL diff --git a/Session/Meta/Translations/de.lproj/Localizable.strings b/Session/Meta/Translations/de.lproj/Localizable.strings index a0c21f35b..90619c0ba 100644 --- a/Session/Meta/Translations/de.lproj/Localizable.strings +++ b/Session/Meta/Translations/de.lproj/Localizable.strings @@ -523,3 +523,4 @@ "vc_share_title" = "Share to Session"; "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; +"view_open_group_invitation_description" = "Open group invitation"; diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index fca861682..0ab7860e8 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -525,3 +525,4 @@ "vc_share_title" = "Share to Session"; "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; +"view_open_group_invitation_description" = "Open group invitation"; diff --git a/Session/Meta/Translations/es.lproj/Localizable.strings b/Session/Meta/Translations/es.lproj/Localizable.strings index 621d7d823..6120375ca 100644 --- a/Session/Meta/Translations/es.lproj/Localizable.strings +++ b/Session/Meta/Translations/es.lproj/Localizable.strings @@ -523,3 +523,4 @@ "vc_share_title" = "Share to Session"; "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; +"view_open_group_invitation_description" = "Open group invitation"; diff --git a/Session/Meta/Translations/fa.lproj/Localizable.strings b/Session/Meta/Translations/fa.lproj/Localizable.strings index 0b0f2c494..0d8831ad8 100644 --- a/Session/Meta/Translations/fa.lproj/Localizable.strings +++ b/Session/Meta/Translations/fa.lproj/Localizable.strings @@ -523,3 +523,4 @@ "vc_share_title" = "اشتراک گذاری با Session"; "vc_share_loading_message" = "آماده سازی پیوست‌ها..."; "vc_share_sending_message" = "در حال ارسال..."; +"view_open_group_invitation_description" = "Open group invitation"; diff --git a/Session/Meta/Translations/fr.lproj/Localizable.strings b/Session/Meta/Translations/fr.lproj/Localizable.strings index 70cc8473c..c24ef9ab0 100644 --- a/Session/Meta/Translations/fr.lproj/Localizable.strings +++ b/Session/Meta/Translations/fr.lproj/Localizable.strings @@ -523,3 +523,4 @@ "vc_share_title" = "Share to Session"; "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; +"view_open_group_invitation_description" = "Open group invitation"; diff --git a/Session/Meta/Translations/id-ID.lproj/Localizable.strings b/Session/Meta/Translations/id-ID.lproj/Localizable.strings index 8c78ed5ae..8ef2eaf81 100644 --- a/Session/Meta/Translations/id-ID.lproj/Localizable.strings +++ b/Session/Meta/Translations/id-ID.lproj/Localizable.strings @@ -523,3 +523,4 @@ "vc_share_title" = "Share to Session"; "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; +"view_open_group_invitation_description" = "Open group invitation"; diff --git a/Session/Meta/Translations/it.lproj/Localizable.strings b/Session/Meta/Translations/it.lproj/Localizable.strings index 01b23c43b..299b21db9 100644 --- a/Session/Meta/Translations/it.lproj/Localizable.strings +++ b/Session/Meta/Translations/it.lproj/Localizable.strings @@ -523,3 +523,4 @@ "vc_share_title" = "Share to Session"; "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; +"view_open_group_invitation_description" = "Open group invitation"; diff --git a/Session/Meta/Translations/ja.lproj/Localizable.strings b/Session/Meta/Translations/ja.lproj/Localizable.strings index de430e75b..711286551 100644 --- a/Session/Meta/Translations/ja.lproj/Localizable.strings +++ b/Session/Meta/Translations/ja.lproj/Localizable.strings @@ -523,3 +523,4 @@ "vc_share_title" = "Share to Session"; "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; +"view_open_group_invitation_description" = "Open group invitation"; diff --git a/Session/Meta/Translations/nl.lproj/Localizable.strings b/Session/Meta/Translations/nl.lproj/Localizable.strings index f01ac9cd2..5bfdc6e91 100644 --- a/Session/Meta/Translations/nl.lproj/Localizable.strings +++ b/Session/Meta/Translations/nl.lproj/Localizable.strings @@ -525,3 +525,4 @@ "vc_share_title" = "Share to Session"; "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; +"view_open_group_invitation_description" = "Open group invitation"; diff --git a/Session/Meta/Translations/pl.lproj/Localizable.strings b/Session/Meta/Translations/pl.lproj/Localizable.strings index ddbb14eb9..385877294 100644 --- a/Session/Meta/Translations/pl.lproj/Localizable.strings +++ b/Session/Meta/Translations/pl.lproj/Localizable.strings @@ -523,3 +523,4 @@ "vc_share_title" = "Share to Session"; "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; +"view_open_group_invitation_description" = "Open group invitation"; diff --git a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings index 1889fdb28..63f82387c 100644 --- a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings +++ b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings @@ -523,3 +523,4 @@ "vc_share_title" = "Compartilhar no Session"; "vc_share_loading_message" = "Preparando anexos..."; "vc_share_sending_message" = "Enviando..."; +"view_open_group_invitation_description" = "Open group invitation"; diff --git a/Session/Meta/Translations/ru.lproj/Localizable.strings b/Session/Meta/Translations/ru.lproj/Localizable.strings index 2254fb24f..3e427faf3 100644 --- a/Session/Meta/Translations/ru.lproj/Localizable.strings +++ b/Session/Meta/Translations/ru.lproj/Localizable.strings @@ -523,3 +523,4 @@ "vc_share_title" = "Share to Session"; "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; +"view_open_group_invitation_description" = "Open group invitation"; diff --git a/Session/Meta/Translations/sk.lproj/Localizable.strings b/Session/Meta/Translations/sk.lproj/Localizable.strings index c60d66f62..e9c40e002 100644 --- a/Session/Meta/Translations/sk.lproj/Localizable.strings +++ b/Session/Meta/Translations/sk.lproj/Localizable.strings @@ -523,3 +523,4 @@ "vc_share_title" = "Share to Session"; "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; +"view_open_group_invitation_description" = "Open group invitation"; diff --git a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings index e532ab9a3..1263c8277 100644 --- a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings +++ b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings @@ -523,3 +523,4 @@ "vc_share_title" = "Share to Session"; "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; +"view_open_group_invitation_description" = "Open group invitation"; diff --git a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings index 75d160738..59f52a88f 100644 --- a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings @@ -523,3 +523,4 @@ "vc_share_title" = "Share to Session"; "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; +"view_open_group_invitation_description" = "Open group invitation"; From 5aab5346ddc92dc6e68b59c0a20650d11e3c75e8 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 7 May 2021 13:39:39 +1000 Subject: [PATCH 03/11] Add invite button to conversation settings --- .../OWSConversationSettingsViewController.m | 19 +++++++++++++++++++ .../Translations/en.lproj/Localizable.strings | 1 + 2 files changed, 20 insertions(+) diff --git a/Session/Conversations/Settings/OWSConversationSettingsViewController.m b/Session/Conversations/Settings/OWSConversationSettingsViewController.m index 016da8c74..c44f7d904 100644 --- a/Session/Conversations/Settings/OWSConversationSettingsViewController.m +++ b/Session/Conversations/Settings/OWSConversationSettingsViewController.m @@ -312,6 +312,20 @@ CGFloat kIconViewLength = 24; actionBlock:^{ [weakSelf showMediaGallery]; }]]; + + if (self.isOpenGroup) { + [mainSection addItem:[OWSTableItem + itemWithCustomCellBlock:^{ + return [weakSelf + disclosureCellWithName:NSLocalizedString(@"vc_conversation_settings_invite_button_title", "") + iconName:@"ic_plus_24" + accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME( + OWSConversationSettingsViewController, @"invite")]; + } + actionBlock:^{ + [weakSelf inviteUsersToOpenGroup]; + }]]; + } [mainSection addItem:[OWSTableItem itemWithCustomCellBlock:^{ @@ -1089,6 +1103,11 @@ CGFloat kIconViewLength = 24; UIPasteboard.generalPasteboard.string = ((TSContactThread *)self.thread).contactSessionID; } +- (void)inviteUsersToOpenGroup +{ + +} + - (void)showMediaGallery { OWSLogDebug(@""); diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index 0ab7860e8..2a835e2e1 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -526,3 +526,4 @@ "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; "view_open_group_invitation_description" = "Open group invitation"; +"vc_conversation_settings_invite_button_title" = "Add Members"; From b3f45455e5df29cf0e9724463c071b4ee9fdce9e Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 7 May 2021 13:50:32 +1000 Subject: [PATCH 04/11] Hook up user selection screen --- .../Settings/OWSConversationSettingsViewController.m | 7 ++++++- Session/Meta/Translations/de.lproj/Localizable.strings | 1 + Session/Meta/Translations/es.lproj/Localizable.strings | 1 + Session/Meta/Translations/fa.lproj/Localizable.strings | 1 + Session/Meta/Translations/fr.lproj/Localizable.strings | 1 + Session/Meta/Translations/id-ID.lproj/Localizable.strings | 1 + Session/Meta/Translations/it.lproj/Localizable.strings | 1 + Session/Meta/Translations/ja.lproj/Localizable.strings | 1 + Session/Meta/Translations/nl.lproj/Localizable.strings | 1 + Session/Meta/Translations/pl.lproj/Localizable.strings | 1 + Session/Meta/Translations/pt_BR.lproj/Localizable.strings | 1 + Session/Meta/Translations/ru.lproj/Localizable.strings | 1 + Session/Meta/Translations/sk.lproj/Localizable.strings | 1 + Session/Meta/Translations/vi-VN.lproj/Localizable.strings | 1 + Session/Meta/Translations/zh_CN.lproj/Localizable.strings | 1 + Session/Shared/UserSelectionVC.swift | 4 +++- 16 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Session/Conversations/Settings/OWSConversationSettingsViewController.m b/Session/Conversations/Settings/OWSConversationSettingsViewController.m index c44f7d904..47bfde914 100644 --- a/Session/Conversations/Settings/OWSConversationSettingsViewController.m +++ b/Session/Conversations/Settings/OWSConversationSettingsViewController.m @@ -1105,7 +1105,12 @@ CGFloat kIconViewLength = 24; - (void)inviteUsersToOpenGroup { - + SNUserSelectionVC *userSelectionVC = [[SNUserSelectionVC alloc] initWithTitle:@"vc_conversation_settings_invite_button_title" + excluding:[NSSet new] + completion:^(NSSet *selectedUsers) { + + }]; + [self.navigationController pushViewController:userSelectionVC animated:YES]; } - (void)showMediaGallery diff --git a/Session/Meta/Translations/de.lproj/Localizable.strings b/Session/Meta/Translations/de.lproj/Localizable.strings index 90619c0ba..d1e31458e 100644 --- a/Session/Meta/Translations/de.lproj/Localizable.strings +++ b/Session/Meta/Translations/de.lproj/Localizable.strings @@ -524,3 +524,4 @@ "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; "view_open_group_invitation_description" = "Open group invitation"; +"vc_conversation_settings_invite_button_title" = "Add Members"; diff --git a/Session/Meta/Translations/es.lproj/Localizable.strings b/Session/Meta/Translations/es.lproj/Localizable.strings index 6120375ca..f7b0dc486 100644 --- a/Session/Meta/Translations/es.lproj/Localizable.strings +++ b/Session/Meta/Translations/es.lproj/Localizable.strings @@ -524,3 +524,4 @@ "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; "view_open_group_invitation_description" = "Open group invitation"; +"vc_conversation_settings_invite_button_title" = "Add Members"; diff --git a/Session/Meta/Translations/fa.lproj/Localizable.strings b/Session/Meta/Translations/fa.lproj/Localizable.strings index 0d8831ad8..d3bb68b22 100644 --- a/Session/Meta/Translations/fa.lproj/Localizable.strings +++ b/Session/Meta/Translations/fa.lproj/Localizable.strings @@ -524,3 +524,4 @@ "vc_share_loading_message" = "آماده سازی پیوست‌ها..."; "vc_share_sending_message" = "در حال ارسال..."; "view_open_group_invitation_description" = "Open group invitation"; +"vc_conversation_settings_invite_button_title" = "Add Members"; diff --git a/Session/Meta/Translations/fr.lproj/Localizable.strings b/Session/Meta/Translations/fr.lproj/Localizable.strings index c24ef9ab0..19c64afab 100644 --- a/Session/Meta/Translations/fr.lproj/Localizable.strings +++ b/Session/Meta/Translations/fr.lproj/Localizable.strings @@ -524,3 +524,4 @@ "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; "view_open_group_invitation_description" = "Open group invitation"; +"vc_conversation_settings_invite_button_title" = "Add Members"; diff --git a/Session/Meta/Translations/id-ID.lproj/Localizable.strings b/Session/Meta/Translations/id-ID.lproj/Localizable.strings index 8ef2eaf81..2d8a1e992 100644 --- a/Session/Meta/Translations/id-ID.lproj/Localizable.strings +++ b/Session/Meta/Translations/id-ID.lproj/Localizable.strings @@ -524,3 +524,4 @@ "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; "view_open_group_invitation_description" = "Open group invitation"; +"vc_conversation_settings_invite_button_title" = "Add Members"; diff --git a/Session/Meta/Translations/it.lproj/Localizable.strings b/Session/Meta/Translations/it.lproj/Localizable.strings index 299b21db9..1c84802bb 100644 --- a/Session/Meta/Translations/it.lproj/Localizable.strings +++ b/Session/Meta/Translations/it.lproj/Localizable.strings @@ -524,3 +524,4 @@ "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; "view_open_group_invitation_description" = "Open group invitation"; +"vc_conversation_settings_invite_button_title" = "Add Members"; diff --git a/Session/Meta/Translations/ja.lproj/Localizable.strings b/Session/Meta/Translations/ja.lproj/Localizable.strings index 711286551..03cd9f569 100644 --- a/Session/Meta/Translations/ja.lproj/Localizable.strings +++ b/Session/Meta/Translations/ja.lproj/Localizable.strings @@ -524,3 +524,4 @@ "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; "view_open_group_invitation_description" = "Open group invitation"; +"vc_conversation_settings_invite_button_title" = "Add Members"; diff --git a/Session/Meta/Translations/nl.lproj/Localizable.strings b/Session/Meta/Translations/nl.lproj/Localizable.strings index 5bfdc6e91..6ee5b7833 100644 --- a/Session/Meta/Translations/nl.lproj/Localizable.strings +++ b/Session/Meta/Translations/nl.lproj/Localizable.strings @@ -526,3 +526,4 @@ "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; "view_open_group_invitation_description" = "Open group invitation"; +"vc_conversation_settings_invite_button_title" = "Add Members"; diff --git a/Session/Meta/Translations/pl.lproj/Localizable.strings b/Session/Meta/Translations/pl.lproj/Localizable.strings index 385877294..921f70388 100644 --- a/Session/Meta/Translations/pl.lproj/Localizable.strings +++ b/Session/Meta/Translations/pl.lproj/Localizable.strings @@ -524,3 +524,4 @@ "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; "view_open_group_invitation_description" = "Open group invitation"; +"vc_conversation_settings_invite_button_title" = "Add Members"; diff --git a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings index 63f82387c..f3f5d87b6 100644 --- a/Session/Meta/Translations/pt_BR.lproj/Localizable.strings +++ b/Session/Meta/Translations/pt_BR.lproj/Localizable.strings @@ -524,3 +524,4 @@ "vc_share_loading_message" = "Preparando anexos..."; "vc_share_sending_message" = "Enviando..."; "view_open_group_invitation_description" = "Open group invitation"; +"vc_conversation_settings_invite_button_title" = "Add Members"; diff --git a/Session/Meta/Translations/ru.lproj/Localizable.strings b/Session/Meta/Translations/ru.lproj/Localizable.strings index 3e427faf3..59d15e9e2 100644 --- a/Session/Meta/Translations/ru.lproj/Localizable.strings +++ b/Session/Meta/Translations/ru.lproj/Localizable.strings @@ -524,3 +524,4 @@ "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; "view_open_group_invitation_description" = "Open group invitation"; +"vc_conversation_settings_invite_button_title" = "Add Members"; diff --git a/Session/Meta/Translations/sk.lproj/Localizable.strings b/Session/Meta/Translations/sk.lproj/Localizable.strings index e9c40e002..836a7d21a 100644 --- a/Session/Meta/Translations/sk.lproj/Localizable.strings +++ b/Session/Meta/Translations/sk.lproj/Localizable.strings @@ -524,3 +524,4 @@ "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; "view_open_group_invitation_description" = "Open group invitation"; +"vc_conversation_settings_invite_button_title" = "Add Members"; diff --git a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings index 1263c8277..53cad3499 100644 --- a/Session/Meta/Translations/vi-VN.lproj/Localizable.strings +++ b/Session/Meta/Translations/vi-VN.lproj/Localizable.strings @@ -524,3 +524,4 @@ "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; "view_open_group_invitation_description" = "Open group invitation"; +"vc_conversation_settings_invite_button_title" = "Add Members"; diff --git a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings index 59f52a88f..cd0acace1 100644 --- a/Session/Meta/Translations/zh_CN.lproj/Localizable.strings +++ b/Session/Meta/Translations/zh_CN.lproj/Localizable.strings @@ -524,3 +524,4 @@ "vc_share_loading_message" = "Preparing attachments..."; "vc_share_sending_message" = "Sending..."; "view_open_group_invitation_description" = "Open group invitation"; +"vc_conversation_settings_invite_button_title" = "Add Members"; diff --git a/Session/Shared/UserSelectionVC.swift b/Session/Shared/UserSelectionVC.swift index b39b8c66a..b62104da3 100644 --- a/Session/Shared/UserSelectionVC.swift +++ b/Session/Shared/UserSelectionVC.swift @@ -1,4 +1,5 @@ +@objc(SNUserSelectionVC) final class UserSelectionVC : BaseVC, UITableViewDataSource, UITableViewDelegate { private let navBarTitle: String private let usersToExclude: Set @@ -25,7 +26,8 @@ final class UserSelectionVC : BaseVC, UITableViewDataSource, UITableViewDelegate }() // MARK: Lifecycle - @objc init(with title: String, excluding usersToExclude: Set, completion: @escaping (Set) -> Void) { + @objc(initWithTitle:excluding:completion:) + init(with title: String, excluding usersToExclude: Set, completion: @escaping (Set) -> Void) { self.navBarTitle = title self.usersToExclude = usersToExclude self.completion = completion From e2715d1ee9c0e39048c076e1ee10e9e87a950067 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 7 May 2021 14:08:52 +1000 Subject: [PATCH 05/11] Implement sending logic --- .../OWSConversationSettingsViewController.m | 20 +++++++++++++++++-- .../VisibleMessage+OpenGroupInvitation.swift | 3 ++- .../Open Groups/V2/OpenGroupV2.swift | 4 ++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Session/Conversations/Settings/OWSConversationSettingsViewController.m b/Session/Conversations/Settings/OWSConversationSettingsViewController.m index 47bfde914..ae8ba7aa0 100644 --- a/Session/Conversations/Settings/OWSConversationSettingsViewController.m +++ b/Session/Conversations/Settings/OWSConversationSettingsViewController.m @@ -1105,10 +1105,26 @@ CGFloat kIconViewLength = 24; - (void)inviteUsersToOpenGroup { - SNUserSelectionVC *userSelectionVC = [[SNUserSelectionVC alloc] initWithTitle:@"vc_conversation_settings_invite_button_title" + NSString *threadID = self.thread.uniqueId; + SNOpenGroupV2 *openGroup = [LKStorage.shared getV2OpenGroupForThreadID:threadID]; + NSString *url = [NSString stringWithFormat:@"%@/%@?public_key=%@", openGroup.server, openGroup.room, openGroup.publicKey]; + SNUserSelectionVC *userSelectionVC = [[SNUserSelectionVC alloc] initWithTitle:NSLocalizedString(@"vc_conversation_settings_invite_button_title", @"") excluding:[NSSet new] completion:^(NSSet *selectedUsers) { - + for (NSString *user in selectedUsers) { + SNVisibleMessage *message = [SNVisibleMessage new]; + message.sentTimestamp = [NSDate millisecondTimestamp]; + message.openGroupInvitation = [[SNOpenGroupInvitation alloc] initWithName:openGroup.name url:url]; + TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:self.thread]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [tsMessage saveWithTransaction:transaction]; + }]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + TSContactThread *thread = [TSContactThread getThreadWithContactSessionID:user transaction:transaction]; + [SNMessageSender send:message inThread:thread usingTransaction:transaction]; + [self.navigationController popViewControllerAnimated:YES]; + }]; + } }]; [self.navigationController pushViewController:userSelectionVC animated:YES]; } diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+OpenGroupInvitation.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+OpenGroupInvitation.swift index 6c3ef7628..97295578a 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+OpenGroupInvitation.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+OpenGroupInvitation.swift @@ -7,7 +7,8 @@ public extension VisibleMessage { public var name: String? public var url: String? - internal init(name: String, url: String) { + @objc + public init(name: String, url: String) { self.name = name self.url = url } diff --git a/SessionMessagingKit/Open Groups/V2/OpenGroupV2.swift b/SessionMessagingKit/Open Groups/V2/OpenGroupV2.swift index bd62c31f7..504920b76 100644 --- a/SessionMessagingKit/Open Groups/V2/OpenGroupV2.swift +++ b/SessionMessagingKit/Open Groups/V2/OpenGroupV2.swift @@ -4,8 +4,8 @@ public final class OpenGroupV2 : NSObject, NSCoding { // NSObject/NSCoding confo @objc public let server: String @objc public let room: String public let id: String - public let name: String - public let publicKey: String + @objc public let name: String + @objc public let publicKey: String /// The ID with which the image can be retrieved from the server. public let imageID: String? From 0153e1cefd7bc1b8280d7b4e25d7b081bbd66b27 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 7 May 2021 14:46:53 +1000 Subject: [PATCH 06/11] Update protos --- .../Protos/Generated/SNProto.swift | 112 ++++++++++++++++++ .../Protos/Generated/SessionProtos.pb.swift | 74 ++++++++++++ .../Protos/SessionProtos.proto | 7 ++ 3 files changed, 193 insertions(+) diff --git a/SessionMessagingKit/Protos/Generated/SNProto.swift b/SessionMessagingKit/Protos/Generated/SNProto.swift index d5ea4e38e..da1d9dc85 100644 --- a/SessionMessagingKit/Protos/Generated/SNProto.swift +++ b/SessionMessagingKit/Protos/Generated/SNProto.swift @@ -1294,6 +1294,118 @@ extension SNProtoDataMessageLokiProfile.SNProtoDataMessageLokiProfileBuilder { #endif +// MARK: - SNProtoDataMessageOpenGroupInvitation + +@objc public class SNProtoDataMessageOpenGroupInvitation: NSObject { + + // MARK: - SNProtoDataMessageOpenGroupInvitationBuilder + + @objc public class func builder(url: String, name: String) -> SNProtoDataMessageOpenGroupInvitationBuilder { + return SNProtoDataMessageOpenGroupInvitationBuilder(url: url, name: name) + } + + // asBuilder() constructs a builder that reflects the proto's contents. + @objc public func asBuilder() -> SNProtoDataMessageOpenGroupInvitationBuilder { + let builder = SNProtoDataMessageOpenGroupInvitationBuilder(url: url, name: name) + return builder + } + + @objc public class SNProtoDataMessageOpenGroupInvitationBuilder: NSObject { + + private var proto = SessionProtos_DataMessage.OpenGroupInvitation() + + @objc fileprivate override init() {} + + @objc fileprivate init(url: String, name: String) { + super.init() + + setUrl(url) + setName(name) + } + + @objc public func setUrl(_ valueParam: String) { + proto.url = valueParam + } + + @objc public func setName(_ valueParam: String) { + proto.name = valueParam + } + + @objc public func build() throws -> SNProtoDataMessageOpenGroupInvitation { + return try SNProtoDataMessageOpenGroupInvitation.parseProto(proto) + } + + @objc public func buildSerializedData() throws -> Data { + return try SNProtoDataMessageOpenGroupInvitation.parseProto(proto).serializedData() + } + } + + fileprivate let proto: SessionProtos_DataMessage.OpenGroupInvitation + + @objc public let url: String + + @objc public let name: String + + private init(proto: SessionProtos_DataMessage.OpenGroupInvitation, + url: String, + name: String) { + self.proto = proto + self.url = url + self.name = name + } + + @objc + public func serializedData() throws -> Data { + return try self.proto.serializedData() + } + + @objc public class func parseData(_ serializedData: Data) throws -> SNProtoDataMessageOpenGroupInvitation { + let proto = try SessionProtos_DataMessage.OpenGroupInvitation(serializedData: serializedData) + return try parseProto(proto) + } + + fileprivate class func parseProto(_ proto: SessionProtos_DataMessage.OpenGroupInvitation) throws -> SNProtoDataMessageOpenGroupInvitation { + guard proto.hasURL else { + throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: url") + } + let url = proto.url + + guard proto.hasName else { + throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: name") + } + let name = proto.name + + // MARK: - Begin Validation Logic for SNProtoDataMessageOpenGroupInvitation - + + // MARK: - End Validation Logic for SNProtoDataMessageOpenGroupInvitation - + + let result = SNProtoDataMessageOpenGroupInvitation(proto: proto, + url: url, + name: name) + return result + } + + @objc public override var debugDescription: String { + return "\(proto)" + } +} + +#if DEBUG + +extension SNProtoDataMessageOpenGroupInvitation { + @objc public func serializedDataIgnoringErrors() -> Data? { + return try! self.serializedData() + } +} + +extension SNProtoDataMessageOpenGroupInvitation.SNProtoDataMessageOpenGroupInvitationBuilder { + @objc public func buildIgnoringErrors() -> SNProtoDataMessageOpenGroupInvitation? { + return try! self.build() + } +} + +#endif + // MARK: - SNProtoDataMessageClosedGroupControlMessageKeyPairWrapper @objc public class SNProtoDataMessageClosedGroupControlMessageKeyPairWrapper: NSObject { diff --git a/SessionMessagingKit/Protos/Generated/SessionProtos.pb.swift b/SessionMessagingKit/Protos/Generated/SessionProtos.pb.swift index 46674b662..4f5b5cfe0 100644 --- a/SessionMessagingKit/Protos/Generated/SessionProtos.pb.swift +++ b/SessionMessagingKit/Protos/Generated/SessionProtos.pb.swift @@ -670,6 +670,39 @@ struct SessionProtos_DataMessage { fileprivate var _profilePicture: String? = nil } + struct OpenGroupInvitation { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + /// @required + var url: String { + get {return _url ?? String()} + set {_url = newValue} + } + /// Returns true if `url` has been explicitly set. + var hasURL: Bool {return self._url != nil} + /// Clears the value of `url`. Subsequent reads from it will return its default value. + mutating func clearURL() {self._url = nil} + + /// @required + var name: String { + get {return _name ?? String()} + set {_name = newValue} + } + /// Returns true if `name` has been explicitly set. + var hasName: Bool {return self._name != nil} + /// Clears the value of `name`. Subsequent reads from it will return its default value. + mutating func clearName() {self._name = nil} + + var unknownFields = SwiftProtobuf.UnknownStorage() + + init() {} + + fileprivate var _url: String? = nil + fileprivate var _name: String? = nil + } + struct ClosedGroupControlMessage { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -2058,6 +2091,47 @@ extension SessionProtos_DataMessage.LokiProfile: SwiftProtobuf.Message, SwiftPro } } +extension SessionProtos_DataMessage.OpenGroupInvitation: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = SessionProtos_DataMessage.protoMessageName + ".OpenGroupInvitation" + static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "url"), + 3: .same(proto: "name"), + ] + + public var isInitialized: Bool { + if self._url == nil {return false} + if self._name == nil {return false} + return true + } + + mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + switch fieldNumber { + case 1: try decoder.decodeSingularStringField(value: &self._url) + case 3: try decoder.decodeSingularStringField(value: &self._name) + default: break + } + } + } + + func traverse(visitor: inout V) throws { + if let v = self._url { + try visitor.visitSingularStringField(value: v, fieldNumber: 1) + } + if let v = self._name { + try visitor.visitSingularStringField(value: v, fieldNumber: 3) + } + try unknownFields.traverse(visitor: &visitor) + } + + static func ==(lhs: SessionProtos_DataMessage.OpenGroupInvitation, rhs: SessionProtos_DataMessage.OpenGroupInvitation) -> Bool { + if lhs._url != rhs._url {return false} + if lhs._name != rhs._name {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension SessionProtos_DataMessage.ClosedGroupControlMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = SessionProtos_DataMessage.protoMessageName + ".ClosedGroupControlMessage" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ diff --git a/SessionMessagingKit/Protos/SessionProtos.proto b/SessionMessagingKit/Protos/SessionProtos.proto index b0b3b45d3..2e22da754 100644 --- a/SessionMessagingKit/Protos/SessionProtos.proto +++ b/SessionMessagingKit/Protos/SessionProtos.proto @@ -101,6 +101,13 @@ message DataMessage { optional string profilePicture = 2; } + message OpenGroupInvitation { + // @required + required string url = 1; + // @required + required string name = 3; + } + message ClosedGroupControlMessage { enum Type { From f3fef3425940333f630dcb0dee95d624c0306dda Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 7 May 2021 14:53:28 +1000 Subject: [PATCH 07/11] Implement proto conversion --- .../VisibleMessage+OpenGroupInvitation.swift | 20 +++++++++++++++---- .../Visible Messages/VisibleMessage.swift | 4 ++++ .../Protos/Generated/SNProto.swift | 17 ++++++++++++++++ .../Protos/Generated/SessionProtos.pb.swift | 18 +++++++++++++++++ .../Protos/SessionProtos.proto | 1 + 5 files changed, 56 insertions(+), 4 deletions(-) diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+OpenGroupInvitation.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+OpenGroupInvitation.swift index 97295578a..678eeb04a 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+OpenGroupInvitation.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+OpenGroupInvitation.swift @@ -23,12 +23,24 @@ public extension VisibleMessage { coder.encode(url, forKey: "url") } - public static func fromProto(_ proto: SNProtoDataMessage) -> Profile? { - notImplemented() + public static func fromProto(_ proto: SNProtoDataMessageOpenGroupInvitation) -> OpenGroupInvitation? { + let url = proto.url + let name = proto.name + return OpenGroupInvitation(name: name, url: url) } - public func toProto() -> SNProtoDataMessage? { - notImplemented() + public func toProto() -> SNProtoDataMessageOpenGroupInvitation? { + guard let url = url, let name = name else { + SNLog("Couldn't construct open group invitation proto from: \(self).") + return nil + } + let openGroupInvitationProto = SNProtoDataMessageOpenGroupInvitation.builder(url: url, name: name) + do { + return try openGroupInvitationProto.build() + } catch { + SNLog("Couldn't construct open group invitation proto from: \(self).") + return nil + } } // MARK: Description diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift index a8d856382..49e70e2c8 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift @@ -63,6 +63,8 @@ public final class VisibleMessage : Message { if let linkPreviewProto = dataMessage.preview.first, let linkPreview = LinkPreview.fromProto(linkPreviewProto) { result.linkPreview = linkPreview } // TODO: Contact if let profile = Profile.fromProto(dataMessage) { result.profile = profile } + if let openGroupInvitationProto = dataMessage.openGroupInvitation, + let openGroupInvitation = OpenGroupInvitation.fromProto(openGroupInvitationProto) { result.openGroupInvitation = openGroupInvitation } result.syncTarget = dataMessage.syncTarget return result } @@ -99,6 +101,8 @@ public final class VisibleMessage : Message { let attachmentProtos = attachments.compactMap { $0.buildProto() } dataMessage.setAttachments(attachmentProtos) // TODO: Contact + // Open group invitation + if let openGroupInvitation = openGroupInvitation, let openGroupInvitationProto = openGroupInvitation.toProto() { dataMessage.setOpenGroupInvitation(openGroupInvitationProto) } // Expiration timer // TODO: We * want * expiration timer updates to be explicit. But currently Android will disable the expiration timer for a conversation // if it receives a message without the current expiration timer value attached to it... diff --git a/SessionMessagingKit/Protos/Generated/SNProto.swift b/SessionMessagingKit/Protos/Generated/SNProto.swift index da1d9dc85..ea256a14d 100644 --- a/SessionMessagingKit/Protos/Generated/SNProto.swift +++ b/SessionMessagingKit/Protos/Generated/SNProto.swift @@ -1808,6 +1808,9 @@ extension SNProtoDataMessageClosedGroupControlMessage.SNProtoDataMessageClosedGr if let _value = profile { builder.setProfile(_value) } + if let _value = openGroupInvitation { + builder.setOpenGroupInvitation(_value) + } if let _value = closedGroupControlMessage { builder.setClosedGroupControlMessage(_value) } @@ -1875,6 +1878,10 @@ extension SNProtoDataMessageClosedGroupControlMessage.SNProtoDataMessageClosedGr proto.profile = valueParam.proto } + @objc public func setOpenGroupInvitation(_ valueParam: SNProtoDataMessageOpenGroupInvitation) { + proto.openGroupInvitation = valueParam.proto + } + @objc public func setClosedGroupControlMessage(_ valueParam: SNProtoDataMessageClosedGroupControlMessage) { proto.closedGroupControlMessage = valueParam.proto } @@ -1904,6 +1911,8 @@ extension SNProtoDataMessageClosedGroupControlMessage.SNProtoDataMessageClosedGr @objc public let profile: SNProtoDataMessageLokiProfile? + @objc public let openGroupInvitation: SNProtoDataMessageOpenGroupInvitation? + @objc public let closedGroupControlMessage: SNProtoDataMessageClosedGroupControlMessage? @objc public var body: String? { @@ -1963,6 +1972,7 @@ extension SNProtoDataMessageClosedGroupControlMessage.SNProtoDataMessageClosedGr quote: SNProtoDataMessageQuote?, preview: [SNProtoDataMessagePreview], profile: SNProtoDataMessageLokiProfile?, + openGroupInvitation: SNProtoDataMessageOpenGroupInvitation?, closedGroupControlMessage: SNProtoDataMessageClosedGroupControlMessage?) { self.proto = proto self.attachments = attachments @@ -1970,6 +1980,7 @@ extension SNProtoDataMessageClosedGroupControlMessage.SNProtoDataMessageClosedGr self.quote = quote self.preview = preview self.profile = profile + self.openGroupInvitation = openGroupInvitation self.closedGroupControlMessage = closedGroupControlMessage } @@ -2005,6 +2016,11 @@ extension SNProtoDataMessageClosedGroupControlMessage.SNProtoDataMessageClosedGr profile = try SNProtoDataMessageLokiProfile.parseProto(proto.profile) } + var openGroupInvitation: SNProtoDataMessageOpenGroupInvitation? = nil + if proto.hasOpenGroupInvitation { + openGroupInvitation = try SNProtoDataMessageOpenGroupInvitation.parseProto(proto.openGroupInvitation) + } + var closedGroupControlMessage: SNProtoDataMessageClosedGroupControlMessage? = nil if proto.hasClosedGroupControlMessage { closedGroupControlMessage = try SNProtoDataMessageClosedGroupControlMessage.parseProto(proto.closedGroupControlMessage) @@ -2020,6 +2036,7 @@ extension SNProtoDataMessageClosedGroupControlMessage.SNProtoDataMessageClosedGr quote: quote, preview: preview, profile: profile, + openGroupInvitation: openGroupInvitation, closedGroupControlMessage: closedGroupControlMessage) return result } diff --git a/SessionMessagingKit/Protos/Generated/SessionProtos.pb.swift b/SessionMessagingKit/Protos/Generated/SessionProtos.pb.swift index 4f5b5cfe0..d9e4a94cf 100644 --- a/SessionMessagingKit/Protos/Generated/SessionProtos.pb.swift +++ b/SessionMessagingKit/Protos/Generated/SessionProtos.pb.swift @@ -440,6 +440,15 @@ struct SessionProtos_DataMessage { /// Clears the value of `profile`. Subsequent reads from it will return its default value. mutating func clearProfile() {_uniqueStorage()._profile = nil} + var openGroupInvitation: SessionProtos_DataMessage.OpenGroupInvitation { + get {return _storage._openGroupInvitation ?? SessionProtos_DataMessage.OpenGroupInvitation()} + set {_uniqueStorage()._openGroupInvitation = newValue} + } + /// Returns true if `openGroupInvitation` has been explicitly set. + var hasOpenGroupInvitation: Bool {return _storage._openGroupInvitation != nil} + /// Clears the value of `openGroupInvitation`. Subsequent reads from it will return its default value. + mutating func clearOpenGroupInvitation() {_uniqueStorage()._openGroupInvitation = nil} + var closedGroupControlMessage: SessionProtos_DataMessage.ClosedGroupControlMessage { get {return _storage._closedGroupControlMessage ?? SessionProtos_DataMessage.ClosedGroupControlMessage()} set {_uniqueStorage()._closedGroupControlMessage = newValue} @@ -1666,6 +1675,7 @@ extension SessionProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa 8: .same(proto: "quote"), 10: .same(proto: "preview"), 101: .same(proto: "profile"), + 102: .same(proto: "openGroupInvitation"), 104: .same(proto: "closedGroupControlMessage"), 105: .same(proto: "syncTarget"), ] @@ -1681,6 +1691,7 @@ extension SessionProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa var _quote: SessionProtos_DataMessage.Quote? = nil var _preview: [SessionProtos_DataMessage.Preview] = [] var _profile: SessionProtos_DataMessage.LokiProfile? = nil + var _openGroupInvitation: SessionProtos_DataMessage.OpenGroupInvitation? = nil var _closedGroupControlMessage: SessionProtos_DataMessage.ClosedGroupControlMessage? = nil var _syncTarget: String? = nil @@ -1699,6 +1710,7 @@ extension SessionProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa _quote = source._quote _preview = source._preview _profile = source._profile + _openGroupInvitation = source._openGroupInvitation _closedGroupControlMessage = source._closedGroupControlMessage _syncTarget = source._syncTarget } @@ -1717,6 +1729,7 @@ extension SessionProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa if let v = _storage._group, !v.isInitialized {return false} if let v = _storage._quote, !v.isInitialized {return false} if !SwiftProtobuf.Internal.areAllInitialized(_storage._preview) {return false} + if let v = _storage._openGroupInvitation, !v.isInitialized {return false} if let v = _storage._closedGroupControlMessage, !v.isInitialized {return false} return true } @@ -1737,6 +1750,7 @@ extension SessionProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa case 8: try decoder.decodeSingularMessageField(value: &_storage._quote) case 10: try decoder.decodeRepeatedMessageField(value: &_storage._preview) case 101: try decoder.decodeSingularMessageField(value: &_storage._profile) + case 102: try decoder.decodeSingularMessageField(value: &_storage._openGroupInvitation) case 104: try decoder.decodeSingularMessageField(value: &_storage._closedGroupControlMessage) case 105: try decoder.decodeSingularStringField(value: &_storage._syncTarget) default: break @@ -1777,6 +1791,9 @@ extension SessionProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa if let v = _storage._profile { try visitor.visitSingularMessageField(value: v, fieldNumber: 101) } + if let v = _storage._openGroupInvitation { + try visitor.visitSingularMessageField(value: v, fieldNumber: 102) + } if let v = _storage._closedGroupControlMessage { try visitor.visitSingularMessageField(value: v, fieldNumber: 104) } @@ -1802,6 +1819,7 @@ extension SessionProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa if _storage._quote != rhs_storage._quote {return false} if _storage._preview != rhs_storage._preview {return false} if _storage._profile != rhs_storage._profile {return false} + if _storage._openGroupInvitation != rhs_storage._openGroupInvitation {return false} if _storage._closedGroupControlMessage != rhs_storage._closedGroupControlMessage {return false} if _storage._syncTarget != rhs_storage._syncTarget {return false} return true diff --git a/SessionMessagingKit/Protos/SessionProtos.proto b/SessionMessagingKit/Protos/SessionProtos.proto index 2e22da754..bdb101bcc 100644 --- a/SessionMessagingKit/Protos/SessionProtos.proto +++ b/SessionMessagingKit/Protos/SessionProtos.proto @@ -147,6 +147,7 @@ message DataMessage { optional Quote quote = 8; repeated Preview preview = 10; optional LokiProfile profile = 101; + optional OpenGroupInvitation openGroupInvitation = 102; optional ClosedGroupControlMessage closedGroupControlMessage = 104; optional string syncTarget = 105; } From 216c4a92e524875048acc7ae063a70e96bfa6936 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 7 May 2021 15:06:20 +1000 Subject: [PATCH 08/11] Debug --- .../Settings/OWSConversationSettingsViewController.m | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Session/Conversations/Settings/OWSConversationSettingsViewController.m b/Session/Conversations/Settings/OWSConversationSettingsViewController.m index ae8ba7aa0..2adb62bed 100644 --- a/Session/Conversations/Settings/OWSConversationSettingsViewController.m +++ b/Session/Conversations/Settings/OWSConversationSettingsViewController.m @@ -1115,14 +1115,13 @@ CGFloat kIconViewLength = 24; SNVisibleMessage *message = [SNVisibleMessage new]; message.sentTimestamp = [NSDate millisecondTimestamp]; message.openGroupInvitation = [[SNOpenGroupInvitation alloc] initWithName:openGroup.name url:url]; - TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:self.thread]; + TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactSessionID:user]; + TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:thread]; [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [tsMessage saveWithTransaction:transaction]; }]; [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - TSContactThread *thread = [TSContactThread getThreadWithContactSessionID:user transaction:transaction]; [SNMessageSender send:message inThread:thread usingTransaction:transaction]; - [self.navigationController popViewControllerAnimated:YES]; }]; } }]; From e4d1925436c4fe7d4a5e39f2f3b69dbceefd1787 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 7 May 2021 15:18:57 +1000 Subject: [PATCH 09/11] Show confirmation dialog --- Session.xcodeproj/project.pbxproj | 4 ++ .../ConversationVC+Interaction.swift | 11 +++ .../Views & Modals/JoinOpenGroupModal.swift | 68 +++++++++++++++++++ .../Messages/Signal/TSMessage.m | 2 + 4 files changed, 85 insertions(+) create mode 100644 Session/Conversations/Views & Modals/JoinOpenGroupModal.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 6cc48e38b..dc09384c8 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -202,6 +202,7 @@ B866CE112581C1A900535CC4 /* Sodium+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E7134E251C867C009649BB /* Sodium+Conversion.swift */; }; B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; }; B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; }; + B875885A264503A6000E60D0 /* JoinOpenGroupModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8758859264503A6000E60D0 /* JoinOpenGroupModal.swift */; }; B8783E9E23EB948D00404FB8 /* UILabel+Interaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */; }; B879D449247E1BE300DB3608 /* PathVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B879D448247E1BE300DB3608 /* PathVC.swift */; }; B87EF17126367CF800124B3C /* FileServerAPIV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B87EF17026367CF800124B3C /* FileServerAPIV2.swift */; }; @@ -1198,6 +1199,7 @@ B86BD08323399ACF000F5AE3 /* Modal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modal.swift; sourceTree = ""; }; B86BD08523399CEF000F5AE3 /* SeedModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedModal.swift; sourceTree = ""; }; B87588582644CA9D000E60D0 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; + B8758859264503A6000E60D0 /* JoinOpenGroupModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinOpenGroupModal.swift; sourceTree = ""; }; B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Interaction.swift"; sourceTree = ""; }; B879D448247E1BE300DB3608 /* PathVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathVC.swift; sourceTree = ""; }; B879D44A247E1D9200DB3608 /* PathStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathStatusView.swift; sourceTree = ""; }; @@ -2139,6 +2141,7 @@ B8F5F72225F1B4CA003BF8D4 /* DownloadAttachmentModal.swift */, C3A76A8C25DB83F90074CB90 /* PermissionMissingModal.swift */, B821494525D4D6FF009C0F2A /* URLModal.swift */, + B8758859264503A6000E60D0 /* JoinOpenGroupModal.swift */, B821494E25D4E163009C0F2A /* BodyTextView.swift */, B82149B725D60393009C0F2A /* BlockedModal.swift */, C374EEE125DA26740073A857 /* LinkPreviewModal.swift */, @@ -4927,6 +4930,7 @@ B85357C323A1BD1200AAF6CD /* SeedVC.swift in Sources */, 45B5360E206DD8BB00D61655 /* UIResponder+OWS.swift in Sources */, B8D84ECF25E3108A005A043E /* ExpandingAttachmentsButton.swift in Sources */, + B875885A264503A6000E60D0 /* JoinOpenGroupModal.swift in Sources */, B8CCF6432397711F0091D419 /* SettingsVC.swift in Sources */, C354E75A23FE2A7600CE22E3 /* BaseVC.swift in Sources */, 3441FD9F21A3604F00BB9542 /* BackupRestoreViewController.swift in Sources */, diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index 1dbdfea19..61d2c37bf 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -447,6 +447,9 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc // Scroll to the source of the reply guard let indexPath = viewModel.ensureLoadWindowContainsQuotedReply(reply) else { return } messagesTableView.scrollToRow(at: indexPath, at: UITableView.ScrollPosition.middle, animated: true) + } else if let message = viewItem.interaction as? TSIncomingMessage, let name = message.openGroupInvitationName, + let url = message.openGroupInvitationURL { + joinOpenGroup(name: name, url: url) } default: break } @@ -555,6 +558,14 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc present(urlModal, animated: true, completion: nil) } + func joinOpenGroup(name: String, url: String) { + // Open groups can be unsafe, so always ask the user whether they want to join one + let joinOpenGroupModal = JoinOpenGroupModal(name: name, url: url) + joinOpenGroupModal.modalPresentationStyle = .overFullScreen + joinOpenGroupModal.modalTransitionStyle = .crossDissolve + present(joinOpenGroupModal, animated: true, completion: nil) + } + func handleReplyButtonTapped(for viewItem: ConversationViewItem) { reply(viewItem) } diff --git a/Session/Conversations/Views & Modals/JoinOpenGroupModal.swift b/Session/Conversations/Views & Modals/JoinOpenGroupModal.swift new file mode 100644 index 000000000..58bd69644 --- /dev/null +++ b/Session/Conversations/Views & Modals/JoinOpenGroupModal.swift @@ -0,0 +1,68 @@ + +final class JoinOpenGroupModal : Modal { + private let name: String + private let url: String + + // MARK: Lifecycle + init(name: String, url: String) { + self.name = name + self.url = url + super.init(nibName: nil, bundle: nil) + } + + override init(nibName: String?, bundle: Bundle?) { + preconditionFailure("Use init(name:url:) instead.") + } + + required init?(coder: NSCoder) { + preconditionFailure("Use init(name:url:) instead.") + } + + override func populateContentView() { + // Title + let titleLabel = UILabel() + titleLabel.textColor = Colors.text + titleLabel.font = .boldSystemFont(ofSize: Values.largeFontSize) + titleLabel.text = "Join \(name)?" + titleLabel.textAlignment = .center + // Message + let messageLabel = UILabel() + messageLabel.textColor = Colors.text + messageLabel.font = .systemFont(ofSize: Values.smallFontSize) + let message = "Are you sure you want to join the \(name) open group?"; + let attributedMessage = NSMutableAttributedString(string: message) + attributedMessage.addAttributes([ .font : UIFont.boldSystemFont(ofSize: Values.smallFontSize) ], range: (message as NSString).range(of: name)) + messageLabel.attributedText = attributedMessage + messageLabel.numberOfLines = 0 + messageLabel.lineBreakMode = .byWordWrapping + messageLabel.textAlignment = .center + // Join button + let joinButton = UIButton() + joinButton.set(.height, to: Values.mediumButtonHeight) + joinButton.layer.cornerRadius = Modal.buttonCornerRadius + joinButton.backgroundColor = Colors.buttonBackground + joinButton.titleLabel!.font = .systemFont(ofSize: Values.smallFontSize) + joinButton.setTitleColor(Colors.text, for: UIControl.State.normal) + joinButton.setTitle("Join", for: UIControl.State.normal) + joinButton.addTarget(self, action: #selector(openURL), for: UIControl.Event.touchUpInside) + // Button stack view + let buttonStackView = UIStackView(arrangedSubviews: [ cancelButton, joinButton ]) + buttonStackView.axis = .horizontal + buttonStackView.spacing = Values.mediumSpacing + buttonStackView.distribution = .fillEqually + // Main stack view + let mainStackView = UIStackView(arrangedSubviews: [ titleLabel, messageLabel, buttonStackView ]) + mainStackView.axis = .vertical + mainStackView.spacing = Values.largeSpacing + contentView.addSubview(mainStackView) + mainStackView.pin(.leading, to: .leading, of: contentView, withInset: Values.largeSpacing) + mainStackView.pin(.top, to: .top, of: contentView, withInset: Values.largeSpacing) + contentView.pin(.trailing, to: .trailing, of: mainStackView, withInset: Values.largeSpacing) + contentView.pin(.bottom, to: .bottom, of: mainStackView, withInset: Values.largeSpacing) + } + + // MARK: Interaction + @objc private func openURL() { + + } +} diff --git a/SessionMessagingKit/Messages/Signal/TSMessage.m b/SessionMessagingKit/Messages/Signal/TSMessage.m index 8ea5f61c2..5b0634fe8 100644 --- a/SessionMessagingKit/Messages/Signal/TSMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSMessage.m @@ -346,6 +346,8 @@ const NSUInteger kOversizeTextMessageSizeThreshold = 2 * 1024; return bodyDescription; } else if (attachmentDescription.length > 0) { return attachmentDescription; + } else if (self.openGroupInvitationName != nil) { + return @"😎 Open group invitation"; } else { // TODO: We should do better here. return @""; From 4eff61595a7d3d92f8ba2365199424c2ae8fd7ad Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 7 May 2021 15:29:54 +1000 Subject: [PATCH 10/11] Implement open group joining business logic --- .../Views & Modals/JoinOpenGroupModal.swift | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/Session/Conversations/Views & Modals/JoinOpenGroupModal.swift b/Session/Conversations/Views & Modals/JoinOpenGroupModal.swift index 58bd69644..0269bb943 100644 --- a/Session/Conversations/Views & Modals/JoinOpenGroupModal.swift +++ b/Session/Conversations/Views & Modals/JoinOpenGroupModal.swift @@ -44,7 +44,7 @@ final class JoinOpenGroupModal : Modal { joinButton.titleLabel!.font = .systemFont(ofSize: Values.smallFontSize) joinButton.setTitleColor(Colors.text, for: UIControl.State.normal) joinButton.setTitle("Join", for: UIControl.State.normal) - joinButton.addTarget(self, action: #selector(openURL), for: UIControl.Event.touchUpInside) + joinButton.addTarget(self, action: #selector(joinOpenGroup), for: UIControl.Event.touchUpInside) // Button stack view let buttonStackView = UIStackView(arrangedSubviews: [ cancelButton, joinButton ]) buttonStackView.axis = .horizontal @@ -62,7 +62,24 @@ final class JoinOpenGroupModal : Modal { } // MARK: Interaction - @objc private func openURL() { - + @objc private func joinOpenGroup() { + guard let (room, server, publicKey) = OpenGroupManagerV2.parseV2OpenGroup(from: url), Features.useV2OpenGroups else { + let alert = UIAlertController(title: "Couldn't Join", message: nil, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)) + return presentingViewController!.present(alert, animated: true, completion: nil) + } + presentingViewController!.dismiss(animated: true, completion: nil) + Storage.shared.write { [presentingViewController = self.presentingViewController!] transaction in + OpenGroupManagerV2.shared.add(room: room, server: server, publicKey: publicKey, using: transaction) + .done(on: DispatchQueue.main) { _ in + let appDelegate = UIApplication.shared.delegate as! AppDelegate + appDelegate.forceSyncConfigurationNowIfNeeded().retainUntilComplete() // FIXME: It's probably cleaner to do this inside addOpenGroup(...) + } + .catch(on: DispatchQueue.main) { error in + let alert = UIAlertController(title: "Couldn't Join", message: error.localizedDescription, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)) + presentingViewController.present(alert, animated: true, completion: nil) + } + } } } From 00300afecb20385e97fef846b8f2e0a4bbc5d53d Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Fri, 7 May 2021 15:47:40 +1000 Subject: [PATCH 11/11] Swap out sent open group invitation icon --- .../Content Views/OpenGroupInvitationView.swift | 7 +++++-- .../Conversations/Message Cells/VisibleMessageCell.swift | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift b/Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift index bd328fe8d..7a1065044 100644 --- a/Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift +++ b/Session/Conversations/Message Cells/Content Views/OpenGroupInvitationView.swift @@ -3,6 +3,7 @@ final class OpenGroupInvitationView : UIView { private let name: String private let rawURL: String private let textColor: UIColor + private let isOutgoing: Bool private lazy var url: String = { if let range = rawURL.range(of: "?public_key=") { @@ -17,10 +18,11 @@ final class OpenGroupInvitationView : UIView { private static let iconImageViewSize: CGFloat = 48 // MARK: Lifecycle - init(name: String, url: String, textColor: UIColor) { + init(name: String, url: String, textColor: UIColor, isOutgoing: Bool) { self.name = name self.rawURL = url self.textColor = textColor + self.isOutgoing = isOutgoing super.init(frame: CGRect.zero) setUpViewHierarchy() } @@ -58,7 +60,8 @@ final class OpenGroupInvitationView : UIView { labelStackView.axis = .vertical // Icon let iconSize = OpenGroupInvitationView.iconSize - let icon = UIImage(named: "Plus")?.withTint(.white)?.resizedImage(to: CGSize(width: iconSize, height: iconSize)) + let iconName = isOutgoing ? "Globe" : "Plus" + let icon = UIImage(named: iconName)?.withTint(.white)?.resizedImage(to: CGSize(width: iconSize, height: iconSize)) let iconImageViewSize = OpenGroupInvitationView.iconImageViewSize let iconImageView = UIImageView(image: icon) iconImageView.contentMode = .center diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index 064065f84..d6c1e2977 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -321,7 +321,7 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate { snContentView.addSubview(linkPreviewView) linkPreviewView.pin(to: snContentView) } else if let openGroupInvitationName = message.openGroupInvitationName, let openGroupInvitationURL = message.openGroupInvitationURL { - let openGroupInvitationView = OpenGroupInvitationView(name: openGroupInvitationName, url: openGroupInvitationURL, textColor: bodyLabelTextColor) + let openGroupInvitationView = OpenGroupInvitationView(name: openGroupInvitationName, url: openGroupInvitationURL, textColor: bodyLabelTextColor, isOutgoing: isOutgoing) snContentView.addSubview(openGroupInvitationView) openGroupInvitationView.pin(to: snContentView) } else {