Commit cb1356b9 authored by edchin's avatar edchin Committed by Commit Bot

[ios] Separately handle sync vs async drops in tab grid

Handles synchronous localObject drops differently from
asynchronous drops from another app.

Bug: 1128531, 1128656
Change-Id: I45b124f1f8bb887a465a753e40a9fa5cc74c5e78
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2438011
Commit-Queue: Mark Cogan <marq@chromium.org>
Reviewed-by: default avatarMark Cogan <marq@chromium.org>
Cr-Commit-Position: refs/heads/master@{#811653}
parent 698ab388
......@@ -32,7 +32,7 @@
@property(nonatomic, weak) UIImage* snapshot;
@property(nonatomic, copy) NSString* title;
@property(nonatomic, assign) BOOL titleHidden;
@property(nonatomic, readonly) UIBezierPath* visiblePath;
@property(nonatomic, readonly) UIDragPreviewParameters* dragPreviewParameters;
@end
// A GridCell for use in animated transitions that only shows selection state
......
......@@ -255,10 +255,13 @@ void PositionView(UIView* view, CGPoint point) {
_titleHidden = titleHidden;
}
- (UIBezierPath*)visiblePath {
return [UIBezierPath
- (UIDragPreviewParameters*)dragPreviewParameters {
UIBezierPath* visiblePath = [UIBezierPath
bezierPathWithRoundedRect:self.bounds
cornerRadius:self.contentView.layer.cornerRadius];
UIDragPreviewParameters* params = [[UIDragPreviewParameters alloc] init];
params.visiblePath = visiblePath;
return params;
}
#pragma mark - Private
......
......@@ -25,10 +25,21 @@
// Tells the receiver to incorporate the |dragItem| into the model layer at the
// |destinationIndex|. |fromSameCollection| is an indication that the operation
// is a reorder within the same collection.
// is a reorder within the same collection. |dragItem| must have a localObject,
// which means the item is dragged from within the same app.
- (void)dropItem:(UIDragItem*)dragItem
toIndex:(NSUInteger)destinationIndex
fromSameCollection:(BOOL)fromSameCollection;
// Tells the receiver to asynchronously extract data from |itemProvider| into
// the model layer at the |destinationIndex|. |placeholderContext| is used to
// delete the placeholder once the item is ready to be inserted into the model
// layer.
- (void)dropItemFromProvider:(NSItemProvider*)itemProvider
toIndex:(NSUInteger)destinationIndex
placeholderContext:
(id<UICollectionViewDropPlaceholderContext>)placeholderContext;
@end
#endif // IOS_CHROME_BROWSER_UI_TAB_GRID_GRID_GRID_DRAG_DROP_HANDLER_H_
......@@ -438,11 +438,9 @@ NSIndexPath* CreateIndexPath(NSInteger index) {
- (UIDragPreviewParameters*)collectionView:(UICollectionView*)collectionView
dragPreviewParametersForItemAtIndexPath:(NSIndexPath*)indexPath {
UIDragPreviewParameters* params = [[UIDragPreviewParameters alloc] init];
GridCell* cell = base::mac::ObjCCastStrict<GridCell>(
GridCell* gridCell = base::mac::ObjCCastStrict<GridCell>(
[self.collectionView cellForItemAtIndexPath:indexPath]);
params.visiblePath = cell.visiblePath;
return params;
return gridCell.dragPreviewParameters;
}
#pragma mark - UICollectionViewDropDelegate
......@@ -471,21 +469,52 @@ NSIndexPath* CreateIndexPath(NSInteger index) {
(id<UICollectionViewDropCoordinator>)coordinator {
id<UICollectionViewDropItem> item = coordinator.items.firstObject;
NSIndexPath* dropIndexPath = coordinator.destinationIndexPath;
if (!dropIndexPath) {
dropIndexPath = [NSIndexPath indexPathForItem:(self.items.count - 1)
inSection:0];
// Append to the end of the collection, unless drop index is specified.
NSUInteger destinationIndex = self.items.count;
if (item.sourceIndexPath) {
// The sourceIndexPath is non-nil if the drop item is from this same
// collection view. Move to last position rather than appending if this is a
// reorder operation.
destinationIndex = self.items.count - 1;
}
if (coordinator.destinationIndexPath) {
destinationIndex =
base::checked_cast<NSUInteger>(coordinator.destinationIndexPath.item);
}
NSIndexPath* dropIndexPath = [NSIndexPath indexPathForItem:destinationIndex
inSection:0];
// Drop synchronously if local object is available.
if (item.dragItem.localObject) {
[coordinator dropItem:item.dragItem toItemAtIndexPath:dropIndexPath];
// The sourceIndexPath is non-nil if the drop item is from this same
// collection view.
[self.dragDropHandler dropItem:item.dragItem
toIndex:destinationIndex
fromSameCollection:(item.sourceIndexPath != nil)];
return;
}
NSUInteger destinationIndex =
base::checked_cast<NSUInteger>(dropIndexPath.item);
[coordinator dropItem:item.dragItem toItemAtIndexPath:dropIndexPath];
// Drop asynchronously if local object is not available.
UICollectionViewDropPlaceholder* placeholder =
[[UICollectionViewDropPlaceholder alloc]
initWithInsertionIndexPath:dropIndexPath
reuseIdentifier:kCellIdentifier];
placeholder.cellUpdateHandler = ^(UICollectionViewCell* placeholderCell) {
GridCell* gridCell = base::mac::ObjCCastStrict<GridCell>(placeholderCell);
gridCell.theme = self.theme;
};
placeholder.previewParametersProvider =
^UIDragPreviewParameters*(UICollectionViewCell* placeholderCell) {
GridCell* gridCell = base::mac::ObjCCastStrict<GridCell>(placeholderCell);
return gridCell.dragPreviewParameters;
};
// TODO(crbug.com/1095200): Handle the edge case that two windows are
// simultaneously dragging and dropping.
[self.dragDropHandler dropItem:item.dragItem
toIndex:destinationIndex
fromSameCollection:collectionView.hasActiveDrag];
id<UICollectionViewDropPlaceholderContext> context =
[coordinator dropItem:item.dragItem toPlaceholder:placeholder];
[self.dragDropHandler dropItemFromProvider:item.dragItem.itemProvider
toIndex:destinationIndex
placeholderContext:context];
}
#pragma mark - UIScrollViewDelegate
......
......@@ -465,31 +465,34 @@ web::WebState* GetWebStateWithId(WebStateList* web_state_list,
withURL:net::GURLWithNSURL(droppedURL)];
return;
}
}
- (void)dropItemFromProvider:(NSItemProvider*)itemProvider
toIndex:(NSUInteger)destinationIndex
placeholderContext:
(id<UICollectionViewDropPlaceholderContext>)placeholderContext {
if (![itemProvider canLoadObjectOfClass:[NSURL class]]) {
[placeholderContext deletePlaceholder];
return;
}
// Handle URLs from other apps asynchronously, as synchronous is not possible
// with NSItemProvider.
NSItemProvider* itemProvider = dragItem.itemProvider;
if ([itemProvider canLoadObjectOfClass:[NSURL class]]) {
// The parameter type has changed with Xcode 12 SDK.
// TODO(crbug.com/1098318): Remove this once Xcode 11 support is dropped.
// The parameter type has changed with Xcode 12 SDK.
// TODO(crbug.com/1098318): Remove this once Xcode 11 support is dropped.
#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
using providerType = __kindof id<NSItemProviderReading>;
using providerType = __kindof id<NSItemProviderReading>;
#else
using providerType = id<NSItemProviderReading>;
using providerType = id<NSItemProviderReading>;
#endif
auto loadHandler = ^(providerType providedItem, NSError* error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSURL* droppedURL = static_cast<NSURL*>(providedItem);
[self insertNewItemAtIndex:destinationIndex
withURL:net::GURLWithNSURL(droppedURL)];
});
};
[itemProvider loadObjectOfClass:[NSURL class]
completionHandler:loadHandler];
return;
}
auto loadHandler = ^(providerType providedItem, NSError* error) {
dispatch_async(dispatch_get_main_queue(), ^{
[placeholderContext deletePlaceholder];
NSURL* droppedURL = static_cast<NSURL*>(providedItem);
[self insertNewItemAtIndex:destinationIndex
withURL:net::GURLWithNSURL(droppedURL)];
});
};
[itemProvider loadObjectOfClass:[NSURL class] completionHandler:loadHandler];
}
#pragma mark - GridImageDataSource
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment