Explorar o código

basic implementation to support the new context menu in chats

cyberta %!s(int64=4) %!d(string=hai) anos
pai
achega
6cee4c6d27

+ 26 - 0
deltachat-ios/Assets.xcassets/ic_content_copy_white_36pt.imageset/Contents.json

@@ -0,0 +1,26 @@
+{
+  "images" : [
+    {
+      "filename" : "baseline_content_copy_white_36pt_1x.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "baseline_content_copy_white_36pt_2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "baseline_content_copy_white_36pt_3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "template-rendering-intent" : "template"
+  }
+}

BIN=BIN
deltachat-ios/Assets.xcassets/ic_content_copy_white_36pt.imageset/baseline_content_copy_white_36pt_1x.png


BIN=BIN
deltachat-ios/Assets.xcassets/ic_content_copy_white_36pt.imageset/baseline_content_copy_white_36pt_2x.png


BIN=BIN
deltachat-ios/Assets.xcassets/ic_content_copy_white_36pt.imageset/baseline_content_copy_white_36pt_3x.png


+ 80 - 36
deltachat-ios/Chat/ChatViewController.swift

@@ -93,6 +93,72 @@ class ChatViewController: UITableViewController {
         return UIBarButtonItem(customView: badge)
         return UIBarButtonItem(customView: badge)
     }()
     }()
 
 
+    private lazy var contextMenu: ContextMenuProvider = {
+        let copyItem = ContextMenuProvider.ContextMenuItem(
+        title: String.localized("global_menu_edit_copy_desktop"),
+        imageNames: ("ic_content_copy_white_36pt", nil),
+        isDestructive: false,
+        action: #selector(UIResponderStandardEditActions.copy(_:)),
+        onPerform: { [weak self] indexPath in
+                guard let self = self else { return }
+                let id = self.messageIds[indexPath.row]
+                let msg = DcMsg(id: id)
+
+                let pasteboard = UIPasteboard.general
+                if msg.type == DC_MSG_TEXT {
+                    pasteboard.string = msg.text
+                } else {
+                    pasteboard.string = msg.summary(chars: 10000000)
+                }
+            }
+        )
+
+        let infoItem = ContextMenuProvider.ContextMenuItem(
+            title: String.localized("info"),
+            imageNames: ("info", nil),
+            isDestructive: false,
+            action: #selector(BaseMessageCell.messageInfo),
+            onPerform: { [weak self] indexPath in
+                guard let self = self else { return }
+                let msg = DcMsg(id: self.messageIds[indexPath.row])
+                let msgViewController = MessageInfoViewController(dcContext: self.dcContext, message: msg)
+                if let ctrl = self.navigationController {
+                    ctrl.pushViewController(msgViewController, animated: true)
+                }
+            }
+        )
+
+        let deleteItem = ContextMenuProvider.ContextMenuItem(
+            title: String.localized("delete"),
+            imageNames: ("trash", nil),
+            isDestructive: true,
+            action: #selector(BaseMessageCell.messageDelete),
+            onPerform: { [weak self] indexPath in
+                guard let self = self else { return }
+                logger.debug("delete message")
+                let msg = DcMsg(id: self.messageIds[indexPath.row])
+                self.askToDeleteMessage(id: msg.id)
+            }
+        )
+
+        let forwardItem = ContextMenuProvider.ContextMenuItem(
+            title: String.localized("forward"),
+            imageNames: ("ic_reply", nil),
+            isDestructive: false,
+            action: #selector(BaseMessageCell.messageForward),
+            onPerform: { [weak self] indexPath in
+                guard let self = self else { return }
+                let msg = DcMsg(id: self.messageIds[indexPath.row])
+                RelayHelper.sharedInstance.setForwardMessage(messageId: msg.id)
+                self.navigationController?.popViewController(animated: true)
+            }
+        )
+
+        let config = ContextMenuProvider()
+        config.setMenu([copyItem, infoItem, forwardItem, deleteItem])
+        return config
+    }()
+
     /// The `BasicAudioController` controll the AVAudioPlayer state (play, pause, stop) and update audio cell UI accordingly.
     /// The `BasicAudioController` controll the AVAudioPlayer state (play, pause, stop) and update audio cell UI accordingly.
     private lazy var audioController = AudioController(dcContext: dcContext, chatId: chatId)
     private lazy var audioController = AudioController(dcContext: dcContext, chatId: chatId)
 
 
@@ -994,11 +1060,7 @@ class ChatViewController: UITableViewController {
 
 
     // MARK: - Context menu
     // MARK: - Context menu
     private func prepareContextMenu() {
     private func prepareContextMenu() {
-        UIMenuController.shared.menuItems = [
-            UIMenuItem(title: String.localized("info"), action: #selector(BaseMessageCell.messageInfo)),
-            UIMenuItem(title: String.localized("delete"), action: #selector(BaseMessageCell.messageDelete)),
-            UIMenuItem(title: String.localized("forward"), action: #selector(BaseMessageCell.messageForward))
-        ]
+        UIMenuController.shared.menuItems = contextMenu.menuItems
         UIMenuController.shared.update()
         UIMenuController.shared.update()
     }
     }
 
 
@@ -1007,42 +1069,24 @@ class ChatViewController: UITableViewController {
     }
     }
 
 
     override func tableView(_ tableView: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
     override func tableView(_ tableView: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
-        return action == #selector(UIResponderStandardEditActions.copy(_:))
-            || action == #selector(BaseMessageCell.messageInfo)
-            || action == #selector(BaseMessageCell.messageDelete)
-            || action == #selector(BaseMessageCell.messageForward)
+        return contextMenu.canPerformAction(action: action)
     }
     }
 
 
     override func tableView(_ tableView: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) {
     override func tableView(_ tableView: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) {
         // handle standard actions here, but custom actions never trigger this. it still needs to be present for the menu to display, though.
         // handle standard actions here, but custom actions never trigger this. it still needs to be present for the menu to display, though.
-        switch action {
-        case #selector(copy(_:)):
-            let id = messageIds[indexPath.row]
-            let msg = DcMsg(id: id)
-
-            let pasteboard = UIPasteboard.general
-            if msg.type == DC_MSG_TEXT {
-                pasteboard.string = msg.text
-            } else {
-                pasteboard.string = msg.summary(chars: 10000000)
-            }
-        case #selector(BaseMessageCell.messageInfo(_:)):
-            let msg = DcMsg(id: messageIds[indexPath.row])
-            let msgViewController = MessageInfoViewController(dcContext: dcContext, message: msg)
-            if let ctrl = navigationController {
-                ctrl.pushViewController(msgViewController, animated: true)
+        contextMenu.performAction(action: action, indexPath: indexPath)
+    }
+
+    // context menu for iOS 13+
+    @available(iOS 13, *)
+    override func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
+        return UIContextMenuConfiguration(
+            identifier: nil,
+            previewProvider: nil,
+            actionProvider: { [weak self] _ in
+                self?.contextMenu.actionProvider(indexPath: indexPath)
             }
             }
-        case #selector(BaseMessageCell.messageDelete(_:)):
-            let msg = DcMsg(id: messageIds[indexPath.row])
-            askToDeleteMessage(id: msg.id)
-
-        case #selector(BaseMessageCell.messageForward(_:)):
-            let msg = DcMsg(id: messageIds[indexPath.row])
-            RelayHelper.sharedInstance.setForwardMessage(messageId: msg.id)
-            navigationController?.popViewController(animated: true)
-        default:
-            break
-        }
+        )
     }
     }
 
 
     func showMediaGalleryFor(indexPath: IndexPath) {
     func showMediaGalleryFor(indexPath: IndexPath) {

+ 3 - 1
deltachat-ios/Controller/ContextMenuController.swift

@@ -143,7 +143,9 @@ class ContextMenuProvider {
 
 
         for item in menu {
         for item in menu {
             // some system images are not available in iOS 13
             // some system images are not available in iOS 13
-            let image = UIImage(systemName: item.imageNames.0) ?? UIImage(systemName: item.imageNames.1 ?? "")
+            let image = UIImage(systemName: item.imageNames.0) ??
+                UIImage(systemName: item.imageNames.1 ?? "") ??
+                UIImage(named: item.imageNames.0)
 
 
             let action = UIAction(
             let action = UIAction(
                 title: item.title,
                 title: item.title,