chromium/ios/chrome/browser/drag_and_drop/model/table_view_url_drag_drop_handler.mm

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/drag_and_drop/model/table_view_url_drag_drop_handler.h"

#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>

#import "base/apple/foundation_util.h"
#import "base/check_op.h"
#import "ios/chrome/browser/drag_and_drop/model/drag_item_util.h"
#import "net/base/apple/url_conversions.h"
#import "url/gurl.h"

@implementation TableViewURLDragDropHandler

#pragma mark - UITableViewDragDelegate

- (NSArray<UIDragItem*>*)tableView:(UITableView*)tableView
      itemsForBeginningDragSession:(id<UIDragSession>)session
                       atIndexPath:(NSIndexPath*)indexPath {
  DCHECK(self.dragDataSource && self.origin);
  URLInfo* info = [self.dragDataSource tableView:tableView
                              URLInfoAtIndexPath:indexPath];
  // Returning nil indicates that the drag item has no content to be dropped.
  // However, drag to reorder within the table view is still enabled/controlled
  // by the UITableViewDataSource reordering methods.
  return info ? @[ CreateURLDragItem(info, self.origin) ] : nil;
}

- (NSArray<UIDragItem*>*)tableView:(UITableView*)tableView
       itemsForAddingToDragSession:(id<UIDragSession>)session
                       atIndexPath:(NSIndexPath*)indexPath
                             point:(CGPoint)point {
  // TODO(crbug.com/40138131): Enable multi-select dragging.
  return nil;
}

- (void)tableView:(UITableView*)tableView
    dragSessionWillBegin:(id<UIDragSession>)session {
  DCHECK_EQ(1U, session.items.count);
  UIDragItem* item = session.items.firstObject;
  URLInfo* info = base::apple::ObjCCastStrict<URLInfo>(item.localObject);
  session.items.firstObject.previewProvider = ^{
    return [UIDragPreview previewForURL:net::NSURLWithGURL(info.URL)
                                  title:info.title];
  };
}

#pragma mark - UITableViewDropDelegate

- (BOOL)tableView:(UITableView*)tableView
    canHandleDropSession:(id<UIDropSession>)session {
  DCHECK(self.dropDelegate);
  // TODO(crbug.com/40138131): Enable multi-item drops.
  return session.items.count == 1U &&
         [self.dropDelegate canHandleURLDropInTableView:tableView] &&
         [session
             hasItemsConformingToTypeIdentifiers:@[ UTTypeURL.identifier ]];
}

- (UITableViewDropProposal*)tableView:(UITableView*)tableView
                 dropSessionDidUpdate:(id<UIDropSession>)session
             withDestinationIndexPath:(NSIndexPath*)destinationIndexPath {
  UIDropOperation operation =
      tableView.hasActiveDrag ? UIDropOperationMove : UIDropOperationCopy;
  return [[UITableViewDropProposal alloc]
      initWithDropOperation:operation
                     intent:UITableViewDropIntentInsertAtDestinationIndexPath];
}

- (void)tableView:(UITableView*)tableView
    performDropWithCoordinator:(id<UITableViewDropCoordinator>)coordinator {
  DCHECK(self.dropDelegate);
  if ([coordinator.session canLoadObjectsOfClass:[NSURL class]]) {
    __weak TableViewURLDragDropHandler* weakSelf = self;
    [coordinator.session
        loadObjectsOfClass:[NSURL class]
                completion:^(NSArray<NSURL*>* objects) {
                  // TODO(crbug.com/40138131): Enable multi-item drops.
                  DCHECK_EQ(1U, objects.count);
                  GURL URL = net::GURLWithNSURL(objects.firstObject);
                  if (URL.is_valid()) {
                    [weakSelf.dropDelegate
                          tableView:tableView
                         didDropURL:URL
                        atIndexPath:coordinator.destinationIndexPath];
                  }
                }];
  }
}

@end