mirror of
https://github.com/danog/Telegram.git
synced 2024-12-02 09:27:55 +01:00
1782 lines
68 KiB
Objective-C
1782 lines
68 KiB
Objective-C
#import "TGWebSearchController.h"
|
|
|
|
#import "ActionStage.h"
|
|
|
|
#import "TGSearchBar.h"
|
|
#import "TGModernButton.h"
|
|
|
|
#import "TGStringUtils.h"
|
|
#import "TGImageUtils.h"
|
|
#import "TGFont.h"
|
|
#import "UIImage+TG.h"
|
|
|
|
#import "TGNavigationController.h"
|
|
|
|
#import "TGModernMediaCollectionView.h"
|
|
#import "TGModernMediaListLayout.h"
|
|
#import "TGModernMediaListItem.h"
|
|
#import "TGModernMediaListItemView.h"
|
|
#import "TGModernMediaListItemContentView.h"
|
|
|
|
#import "TGImageView.h"
|
|
|
|
#import "TGGiphySearchResultItem+TGMediaItem.h"
|
|
#import "TGWebSearchGifItem.h"
|
|
#import "TGWebSearchGifItemView.h"
|
|
|
|
#import "TGBingSearchResultItem+TGMediaItem.h"
|
|
#import "TGWebSearchImageItem.h"
|
|
#import "TGWebSearchImageItemView.h"
|
|
|
|
#import "TGInternalGifSearchResult+TGMediaItem.h"
|
|
#import "TGInternalGifSearchResultItem.h"
|
|
#import "TGInternalGifSearchResultItemView.h"
|
|
|
|
#import "TGExternalGifSearchResult+TGMediaItem.h"
|
|
#import "TGExternalGifSearchResultItem.h"
|
|
#import "TGExternalGifSearchResultItemView.h"
|
|
|
|
#import "TGWebSearchInternalImageResult+TGMediaItem.h"
|
|
#import "TGWebSearchInternalImageItem.h"
|
|
#import "TGWebSearchInternalImageItemView.h"
|
|
|
|
#import "TGWebSearchInternalGifResult+TGMediaItem.h"
|
|
#import "TGWebSearchInternalGifItem.h"
|
|
#import "TGWebSearchInternalGifItemView.h"
|
|
|
|
#import "TGModernGalleryController.h"
|
|
#import "TGWebSearchResultsGalleryImageItem.h"
|
|
#import "TGWebSearchResultsGalleryGifItem.h"
|
|
#import "TGWebSearchResultsGalleryInternalImageItem.h"
|
|
#import "TGWebSearchResultsGalleryInternalGifItem.h"
|
|
|
|
#import "TGInternalGifSearchResultGalleryItem.h"
|
|
#import "TGExternalGifSearchResultGalleryItem.h"
|
|
|
|
#import "TGMediaPickerGalleryModel.h"
|
|
#import "TGMediaPickerGallerySelectedItemsModel.h"
|
|
|
|
#import "TGActionSheet.h"
|
|
|
|
#import "TGMediaAssetsLibrary.h"
|
|
|
|
#import "TGMediaSelectionContext.h"
|
|
#import "TGMediaEditingContext.h"
|
|
|
|
#import "PGPhotoEditorValues.h"
|
|
|
|
#import "TGPhotoEditorController.h"
|
|
|
|
#import "TGOverlayControllerWindow.h"
|
|
|
|
#import "TGRecentSearchResultsTableView.h"
|
|
|
|
#import "TGDoubleTapGestureRecognizer.h"
|
|
|
|
#import "TGMediaPickerLayoutMetrics.h"
|
|
|
|
@interface TGWebSearchController () <TGSearchBarDelegate, ASWatcher, UICollectionViewDataSource, UICollectionViewDelegate>
|
|
{
|
|
TGMediaPickerLayoutMetrics *_layoutMetrics;
|
|
|
|
TGSearchBar *_searchBar;
|
|
UIView *_toolbarView;
|
|
UIImageView *_toolbarLogoView;
|
|
TGModernButton *_doneButton;
|
|
UIImageView *_countBadge;
|
|
UILabel *_countLabel;
|
|
TGModernButton *_clearButton;
|
|
|
|
NSString *_searchString;
|
|
|
|
NSString *_imageSearchPath;
|
|
NSString *_gifSearchPath;
|
|
|
|
NSArray *_imageSearchResults;
|
|
NSArray *_rawImageSearchResults;
|
|
TGMediaSelectionContext *_imageSelectionContext;
|
|
bool _imageMoreResultsAvailable;
|
|
bool _searchingImage;
|
|
|
|
NSArray *_gifSearchResults;
|
|
NSArray *_rawGifSearchResults;
|
|
bool _gifMoreResultsAvailable;
|
|
TGMediaSelectionContext *_gifSelectionContext;
|
|
int32_t _gifMoreResultsOffset;
|
|
bool _searchingGif;
|
|
|
|
NSArray *_recentSearchResults;
|
|
TGMediaSelectionContext *_recentSelectionContext;
|
|
|
|
NSArray *_selectedItems;
|
|
|
|
UIView *_nothingFoundView;
|
|
|
|
bool _appeared;
|
|
|
|
UICollectionView *_collectionView;
|
|
CGFloat _collectionViewWidth;
|
|
TGModernMediaListLayout *_collectionLayout;
|
|
UIView *_collectionContainer;
|
|
NSMutableDictionary *_reusableItemContentViewsByIdentifier;
|
|
bool _loadItemsSynchronously;
|
|
|
|
TGRecentSearchResultsTableView *_recentSearchResultsTableView;
|
|
|
|
id<TGModernMediaListItem> _hiddenItem;
|
|
|
|
bool _embedded;
|
|
NSArray *_scopeButtonTitles;
|
|
|
|
void (^_recycleItemContentView)(TGModernMediaListItemContentView *);
|
|
NSMutableArray *_storedItemContentViews;
|
|
|
|
__weak TGMediaPickerGalleryModel *_galleryModel;
|
|
|
|
TGMediaEditingContext *_editingContext;
|
|
|
|
SMetaDisposable *_selectionChangedDisposable;
|
|
|
|
void(^_fetchOriginalImage)(id<TGMediaEditableItem>, void(^)(UIImage *));
|
|
void(^_fetchOriginalThumbnailImage)(id<TGMediaEditableItem>, void(^)(UIImage *));
|
|
}
|
|
|
|
@property (nonatomic, strong) ASHandle *actionHandle;
|
|
|
|
@end
|
|
|
|
@implementation TGWebSearchController
|
|
|
|
- (instancetype)init
|
|
{
|
|
return [self initForAvatarSelection:false embedded:false];
|
|
}
|
|
|
|
- (instancetype)initForAvatarSelection:(bool)avatarSelection embedded:(bool)embedded
|
|
{
|
|
self = [super init];
|
|
if (self != nil)
|
|
{
|
|
_actionHandle = [[ASHandle alloc] initWithDelegate:self releaseOnMainThread:true];
|
|
|
|
_avatarSelection = avatarSelection;
|
|
|
|
if (!avatarSelection)
|
|
{
|
|
_imageSelectionContext = [[TGMediaSelectionContext alloc] init];
|
|
_gifSelectionContext = [[TGMediaSelectionContext alloc] init];
|
|
_recentSelectionContext = [[TGMediaSelectionContext alloc] init];
|
|
}
|
|
_editingContext = [[TGMediaEditingContext alloc] init];
|
|
|
|
if (!embedded)
|
|
self.navigationBarShouldBeHidden = true;
|
|
|
|
_reusableItemContentViewsByIdentifier = [[NSMutableDictionary alloc] init];
|
|
_storedItemContentViews = [[NSMutableArray alloc] init];
|
|
|
|
__weak TGWebSearchController *weakSelf = self;
|
|
_recycleItemContentView = ^(TGModernMediaListItemContentView *itemContentView)
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
[strongSelf enqueueView:itemContentView];
|
|
};
|
|
|
|
_layoutMetrics = [TGMediaPickerLayoutMetrics defaultLayoutMetrics];
|
|
|
|
_fetchOriginalImage = ^void(id<TGMediaEditableItem> item, void(^completion)(UIImage *))
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf == nil)
|
|
return;
|
|
|
|
[strongSelf->_editingContext requestOriginalImageForItem:item completion:completion];
|
|
};
|
|
|
|
_fetchOriginalThumbnailImage = ^void(id<TGMediaEditableItem> item, void(^completion)(UIImage *))
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf == nil)
|
|
return;
|
|
|
|
[strongSelf->_editingContext requestOriginalThumbnailImageForItem:item completion:completion];
|
|
};
|
|
|
|
_recentSearchResults = [self _listItemsFromResults:[TGWebSearchController recentSelectedItems]];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[_actionHandle reset];
|
|
[ActionStageInstance() removeWatcher:self];
|
|
}
|
|
|
|
- (NSArray *)scopeSearchResults
|
|
{
|
|
if (_searchBar.selectedScopeButtonIndex == [self imagesScopeIndex])
|
|
return _imageSearchResults;
|
|
else if (_searchBar.selectedScopeButtonIndex == [self gifsScopeIndex])
|
|
return _gifSearchResults;
|
|
else
|
|
return _recentSearchResults;
|
|
}
|
|
|
|
- (NSArray *)scopeRawSearchResults
|
|
{
|
|
if (_searchBar.selectedScopeButtonIndex == [self imagesScopeIndex])
|
|
return _rawImageSearchResults;
|
|
else if (_searchBar.selectedScopeButtonIndex == [self gifsScopeIndex])
|
|
return _rawGifSearchResults;
|
|
else
|
|
return @[];
|
|
}
|
|
|
|
- (bool)scopeMoreResultsAvailable
|
|
{
|
|
if (_searchBar.selectedScopeButtonIndex == [self imagesScopeIndex])
|
|
return _imageMoreResultsAvailable;
|
|
else if (_searchBar.selectedScopeButtonIndex == [self gifsScopeIndex])
|
|
return _gifMoreResultsAvailable;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
- (int32_t)scopeMoreResultsOffset {
|
|
if (_searchBar.selectedScopeButtonIndex == [self imagesScopeIndex])
|
|
return 0;
|
|
else if (_searchBar.selectedScopeButtonIndex == [self gifsScopeIndex])
|
|
return _gifMoreResultsOffset;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
- (NSString *)scopeSearchPath
|
|
{
|
|
if (_searchBar.selectedScopeButtonIndex == [self imagesScopeIndex])
|
|
return _imageSearchPath;
|
|
else if (_searchBar.selectedScopeButtonIndex == [self gifsScopeIndex])
|
|
return _gifSearchPath;
|
|
else
|
|
return nil;
|
|
}
|
|
|
|
- (UIView *)nothingFoundView
|
|
{
|
|
if (_nothingFoundView == nil)
|
|
{
|
|
_nothingFoundView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 20.0f, 20.0f)];
|
|
[self.view insertSubview:_nothingFoundView belowSubview:_collectionView];
|
|
_nothingFoundView.frame = CGRectMake(CGFloor((self.view.frame.size.width - _nothingFoundView.frame.size.width) / 2.0f), CGFloor((self.view.frame.size.height - _nothingFoundView.frame.size.height) / 2.0f), _nothingFoundView.frame.size.width, _nothingFoundView.frame.size.height);
|
|
_nothingFoundView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
|
|
|
|
UILabel *nothingFoundLabel = [[UILabel alloc] init];
|
|
nothingFoundLabel.backgroundColor = [UIColor clearColor];
|
|
nothingFoundLabel.textColor = UIColorRGB(0x808080);
|
|
nothingFoundLabel.font = TGLightSystemFontOfSize(16);
|
|
nothingFoundLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
|
nothingFoundLabel.numberOfLines = 0;
|
|
nothingFoundLabel.textAlignment = NSTextAlignmentCenter;
|
|
nothingFoundLabel.text = TGLocalized(@"SearchImages.NoImagesFound");
|
|
[_nothingFoundView addSubview:nothingFoundLabel];
|
|
|
|
UIImageView *nothingFoundIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"NothingFoundIcon.png"]];
|
|
[_nothingFoundView addSubview:nothingFoundIcon];
|
|
|
|
CGSize size = [nothingFoundLabel sizeThatFits:CGSizeMake(320 - 20, 1000)];
|
|
nothingFoundLabel.frame = CGRectMake(CGFloor((_nothingFoundView.frame.size.width - size.width) / 2), nothingFoundIcon.frame.size.height / 2.0f + 4.0f, size.width, size.height);
|
|
|
|
nothingFoundIcon.frame = CGRectMake(CGFloor((_nothingFoundView.frame.size.width - nothingFoundIcon.frame.size.width) / 2), -nothingFoundIcon.frame.size.height / 2.0f - 4.0f, nothingFoundIcon.frame.size.width, nothingFoundIcon.frame.size.height);
|
|
}
|
|
|
|
return _nothingFoundView;
|
|
}
|
|
|
|
- (void)loadView
|
|
{
|
|
[super loadView];
|
|
|
|
self.view.clipsToBounds = true;
|
|
self.view.backgroundColor = [UIColor whiteColor];
|
|
|
|
_collectionContainer = [[UIView alloc] initWithFrame:self.view.bounds];
|
|
_collectionContainer.backgroundColor = [UIColor whiteColor];
|
|
_collectionContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
[self.view addSubview:_collectionContainer];
|
|
|
|
CGSize frameSize = self.view.bounds.size;
|
|
|
|
_collectionLayout = [[TGModernMediaListLayout alloc] init];
|
|
_collectionView = [[TGModernMediaCollectionView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, frameSize.width, frameSize.height) collectionViewLayout:_collectionLayout];
|
|
_collectionView.alwaysBounceVertical = true;
|
|
_collectionView.backgroundColor = [UIColor clearColor];
|
|
_collectionView.delaysContentTouches = true;
|
|
_collectionView.canCancelContentTouches = true;
|
|
_collectionView.delegate = self;
|
|
_collectionView.dataSource = self;
|
|
[_collectionView registerClass:[TGModernMediaListItemView class] forCellWithReuseIdentifier:@"TGModernMediaListItemView"];
|
|
[_collectionContainer addSubview:_collectionView];
|
|
|
|
_recentSearchResultsTableView = [[TGRecentSearchResultsTableView alloc] initWithFrame:_collectionView.frame style:UITableViewStylePlain];
|
|
_recentSearchResultsTableView.items = [self _recentSearchItems];
|
|
__weak TGWebSearchController *weakSelf = self;
|
|
_recentSearchResultsTableView.itemSelected = ^(NSString *item)
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf != nil)
|
|
{
|
|
[strongSelf->_searchBar resignFirstResponder];
|
|
[strongSelf->_searchBar setText:item];
|
|
[strongSelf searchBarSearchButtonClicked:(UISearchBar *)strongSelf->_searchBar];
|
|
}
|
|
};
|
|
_recentSearchResultsTableView.clearPressed = ^
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf != nil)
|
|
{
|
|
[strongSelf _clearRecentSearchItems];
|
|
}
|
|
};
|
|
[self.view addSubview:_recentSearchResultsTableView];
|
|
|
|
self.scrollViewsForAutomaticInsetsAdjustment = @[_collectionView, _recentSearchResultsTableView];
|
|
|
|
if (self.avatarSelection)
|
|
_scopeButtonTitles = @[TGLocalized(@"WebSearch.Images"), TGLocalized(@"WebSearch.RecentSectionTitle")];
|
|
else
|
|
_scopeButtonTitles = @[TGLocalized(@"WebSearch.Images"), TGLocalized(@"WebSearch.GIFs"), TGLocalized(@"WebSearch.RecentSectionTitle")];
|
|
|
|
_searchBar = [[TGSearchBar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, frameSize.width, 0.0f) style:TGSearchBarStyleHeader];
|
|
_searchBar.customScopeButtonTitles = _scopeButtonTitles;
|
|
_searchBar.scopeBarCollapsed = _embedded;
|
|
_searchBar.showsScopeBar = true;
|
|
[_searchBar setAlwaysExtended:true];
|
|
[_searchBar setShowsCancelButton:true animated:false];
|
|
_searchBar.delegate = self;
|
|
[_searchBar sizeToFit];
|
|
_searchBar.delayActivity = false;
|
|
if (!self.avatarSelection)
|
|
_searchBar.selectedScopeButtonIndex = MAX(0, MIN(2, [[[NSUserDefaults standardUserDefaults] objectForKey:@"webSearchSelectedScope"] intValue]));
|
|
[self searchBar:(UISearchBar *)_searchBar selectedScopeButtonIndexDidChange:_searchBar.selectedScopeButtonIndex];
|
|
[self.view addSubview:_searchBar];
|
|
|
|
if (!self.avatarSelection)
|
|
{
|
|
_toolbarView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, self.view.frame.size.height - 44.0f, self.view.frame.size.width, 44.0f)];
|
|
_toolbarView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
|
|
_toolbarView.backgroundColor = UIColorRGBA(0xf7f7f7, 1.0f);
|
|
UIView *stripeView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, _toolbarView.frame.size.width, TGIsRetina() ? 0.5f : 1.0f)];
|
|
stripeView.backgroundColor = UIColorRGB(0xb2b2b2);
|
|
stripeView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
|
[_toolbarView addSubview:stripeView];
|
|
[self.view addSubview:_toolbarView];
|
|
|
|
_toolbarLogoView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"GiphyToolbarLogo.png"]];
|
|
_toolbarLogoView.frame = CGRectMake(CGFloor((_toolbarView.frame.size.width - _toolbarLogoView.frame.size.width) / 2.0f), 9.0f, _toolbarLogoView.frame.size.width, _toolbarLogoView.frame.size.height);
|
|
_toolbarLogoView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
|
|
_toolbarLogoView.hidden = _searchBar.selectedScopeButtonIndex != [self gifsScopeIndex];
|
|
_toolbarLogoView.alpha = _toolbarLogoView.hidden ? 0.0f : 1.0f;
|
|
[_toolbarView addSubview:_toolbarLogoView];
|
|
|
|
_clearButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 60, 44)];
|
|
_clearButton.hidden = _searchBar.selectedScopeButtonIndex != [self recentScopeIndex] || _recentSearchResults.count == 0;
|
|
_clearButton.exclusiveTouch = true;
|
|
[_clearButton setTitle:TGLocalized(@"WebSearch.RecentSectionClear") forState:UIControlStateNormal];
|
|
[_clearButton setTitleColor:TGAccentColor()];
|
|
_clearButton.titleLabel.font = TGSystemFontOfSize(17);
|
|
_clearButton.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
|
|
[_clearButton sizeToFit];
|
|
_clearButton.frame = CGRectMake(0, 0, MAX(60, _clearButton.frame.size.width), 44);
|
|
_clearButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
|
|
[_clearButton addTarget:self action:@selector(clearButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
|
[_toolbarView addSubview:_clearButton];
|
|
|
|
_doneButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 40, 44)];
|
|
_doneButton.exclusiveTouch = true;
|
|
[_doneButton setTitle:TGLocalized(@"MediaPicker.Send") forState:UIControlStateNormal];
|
|
[_doneButton setTitleColor:TGAccentColor()];
|
|
_doneButton.titleLabel.font = TGMediumSystemFontOfSize(17);
|
|
_doneButton.contentEdgeInsets = UIEdgeInsetsMake(0, 27, 0, 10);
|
|
[_doneButton sizeToFit];
|
|
CGFloat doneButtonWidth = MAX(40, _doneButton.frame.size.width);
|
|
_doneButton.frame = CGRectMake(_toolbarView.frame.size.width - doneButtonWidth, 0, doneButtonWidth, 44);
|
|
_doneButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;
|
|
[_doneButton addTarget:self action:@selector(doneButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
|
_doneButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
|
|
_doneButton.enabled = false;
|
|
[_toolbarView addSubview:_doneButton];
|
|
|
|
static UIImage *countBadgeBackground = nil;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^
|
|
{
|
|
UIGraphicsBeginImageContextWithOptions(CGSizeMake(22.0f, 22.0f), false, 0.0f);
|
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
CGContextSetFillColorWithColor(context, TGAccentColor().CGColor);
|
|
CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, 22.0f, 22.0f));
|
|
countBadgeBackground = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:11.0f topCapHeight:11.0f];
|
|
UIGraphicsEndImageContext();
|
|
});
|
|
_countBadge = [[UIImageView alloc] initWithImage:countBadgeBackground];
|
|
_countBadge.alpha = 0.0f;
|
|
_countLabel = [[UILabel alloc] init];
|
|
_countLabel.backgroundColor = [UIColor clearColor];
|
|
_countLabel.textColor = [UIColor whiteColor];
|
|
_countLabel.font = TGLightSystemFontOfSize(14);
|
|
[_countBadge addSubview:_countLabel];
|
|
[_doneButton addSubview:_countBadge];
|
|
|
|
_selectionChangedDisposable = [[SMetaDisposable alloc] init];
|
|
SSignal *combinedSignal = [TGMediaSelectionContext combinedSelectionChangedSignalForContexts:@[ _imageSelectionContext, _gifSelectionContext, _recentSelectionContext ]];
|
|
[_selectionChangedDisposable setDisposable:[combinedSignal startWithNext:^(TGMediaSelectionChange *next)
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf == nil)
|
|
return;
|
|
|
|
[strongSelf updateSelectionInterface:![next.sender isKindOfClass:[TGMediaSelectionContext class]]];
|
|
}]];
|
|
}
|
|
|
|
[self _updateExplicitTableInset];
|
|
|
|
if (![self _updateControllerInset:false])
|
|
[self controllerInsetUpdated:UIEdgeInsetsZero];
|
|
}
|
|
|
|
- (void)_updateExplicitTableInset
|
|
{
|
|
self.explicitTableInset = UIEdgeInsetsMake(_searchBar.frame.size.height, 0.0f, (_toolbarView != nil) ? 44.0f : 0.0f, 0.0f);
|
|
self.explicitScrollIndicatorInset = self.explicitTableInset;
|
|
}
|
|
|
|
- (CGFloat)_searchBarHeight
|
|
{
|
|
return MAX(88.0f, _searchBar.frame.size.height);
|
|
}
|
|
|
|
+ (NSString *)recentSelectedItemsKey
|
|
{
|
|
return @"webSearchRecentSelectedItems_v1";
|
|
}
|
|
|
|
+ (void)addRecentSelectedItems:(NSArray *)items
|
|
{
|
|
NSMutableArray *updatedItems = [[NSMutableArray alloc] init];
|
|
[updatedItems addObjectsFromArray:items];
|
|
for (id item in [self recentSelectedItems])
|
|
{
|
|
if (![updatedItems containsObject:item])
|
|
[updatedItems addObject:item];
|
|
}
|
|
|
|
if (updatedItems.count > 1024)
|
|
[updatedItems removeObjectsInRange:NSMakeRange(4, updatedItems.count - 4)];
|
|
|
|
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:updatedItems];
|
|
if (data != nil)
|
|
[[NSUserDefaults standardUserDefaults] setObject:data forKey:[self recentSelectedItemsKey]];
|
|
}
|
|
|
|
+ (NSArray *)recentSelectedItems
|
|
{
|
|
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:[self recentSelectedItemsKey]];
|
|
if (data != nil)
|
|
{
|
|
@try {
|
|
return [NSKeyedUnarchiver unarchiveObjectWithData:data];
|
|
} @catch (NSException *e) {
|
|
return @[];
|
|
}
|
|
}
|
|
return @[];
|
|
}
|
|
|
|
+ (void)clearRecents
|
|
{
|
|
[[NSUserDefaults standardUserDefaults] removeObjectForKey:[self recentSelectedItemsKey]];
|
|
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
}
|
|
|
|
- (NSArray *)_listItemsFromResults:(NSArray *)results
|
|
{
|
|
NSMutableArray *items = [[NSMutableArray alloc] init];
|
|
for (id item in results)
|
|
{
|
|
if ([item isKindOfClass:[TGGiphySearchResultItem class]] && !self.avatarSelection)
|
|
{
|
|
TGGiphySearchResultItem *concreteItem = item;
|
|
TGWebSearchGifItem *listItem = [[TGWebSearchGifItem alloc] initWithPreviewUrl:concreteItem.previewUrl searchResultItem:item];
|
|
listItem.selectionContext = _recentSelectionContext;
|
|
[items addObject:listItem];
|
|
}
|
|
else if ([item isKindOfClass:[TGBingSearchResultItem class]])
|
|
{
|
|
TGBingSearchResultItem *concreteItem = item;
|
|
TGWebSearchImageItem *listItem = [[TGWebSearchImageItem alloc] initWithPreviewUrl:concreteItem.previewUrl searchResultItem:item];
|
|
listItem.selectionContext = _recentSelectionContext;
|
|
listItem.editingContext = _editingContext;
|
|
[items addObject:listItem];
|
|
|
|
if (!self.avatarSelection)
|
|
{
|
|
concreteItem.fetchOriginalImage = _fetchOriginalImage;
|
|
concreteItem.fetchOriginalThumbnailImage = _fetchOriginalThumbnailImage;
|
|
}
|
|
}
|
|
else if ([item isKindOfClass:[TGWebSearchInternalImageResult class]])
|
|
{
|
|
TGWebSearchInternalImageResult *concreteItem = item;
|
|
TGWebSearchInternalImageItem *listItem = [[TGWebSearchInternalImageItem alloc] initWithSearchResult:concreteItem];
|
|
listItem.selectionContext = _recentSelectionContext;
|
|
listItem.editingContext = _editingContext;
|
|
[items addObject:listItem];
|
|
|
|
if (!self.avatarSelection)
|
|
{
|
|
concreteItem.fetchOriginalImage = _fetchOriginalImage;
|
|
concreteItem.fetchOriginalThumbnailImage = _fetchOriginalThumbnailImage;
|
|
}
|
|
}
|
|
else if ([item isKindOfClass:[TGWebSearchInternalGifResult class]] && !self.avatarSelection)
|
|
{
|
|
TGWebSearchInternalGifItem *listItem = [[TGWebSearchInternalGifItem alloc] initWithSearchResult:item];
|
|
listItem.selectionContext = _recentSelectionContext;
|
|
[items addObject:listItem];
|
|
}
|
|
else if ([item isKindOfClass:[TGInternalGifSearchResult class]] && !self.avatarSelection)
|
|
{
|
|
TGInternalGifSearchResultItem *listItem = [[TGInternalGifSearchResultItem alloc] initWithSearchResult:item];
|
|
listItem.selectionContext = _recentSelectionContext;
|
|
[items addObject:listItem];
|
|
}
|
|
else if ([item isKindOfClass:[TGExternalGifSearchResult class]] && !self.avatarSelection)
|
|
{
|
|
TGExternalGifSearchResultItem *listItem = [[TGExternalGifSearchResultItem alloc] initWithSearchResult:item];
|
|
listItem.selectionContext = _recentSelectionContext;
|
|
[items addObject:listItem];
|
|
}
|
|
}
|
|
return items;
|
|
}
|
|
|
|
- (NSArray *)_recentSearchItems
|
|
{
|
|
NSArray *array = [[NSUserDefaults standardUserDefaults] objectForKey:@"webSearchRecentQueries"];
|
|
return array;
|
|
}
|
|
|
|
- (void)_addRecentSearchItem:(NSString *)item
|
|
{
|
|
NSMutableArray *array = [[NSMutableArray alloc] initWithArray:[self _recentSearchItems]];
|
|
[array removeObject:item];
|
|
[array insertObject:item atIndex:0];
|
|
[[NSUserDefaults standardUserDefaults] setObject:array forKey:@"webSearchRecentQueries"];
|
|
|
|
[_recentSearchResultsTableView setItems:array];
|
|
}
|
|
|
|
- (void)_clearRecentSearchItems
|
|
{
|
|
[[NSUserDefaults standardUserDefaults] setObject:@[] forKey:@"webSearchRecentQueries"];
|
|
[_recentSearchResultsTableView setItems:@[]];
|
|
}
|
|
|
|
- (void)viewWillAppear:(BOOL)animated
|
|
{
|
|
[super viewWillAppear:animated];
|
|
|
|
CGSize frameSize = self.view.bounds.size;
|
|
CGRect collectionViewFrame = CGRectMake(0.0f, 0.0f, frameSize.width, frameSize.height);
|
|
_collectionViewWidth = collectionViewFrame.size.width;
|
|
_collectionView.frame = collectionViewFrame;
|
|
|
|
_recentSearchResultsTableView.frame = collectionViewFrame;
|
|
}
|
|
|
|
- (void)viewDidAppear:(BOOL)animated
|
|
{
|
|
[super viewDidAppear:animated];
|
|
|
|
if (!_appeared)
|
|
{
|
|
[UIView performWithoutAnimation:^
|
|
{
|
|
[_searchBar layoutSubviews];
|
|
}];
|
|
|
|
if (_searchBar.selectedScopeButtonIndex != [self recentScopeIndex])
|
|
[_searchBar becomeFirstResponder];
|
|
|
|
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad || _searchBar.selectedScopeButtonIndex == [self recentScopeIndex])
|
|
{
|
|
dispatch_async(dispatch_get_main_queue(), ^
|
|
{
|
|
[self _performEmbeddedTransitionIn];
|
|
});
|
|
}
|
|
|
|
_appeared = true;
|
|
}
|
|
}
|
|
|
|
- (BOOL)shouldAutorotate
|
|
{
|
|
return true;
|
|
}
|
|
|
|
- (bool)shouldIgnoreNavigationBar
|
|
{
|
|
return _embedded;
|
|
}
|
|
|
|
- (void)controllerInsetUpdated:(UIEdgeInsets)previousInset
|
|
{
|
|
CGRect navigationBarFrame = _searchBar.frame;
|
|
navigationBarFrame.origin.y = self.controllerCleanInset.top;
|
|
_searchBar.frame = navigationBarFrame;
|
|
|
|
[super controllerInsetUpdated:previousInset];
|
|
}
|
|
|
|
- (void)layoutControllerForSize:(CGSize)size duration:(NSTimeInterval)duration
|
|
{
|
|
[super layoutControllerForSize:size duration:duration];
|
|
|
|
UIView *snapshotView = [_collectionContainer snapshotViewAfterScreenUpdates:false];
|
|
snapshotView.frame = _collectionContainer.frame;
|
|
[self.view insertSubview:snapshotView aboveSubview:_collectionContainer];
|
|
[UIView animateWithDuration:duration animations:^
|
|
{
|
|
snapshotView.alpha = 0.0f;
|
|
} completion:^(__unused BOOL finished)
|
|
{
|
|
[snapshotView removeFromSuperview];
|
|
}];
|
|
|
|
CGSize screenSize = size;
|
|
|
|
CGAffineTransform tableTransform = _collectionView.transform;
|
|
_collectionView.transform = CGAffineTransformIdentity;
|
|
|
|
CGRect tableFrame = CGRectMake(0, 0, screenSize.width, screenSize.height);
|
|
_collectionViewWidth = tableFrame.size.width;
|
|
_collectionView.frame = tableFrame;
|
|
|
|
_recentSearchResultsTableView.frame = _collectionView.frame;
|
|
|
|
_collectionView.transform = tableTransform;
|
|
|
|
[_collectionLayout invalidateLayout];
|
|
[_collectionView layoutSubviews];
|
|
|
|
void (^changeBlock)(void) = ^
|
|
{
|
|
_searchBar.frame = CGRectMake(_searchBar.frame.origin.x, _searchBar.frame.origin.y, size.width, 0.0f);
|
|
[_searchBar sizeToFit];
|
|
};
|
|
|
|
if (duration > DBL_EPSILON)
|
|
{
|
|
[UIView animateWithDuration:duration animations:changeBlock];
|
|
}
|
|
else
|
|
{
|
|
changeBlock();
|
|
}
|
|
|
|
[self _updateExplicitTableInset];
|
|
}
|
|
|
|
- (NSInteger)totalSelectionCount
|
|
{
|
|
return _imageSelectionContext.count + _gifSelectionContext.count + _recentSelectionContext.count;
|
|
}
|
|
|
|
- (NSMutableArray *)selectedItems
|
|
{
|
|
NSMutableArray *items = [[NSMutableArray alloc] init];
|
|
[items addObjectsFromArray:_imageSelectionContext.selectedItems];
|
|
[items addObjectsFromArray:_gifSelectionContext.selectedItems];
|
|
[items addObjectsFromArray:_recentSelectionContext.selectedItems];
|
|
|
|
return items;
|
|
}
|
|
|
|
- (void)updateSelectionInterface:(bool)animated
|
|
{
|
|
NSUInteger selectedCount = [self totalSelectionCount];
|
|
_doneButton.enabled = selectedCount != 0;
|
|
|
|
bool incremented = true;
|
|
|
|
CGFloat badgeAlpha = 0.0f;
|
|
if (selectedCount != 0)
|
|
{
|
|
badgeAlpha = 1.0f;
|
|
|
|
if (_countLabel.text.length != 0)
|
|
incremented = [_countLabel.text intValue] < (int)selectedCount;
|
|
|
|
_countLabel.text = [[NSString alloc] initWithFormat:@"%d", (int)selectedCount];
|
|
[_countLabel sizeToFit];
|
|
}
|
|
|
|
CGFloat badgeWidth = MAX(22, _countLabel.frame.size.width + 14);
|
|
_countBadge.transform = CGAffineTransformIdentity;
|
|
_countBadge.frame = CGRectMake(-badgeWidth + 22, 10 + TGRetinaPixel, badgeWidth, 22);
|
|
_countLabel.frame = CGRectMake(TGRetinaFloor((badgeWidth - _countLabel.frame.size.width) / 2), 2 + TGRetinaPixel, _countLabel.frame.size.width, _countLabel.frame.size.height);
|
|
|
|
if (animated)
|
|
{
|
|
if (_countBadge.alpha < FLT_EPSILON && badgeAlpha > FLT_EPSILON)
|
|
{
|
|
_countBadge.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
|
|
[UIView animateWithDuration:0.12 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^
|
|
{
|
|
_countBadge.alpha = badgeAlpha;
|
|
_countBadge.transform = CGAffineTransformMakeScale(1.2f, 1.2f);
|
|
} completion:^(BOOL finished)
|
|
{
|
|
if (finished)
|
|
{
|
|
[UIView animateWithDuration:0.08 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^
|
|
{
|
|
_countBadge.transform = CGAffineTransformIdentity;
|
|
} completion:nil];
|
|
}
|
|
}];
|
|
}
|
|
else if (_countBadge.alpha > FLT_EPSILON && badgeAlpha < FLT_EPSILON)
|
|
{
|
|
[UIView animateWithDuration:0.16 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^
|
|
{
|
|
_countBadge.alpha = badgeAlpha;
|
|
_countBadge.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
|
|
} completion:^(BOOL finished)
|
|
{
|
|
if (finished)
|
|
{
|
|
_countBadge.transform = CGAffineTransformIdentity;
|
|
}
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
[UIView animateWithDuration:0.12 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^
|
|
{
|
|
_countBadge.transform = incremented ? CGAffineTransformMakeScale(1.2f, 1.2f) : CGAffineTransformMakeScale(0.8f, 0.8f);
|
|
} completion:^(BOOL finished)
|
|
{
|
|
if (finished)
|
|
{
|
|
[UIView animateWithDuration:0.08 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^
|
|
{
|
|
_countBadge.transform = CGAffineTransformIdentity;
|
|
} completion:nil];
|
|
}
|
|
}];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_countBadge.transform = CGAffineTransformIdentity;
|
|
_countBadge.alpha = badgeAlpha;
|
|
}
|
|
}
|
|
|
|
- (void)updateEmptyState
|
|
{
|
|
bool searching = false;
|
|
if (_searchBar.selectedScopeButtonIndex == [self imagesScopeIndex])
|
|
searching = _searchingImage;
|
|
else if (_searchBar.selectedScopeButtonIndex == [self gifsScopeIndex])
|
|
searching = _searchingGif;
|
|
if ([self scopeSearchPath].length != 0 && !searching && [self scopeSearchResults].count == 0 && _searchBar.selectedScopeButtonIndex != [self recentScopeIndex])
|
|
[self nothingFoundView].hidden = false;
|
|
else
|
|
_nothingFoundView.hidden = true;
|
|
}
|
|
|
|
- (void)reloadData
|
|
{
|
|
for (TGModernMediaListItemView *itemView in [_collectionView visibleCells])
|
|
{
|
|
TGModernMediaListItemContentView *itemContentView = [itemView _takeItemContentView];
|
|
if (itemContentView != nil)
|
|
[_storedItemContentViews addObject:itemContentView];
|
|
}
|
|
|
|
[_collectionView reloadData];
|
|
|
|
[_collectionLayout invalidateLayout];
|
|
[_collectionView layoutSubviews];
|
|
|
|
for (TGModernMediaListItemContentView *itemContentView in _storedItemContentViews)
|
|
{
|
|
[self enqueueView:itemContentView];
|
|
}
|
|
|
|
[_storedItemContentViews removeAllObjects];
|
|
|
|
[self updateEmptyState];
|
|
}
|
|
|
|
- (CGSize)collectionView:(UICollectionView *)__unused collectionView layout:(UICollectionViewLayout *)__unused collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)__unused indexPath
|
|
{
|
|
return (_collectionViewWidth >= _layoutMetrics.widescreenWidth - FLT_EPSILON) ? _layoutMetrics.wideItemSize : _layoutMetrics.normalItemSize;
|
|
}
|
|
|
|
- (UIEdgeInsets)collectionView:(UICollectionView *)__unused collectionView layout:(UICollectionViewLayout *)__unused collectionViewLayout insetForSectionAtIndex:(NSInteger)__unused section
|
|
{
|
|
if (ABS(_collectionViewWidth - 540.0f) < FLT_EPSILON)
|
|
return UIEdgeInsetsMake(10.0f, 10.0f, 10.0f, 10.0f);
|
|
|
|
return (_collectionViewWidth >= _layoutMetrics.widescreenWidth - FLT_EPSILON) ? _layoutMetrics.wideEdgeInsets : _layoutMetrics.normalEdgeInsets;
|
|
}
|
|
|
|
- (CGFloat)collectionView:(UICollectionView *)__unused collectionView layout:(UICollectionViewLayout *)__unused collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)__unused section
|
|
{
|
|
return (_collectionViewWidth >= _layoutMetrics.widescreenWidth - FLT_EPSILON) ? _layoutMetrics.wideLineSpacing : _layoutMetrics.normalLineSpacing;
|
|
}
|
|
|
|
- (CGFloat)collectionView:(UICollectionView *)__unused collectionView layout:(UICollectionViewLayout *)__unused collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)__unused section
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
- (NSInteger)collectionView:(UICollectionView *)__unused collectionView numberOfItemsInSection:(NSInteger)__unused section
|
|
{
|
|
return (NSInteger)[self scopeSearchResults].count;
|
|
}
|
|
|
|
- (TGModernMediaListItemContentView *)dequeueViewForItem:(id<TGModernMediaListItem>)item synchronously:(bool)synchronously
|
|
{
|
|
if (item == nil || [item viewClass] == nil)
|
|
return nil;
|
|
|
|
NSString *identifier = NSStringFromClass([item viewClass]);
|
|
NSMutableArray *views = _reusableItemContentViewsByIdentifier[identifier];
|
|
if (views == nil)
|
|
{
|
|
views = [[NSMutableArray alloc] init];
|
|
_reusableItemContentViewsByIdentifier[identifier] = views;
|
|
}
|
|
|
|
if (views.count == 0)
|
|
{
|
|
Class itemClass = [item viewClass];
|
|
TGModernMediaListItemContentView *itemView = [[itemClass alloc] init];
|
|
[itemView setItem:item synchronously:synchronously];
|
|
|
|
return itemView;
|
|
}
|
|
|
|
TGModernMediaListItemContentView *itemView = [views lastObject];
|
|
[views removeLastObject];
|
|
|
|
[itemView setItem:item synchronously:synchronously];
|
|
|
|
return itemView;
|
|
}
|
|
|
|
- (void)enqueueView:(TGModernMediaListItemContentView *)itemView
|
|
{
|
|
if (itemView == nil)
|
|
return;
|
|
|
|
NSString *identifier = NSStringFromClass([itemView class]);
|
|
if (identifier != nil)
|
|
{
|
|
NSMutableArray *views = _reusableItemContentViewsByIdentifier[identifier];
|
|
if (views == nil)
|
|
{
|
|
views = [[NSMutableArray alloc] init];
|
|
_reusableItemContentViewsByIdentifier[identifier] = views;
|
|
}
|
|
[itemView prepareForReuse];
|
|
[views addObject:itemView];
|
|
}
|
|
}
|
|
|
|
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
NSInteger index = indexPath.item;
|
|
if (index < 0)
|
|
{
|
|
TGModernMediaListItemView *itemView = (TGModernMediaListItemView *)[collectionView dequeueReusableCellWithReuseIdentifier:@"TGModernMediaListItemView" forIndexPath:indexPath];
|
|
return itemView;
|
|
}
|
|
else
|
|
{
|
|
id<TGModernMediaListItem> item = [self scopeSearchResults][index];
|
|
|
|
TGModernMediaListItemView *itemView = (TGModernMediaListItemView *)[collectionView dequeueReusableCellWithReuseIdentifier:@"TGModernMediaListItemView" forIndexPath:indexPath];
|
|
|
|
if (itemView.recycleItemContentView == nil)
|
|
itemView.recycleItemContentView = _recycleItemContentView;
|
|
|
|
TGModernMediaListItemContentView *itemContentView = nil;
|
|
if (_storedItemContentViews.count != 0)
|
|
{
|
|
NSInteger index = -1;
|
|
for (TGModernMediaListItemContentView *stroredItemContentView in _storedItemContentViews)
|
|
{
|
|
index++;
|
|
|
|
if ([item isEqual:stroredItemContentView.item])
|
|
{
|
|
itemContentView = stroredItemContentView;
|
|
[_storedItemContentViews removeObjectAtIndex:(NSUInteger)index];
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (itemContentView == nil)
|
|
itemContentView = [self dequeueViewForItem:item synchronously:_loadItemsSynchronously];
|
|
|
|
[itemView setItemContentView:itemContentView];
|
|
|
|
bool hidden = (_hiddenItem != nil && [_hiddenItem isEqual:itemContentView.item]);
|
|
[itemContentView setHidden:hidden animated:false];
|
|
|
|
return itemView;
|
|
}
|
|
}
|
|
|
|
- (UIView *)referenceViewForSearchResult:(id<TGWebSearchResult>)searchResult
|
|
{
|
|
if (searchResult == nil)
|
|
return nil;
|
|
|
|
for (TGModernMediaListItemView *itemView in [_collectionView visibleCells])
|
|
{
|
|
if ([[(id<TGWebSearchListItem>)itemView.itemContentView.item webSearchResult] isEqual:searchResult])
|
|
return itemView.itemContentView;
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (id<TGWebSearchListItem>)listItemForSearchResult:(id<TGWebSearchResult>)searchResult
|
|
{
|
|
if (searchResult == nil)
|
|
return nil;
|
|
|
|
for (id<TGWebSearchListItem> item in [self scopeSearchResults])
|
|
{
|
|
if ([[item webSearchResult] isEqual:searchResult])
|
|
return item;
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (id<TGWebSearchResultsGalleryItem>)galleryItemForWebSearchResult:(id<TGWebSearchResult>)result
|
|
{
|
|
if ([result isKindOfClass:[TGWebSearchInternalImageResult class]])
|
|
{
|
|
return [[TGWebSearchResultsGalleryInternalImageItem alloc] initWithSearchResult:(TGWebSearchInternalImageResult *)result];
|
|
}
|
|
else if ([result isKindOfClass:[TGWebSearchInternalGifResult class]])
|
|
{
|
|
return [[TGWebSearchResultsGalleryInternalGifItem alloc] initWithSearchResult:(TGWebSearchInternalGifResult *)result];
|
|
}
|
|
else if ([result isKindOfClass:[TGBingSearchResultItem class]])
|
|
{
|
|
return [[TGWebSearchResultsGalleryImageItem alloc] initWithImageUrl:((TGBingSearchResultItem *)result).imageUrl imageSize:((TGBingSearchResultItem *)result).imageSize searchResultItem:(TGBingSearchResultItem *)result];
|
|
}
|
|
else if ([result isKindOfClass:[TGGiphySearchResultItem class]])
|
|
{
|
|
return [[TGWebSearchResultsGalleryGifItem alloc] initWithGiphySearchResultItem:(TGGiphySearchResultItem *)result];
|
|
}
|
|
else if ([result isKindOfClass:[TGInternalGifSearchResult class]]) {
|
|
return [[TGInternalGifSearchResultGalleryItem alloc] initWithSearchResult:(TGInternalGifSearchResult *)result];
|
|
} else if ([result isKindOfClass:[TGExternalGifSearchResult class]]) {
|
|
return [[TGExternalGifSearchResultGalleryItem alloc] initWithSearchResultItem:(TGExternalGifSearchResult *)result];
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (NSArray *)prepareGalleryItemsWithEnumerationBlock:(void (^)(id<TGWebSearchResultsGalleryItem> item))enumerationBlock
|
|
{
|
|
NSMutableArray *galleryItems = [[NSMutableArray alloc] init];
|
|
|
|
for (id<TGWebSearchListItem> item in [self scopeSearchResults])
|
|
{
|
|
id<TGWebSearchResultsGalleryItem> galleryItem = [self galleryItemForWebSearchResult:[item webSearchResult]];
|
|
galleryItem.selectionContext = item.selectionContext;
|
|
if ([galleryItem conformsToProtocol:@protocol(TGModernGalleryEditableItem)])
|
|
((id<TGModernGalleryEditableItem>)galleryItem).editingContext = _editingContext;
|
|
|
|
if (galleryItem != nil)
|
|
{
|
|
if (enumerationBlock != nil)
|
|
enumerationBlock(galleryItem);
|
|
|
|
[galleryItems addObject:galleryItem];
|
|
}
|
|
}
|
|
return galleryItems;
|
|
}
|
|
|
|
- (TGModernGalleryController *)createGalleryControllerForItem:(id<TGWebSearchListItem>)item
|
|
{
|
|
__weak TGWebSearchController *weakSelf = self;
|
|
TGModernGalleryController *modernGallery = [[TGModernGalleryController alloc] init];
|
|
|
|
__block id<TGModernGalleryItem> focusItem = nil;
|
|
NSArray *galleryItems = [self prepareGalleryItemsWithEnumerationBlock:^(id<TGWebSearchResultsGalleryItem> galleryItem)
|
|
{
|
|
if ([[galleryItem webSearchResult] isEqual:[item webSearchResult]])
|
|
focusItem = galleryItem;
|
|
}];
|
|
|
|
TGMediaPickerGalleryModel *model = [[TGMediaPickerGalleryModel alloc] initWithItems:galleryItems focusItem:focusItem selectionContext:item.selectionContext editingContext:_editingContext hasCaptions:self.captionsEnabled hasSelectionPanel:false];
|
|
model.suggestionContext = self.suggestionContext;
|
|
model.controller = modernGallery;
|
|
model.externalSelectionCount = ^NSInteger
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf == nil)
|
|
return 0;
|
|
|
|
return [strongSelf totalSelectionCount];
|
|
};
|
|
model.useGalleryImageAsEditableItemImage = true;
|
|
model.storeOriginalImageForItem = ^(id<TGMediaEditableItem> editableItem, UIImage *originalImage)
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf == nil)
|
|
return;
|
|
|
|
[strongSelf->_editingContext setOriginalImage:originalImage forItem:editableItem synchronous:false];
|
|
};
|
|
model.willFinishEditingItem = ^(id<TGMediaEditableItem> editableItem, id<TGMediaEditAdjustments> adjustments, id representation, bool hasChanges)
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf == nil)
|
|
return;
|
|
|
|
if (hasChanges)
|
|
[strongSelf->_editingContext setAdjustments:adjustments forItem:editableItem];
|
|
|
|
[strongSelf->_editingContext setTemporaryRep:representation forItem:editableItem];
|
|
|
|
if (item.selectionContext != nil && adjustments != nil && [editableItem conformsToProtocol:@protocol(TGMediaSelectableItem)])
|
|
[item.selectionContext setItem:(id<TGMediaSelectableItem>)editableItem selected:true];
|
|
};
|
|
model.didFinishEditingItem = ^(id<TGMediaEditableItem> editableItem, __unused id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage)
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf == nil)
|
|
return;
|
|
|
|
[strongSelf->_editingContext setImage:resultImage thumbnailImage:thumbnailImage forItem:editableItem synchronous:true];
|
|
};
|
|
model.saveItemCaption = ^(id<TGMediaEditableItem> editableItem, NSString *caption)
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf == nil)
|
|
return;
|
|
|
|
[strongSelf->_editingContext setCaption:caption forItem:editableItem];
|
|
|
|
if (item.selectionContext != nil && caption.length > 0 && [editableItem conformsToProtocol:@protocol(TGMediaSelectableItem)])
|
|
[item.selectionContext setItem:(id<TGMediaSelectableItem>)editableItem selected:true];
|
|
};
|
|
[model.interfaceView updateSelectionInterface:[self totalSelectionCount] counterVisible:([self totalSelectionCount] > 0) animated:false];
|
|
model.interfaceView.donePressed = ^(id<TGWebSearchResultsGalleryItem> item)
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf == nil)
|
|
return;
|
|
|
|
NSMutableArray *selectedItems = [strongSelf selectedItems];
|
|
|
|
if (selectedItems.count == 0)
|
|
[selectedItems addObject:[item webSearchResult]];
|
|
|
|
strongSelf->_selectedItems = selectedItems;
|
|
[strongSelf complete];
|
|
};
|
|
_galleryModel = model;
|
|
modernGallery.model = model;
|
|
|
|
modernGallery.itemFocused = ^(id<TGWebSearchResultsGalleryItem> item)
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf != nil)
|
|
{
|
|
id<TGWebSearchListItem> listItem = [strongSelf listItemForSearchResult:[item webSearchResult]];
|
|
strongSelf->_hiddenItem = listItem;
|
|
[strongSelf updateHiddenItemAnimated:false];
|
|
}
|
|
};
|
|
|
|
modernGallery.beginTransitionIn = ^UIView *(id<TGWebSearchResultsGalleryItem> item, __unused TGModernGalleryItemView *itemView)
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf != nil)
|
|
{
|
|
return [strongSelf referenceViewForSearchResult:[item webSearchResult]];
|
|
}
|
|
|
|
return nil;
|
|
};
|
|
|
|
modernGallery.beginTransitionOut = ^UIView *(id<TGWebSearchResultsGalleryItem> item, __unused TGModernGalleryItemView *itemView)
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf != nil)
|
|
{
|
|
return [strongSelf referenceViewForSearchResult:[item webSearchResult]];
|
|
}
|
|
|
|
return nil;
|
|
};
|
|
|
|
modernGallery.completedTransitionOut = ^
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf != nil)
|
|
{
|
|
strongSelf->_hiddenItem = nil;
|
|
[strongSelf updateHiddenItemAnimated:true];
|
|
}
|
|
};
|
|
|
|
return modernGallery;
|
|
}
|
|
|
|
- (void)updateHiddenItemAnimated:(bool)animated
|
|
{
|
|
for (TGModernMediaListItemView *itemView in [_collectionView visibleCells])
|
|
{
|
|
bool hidden = (_hiddenItem != nil && [_hiddenItem isEqual:itemView.itemContentView.item]);
|
|
[itemView.itemContentView setHidden:hidden animated:animated];
|
|
}
|
|
}
|
|
|
|
- (void)collectionView:(UICollectionView *)__unused collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
id<TGWebSearchListItem> item = [self scopeSearchResults][indexPath.row];
|
|
|
|
if (self.avatarSelection)
|
|
{
|
|
if (![[item webSearchResult] conformsToProtocol:@protocol(TGMediaEditableItem)])
|
|
return;
|
|
|
|
UIImage *thumbnailImage = nil;
|
|
TGModernMediaListItemView *listItemView = (TGModernMediaListItemView *)[_collectionView cellForItemAtIndexPath:indexPath];
|
|
|
|
if ([listItemView.itemContentView isKindOfClass:[TGWebSearchImageItemView class]])
|
|
{
|
|
TGWebSearchImageItemView *itemContentView = (TGWebSearchImageItemView *)listItemView.itemContentView;
|
|
thumbnailImage = itemContentView.imageView.image;
|
|
}
|
|
|
|
__weak TGWebSearchController *weakSelf = self;
|
|
TGPhotoEditorController *controller = [[TGPhotoEditorController alloc] initWithItem:(id<TGMediaEditableItem>)item.webSearchResult intent:TGPhotoEditorControllerAvatarIntent | TGPhotoEditorControllerWebIntent adjustments:nil caption:nil screenImage:thumbnailImage availableTabs:[TGPhotoEditorController defaultTabsForAvatarIntent] selectedTab:TGPhotoEditorCropTab];
|
|
controller.didFinishEditing = ^(PGPhotoEditorValues *editorValues, UIImage *resultImage, __unused UIImage *thumbnailImage, bool hasChanges)
|
|
{
|
|
if (!hasChanges)
|
|
return;
|
|
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf == nil)
|
|
return;
|
|
|
|
if (strongSelf.avatarCompletionBlock != nil)
|
|
strongSelf.avatarCompletionBlock(resultImage);
|
|
|
|
if ([editorValues toolsApplied])
|
|
[[[TGMediaAssetsLibrary sharedLibrary] saveAssetWithImage:resultImage] startWithNext:nil];
|
|
};
|
|
controller.requestThumbnailImage = ^SSignal *(id<TGMediaEditableItem> editableItem)
|
|
{
|
|
return [editableItem thumbnailImageSignal];
|
|
};
|
|
controller.requestOriginalScreenSizeImage = ^SSignal *(id<TGMediaEditableItem> editableItem)
|
|
{
|
|
return [editableItem screenImageSignal];
|
|
};
|
|
controller.requestOriginalFullSizeImage = ^SSignal *(id<TGMediaEditableItem> editableItem)
|
|
{
|
|
return [editableItem originalImageSignal];
|
|
};
|
|
|
|
UINavigationController *navController = self.parentNavigationController ? : self.navigationController;
|
|
[navController pushViewController:controller animated:true];
|
|
}
|
|
else
|
|
{
|
|
TGModernGalleryController *controller = [self createGalleryControllerForItem:item];
|
|
if (controller == nil)
|
|
return;
|
|
|
|
TGOverlayControllerWindow *controllerWindow = [[TGOverlayControllerWindow alloc] initWithParentController:self contentController:controller];
|
|
controllerWindow.hidden = false;
|
|
controller.view.clipsToBounds = true;
|
|
}
|
|
}
|
|
|
|
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
|
|
{
|
|
if ([self scopeSearchPath].length != 0 && !_searchBar.showActivity && scrollView.contentOffset.y > scrollView.contentSize.height - scrollView.bounds.size.height && _searchString.length != 0 && [self scopeMoreResultsAvailable])
|
|
{
|
|
_searchBar.showActivity = true;
|
|
|
|
[ActionStageInstance() requestActor:[self scopeSearchPath] options:@{@"query": _searchString, @"currentItems": [self scopeRawSearchResults], @"moreResultsOffset": @([self scopeMoreResultsOffset])} flags:0 watcher:self];
|
|
}
|
|
}
|
|
|
|
- (void)_updateSearchQuery:(NSString *)query
|
|
{
|
|
NSString *currentImageSearchPath = _imageSearchPath;
|
|
NSString *currentGifSearchPath = _gifSearchPath;
|
|
|
|
if (currentImageSearchPath != nil)
|
|
[ActionStageInstance() removeWatcher:self fromPath:currentImageSearchPath];
|
|
if (currentGifSearchPath != nil)
|
|
[ActionStageInstance() removeWatcher:self fromPath:currentGifSearchPath];
|
|
|
|
if (query.length == 0)
|
|
{
|
|
_imageSearchPath = nil;
|
|
_gifSearchPath = nil;
|
|
_searchString = nil;
|
|
_imageMoreResultsAvailable = false;
|
|
_gifMoreResultsAvailable = false;
|
|
_gifMoreResultsOffset = 0;
|
|
_searchBar.showActivity = false;
|
|
|
|
_rawImageSearchResults = nil;
|
|
_imageSearchResults = nil;
|
|
[_imageSelectionContext clear];
|
|
|
|
_rawGifSearchResults = nil;
|
|
_gifSearchResults = nil;
|
|
[_gifSelectionContext clear];
|
|
|
|
[self updateSelectionInterface:false];
|
|
|
|
_recentSearchResultsTableView.hidden = _searchBar.selectedScopeButtonIndex == [self recentScopeIndex];
|
|
}
|
|
else
|
|
{
|
|
_recentSearchResultsTableView.hidden = true;
|
|
|
|
_imageSearchPath = [[NSString alloc] initWithFormat:@"/search/%@/(%d)", @"bing", (int)murMurHash32(query)];
|
|
_gifSearchPath = [[NSString alloc] initWithFormat:@"/search/%@/(%d)", @"giphy", (int)murMurHash32(query)];
|
|
}
|
|
|
|
_nothingFoundView.hidden = true;
|
|
|
|
if (!TGStringCompare(_imageSearchPath, currentImageSearchPath))
|
|
{
|
|
_rawImageSearchResults = nil;
|
|
_imageSearchResults = nil;
|
|
[_imageSelectionContext clear];
|
|
|
|
_rawGifSearchResults = nil;
|
|
_gifSearchResults = nil;
|
|
[_gifSelectionContext clear];
|
|
|
|
[self updateSelectionInterface:false];
|
|
|
|
_searchString = query;
|
|
_imageMoreResultsAvailable = false;
|
|
_gifMoreResultsAvailable = false;
|
|
_gifMoreResultsOffset = 0;
|
|
|
|
if (_imageSearchPath.length != 0)
|
|
{
|
|
_searchBar.showActivity = true;
|
|
_searchingImage = true;
|
|
[ActionStageInstance() requestActor:_imageSearchPath options:@{@"query": query} flags:0 watcher:self];
|
|
}
|
|
|
|
if (_gifSearchPath.length != 0)
|
|
{
|
|
_searchBar.showActivity = true;
|
|
_searchingGif = true;
|
|
[ActionStageInstance() requestActor:_gifSearchPath options:@{@"query": query} flags:0 watcher:self];
|
|
}
|
|
|
|
[self reloadData];
|
|
}
|
|
}
|
|
|
|
- (void)searchBar:(TGSearchBar *)__unused searchBar willChangeHeight:(CGFloat)__unused newHeight
|
|
{
|
|
searchBar.frame = CGRectMake(searchBar.frame.origin.x, searchBar.frame.origin.y, searchBar.frame.size.width, newHeight);
|
|
}
|
|
|
|
- (void)searchBarCancelButtonClicked:(TGSearchBar *)__unused searchBar
|
|
{
|
|
[_searchBar endEditing:true];
|
|
|
|
if (self.dismiss != nil)
|
|
self.dismiss();
|
|
}
|
|
|
|
- (void)searchBarSearchButtonClicked:(UISearchBar *)__unused searchBar
|
|
{
|
|
if (_searchBar.text.length != 0)
|
|
[self _addRecentSearchItem:_searchBar.text];
|
|
[_collectionView setContentOffset:CGPointMake(0.0f, -_collectionView.contentInset.top)];
|
|
[self _updateSearchQuery:_searchBar.text];
|
|
|
|
if (_searchBar.selectedScopeButtonIndex == [self recentScopeIndex])
|
|
{
|
|
_searchBar.selectedScopeButtonIndex = 0;
|
|
[self searchBar:(UISearchBar *)_searchBar selectedScopeButtonIndexDidChange:0];
|
|
}
|
|
}
|
|
|
|
- (void)searchBar:(UISearchBar *)__unused searchBar textDidChange:(NSString *)searchText
|
|
{
|
|
if (searchText.length == 0)
|
|
[self _updateSearchQuery:searchText];
|
|
}
|
|
|
|
- (void)searchBar:(UISearchBar *)__unused searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope
|
|
{
|
|
[_searchBar resignFirstResponder];
|
|
|
|
if (!self.avatarSelection)
|
|
[[NSUserDefaults standardUserDefaults] setObject:@((int)selectedScope) forKey:@"webSearchSelectedScope"];
|
|
[self updateToolbarItemsAnimated:true];
|
|
_recentSearchResultsTableView.hidden = selectedScope == [self recentScopeIndex] || _searchString.length != 0;
|
|
[_collectionView setContentOffset:CGPointMake(0.0f, -_collectionView.contentInset.top)];
|
|
_loadItemsSynchronously = true;
|
|
[_collectionView reloadData];
|
|
[_collectionView layoutSubviews];
|
|
_loadItemsSynchronously = false;
|
|
|
|
bool searching = false;
|
|
if (_searchBar.selectedScopeButtonIndex == [self imagesScopeIndex])
|
|
searching = _searchingImage;
|
|
else if (_searchBar.selectedScopeButtonIndex == [self gifsScopeIndex])
|
|
searching = _searchingGif;
|
|
if ([self scopeSearchPath].length != 0 && !searching && [self scopeSearchResults].count == 0 && _searchBar.selectedScopeButtonIndex != [self recentScopeIndex])
|
|
[self nothingFoundView].hidden = false;
|
|
else
|
|
_nothingFoundView.hidden = true;
|
|
}
|
|
|
|
- (void)searchBarTextDidBeginEditing:(UISearchBar *)__unused searchBar
|
|
{
|
|
if ([UIDevice currentDevice].userInterfaceIdiom != UIUserInterfaceIdiomPad)
|
|
[self _performEmbeddedTransitionIn];
|
|
}
|
|
|
|
- (void)updateToolbarItemsAnimated:(bool)animated
|
|
{
|
|
bool logoViewHidden = _searchBar.selectedScopeButtonIndex != [self gifsScopeIndex];
|
|
bool clearButtonHidden = _searchBar.selectedScopeButtonIndex != [self recentScopeIndex] || _recentSearchResults.count == 0;
|
|
|
|
if (animated)
|
|
{
|
|
_toolbarLogoView.hidden = false;
|
|
_clearButton.hidden = clearButtonHidden;
|
|
|
|
[UIView animateWithDuration:0.15f animations:^
|
|
{
|
|
_toolbarLogoView.alpha = logoViewHidden ? 0.0f : 1.0f;
|
|
} completion:^(BOOL finished)
|
|
{
|
|
if (finished)
|
|
{
|
|
_toolbarLogoView.hidden = logoViewHidden;
|
|
_clearButton.hidden = clearButtonHidden;
|
|
}
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
_toolbarLogoView.hidden = logoViewHidden;
|
|
_toolbarLogoView.alpha = _toolbarLogoView.hidden ? 0.0f : 1.0f;
|
|
_clearButton.hidden = clearButtonHidden;
|
|
}
|
|
}
|
|
|
|
- (void)scrollViewWillBeginDragging:(UIScrollView *)__unused scrollView
|
|
{
|
|
[_searchBar resignFirstResponder];
|
|
}
|
|
|
|
- (void)clearButtonPressed
|
|
{
|
|
__weak TGWebSearchController *weakSelf = self;
|
|
|
|
TGActionSheetAction *confirmAction = [[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"WebSearch.RecentSectionClear") action:@"confirm" type:TGActionSheetActionTypeDestructive];
|
|
TGActionSheetAction *cancelAction = [[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"Common.Cancel") action:@"cancel" type:TGActionSheetActionTypeCancel];
|
|
TGActionSheet *actionSheet = [[TGActionSheet alloc] initWithTitle:TGLocalized(@"WebSearch.RecentClearConfirmation") actions:@[ confirmAction, cancelAction ] actionBlock:^(__unused id target, NSString *action)
|
|
{
|
|
if ([action isEqualToString:@"confirm"])
|
|
{
|
|
__strong TGWebSearchController *strongSelf = weakSelf;
|
|
if (strongSelf == nil)
|
|
return;
|
|
|
|
[TGWebSearchController clearRecents];
|
|
|
|
strongSelf->_recentSearchResults = nil;
|
|
[strongSelf reloadData];
|
|
|
|
[strongSelf->_recentSelectionContext clear];
|
|
|
|
strongSelf->_clearButton.hidden = true;
|
|
}
|
|
} target:self];
|
|
|
|
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone)
|
|
[actionSheet showInView:self.view];
|
|
else
|
|
[actionSheet showFromRect:[self.view convertRect:_clearButton.frame fromView:_clearButton.superview] inView:self.view animated:true];
|
|
}
|
|
|
|
- (void)doneButtonPressed
|
|
{
|
|
_selectedItems = [self selectedItems];
|
|
|
|
[self complete];
|
|
}
|
|
|
|
- (void)complete
|
|
{
|
|
[TGWebSearchController addRecentSelectedItems:_selectedItems];
|
|
|
|
if (self.completionBlock != nil)
|
|
self.completionBlock(self);
|
|
|
|
TGMediaPickerGalleryModel *galleryModel = _galleryModel;
|
|
if (galleryModel != nil)
|
|
{
|
|
if (galleryModel.dismiss)
|
|
galleryModel.dismiss(true, false);
|
|
}
|
|
|
|
[self.presentingViewController dismissViewControllerAnimated:true completion:nil];
|
|
}
|
|
|
|
- (NSArray *)selectedItemSignals:(id (^)(id, NSString *))imageDescriptionGenerator
|
|
{
|
|
NSMutableArray *resultSignals = [[NSMutableArray alloc] init];
|
|
|
|
for (id<TGWebSearchResult> item in _selectedItems)
|
|
{
|
|
NSString *caption = nil;
|
|
if ([item conformsToProtocol:@protocol(TGMediaEditableItem)])
|
|
caption = [_editingContext captionForItem:(id<TGMediaEditableItem>)item];
|
|
|
|
if (caption.length == 0)
|
|
caption = nil;
|
|
|
|
SSignal *signal = [SSignal single:item];
|
|
|
|
if ([item conformsToProtocol:@protocol(TGMediaEditableItem)])
|
|
{
|
|
signal = [[[[_editingContext imageSignalForItem:(id<TGMediaEditableItem>)item] filter:^bool(id result)
|
|
{
|
|
return result == nil || ([result isKindOfClass:[UIImage class]] && !((UIImage *)result).degraded);
|
|
}] take:1] mapToSignal:^SSignal *(id result)
|
|
{
|
|
if (result == nil)
|
|
{
|
|
return [SSignal single:item];
|
|
}
|
|
else if ([result isKindOfClass:[UIImage class]])
|
|
{
|
|
UIImage *image = (UIImage *)result;
|
|
image.edited = true;
|
|
return [SSignal single:image];
|
|
}
|
|
|
|
return [SSignal complete];
|
|
}];
|
|
}
|
|
|
|
signal = [signal mapToSignal:^SSignal *(id item)
|
|
{
|
|
if (item == nil)
|
|
return [SSignal complete];
|
|
|
|
id generatedItem = imageDescriptionGenerator(item, caption);
|
|
if (generatedItem == nil)
|
|
return [SSignal complete];
|
|
|
|
return [SSignal single:generatedItem];
|
|
}];
|
|
|
|
[resultSignals addObject:signal];
|
|
}
|
|
|
|
return resultSignals;
|
|
}
|
|
|
|
- (NSArray *)uniqueItemsInArray:(NSArray *)array
|
|
{
|
|
NSMutableArray *result = [[NSMutableArray alloc] init];
|
|
NSMutableArray *set = [[NSMutableArray alloc] init];
|
|
|
|
for (id item in array)
|
|
{
|
|
if (![set containsObject:item])
|
|
{
|
|
[set addObject:item];
|
|
[result addObject:item];
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
- (void)actorCompleted:(int)status path:(NSString *)path result:(id)result
|
|
{
|
|
TGDispatchOnMainThread(^
|
|
{
|
|
if ([path isEqualToString:_imageSearchPath])
|
|
{
|
|
_searchingImage = false;
|
|
_searchBar.showActivity = _searchingGif;
|
|
|
|
if (status == ASStatusSuccess)
|
|
{
|
|
NSMutableArray *searchResults = [[NSMutableArray alloc] init];
|
|
|
|
for (id item in result[@"items"])
|
|
{
|
|
if ([item isKindOfClass:[TGGiphySearchResultItem class]])
|
|
{
|
|
TGGiphySearchResultItem *concreteItem = item;
|
|
TGWebSearchGifItem *listItem = [[TGWebSearchGifItem alloc] initWithPreviewUrl:concreteItem.previewUrl searchResultItem:concreteItem];
|
|
listItem.selectionContext = _gifSelectionContext;
|
|
[searchResults addObject:listItem];
|
|
}
|
|
else if ([item isKindOfClass:[TGBingSearchResultItem class]])
|
|
{
|
|
TGBingSearchResultItem *concreteItem = item;
|
|
TGWebSearchImageItem *listItem = [[TGWebSearchImageItem alloc] initWithPreviewUrl:concreteItem.previewUrl searchResultItem:concreteItem];
|
|
listItem.selectionContext = _imageSelectionContext;
|
|
listItem.editingContext = _editingContext;
|
|
[searchResults addObject:listItem];
|
|
|
|
if (!self.avatarSelection)
|
|
{
|
|
concreteItem.fetchOriginalImage = _fetchOriginalImage;
|
|
concreteItem.fetchOriginalThumbnailImage = _fetchOriginalThumbnailImage;
|
|
}
|
|
}
|
|
else if ([item isKindOfClass:[TGInternalGifSearchResult class]] && !self.avatarSelection)
|
|
{
|
|
TGInternalGifSearchResultItem *listItem = [[TGInternalGifSearchResultItem alloc] initWithSearchResult:item];
|
|
listItem.selectionContext = _gifSelectionContext;
|
|
[searchResults addObject:listItem];
|
|
}
|
|
else if ([item isKindOfClass:[TGExternalGifSearchResult class]] && !self.avatarSelection)
|
|
{
|
|
TGExternalGifSearchResultItem *listItem = [[TGExternalGifSearchResultItem alloc] initWithSearchResult:item];
|
|
listItem.selectionContext = _gifSelectionContext;
|
|
[searchResults addObject:listItem];
|
|
}
|
|
}
|
|
|
|
_imageSearchResults = [self uniqueItemsInArray:searchResults];
|
|
_rawImageSearchResults = result[@"items"];
|
|
_imageMoreResultsAvailable = [result[@"moreResultsAvailable"] boolValue];
|
|
|
|
if (_searchBar.selectedScopeButtonIndex == [self imagesScopeIndex])
|
|
[self reloadData];
|
|
}
|
|
}
|
|
else if ([path isEqualToString:_gifSearchPath])
|
|
{
|
|
_searchingGif = false;
|
|
_searchBar.showActivity = _searchingImage;
|
|
|
|
if (status == ASStatusSuccess)
|
|
{
|
|
NSMutableArray *searchResults = [[NSMutableArray alloc] init];
|
|
|
|
for (id item in result[@"items"])
|
|
{
|
|
if ([item isKindOfClass:[TGGiphySearchResultItem class]])
|
|
{
|
|
TGGiphySearchResultItem *concreteItem = item;
|
|
TGWebSearchGifItem *listItem = [[TGWebSearchGifItem alloc] initWithPreviewUrl:concreteItem.previewUrl searchResultItem:concreteItem];
|
|
listItem.selectionContext = _gifSelectionContext;
|
|
[searchResults addObject:listItem];
|
|
}
|
|
else if ([item isKindOfClass:[TGBingSearchResultItem class]])
|
|
{
|
|
TGBingSearchResultItem *concreteItem = item;
|
|
TGWebSearchImageItem *listItem = [[TGWebSearchImageItem alloc] initWithPreviewUrl:concreteItem.previewUrl searchResultItem:concreteItem];
|
|
listItem.selectionContext = _imageSelectionContext;
|
|
listItem.editingContext = _editingContext;
|
|
[searchResults addObject:listItem];
|
|
|
|
if (!self.avatarSelection)
|
|
{
|
|
concreteItem.fetchOriginalImage = _fetchOriginalImage;
|
|
concreteItem.fetchOriginalThumbnailImage = _fetchOriginalThumbnailImage;
|
|
}
|
|
}
|
|
else if ([item isKindOfClass:[TGInternalGifSearchResult class]] && !self.avatarSelection)
|
|
{
|
|
TGInternalGifSearchResultItem *listItem = [[TGInternalGifSearchResultItem alloc] initWithSearchResult:item];
|
|
listItem.selectionContext = _gifSelectionContext;
|
|
[searchResults addObject:listItem];
|
|
}
|
|
else if ([item isKindOfClass:[TGExternalGifSearchResult class]] && !self.avatarSelection)
|
|
{
|
|
TGExternalGifSearchResultItem *listItem = [[TGExternalGifSearchResultItem alloc] initWithSearchResult:item];
|
|
listItem.selectionContext = _gifSelectionContext;
|
|
[searchResults addObject:listItem];
|
|
}
|
|
}
|
|
|
|
_gifSearchResults = [self uniqueItemsInArray:searchResults];
|
|
_rawGifSearchResults = result[@"items"];
|
|
_gifMoreResultsAvailable = [result[@"moreResultsAvailable"] boolValue];
|
|
_gifMoreResultsOffset = [result[@"moreResultsOffset"] intValue];
|
|
|
|
if (_searchBar.selectedScopeButtonIndex == [self gifsScopeIndex])
|
|
[self reloadData];
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
- (NSInteger)imagesScopeIndex
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
- (NSInteger)gifsScopeIndex
|
|
{
|
|
if (_avatarSelection)
|
|
return -1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
- (NSInteger)recentScopeIndex
|
|
{
|
|
if (_avatarSelection)
|
|
return 1;
|
|
|
|
return 2;
|
|
}
|
|
|
|
- (void)presentEmbeddedInController:(UIViewController *)controller animated:(bool)__unused animated
|
|
{
|
|
_embedded = true;
|
|
//[controller addChildViewController:self];
|
|
|
|
self.view.frame = controller.view.bounds;
|
|
|
|
[self beginAppearanceTransition:true animated:false];
|
|
[controller.view addSubview:self.view];
|
|
|
|
self.view.backgroundColor = [UIColor clearColor];
|
|
_collectionContainer.alpha = 0.0f;
|
|
_searchBar.alpha = 0.0f;
|
|
_toolbarView.alpha = 0.0f;
|
|
_recentSearchResultsTableView.alpha = 0.0f;
|
|
|
|
[self endAppearanceTransition];
|
|
}
|
|
|
|
- (void)_performEmbeddedTransitionIn
|
|
{
|
|
if (!_embedded || !_searchBar.scopeBarCollapsed)
|
|
return;
|
|
|
|
CGRect recentTableFrame = _recentSearchResultsTableView.frame;
|
|
CGRect collectionFrame = _collectionContainer.frame;
|
|
[UIView performWithoutAnimation:^
|
|
{
|
|
[_searchBar setCustomScopeBarHidden:true];
|
|
[_searchBar layoutSubviews];
|
|
|
|
_recentSearchResultsTableView.frame = CGRectOffset(_recentSearchResultsTableView.frame, 0, -44);
|
|
_collectionContainer.frame = CGRectOffset(_collectionContainer.frame, 0, -44);
|
|
}];
|
|
|
|
TGDispatchAfter(0.015, dispatch_get_main_queue(), ^
|
|
{
|
|
[UIView animateWithDuration:0.2 animations:^
|
|
{
|
|
_searchBar.alpha = 1.0f;
|
|
}];
|
|
|
|
[UIView animateWithDuration:0.3 delay:0.0 options:7 << 16 | UIViewAnimationOptionLayoutSubviews | UIViewAnimationOptionAllowAnimatedContent animations:^
|
|
{
|
|
_searchBar.scopeBarCollapsed = false;
|
|
[_searchBar setSearchBarShouldShowScopeControl:true];
|
|
|
|
_collectionContainer.alpha = 1.0f;
|
|
_collectionContainer.frame = collectionFrame;
|
|
|
|
_toolbarView.alpha = 1.0f;
|
|
|
|
if (_recentSearchResultsTableView.items.count > 0)
|
|
_recentSearchResultsTableView.alpha = 1.0f;
|
|
_recentSearchResultsTableView.frame = recentTableFrame;
|
|
} completion:^(__unused BOOL finished)
|
|
{
|
|
self.view.backgroundColor = [UIColor whiteColor];
|
|
}];
|
|
|
|
[UIView animateWithDuration:0.2 delay:0.08 options:UIViewAnimationOptionAllowAnimatedContent animations:^
|
|
{
|
|
[_searchBar setCustomScopeBarHidden:false];
|
|
} completion:nil];
|
|
|
|
[self _updateExplicitTableInset];
|
|
});
|
|
}
|
|
|
|
- (void)dismissEmbeddedAnimated:(bool)__unused animated
|
|
{
|
|
[self beginAppearanceTransition:false animated:false];
|
|
|
|
self.view.backgroundColor = [UIColor clearColor];
|
|
|
|
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionAllowAnimatedContent animations:^
|
|
{
|
|
_searchBar.alpha = 0.0f;
|
|
[_searchBar setCustomScopeBarHidden:true];
|
|
} completion:nil];
|
|
|
|
[UIView animateWithDuration:0.3 delay:0.0 options:7 << 16 | UIViewAnimationOptionLayoutSubviews | UIViewAnimationOptionAllowAnimatedContent animations:^
|
|
{
|
|
_searchBar.scopeBarCollapsed = true;
|
|
[_searchBar setSearchBarShouldShowScopeControl:false];
|
|
|
|
_collectionContainer.alpha = 0.0f;
|
|
_collectionContainer.frame = CGRectOffset(_collectionContainer.frame, 0, -44);
|
|
|
|
_toolbarView.alpha = 0.0f;
|
|
|
|
_recentSearchResultsTableView.alpha = 0.0f;
|
|
_recentSearchResultsTableView.frame = CGRectOffset(_recentSearchResultsTableView.frame, 0, -44);
|
|
} completion:^(__unused BOOL finished)
|
|
{
|
|
[self.view removeFromSuperview];
|
|
|
|
[self endAppearanceTransition];
|
|
[self removeFromParentViewController];
|
|
}];
|
|
}
|
|
|
|
@end
|