mirror of
https://github.com/danog/Telegram.git
synced 2024-12-02 09:27:55 +01:00
347 lines
11 KiB
Objective-C
347 lines
11 KiB
Objective-C
#import "TGMediaPickerController.h"
|
|
|
|
#import "TGAppDelegate.h"
|
|
|
|
#import "TGMediaEditingContext.h"
|
|
#import "TGMediaSelectionContext.h"
|
|
|
|
#import "TGMediaPickerSelectionGestureRecognizer.h"
|
|
|
|
#import "TGMediaPickerLayoutMetrics.h"
|
|
#import "TGMediaPickerCell.h"
|
|
|
|
#import "TGMediaPickerToolbarView.h"
|
|
|
|
#import "TGPhotoEditorController.h"
|
|
|
|
@interface TGMediaPickerController () <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
|
|
{
|
|
TGMediaSelectionContext *_selectionContext;
|
|
TGMediaEditingContext *_editingContext;
|
|
|
|
SMetaDisposable *_selectionChangedDisposable;
|
|
|
|
UIView *_wrapperView;
|
|
CGFloat _collectionViewWidth;
|
|
id _hiddenItem;
|
|
|
|
TGMediaPickerSelectionGestureRecognizer *_selectionGestureRecognizer;
|
|
}
|
|
@end
|
|
|
|
@implementation TGMediaPickerController
|
|
|
|
- (instancetype)initWithSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext
|
|
{
|
|
self = [super init];
|
|
if (self != nil)
|
|
{
|
|
_selectionContext = selectionContext;
|
|
_editingContext = editingContext;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
_collectionView.delegate = nil;
|
|
_collectionView.dataSource = nil;
|
|
[_selectionChangedDisposable dispose];
|
|
}
|
|
|
|
- (void)loadView
|
|
{
|
|
[super loadView];
|
|
|
|
self.view.backgroundColor = [UIColor whiteColor];
|
|
|
|
_wrapperView = [[UIView alloc] initWithFrame:self.view.bounds];
|
|
_wrapperView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
[self.view addSubview:_wrapperView];
|
|
|
|
_collectionView = [[UICollectionView alloc] initWithFrame:_wrapperView.bounds collectionViewLayout:[[UICollectionViewFlowLayout alloc] init]];
|
|
_collectionView.alwaysBounceVertical = true;
|
|
_collectionView.backgroundColor = [UIColor whiteColor];
|
|
_collectionView.delaysContentTouches = true;
|
|
_collectionView.canCancelContentTouches = true;
|
|
_collectionView.delegate = self;
|
|
_collectionView.dataSource = self;
|
|
[_wrapperView addSubview:_collectionView];
|
|
|
|
self.scrollViewsForAutomaticInsetsAdjustment = @[ _collectionView ];
|
|
|
|
self.explicitTableInset = UIEdgeInsetsMake(0, 0, TGMediaPickerToolbarHeight, 0);
|
|
self.explicitScrollIndicatorInset = self.explicitTableInset;
|
|
|
|
if (![self _updateControllerInset:false])
|
|
[self controllerInsetUpdated:UIEdgeInsetsZero];
|
|
|
|
if (_selectionContext != nil)
|
|
{
|
|
__weak TGMediaPickerController *weakSelf = self;
|
|
|
|
_selectionGestureRecognizer = [[TGMediaPickerSelectionGestureRecognizer alloc] initForCollectionView:_collectionView];
|
|
_selectionGestureRecognizer.isItemSelected = ^bool (NSIndexPath *indexPath)
|
|
{
|
|
__strong TGMediaPickerController *strongSelf = weakSelf;
|
|
if (strongSelf == nil)
|
|
return false;
|
|
|
|
id item = [strongSelf _itemAtIndexPath:indexPath];
|
|
return [strongSelf->_selectionContext isItemSelected:item];
|
|
};
|
|
_selectionGestureRecognizer.toggleItemSelection = ^(NSIndexPath *indexPath)
|
|
{
|
|
__strong TGMediaPickerController *strongSelf = weakSelf;
|
|
if (strongSelf == nil)
|
|
return;
|
|
|
|
id item = [strongSelf _itemAtIndexPath:indexPath];
|
|
[strongSelf->_selectionContext toggleItemSelection:item animated:true sender:nil];
|
|
};
|
|
}
|
|
}
|
|
|
|
- (void)viewDidLoad
|
|
{
|
|
[super viewDidLoad];
|
|
|
|
CGSize frameSize = self.view.frame.size;
|
|
CGRect collectionViewFrame = CGRectMake(0.0f, 0.0f, frameSize.width, frameSize.height);
|
|
_collectionViewWidth = collectionViewFrame.size.width;
|
|
_collectionView.frame = collectionViewFrame;
|
|
}
|
|
|
|
- (void)viewDidAppear:(BOOL)animated
|
|
{
|
|
[super viewDidAppear:animated];
|
|
|
|
if (self.catchToolbarView != nil)
|
|
self.catchToolbarView(false);
|
|
}
|
|
|
|
- (void)viewWillDisappear:(BOOL)animated
|
|
{
|
|
[super viewWillDisappear:animated];
|
|
|
|
NSArray *viewControllers = self.navigationController.viewControllers;
|
|
|
|
bool shouldCatch = false;
|
|
if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count - 2] == self)
|
|
shouldCatch = true;
|
|
else if ([viewControllers indexOfObject:self] == NSNotFound)
|
|
shouldCatch = false;
|
|
|
|
if (self.catchToolbarView != nil)
|
|
self.catchToolbarView(shouldCatch);
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (bool)shouldAdjustScrollViewInsetsForInversedLayout
|
|
{
|
|
return true;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (bool)hasSelection
|
|
{
|
|
return (_selectionContext != nil);
|
|
}
|
|
|
|
- (bool)hasEditing
|
|
{
|
|
return (_editingContext != nil);
|
|
}
|
|
|
|
- (void)setCell:(TGMediaPickerCell *)cell checked:(bool)checked
|
|
{
|
|
NSIndexPath *indexPath = [_collectionView indexPathForCell:cell];
|
|
|
|
if (indexPath == nil)
|
|
return;
|
|
|
|
id item = [self _itemAtIndexPath:indexPath];
|
|
[_selectionContext setItem:item selected:checked];
|
|
}
|
|
|
|
#pragma mark - Data Source
|
|
|
|
- (NSInteger)_numberOfItems
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
- (id)_itemAtIndexPath:(id)__unused indexPath
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
- (SSignal *)_signalForItem:(id)__unused item
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
- (NSString *)_cellKindForItem:(id)__unused item
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (NSArray *)resultSignals:(id (^)(id, NSString *, NSString *))__unused descriptionGenerator
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
#pragma mark - Collection View Data Source & Delegate
|
|
|
|
- (NSInteger)collectionView:(UICollectionView *)__unused collectionView numberOfItemsInSection:(NSInteger)__unused section
|
|
{
|
|
return [self _numberOfItems];
|
|
}
|
|
|
|
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
|
{
|
|
id item = [self _itemAtIndexPath:indexPath];
|
|
NSString *cellKind = [self _cellKindForItem:item];
|
|
|
|
TGMediaPickerCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellKind forIndexPath:indexPath];
|
|
cell.selectionContext = self.selectionContext;
|
|
cell.editingContext = self.editingContext;
|
|
[cell setItem:item signal:[self _signalForItem:item]];
|
|
[cell setHidden:([cell.item isEqual:_hiddenItem]) animated:false];
|
|
|
|
return cell;
|
|
}
|
|
|
|
#pragma mark - Collection View Layout Delegate
|
|
|
|
- (CGSize)collectionView:(UICollectionView *)__unused collectionView layout:(UICollectionViewLayout *)__unused collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)__unused indexPath
|
|
{
|
|
return [_layoutMetrics itemSizeForCollectionViewWidth:_collectionViewWidth];
|
|
}
|
|
|
|
- (UIEdgeInsets)collectionView:(UICollectionView *)__unused collectionView layout:(UICollectionViewLayout *)__unused collectionViewLayout insetForSectionAtIndex:(NSInteger)__unused section
|
|
{
|
|
if (ABS(_collectionViewWidth - 540) < FLT_EPSILON)
|
|
return UIEdgeInsetsMake(10, 10, 10, 10);
|
|
|
|
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;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
- (void)_adjustContentOffsetToBottom
|
|
{
|
|
UIEdgeInsets sectionInsets = [self collectionView:_collectionView layout:_collectionView.collectionViewLayout insetForSectionAtIndex:0];
|
|
|
|
CGFloat itemSpacing = [self collectionView:_collectionView layout:_collectionView.collectionViewLayout minimumInteritemSpacingForSectionAtIndex:0];
|
|
CGFloat lineSpacing = [self collectionView:_collectionView layout:_collectionView.collectionViewLayout minimumLineSpacingForSectionAtIndex:0];
|
|
|
|
CGFloat additionalRowWidth = sectionInsets.left + sectionInsets.right;
|
|
CGFloat currentRowWidth = 0.0f;
|
|
CGFloat maxRowWidth = _collectionView.frame.size.width;
|
|
|
|
CGSize itemSize = CGSizeZero;
|
|
if ([self collectionView:_collectionView numberOfItemsInSection:0] != 0)
|
|
{
|
|
itemSize = [self collectionView:_collectionView layout:_collectionView.collectionViewLayout sizeForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
|
|
}
|
|
|
|
CGFloat contentSize = 0.0f;
|
|
|
|
for (NSInteger i = [self collectionView:_collectionView numberOfItemsInSection:0] - 1; i >= 0; i--)
|
|
{
|
|
if (currentRowWidth + itemSize.width + (currentRowWidth > FLT_EPSILON ? itemSpacing : 0.0f) + additionalRowWidth > maxRowWidth)
|
|
{
|
|
if (contentSize > FLT_EPSILON)
|
|
contentSize += lineSpacing;
|
|
contentSize += itemSize.height;
|
|
|
|
currentRowWidth = 0.0f;
|
|
}
|
|
|
|
if (currentRowWidth > FLT_EPSILON)
|
|
currentRowWidth += itemSpacing;
|
|
currentRowWidth += itemSize.width;
|
|
}
|
|
|
|
if (currentRowWidth > FLT_EPSILON)
|
|
{
|
|
if (contentSize > FLT_EPSILON)
|
|
contentSize += lineSpacing;
|
|
contentSize += itemSize.height;
|
|
}
|
|
|
|
contentSize += sectionInsets.top + sectionInsets.bottom;
|
|
|
|
UIEdgeInsets contentInset = [self controllerInsetForInterfaceOrientation:self.interfaceOrientation];
|
|
|
|
CGPoint contentOffset = CGPointMake(0, contentSize - _collectionView.frame.size.height + contentInset.bottom);
|
|
if (contentOffset.y < -contentInset.top)
|
|
contentOffset.y = -contentInset.top;
|
|
[_collectionView setContentOffset:contentOffset animated:false];
|
|
}
|
|
|
|
- (void)layoutControllerForSize:(CGSize)size duration:(NSTimeInterval)duration
|
|
{
|
|
[super layoutControllerForSize:size duration:duration];
|
|
|
|
UIView *snapshotView = [_wrapperView snapshotViewAfterScreenUpdates:false];
|
|
snapshotView.frame = _wrapperView.frame;
|
|
[self.view insertSubview:snapshotView aboveSubview:_wrapperView];
|
|
[UIView animateWithDuration:duration animations:^
|
|
{
|
|
snapshotView.alpha = 0.0f;
|
|
} completion:^(__unused BOOL finished)
|
|
{
|
|
[snapshotView removeFromSuperview];
|
|
}];
|
|
|
|
CGFloat lastInverseOffset = MAX(0, _collectionView.contentSize.height - (_collectionView.contentOffset.y + _collectionView.frame.size.height - _collectionView.contentInset.bottom));
|
|
CGFloat lastOffset = _collectionView.contentOffset.y;
|
|
|
|
CGRect frame = CGRectMake(0, 0, size.width, size.height);
|
|
_collectionViewWidth = frame.size.width;
|
|
_collectionView.frame = frame;
|
|
|
|
if (lastInverseOffset < 2)
|
|
{
|
|
[self _adjustContentOffsetToBottom];
|
|
}
|
|
else if (lastOffset < -_collectionView.contentInset.top + 2)
|
|
{
|
|
UIEdgeInsets contentInset = [self controllerInsetForInterfaceOrientation:self.interfaceOrientation];
|
|
|
|
CGPoint contentOffset = CGPointMake(0, -contentInset.top);
|
|
[_collectionView setContentOffset:contentOffset animated:false];
|
|
}
|
|
|
|
[_collectionView.collectionViewLayout invalidateLayout];
|
|
[_collectionView layoutSubviews];
|
|
}
|
|
|
|
#pragma mark - Gallery
|
|
|
|
- (void)_hideCellForItem:(id)item animated:(bool)animated
|
|
{
|
|
_hiddenItem = item;
|
|
|
|
for (TGMediaPickerCell *cell in [_collectionView visibleCells])
|
|
[cell setHidden:([cell.item isEqual:_hiddenItem]) animated:animated];
|
|
}
|
|
|
|
@end
|