Fix Delete

from conversation settings > tile > tap for details > delete

TODO:

- Don't dismiss pager, show next item
- dismiss pager if deleting last media

// FREEBIE
This commit is contained in:
Michael Kirk 2018-03-22 14:10:41 -04:00
parent e751bbfbbd
commit 6e20f5b654
6 changed files with 134 additions and 31 deletions

View File

@ -17,7 +17,9 @@ typedef NS_OPTIONS(NSInteger, MediaGalleryOption) {
@protocol MediaDetailViewControllerDelegate <NSObject>
- (void)dismissSelfAnimated:(BOOL)isAnimated completion:(void (^_Nullable)(void))completionBlock;
- (void)mediaDetailViewController:(MediaDetailViewController *)mediaDetailViewController
requestDeleteConversationViewItem:(ConversationViewItem *)conversationViewItem;
- (void)mediaDetailViewController:(MediaDetailViewController *)mediaDetailViewController
isPlayingVideo:(BOOL)isPlayingVideo;

View File

@ -411,35 +411,27 @@ NS_ASSUME_NONNULL_BEGIN
[UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
[actionSheet
addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"TXT_DELETE_TITLE", nil)
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *action) {
OWSAssert([self.presentingViewController
isKindOfClass:[UINavigationController class]]);
UINavigationController *navController
= (UINavigationController *)self.presentingViewController;
addAction:[UIAlertAction
actionWithTitle:NSLocalizedString(@"TXT_DELETE_TITLE", nil)
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *action) {
[self.delegate mediaDetailViewController:self
requestDeleteConversationViewItem:self.viewItem];
if ([navController.topViewController
isKindOfClass:[ConversationViewController class]]) {
[self.delegate dismissSelfAnimated:YES
completion:^{
[self.viewItem deleteAction];
}];
} else if ([navController.topViewController
isKindOfClass:[MessageDetailViewController class]]) {
[self.delegate dismissSelfAnimated:YES
completion:^{
[self.viewItem deleteAction];
}];
[navController popViewControllerAnimated:YES];
} else {
OWSFail(@"Unexpected presentation context.");
[self.delegate dismissSelfAnimated:YES
completion:^{
[self.viewItem deleteAction];
}];
}
}]];
// TODO maybe this would be more straight forward if the MessageDetailVC was the
// deleteDelegate
if ([self.presentingViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navController
= (UINavigationController *)self.presentingViewController;
if ([navController.topViewController
isKindOfClass:[MessageDetailViewController class]]) {
MessageDetailViewController *messageDetailViewController
= (MessageDetailViewController *)navController.topViewController;
messageDetailViewController.wasDeleted = YES;
[navController popViewControllerAnimated:YES];
}
}
}]];
[actionSheet addAction:[OWSAlerts cancelAction]];

View File

@ -175,6 +175,8 @@ protocol MediaGalleryDataSource: class {
func showAllMedia(focusedItem: MediaGalleryItem)
func dismissMediaDetailViewController(_ mediaDetailViewController: MediaPageViewController, animated isAnimated: Bool, completion: (() -> Void)?)
func delete(message: TSMessage)
}
class MediaGalleryViewController: UINavigationController, MediaGalleryDataSource, MediaTileViewControllerDelegate {
@ -182,6 +184,7 @@ class MediaGalleryViewController: UINavigationController, MediaGalleryDataSource
private var pageViewController: MediaPageViewController?
private let uiDatabaseConnection: YapDatabaseConnection
private let editingDatabaseConnection: YapDatabaseConnection
private let mediaGalleryFinder: OWSMediaGalleryFinder
private var initialDetailItem: MediaGalleryItem?
@ -199,6 +202,9 @@ class MediaGalleryViewController: UINavigationController, MediaGalleryDataSource
self.thread = thread
assert(uiDatabaseConnection.isInLongLivedReadTransaction())
self.uiDatabaseConnection = uiDatabaseConnection
self.editingDatabaseConnection = OWSPrimaryStorage.shared().newDatabaseConnection()
self.options = options
self.mediaGalleryFinder = OWSMediaGalleryFinder(thread: thread)
@ -631,6 +637,12 @@ class MediaGalleryViewController: UINavigationController, MediaGalleryDataSource
Logger.debug("\(self.logTag) in \(#function) fetching set: \(unfetchedSet)")
let nsRange: NSRange = NSRange(location: unfetchedSet.min()!, length: unfetchedSet.count)
self.mediaGalleryFinder.enumerateMediaMessages(range: nsRange, transaction: transaction) { (message: TSMessage) in
guard !self.deletedMessages.contains(message) else {
Logger.debug("\(self.logTag) skipping \(message) which has been deleted.")
return
}
guard let item: MediaGalleryItem = self.buildGalleryItem(message: message, transaction: transaction) else {
owsFail("\(self.logTag) in \(#function) unexpectedly failed to buildGalleryItem")
return
@ -700,6 +712,65 @@ class MediaGalleryViewController: UINavigationController, MediaGalleryDataSource
}
}
var deletedMessages: Set<TSMessage> = Set()
func delete(message: TSMessage) {
Logger.info("\(logTag) in \(#function) with message: \(String(describing: message.uniqueId)) attachmentId: \(String(describing: message.attachmentIds.firstObject))")
// TODO put this somewhere reasonable...
self.mediaTileViewController.collectionView!.layoutIfNeeded()
self.editingDatabaseConnection.asyncReadWrite { transaction in
message.remove(with: transaction)
}
self.deletedMessages.insert(message)
var deletedSections: IndexSet = IndexSet()
var deletedIndexPaths: [IndexPath] = []
guard let itemIndex = galleryItems.index(where: { $0.message == message }) else {
owsFail("\(logTag) in \(#function) removing unknown item.")
return
}
let item: MediaGalleryItem = galleryItems[itemIndex]
self.galleryItems.remove(at: itemIndex)
guard let sectionIndex = sectionDates.index(where: { $0 == item.galleryDate }) else {
owsFail("\(logTag) in \(#function) item with unknown date.")
return
}
guard var sectionItems = self.sections[item.galleryDate] else {
owsFail("\(logTag) in \(#function) item with unknown section")
return
}
if sectionItems == [item] {
// Last item in section. Delete section.
self.sections[item.galleryDate] = nil
self.sectionDates.remove(at: sectionIndex)
deletedSections.insert(sectionIndex + 1)
deletedIndexPaths.append(IndexPath(row: 0, section: sectionIndex + 1))
} else {
guard let sectionRowIndex = sectionItems.index(of: item) else {
owsFail("\(logTag) in \(#function) item with unknown sectionRowIndex")
return
}
sectionItems.remove(at: sectionRowIndex)
self.sections[item.galleryDate] = sectionItems
deletedIndexPaths.append(IndexPath(row: sectionRowIndex, section: sectionIndex + 1))
}
// TODO? notify pager view
// notify tile view
self.mediaTileViewController.updatedDataSource(deletedSections: deletedSections, deletedItems: deletedIndexPaths)
}
let kGallerySwipeLoadBatchSize: UInt = 5
internal func galleryItem(after currentItem: MediaGalleryItem) -> MediaGalleryItem? {

View File

@ -440,8 +440,6 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
return viewController
}
// MARK: MediaDetailViewControllerDelegate
public func dismissSelf(animated isAnimated: Bool, completion: (() -> Void)? = nil) {
// Swapping mediaView for presentationView will be perceptible if we're not zoomed out all the way.
// currentVC
@ -457,6 +455,28 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
mediaGalleryDataSource.dismissMediaDetailViewController(self, animated: isAnimated, completion: completion)
}
// MARK: MediaDetailViewControllerDelegate
public func mediaDetailViewController(_ mediaDetailViewController: MediaDetailViewController, requestDelete conversationViewItem: ConversationViewItem) {
guard let mediaGalleryDataSource = self.mediaGalleryDataSource else {
owsFail("\(logTag) in \(#function) mediaGalleryDataSource was unexpectedly nil")
self.presentingViewController?.dismiss(animated: true)
return
}
guard let message = conversationViewItem.interaction as? TSMessage else {
owsFail("\(logTag) in \(#function) unexpected interaction: \(type(of: conversationViewItem))")
self.presentingViewController?.dismiss(animated: true)
return
}
dismissSelf(animated: true) {
mediaGalleryDataSource.delete(message: message)
}
}
public func mediaDetailViewController(_ mediaDetailViewController: MediaDetailViewController, isPlayingVideo: Bool) {
guard mediaDetailViewController == currentViewController else {
Logger.verbose("\(logTag) in \(#function) ignoring stale delegate.")

View File

@ -145,6 +145,19 @@ public class MediaTileViewController: UICollectionViewController, MediaGalleryCe
// MARK: UIColletionViewDataSource
public func updatedDataSource(deletedSections: IndexSet, deletedItems: [IndexPath]) {
guard let collectionView = self.collectionView else {
owsFail("\(logTag) in \(#function) collectionView was unexpetedly nil")
return
}
// If collectionView hasn't been laid out yet, it won't have the sections/rows to remove.
collectionView.performBatchUpdates({
collectionView.deleteSections(deletedSections)
collectionView.deleteItems(at: deletedItems)
})
}
override public func numberOfSections(in collectionView: UICollectionView) -> Int {
guard galleryDates.count > 0 else {
// empty gallery

View File

@ -29,6 +29,7 @@ class MessageDetailViewController: OWSViewController, UIScrollViewDelegate, Medi
let mode: MessageMetadataViewMode
let viewItem: ConversationViewItem
var message: TSMessage
var wasDeleted: Bool = false
var mediaMessageView: MediaMessageView?
@ -622,6 +623,10 @@ class MessageDetailViewController: OWSViewController, UIScrollViewDelegate, Medi
updateDBConnectionAndMessageToLatest()
guard !wasDeleted else {
// Item was deleted. Don't bother re-rendering, it will fail and we'll soon be dismissed.
return
}
updateContent()
}