Эх сурвалжийг харах

Merge pull request #1051 from deltachat/mailinglists

add mailinglist and bot-impersonation support
cyBerta 4 жил өмнө
parent
commit
921e878822

+ 38 - 22
DcCore/DcCore/DC/Wrapper.swift

@@ -85,8 +85,9 @@ public class DcContext {
         }
     }
 
-    public func createChatByMessageId(_ messageId: Int) -> DcChat {
-        let chatId = dc_create_chat_by_msg_id(contextPointer, UInt32(messageId))
+    @discardableResult
+    public func decideOnContactRequest(_ messageId: Int, _ decision: Int32) -> DcChat {
+        let chatId = dc_decide_on_contact_request(contextPointer, UInt32(messageId), decision)
         return getChat(chatId: Int(chatId))
     }
 
@@ -664,14 +665,6 @@ public class DcChat {
         return swiftString
     }
 
-    public var type: Int {
-        return Int(dc_chat_get_type(chatPointer))
-    }
-
-    public var chatType: ChatType {
-        return ChatType(rawValue: type) ?? ChatType.GROUP // group as fallback - shouldn't get here
-    }
-
     public var color: UIColor {
         return UIColor(netHex: Int(dc_chat_get_color(chatPointer)))
     }
@@ -689,7 +682,14 @@ public class DcChat {
     }
 
     public var isGroup: Bool {
-        return Int(dc_chat_get_type(chatPointer)) == DC_CHAT_TYPE_GROUP
+        // isMultiUser() might fit better,
+        // however, would result in lots of code changes, so we leave this as is for now.
+        let type = Int(dc_chat_get_type(chatPointer))
+        return type == DC_CHAT_TYPE_GROUP || type == DC_CHAT_TYPE_MAILINGLIST
+    }
+
+    public var isMailinglist: Bool {
+        return Int(dc_chat_get_type(chatPointer)) == DC_CHAT_TYPE_MAILINGLIST
     }
 
     public var isSelfTalk: Bool {
@@ -833,6 +833,25 @@ public class DcMsg {
         return Int(dc_msg_get_chat_id(messagePointer))
     }
 
+    public var realChatId: Int {
+        return Int(dc_msg_get_real_chat_id(messagePointer))
+    }
+
+    public var overrideSenderName: String? {
+        guard let cString = dc_msg_get_override_sender_name(messagePointer) else { return nil }
+        let swiftString = String(cString: cString)
+        dc_str_unref(cString)
+        return swiftString
+    }
+
+    public func getSenderName(_ dcContact: DcContact, markOverride: Bool = false) -> String {
+        if let overrideName = overrideSenderName {
+            return (markOverride ? "~" : "") + overrideName
+        } else {
+            return dcContact.displayName
+        }
+    }
+
     public var text: String? {
         set {
             if let newValue = newValue {
@@ -1080,13 +1099,20 @@ public class DcContact {
         return swiftString
     }
 
-    public var name: String {
+    public var editedName: String {
         guard let cString = dc_contact_get_name(contactPointer) else { return "" }
         let swiftString = String(cString: cString)
         dc_str_unref(cString)
         return swiftString
     }
 
+    public var authName: String {
+        guard let cString = dc_contact_get_auth_name(contactPointer) else { return "" }
+        let swiftString = String(cString: cString)
+        dc_str_unref(cString)
+        return swiftString
+    }
+
     public var email: String {
         guard let cString = dc_contact_get_addr(contactPointer) else { return "" }
         let swiftString = String(cString: cString)
@@ -1141,10 +1167,6 @@ public class DcContact {
     public func unblock() {
         dc_block_contact(DcContext.shared.contextPointer, UInt32(id), 0)
     }
-
-    public func marknoticed() {
-        dc_marknoticed_contact(DcContext.shared.contextPointer, UInt32(id))
-    }
 }
 
 public class DcLot {
@@ -1221,12 +1243,6 @@ public class DcProvider {
     }
 }
 
-public enum ChatType: Int {
-    case SINGLE = 100
-    case GROUP = 120
-    case VERIFIEDGROUP = 130
-}
-
 public enum MessageViewType: CustomStringConvertible {
     case audio
     case file

+ 1 - 1
DcCore/DcCore/DC/events.swift

@@ -149,7 +149,7 @@ public func handleEvent(event: DcEvent) {
             if !UserDefaults.standard.bool(forKey: "notifications_disabled") && !chat.isMuted {
                 let content = UNMutableNotificationContent()
                 let msg = DcMsg(id: Int(data2))
-                content.title = msg.fromContact.displayName
+                content.title = msg.getSenderName(msg.fromContact)
                 content.body = msg.summary(chars: 40) ?? ""
                 content.userInfo = userInfo
                 content.sound = .default

+ 10 - 11
deltachat-ios/Chat/ChatViewController.swift

@@ -621,16 +621,16 @@ class ChatViewController: UITableViewController {
 
         var subtitle = "ErrSubtitle"
         let chatContactIds = chat.contactIds
-        if chat.isGroup {
+        if chat.isMailinglist {
+            subtitle = String.localized("mailing_list")
+        } else if chat.isGroup {
             subtitle = String.localized(stringID: "n_members", count: chatContactIds.count)
+        } else if chat.isDeviceTalk {
+            subtitle = String.localized("device_talk_subtitle")
+        } else if chat.isSelfTalk {
+            subtitle = String.localized("chat_self_talk_subtitle")
         } else if chatContactIds.count >= 1 {
-            if chat.isDeviceTalk {
-                subtitle = String.localized("device_talk_subtitle")
-            } else if chat.isSelfTalk {
-                subtitle = String.localized("chat_self_talk_subtitle")
-            } else {
-                subtitle = DcContact(id: chatContactIds[0]).email
-            }
+            subtitle = DcContact(id: chatContactIds[0]).email
         }
 
         titleView.updateTitleView(title: chat.name, subtitle: subtitle)
@@ -931,13 +931,12 @@ class ChatViewController: UITableViewController {
     // MARK: - coordinator
     private func showChatDetail(chatId: Int) {
         let chat = dcContext.getChat(chatId: chatId)
-        switch chat.chatType {
-        case .SINGLE:
+        if !chat.isGroup {
             if let contactId = chat.contactIds.first {
                 let contactDetailController = ContactDetailViewController(dcContext: dcContext, contactId: contactId)
                 navigationController?.pushViewController(contactDetailController, animated: true)
             }
-        case .GROUP, .VERIFIEDGROUP:
+        } else {
             let groupChatDetailViewController = GroupChatDetailViewController(chatId: chatId, dcContext: dcContext)
             navigationController?.pushViewController(groupChatDetailViewController, animated: true)
         }

+ 3 - 3
deltachat-ios/Chat/Views/Cells/BaseMessageCell.swift

@@ -241,7 +241,7 @@ public class BaseMessageCell: UITableViewCell {
 
         } else {
             topLabel.text = msg.isForwarded ? String.localized("forwarded_message") :
-                isGroup ? msg.fromContact.displayName : nil
+                isGroup ? msg.getSenderName(msg.fromContact, markOverride: true) : nil
             topLabel.textColor = msg.isForwarded ? DcColors.grayDateColor :
                 isGroup ? msg.fromContact.color : DcColors.defaultTextColor
             leadingConstraintCurrentSender?.isActive = false
@@ -258,7 +258,7 @@ public class BaseMessageCell: UITableViewCell {
 
         if isAvatarVisible {
             avatarView.isHidden = false
-            avatarView.setName(msg.fromContact.displayName)
+            avatarView.setName(msg.getSenderName(msg.fromContact))
             avatarView.setColor(msg.fromContact.color)
             if let profileImage = msg.fromContact.profileImage {
                 avatarView.setImage(profileImage)
@@ -286,7 +286,7 @@ public class BaseMessageCell: UITableViewCell {
                     quoteView.citeBar.backgroundColor = DcColors.grayDateColor
                 } else {
                     let contact = quoteMsg.fromContact
-                    quoteView.senderTitle.text = contact.displayName
+                    quoteView.senderTitle.text = quoteMsg.getSenderName(contact)
                     quoteView.senderTitle.textColor = contact.color
                     quoteView.citeBar.backgroundColor = contact.color
                 }

+ 1 - 1
deltachat-ios/Chat/Views/QuotePreview.swift

@@ -40,7 +40,7 @@ public class QuotePreview: DraftPreview {
                     quoteView.citeBar.backgroundColor = DcColors.grayDateColor
                 } else {
                     let contact = quoteMessage.fromContact
-                    quoteView.senderTitle.text = contact.displayName
+                    quoteView.senderTitle.text = quoteMessage.getSenderName(contact)
                     quoteView.senderTitle.textColor = contact.color
                     quoteView.citeBar.backgroundColor = contact.color
                 }

+ 1 - 1
deltachat-ios/Controller/BlockedContactsViewController.swift

@@ -43,7 +43,7 @@ class BlockedContactsViewController: GroupMembersViewController, GroupMemberSele
     func selected(contactId: Int, selected: Bool) {
         if !selected {
             let dcContact = DcContact(id: contactId)
-            let title = dcContact.displayName.isEmpty ? dcContact.email : dcContact.displayName
+            let title = dcContact.displayName
             let alert = UIAlertController(title: title, message: String.localized("ask_unblock_contact"), preferredStyle: .safeActionSheet)
             alert.addAction(UIAlertAction(title: String.localized("menu_unblock_contact"), style: .default, handler: { _ in
                 let contact = DcContact(id: contactId)

+ 6 - 7
deltachat-ios/Controller/ChatListController.swift

@@ -337,21 +337,20 @@ class ChatListController: UITableViewController {
 
     private func showDeaddropRequestAlert(msgId: Int) {
         let dcMsg = DcMsg(id: msgId)
-        let dcContact = DcContact(id: dcMsg.fromContactId)
-        let title = String.localizedStringWithFormat(String.localized("ask_start_chat_with"), dcContact.nameNAddr)
+        let (title, startButton, blockButton) = MailboxViewController.deaddropQuestion(context: dcContext, msg: dcMsg)
         let alert = UIAlertController(title: title, message: nil, preferredStyle: .safeActionSheet)
-        alert.addAction(UIAlertAction(title: String.localized("start_chat"), style: .default, handler: { _ in
-            let chat = self.dcContext.createChatByMessageId(msgId)
+        alert.addAction(UIAlertAction(title: startButton, style: .default, handler: { _ in
+            let chat = self.dcContext.decideOnContactRequest(msgId, DC_DECISION_START_CHAT)
             self.showChat(chatId: chat.id)
         }))
         alert.addAction(UIAlertAction(title: String.localized("not_now"), style: .default, handler: { _ in
             DispatchQueue.global(qos: .background).async {
-                dcContact.marknoticed()
+                self.dcContext.decideOnContactRequest(msgId, DC_DECISION_NOT_NOW)
             }
         }))
-        alert.addAction(UIAlertAction(title: String.localized("menu_block_contact"), style: .destructive, handler: { _ in
+        alert.addAction(UIAlertAction(title: blockButton, style: .destructive, handler: { _ in
             DispatchQueue.global(qos: .background).async {
-                dcContact.block()
+                self.dcContext.decideOnContactRequest(msgId, DC_DECISION_BLOCK)
             }
         }))
         alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .cancel))

+ 6 - 2
deltachat-ios/Controller/EditContactController.swift

@@ -11,12 +11,16 @@ class EditContactController: NewContactController {
         title = String.localized("edit_contact")
 
         let contact = DcContact(id: contactIdForUpdate)
-        nameCell.textField.text = contact.name
+
+        nameCell.textField.text = contact.editedName
+        if !contact.authName.isEmpty { // else show string "Name" as set by super.init()
+            nameCell.placeholder = contact.authName
+        }
         emailCell.textField.text = contact.email
         emailCell.textField.isEnabled = false
         emailCell.contentView.alpha = 0.3
 
-        model.name = contact.name
+        model.name = contact.editedName
         model.email = contact.email
 
         if contactIsValid() {

+ 22 - 10
deltachat-ios/Controller/GroupChatDetailViewController.swift

@@ -23,13 +23,8 @@ class GroupChatDetailViewController: UIViewController {
         case deleteChat
     }
 
-    private lazy var chatOptions: [ChatOption] = {
-        return [.gallery, .documents, .ephemeralMessages, .muteChat]
-    }()
-
-    private lazy var chatActions: [ChatAction] = {
-        return [.archiveChat, .leaveGroup, .deleteChat]
-    }()
+    private let chatOptions: [ChatOption]
+    private let chatActions: [ChatAction]
 
     private let membersRowAddMembers = 0
     private let membersRowQrInvite = 1
@@ -37,7 +32,7 @@ class GroupChatDetailViewController: UIViewController {
 
     private let dcContext: DcContext
 
-    private let sections: [ProfileSections] = [.chatOptions, .members, .chatActions]
+    private let sections: [ProfileSections]
 
     private var currentUser: DcContact? {
         let myId = groupMemberIds.filter { DcContact(id: $0).email == dcContext.addr }.first
@@ -168,6 +163,18 @@ class GroupChatDetailViewController: UIViewController {
     init(chatId: Int, dcContext: DcContext) {
         self.dcContext = dcContext
         self.chatId = chatId
+
+        let chat = dcContext.getChat(chatId: chatId)
+        if chat.isMailinglist {
+            self.chatOptions = [.gallery, .documents, .muteChat]
+            self.chatActions = [.archiveChat, .deleteChat]
+            self.sections = [.chatOptions, .chatActions]
+        } else {
+            self.chatOptions = [.gallery, .documents, .ephemeralMessages, .muteChat]
+            self.chatActions = [.archiveChat, .leaveGroup, .deleteChat]
+            self.sections = [.chatOptions, .members, .chatActions]
+        }
+
         super.init(nibName: nil, bundle: nil)
         setupSubviews()
     }
@@ -189,7 +196,11 @@ class GroupChatDetailViewController: UIViewController {
     // MARK: - lifecycle
     override func viewDidLoad() {
         super.viewDidLoad()
-        title = String.localized("tab_group")
+        if chat.isMailinglist {
+            title = String.localized("mailing_list")
+        } else {
+            title = String.localized("tab_group")
+        }
         navigationItem.rightBarButtonItem = editBarButtonItem
         groupHeader.frame = CGRect(0, 0, tableView.frame.width, ContactCell.cellHeight)
     }
@@ -220,7 +231,8 @@ class GroupChatDetailViewController: UIViewController {
     private func updateHeader() {
         groupHeader.updateDetails(
             title: chat.name,
-            subtitle: String.localizedStringWithFormat(String.localized("n_members"), chat.contactIds.count)
+            subtitle: chat.isMailinglist ?
+                nil : String.localizedStringWithFormat(String.localized("n_members"), chat.contactIds.count)
         )
         if let img = chat.profileImage {
             groupHeader.setImage(img)

+ 18 - 6
deltachat-ios/Controller/MailboxViewController.swift

@@ -36,6 +36,19 @@ class MailboxViewController: ChatViewController {
         askToChat(messageId: messageIds[indexPath.row])
     }
 
+    // function builds the correct question when tapping on a deaddrop message.
+    // returns a tuple (question, startButton, blockButton)
+    public static func deaddropQuestion(context: DcContext, msg: DcMsg) -> (String, String, String) {
+        let chat = context.getChat(chatId: msg.realChatId)
+        if chat.isMailinglist {
+            let question = String.localizedStringWithFormat(String.localized("ask_show_mailing_list"), chat.name)
+            return (question, String.localized("yes"), String.localized("block"))
+        } else {
+            let contact = msg.fromContact
+            let question = String.localizedStringWithFormat(String.localized("ask_start_chat_with"), contact.nameNAddr)
+            return (question, String.localized("start_chat"), String.localized("menu_block_contact"))
+        }
+    }
 
     func askToChat(messageId: Int) {
         if handleUIMenu() { return }
@@ -43,15 +56,14 @@ class MailboxViewController: ChatViewController {
         if message.isInfo {
             return
         }
-        let dcContact = message.fromContact
-        let title = String.localizedStringWithFormat(String.localized("ask_start_chat_with"), dcContact.nameNAddr)
+        let (title, startButton, blockButton) = MailboxViewController.deaddropQuestion(context: dcContext, msg: message)
         let alert = UIAlertController(title: title, message: nil, preferredStyle: .safeActionSheet)
-        alert.addAction(UIAlertAction(title: String.localized("start_chat"), style: .default, handler: { _ in
-            let chat = self.dcContext.createChatByMessageId(messageId)
+        alert.addAction(UIAlertAction(title: startButton, style: .default, handler: { _ in
+            let chat = self.dcContext.decideOnContactRequest(messageId, DC_DECISION_START_CHAT)
             self.showChat(chatId: chat.id)
         }))
-        alert.addAction(UIAlertAction(title: String.localized("menu_block_contact"), style: .destructive, handler: { _ in
-            dcContact.block()
+        alert.addAction(UIAlertAction(title: blockButton, style: .destructive, handler: { _ in
+            self.dcContext.decideOnContactRequest(messageId, DC_DECISION_BLOCK)
         }))
         alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .cancel))
         present(alert, animated: true, completion: nil)

+ 4 - 4
deltachat-ios/Extensions/DcContact+Extension.swift

@@ -6,15 +6,15 @@ extension DcContact {
         var nameIndexes = [Int]()
         var emailIndexes = [Int]()
 
-        let contactString = name + email
+        let contactString = displayName + email
         let subsequenceIndexes = contactString.contains(subSequence: text)
 
         if !subsequenceIndexes.isEmpty {
             for index in subsequenceIndexes {
-                if index < name.count {
+                if index < displayName.count {
                     nameIndexes.append(index)
                 } else {
-                    let emailIndex = index - name.count
+                    let emailIndex = index - displayName.count
                     emailIndexes.append(emailIndex)
                 }
             }
@@ -27,7 +27,7 @@ extension DcContact {
     func containsExact(searchText text: String) -> [ContactHighlights] {
         var contactHighlights = [ContactHighlights]()
 
-        let nameString = name + ""
+        let nameString = displayName + ""
         let emailString = email + ""
         if let nameRange = nameString.range(of: text, options: .caseInsensitive) {
             let index: Int = nameString.distance(from: nameString.startIndex, to: nameRange.lowerBound)