Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delete message by long press on cell ? #706

Closed
ljs19923 opened this issue May 29, 2018 · 21 comments
Closed

Delete message by long press on cell ? #706

ljs19923 opened this issue May 29, 2018 · 21 comments
Labels

Comments

@ljs19923
Copy link

Hi ! I want to delete message by long press gesture on cell.
Currently i can copy the message, how can i implement the possibility of add one action ?

Thanks

@SD10 SD10 added the question label May 29, 2018
@SD10
Copy link
Member

SD10 commented May 29, 2018

@JulienLevallois You should be able to make Delete an action here by overriding

open func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {

Then implement it here:

open func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {

@ljs19923
Copy link
Author

I dont understand where i need to override this, and what i need to do, to have 2 buttons, copy & delete

@Luke47
Copy link

Luke47 commented Jun 1, 2018

I dont understand where i need to override this, and what i need to do, to have 2 buttons, copy & delete

In the subclass of MessagesViewController, for example for the "delete" action (pseudocode out of my head):

class MyChatViewController: MessagesViewController {

override func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
        
        if action == #selector(UIResponderStandardEditActions.delete(_:)) {
            return true
        }
        
        return super.canPerformAction(action, withSender: sender)

    }
    
override func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {
    
        // Delete action should be handled by yourself
        if action == #selector(UIResponderStandardEditActions.delete(_:)) {
           // Remove entry from datasource
           // Delete section of the collectionView
           return
        }
        
        // Use default handler instead
        super.collectionView(collectionView, performAction: action, forItemAt: indexPath, withSender: sender)
        
    }

}

@Luke47
Copy link

Luke47 commented Jun 1, 2018

Okay, forget my previous comment. I just tested it and it does not seem to work. I will try to get it working (as I also need custom actions) and report back :)

@Luke47
Copy link

Luke47 commented Jun 6, 2018

Okay, so @JulienLevallois here is a working example.

You need to
1.) implement the canPerformAction and performAction delegate methods in your subclass of MessagesViewController, like so:

 override func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
        
        if action == NSSelectorFromString("delete:") {
            return true
        } else {
            return super.collectionView(collectionView, canPerformAction: action, forItemAt: indexPath, withSender: sender)
        }
    }
    
override func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {

        if action == NSSelectorFromString("delete:") {
            // 1.) Remove from datasource
            // insert your code here
            
            // 2.) Delete sections
            collectionView.deleteSections([indexPath.section])
        } else {
            super.collectionView(collectionView, performAction: action, forItemAt: indexPath, withSender: sender)
        }
    }

2.) Also you need to write an extension to the class of the UICollectionView subclass you are using and provide the implementation of the action there, e.g.

extension MessageCollectionViewCell {

    override open func delete(_ sender: Any?) {
        
        // Get the collectionView
        if let collectionView = self.superview as? UICollectionView {
            // Get indexPath
            if let indexPath = collectionView.indexPath(for: self) {
                // Trigger action
                collectionView.delegate?.collectionView?(collectionView, performAction: NSSelectorFromString("delete:"), forItemAt: indexPath, withSender: sender)
            }
        }
    }
}

That is the easiest way that I have found, I hope it helps!

Update: The code above is meant for system actions like copy or delete. In order to add custom actions, just follow the same scheme, but add your custom actions also to the UIMenuController, like so:

class CustomChatViewController: MessagesViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let customMenuItem = UIMenuItem(title: "Quote", action: #selector(MessageCollectionViewCell.quote(_:)))
        UIMenuController.shared.menuItems = [customMenuItem]
     }

}

Of course add the custom actions also to canPerformAction and performAction and to your UICollectionViewCell extension:

extension MessageCollectionViewCell {
    @objc func quote(_ sender: Any?) {
        
        // Get the collectionView
        if let collectionView = self.superview as? UICollectionView {
            // Get indexPath
            if let indexPath = collectionView.indexPath(for: self) {
                // Trigger action
                collectionView.delegate?.collectionView?(collectionView, performAction: #selector(MessageCollectionViewCell.quote(_:)), forItemAt: indexPath, withSender: sender)
            }
        }
    }
}

@stale
Copy link

stale bot commented Jun 20, 2018

This issue has been marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

@stale stale bot added stale and removed stale labels Jun 20, 2018
@ljs19923
Copy link
Author

ljs19923 commented Jun 21, 2018

@Luke47 thank you very much :)

@nathantannar4
Copy link
Member

@JulienLevallois you need to delete the message from your datasource as he commented in the code.

Sent with GitHawk

@SD10
Copy link
Member

SD10 commented Jun 21, 2018

Glad this one could be resolved! Thanks everyone 😃

Sent with GitHawk

@SD10 SD10 closed this as completed Jun 21, 2018
@ljs19923
Copy link
Author

Hi @Luke47 & @SD10 , " delete " messages dont works for Location type message. For text & images its good but long press dont works for location :/ I want to be able to delete a location message.

Do you have ideas why ?
Thanks

@SD10
Copy link
Member

SD10 commented Aug 9, 2018

@kpsdeveloper You'll have to look at my comment above in this thread. This is a general iOS question and not really related to MessageKit 😢

@tobitech
Copy link

tobitech commented Aug 9, 2018

@Luke47 I tried your answer, but my i couldn't get my delete action to do anything, not even a print statement. in other words, the delete action isn't called but it shows with the copy. any idea what might be wrong?

@tobitech
Copy link

Okay this works, the issue i have with this now is in this func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType { return messageList[indexPath.section] } throws an index out of range error. How can I fix this please?

@nathantannar4
Copy link
Member

@tobitech Have you forgotten to call delete on the index path of the collection view while also removing it from your messages array?

Sent with GitHawk

@tobitech
Copy link

@nathantannar4 I did
messageList.remove(at: indexPath.section) collectionView.deleteSections([indexPath.section]) messagesCollectionView.reloadData()
the crash only occurs when i'm deleting the last item in my messages array

@engin7
Copy link

engin7 commented Apr 28, 2020

Hi, solution Luke gave seems like for deleting message from both sides. I need to implement deleting for only user who deletes it. So other person can still see the message like in whatsapp.
What changes should i make, as person leaves chat room and comes back this message will load again as its not deleted from database right? I need to implement a filtering method. Don't know how.

@ghost
Copy link

ghost commented Dec 2, 2021

@Luke47 @kinoroy

#706 (comment)
Does this method work correctly on iOS15?
It doesn't work correctly when I want to change the UIResponderStandardEditActions for my message and the other person's message.
For example, you want to show copy and delete in my message, and only copy in the other message. The other person's message will also show copy and delete.

Thankyou.

@kboirel
Copy link

kboirel commented Dec 13, 2021

I added the code from @Luke47 and it's working very well for texts and images. But it's not working at all for video messages. Do you have any suggestions?
Thank you in advance

@raaed9
Copy link

raaed9 commented Dec 28, 2022

Use messageKit with Firebase When I delete any message in the chat using long press, it gets deleted in front of me, but when I leave the chat and come back, it is not actually deleted.

animation.mp4

` override func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {

       if action == NSSelectorFromString("delete:") {
           // 1.) Remove from datasource
           // insert your code here
           self.mkMessages.remove(at: indexPath.section)
           // 2.) Delete sections
           collectionView.deleteSections([indexPath.section])
       } else {
          return super.collectionView(collectionView, performAction: action, forItemAt: indexPath, withSender: sender)
       }
   }`

@Kenny0105
Copy link

Okay, so @JulienLevallois here is a working example.

You need to 1.) implement the canPerformAction and performAction delegate methods in your subclass of MessagesViewController, like so:

 override func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
        
        if action == NSSelectorFromString("delete:") {
            return true
        } else {
            return super.collectionView(collectionView, canPerformAction: action, forItemAt: indexPath, withSender: sender)
        }
    }
    
override func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {

        if action == NSSelectorFromString("delete:") {
            // 1.) Remove from datasource
            // insert your code here
            
            // 2.) Delete sections
            collectionView.deleteSections([indexPath.section])
        } else {
            super.collectionView(collectionView, performAction: action, forItemAt: indexPath, withSender: sender)
        }
    }

2.) Also you need to write an extension to the class of the UICollectionView subclass you are using and provide the implementation of the action there, e.g.

extension MessageCollectionViewCell {

    override open func delete(_ sender: Any?) {
        
        // Get the collectionView
        if let collectionView = self.superview as? UICollectionView {
            // Get indexPath
            if let indexPath = collectionView.indexPath(for: self) {
                // Trigger action
                collectionView.delegate?.collectionView?(collectionView, performAction: NSSelectorFromString("delete:"), forItemAt: indexPath, withSender: sender)
            }
        }
    }
}

That is the easiest way that I have found, I hope it helps!

Update: The code above is meant for system actions like copy or delete. In order to add custom actions, just follow the same scheme, but add your custom actions also to the UIMenuController, like so:

class CustomChatViewController: MessagesViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let customMenuItem = UIMenuItem(title: "Quote", action: #selector(MessageCollectionViewCell.quote(_:)))
        UIMenuController.shared.menuItems = [customMenuItem]
     }

}

Of course add the custom actions also to canPerformAction and performAction and to your UICollectionViewCell extension:

extension MessageCollectionViewCell {
    @objc func quote(_ sender: Any?) {
        
        // Get the collectionView
        if let collectionView = self.superview as? UICollectionView {
            // Get indexPath
            if let indexPath = collectionView.indexPath(for: self) {
                // Trigger action
                collectionView.delegate?.collectionView?(collectionView, performAction: #selector(MessageCollectionViewCell.quote(_:)), forItemAt: indexPath, withSender: sender)
            }
        }
    }
}

Does anyone know where I can implement "extension MessageCollectionViewCell"?

@hkhl1997
Copy link

hkhl1997 commented Nov 1, 2023

But how to add more button after long press?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

10 participants