diff --git a/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift b/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift index 73e66a7e9..77026a5dd 100644 --- a/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift +++ b/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift @@ -151,6 +151,14 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat } @objc private func createClosedGroup() { + if ClosedGroupsProtocol.isSharedSenderKeysEnabled { + createSSKClosedGroup() + } else { + createLegacyClosedGroup() + } + } + + private func createSSKClosedGroup() { func showError(title: String, message: String = "") { let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)) @@ -182,6 +190,57 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat } } } + + private func createLegacyClosedGroup() { + func showError(title: String, message: String = "") { + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)) + presentAlert(alert) + } + guard let name = nameTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines), name.count > 0 else { + return showError(title: NSLocalizedString("Please enter a group name", comment: "")) + } + guard name.count < 64 else { + return showError(title: NSLocalizedString("Please enter a shorter group name", comment: "")) + } + guard selectedContacts.count >= 2 else { + return showError(title: NSLocalizedString("Please pick at least 2 group members", comment: "")) + } + guard selectedContacts.count <= 10 else { + return showError(title: NSLocalizedString("A closed group cannot have more than 10 members", comment: "")) + } + let userPublicKey = getUserHexEncodedPublicKey() + let storage = OWSPrimaryStorage.shared() + var masterPublicKey = "" + storage.dbReadConnection.read { transaction in + masterPublicKey = storage.getMasterHexEncodedPublicKey(for: userPublicKey, in: transaction) ?? userPublicKey + } + let members = selectedContacts + [ masterPublicKey ] + let admins = [ masterPublicKey ] + let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(Randomness.generateRandomBytes(kGroupIdLength)!.toHexString()) + let group = TSGroupModel(title: name, memberIds: members, image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins) + let thread = TSGroupThread.getOrCreateThread(with: group) + OWSProfileManager.shared().addThread(toProfileWhitelist: thread) + ModalActivityIndicatorViewController.present(fromViewController: navigationController!, canCancel: false) { [weak self] modalActivityIndicator in + let message = TSOutgoingMessage(in: thread, groupMetaMessage: .new, expiresInSeconds: 0) + message.update(withCustomMessage: "Closed group created") + DispatchQueue.main.async { + SSKEnvironment.shared.messageSender.send(message, success: { + DispatchQueue.main.async { + self?.presentingViewController?.dismiss(animated: true, completion: nil) + SignalApp.shared().presentConversation(for: thread, action: .compose, animated: false) + } + }, failure: { error in + let message = TSErrorMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, failedMessageType: .groupCreationFailed) + message.save() + DispatchQueue.main.async { + self?.presentingViewController?.dismiss(animated: true, completion: nil) + SignalApp.shared().presentConversation(for: thread, action: .compose, animated: false) + } + }) + } + } + } @objc private func createNewPrivateChat() { presentingViewController?.dismiss(animated: true, completion: nil) diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index e7309a5a5..b7ff78262 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -2806,7 +2806,9 @@ "Search GIFs?" = "Search GIFs?"; "You will not have full metadata protection when sending GIFs." = "You will not have full metadata protection when sending GIFs."; "The ability to add members to a closed group is coming soon." = "The ability to add members to a closed group is coming soon."; +"A closed group cannot have more than 10 members" = "A closed group cannot have more than 10 members"; "A closed group cannot have more than 20 members" = "A closed group cannot have more than 20 members"; +"Closed groups support up to 10 members" = "Closed groups support up to 10 members"; "Closed groups support up to 20 members" = "Closed groups support up to 20 members"; "No messages yet" = "No messages yet"; "Would you like to join the Session Public Chat?" = "Would you like to join the Session Public Chat?"; diff --git a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift index 3c827dba3..ea1aa033a 100644 --- a/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Closed Groups/ClosedGroupsProtocol.swift @@ -12,11 +12,7 @@ import PromiseKit /// See [the documentation](https://github.com/loki-project/session-protocol-docs/wiki/Medium-Size-Groups) for more information. @objc(LKClosedGroupsProtocol) public final class ClosedGroupsProtocol : NSObject { - - // TODO: - // • Multi device - // • ClosedGroupsProtocol - // • SyncMessagesProtocol + public static let isSharedSenderKeysEnabled = true /// - Note: It's recommended to batch fetch the device links for the given set of members before invoking this, to avoid /// the message sending pipeline making a request for each member. @@ -177,6 +173,7 @@ public final class ClosedGroupsProtocol : NSObject { @objc(handleSharedSenderKeysUpdateIfNeeded:from:transaction:) public static func handleSharedSenderKeysUpdateIfNeeded(_ dataMessage: SSKProtoDataMessage, from publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { + guard isSharedSenderKeysEnabled else { return } // Note that `publicKey` is either the public key of the group or the public key of the // sender, depending on how the message was sent guard let closedGroupUpdate = dataMessage.closedGroupUpdate else { return }