Jelajahi Sumber

manually re-integrated branch due to merge conflicts

nayooti 4 tahun lalu
induk
melakukan
b7420d342c

+ 1 - 1
deltachat-ios/Chat/ChatViewController.swift

@@ -165,7 +165,6 @@ class ChatViewController: UITableViewController {
         notificationCenter.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
         notificationCenter.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
         notificationCenter.addObserver(self, selector: #selector(keyboardDidShow(_:)), name: UIResponder.keyboardDidShowNotification, object: nil)
-        prepareContextMenu()
     }
 
     @objc func keyboardDidShow(_ notification: Notification) {
@@ -277,6 +276,7 @@ class ChatViewController: UITableViewController {
         if RelayHelper.sharedInstance.isForwarding() {
             askToForwardMessage()
         }
+        prepareContextMenu()
     }
 
     override func viewDidAppear(_ animated: Bool) {

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

@@ -396,7 +396,7 @@ class ContactDetailViewController: UITableViewController {
 
     private func showGallery() {
         let messageIds: [Int] = viewModel.galleryItemMessageIds.reversed()
-        let galleryController = GalleryViewController(mediaMessageIds: messageIds)
+        let galleryController = GalleryViewController(context: viewModel.context, mediaMessageIds: messageIds)
         navigationController?.pushViewController(galleryController, animated: true)
     }
 

+ 121 - 5
deltachat-ios/Controller/GalleryViewController.swift

@@ -4,8 +4,9 @@ import SDWebImage
 
 class GalleryViewController: UIViewController {
 
+    private let dcContext: DcContext
     // MARK: - data
-    private let mediaMessageIds: [Int]
+    private var mediaMessageIds: [Int]
     private var items: [Int: GalleryItem] = [:]
 
     // MARK: - subview specs
@@ -46,7 +47,8 @@ class GalleryViewController: UIViewController {
         return label
     }()
 
-    init(mediaMessageIds: [Int]) {
+    init(context: DcContext, mediaMessageIds: [Int]) {
+        self.dcContext = context
         self.mediaMessageIds = mediaMessageIds
         super.init(nibName: nil, bundle: nil)
     }
@@ -67,6 +69,7 @@ class GalleryViewController: UIViewController {
 
     override func viewWillAppear(_ animated: Bool) {
         grid.reloadData()
+        setupContextMenuIfNeeded()
     }
 
     override func viewWillLayoutSubviews() {
@@ -96,6 +99,13 @@ class GalleryViewController: UIViewController {
         emptyStateView.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor).isActive = true
     }
 
+    private func setupContextMenuIfNeeded() {
+        UIMenuController.shared.menuItems = [
+            UIMenuItem(title: String.localized("delete"), action: #selector(GalleryCell.itemDelete(_:))),
+        ]
+        UIMenuController.shared.update()
+    }
+
     // MARK: - updates
     private func updateFloatingTimeLabel() {
         if let indexPath = grid.indexPathsForVisibleItems.min() {
@@ -104,11 +114,17 @@ class GalleryViewController: UIViewController {
             timeLabel.update(date: msg.sentDate)
         }
     }
+
+    private func deleteItem(at indexPath: IndexPath) {
+        let msgId = mediaMessageIds.remove(at: indexPath.row)
+        self.dcContext.deleteMessage(msgId: msgId)
+        self.grid.deleteItems(at: [indexPath])
+    }
 }
 
 extension GalleryViewController: UICollectionViewDataSourcePrefetching {
     func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
-         indexPaths.forEach { if items[$0.row] == nil {
+        indexPaths.forEach { if items[$0.row] == nil {
             let item = GalleryItem(msgId: mediaMessageIds[$0.row])
             items[$0.row] = item
         }}
@@ -128,8 +144,8 @@ extension GalleryViewController: UICollectionViewDataSource, UICollectionViewDel
 
     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
         guard let galleryCell = collectionView.dequeueReusableCell(
-            withReuseIdentifier: GalleryCell.reuseIdentifier,
-            for: indexPath) as? GalleryCell else {
+                withReuseIdentifier: GalleryCell.reuseIdentifier,
+                for: indexPath) as? GalleryCell else {
             return UICollectionViewCell()
         }
 
@@ -143,6 +159,7 @@ extension GalleryViewController: UICollectionViewDataSource, UICollectionViewDel
             item = galleryItem
         }
         galleryCell.update(item: item)
+        UIMenuController.shared.setMenuVisible(false, animated: true)
         return galleryCell
     }
 
@@ -150,6 +167,7 @@ extension GalleryViewController: UICollectionViewDataSource, UICollectionViewDel
         let msgId = mediaMessageIds[indexPath.row]
         showPreview(msgId: msgId)
         collectionView.deselectItem(at: indexPath, animated: true)
+        UIMenuController.shared.setMenuVisible(false, animated: true)
     }
 
     func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
@@ -164,6 +182,62 @@ extension GalleryViewController: UICollectionViewDataSource, UICollectionViewDel
     func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
         timeLabel.hide(animated: true)
     }
+
+    func collectionView(_ collectionView: UICollectionView, shouldShowMenuForItemAt indexPath: IndexPath) -> Bool {
+        return true
+    }
+
+    // MARK: - context menu
+    // context menu for iOS 11, 12
+    func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
+        return action ==  #selector(GalleryCell.itemDelete(_:))
+    }
+
+    func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {
+
+        switch action {
+        case #selector(GalleryCell.itemDelete(_:)):
+            deleteItem(at: indexPath)
+        default:
+            break
+        }
+    }
+
+    // context menu for iOS 13+
+    @available(iOS 13, *)
+    func collectionView(_ collectionView: UICollectionView,
+                        contextMenuConfigurationForItemAt indexPath: IndexPath,
+                        point: CGPoint) -> UIContextMenuConfiguration? {
+        guard let galleryCell = collectionView.cellForItem(at: indexPath) as? GalleryCell, let item = galleryCell.item else {
+            return nil
+        }
+
+        return UIContextMenuConfiguration(
+            identifier: nil,
+            previewProvider: {
+                return XLPreviewViewController(imageUrl: item.fileUrl)
+            },
+            actionProvider: { [weak self] _ in
+                return self?.makeContextMenu(indexPath: indexPath)
+            }
+        )
+    }
+
+    @available(iOS 13, *)
+    private func makeContextMenu(indexPath: IndexPath) -> UIMenu {
+        let deleteAction = UIAction(
+            title: String.localized("delete"),
+            image: UIImage(systemName: "trash")) { _ in
+            self.deleteItem(at: indexPath)
+        }
+
+        return UIMenu(
+            title: "",
+            image: nil,
+            identifier: nil,
+            children: [deleteAction]
+        )
+    }
 }
 
 // MARK: - grid layout + updates
@@ -210,11 +284,53 @@ extension GalleryViewController {
         guard let index = mediaMessageIds.index(of: msgId) else {
             return
         }
+
         let previewController = PreviewController(type: .multi(mediaMessageIds, index))
         present(previewController, animated: true, completion: nil)
     }
 }
 
+private class XLPreviewViewController: UIViewController {
+
+    private lazy var imageView: UIImageView = {
+        let imageView = UIImageView()
+        imageView.clipsToBounds = true
+        imageView.contentMode = .scaleAspectFill
+        imageView.translatesAutoresizingMaskIntoConstraints = false
+        return imageView
+    }()
+
+    init(imageUrl: URL?) {
+        super.init(nibName: nil, bundle: nil)
+        if let url = imageUrl {
+            imageView.image = UIImage(named: url.relativePath)
+        }
+    }
+
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+
+        view.addSubview(imageView)
+
+        NSLayoutConstraint.activate([
+            imageView.leftAnchor.constraint(equalTo: view.leftAnchor),
+            imageView.rightAnchor.constraint(equalTo: view.rightAnchor),
+            imageView.topAnchor.constraint(equalTo: view.topAnchor),
+            imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
+        ])
+
+        let width = view.bounds.width
+        if let image = imageView.image {
+            let height = image.size.height * (width / image.size.width)
+            preferredContentSize = CGSize(width: width, height: height)
+        }
+    }
+}
+
 class GalleryItem {
 
     var onImageLoaded: ((UIImage?) -> Void)?

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

@@ -309,7 +309,7 @@ class GroupChatDetailViewController: UIViewController {
 
     private func showGallery() {
         let messageIds: [Int] = galleryItemMessageIds.reversed()
-        let galleryController = GalleryViewController(mediaMessageIds: messageIds)
+        let galleryController = GalleryViewController(context: dcContext, mediaMessageIds: messageIds)
         navigationController?.pushViewController(galleryController, animated: true)
     }
 

+ 15 - 0
deltachat-ios/View/Cell/GalleryCell.swift

@@ -66,4 +66,19 @@ class GalleryCell: UICollectionViewCell {
             imageView.alpha = newValue ? 0.75 : 1.0
         }
     }
+
+    @objc func itemDelete(_ sender: Any) {
+        self.performAction(#selector(GalleryCell.itemDelete(_:)), with: sender)
+    }
+
+    func performAction(_ action: Selector, with sender: Any?) {
+        if let collectionView = self.superview as? UICollectionView, let indexPath = collectionView.indexPath(for: self) {
+            collectionView.delegate?.collectionView?(
+                collectionView,
+                performAction: action,
+                forItemAt: indexPath,
+                withSender: sender
+            )
+        }
+    }
 }