mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
395 lines
13 KiB
Objective-C
395 lines
13 KiB
Objective-C
#import "TGMediaPickerController.h"
|
|
|
|
#import <LegacyComponents/TGMediaAssetsController.h>
|
|
|
|
#import <LegacyComponents/TGMediaEditingContext.h>
|
|
#import <LegacyComponents/TGMediaSelectionContext.h>
|
|
#import "LegacyComponentsInternal.h"
|
|
|
|
#import "TGMediaPickerSelectionGestureRecognizer.h"
|
|
|
|
#import "TGMediaPickerLayoutMetrics.h"
|
|
#import "TGMediaPickerCell.h"
|
|
|
|
#import "TGMediaPickerToolbarView.h"
|
|
|
|
#import <LegacyComponents/TGPhotoEditorController.h>
|
|
|
|
@interface TGMediaPickerController ()
|
|
{
|
|
TGMediaSelectionContext *_selectionContext;
|
|
TGMediaEditingContext *_editingContext;
|
|
|
|
SMetaDisposable *_selectionChangedDisposable;
|
|
|
|
id _hiddenItem;
|
|
UICollectionViewLayout *_collectionLayout;
|
|
}
|
|
@end
|
|
|
|
@implementation TGMediaPickerController
|
|
|
|
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext
|
|
{
|
|
self = [super initWithContext:context];
|
|
if (self != nil)
|
|
{
|
|
_selectionContext = selectionContext;
|
|
_editingContext = editingContext;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
_collectionView.delegate = nil;
|
|
_collectionView.dataSource = nil;
|
|
[_selectionChangedDisposable dispose];
|
|
}
|
|
|
|
- (void)loadView
|
|
{
|
|
[super loadView];
|
|
|
|
if (self.intrinsicSize.width > FLT_EPSILON) {
|
|
self.view.frame = CGRectMake(0.0f, 0.0f, self.intrinsicSize.width, self.intrinsicSize.height);
|
|
}
|
|
|
|
self.view.backgroundColor = self.pallete != nil ? self.pallete.backgroundColor : [UIColor whiteColor];
|
|
|
|
_wrapperView = [[UIView alloc] initWithFrame:self.view.bounds];
|
|
_wrapperView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
[self.view addSubview:_wrapperView];
|
|
|
|
_collectionView = [[[self _collectionViewClass] alloc] initWithFrame:_wrapperView.bounds collectionViewLayout:[self _collectionLayout]];
|
|
if (iosMajorVersion() >= 11)
|
|
_collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
|
_collectionView.alwaysBounceVertical = true;
|
|
_collectionView.backgroundColor = self.view.backgroundColor;
|
|
_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;
|
|
|
|
[self _setupSelectionGesture];
|
|
|
|
if (![self _updateControllerInset:false])
|
|
[self controllerInsetUpdated:UIEdgeInsetsZero];
|
|
}
|
|
|
|
- (Class)_collectionViewClass
|
|
{
|
|
return [UICollectionView class];
|
|
}
|
|
|
|
- (UICollectionViewLayout *)_collectionLayout
|
|
{
|
|
if (_collectionLayout == nil)
|
|
_collectionLayout = [[UICollectionViewFlowLayout alloc] init];
|
|
|
|
return _collectionLayout;
|
|
}
|
|
|
|
- (void)viewDidLoad
|
|
{
|
|
[super viewDidLoad];
|
|
|
|
bool hasOnScreenNavigation = false;
|
|
if (iosMajorVersion() >= 11)
|
|
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
|
|
|
UIInterfaceOrientation orientation = UIInterfaceOrientationPortrait;
|
|
if (self.view.frame.size.width > self.view.frame.size.height)
|
|
orientation = UIInterfaceOrientationLandscapeLeft;
|
|
UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:hasOnScreenNavigation];
|
|
|
|
CGSize frameSize = self.view.frame.size;
|
|
CGRect collectionViewFrame = CGRectMake(safeAreaInset.left, _topInset, frameSize.width - safeAreaInset.left - safeAreaInset.right, frameSize.height - _topInset);
|
|
_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
|
|
{
|
|
[_collectionView stopScrollingAnimation];
|
|
|
|
[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 -
|
|
|
|
- (void)_cancelSelectionGestureRecognizer
|
|
{
|
|
[_selectionGestureRecognizer cancel];
|
|
}
|
|
|
|
- (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
|
|
|
|
- (NSUInteger)_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)numberOfSectionsInCollectionView:(UICollectionView *)__unused collectionView
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
- (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.pallete = self.pallete;
|
|
cell.selectionContext = self.selectionContext;
|
|
cell.editingContext = self.editingContext;
|
|
[cell setItem:item signal:[self _signalForItem:item]];
|
|
[cell setHidden:([cell.item isEqual:_hiddenItem]) animated:false];
|
|
|
|
if (self.selectionContext != nil)
|
|
[cell.checkButton setNumber:[self.selectionContext indexOfItem:(id<TGMediaSelectableItem>)cell.item]];
|
|
|
|
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
|
|
{
|
|
if (!self.isViewLoaded) {
|
|
return;
|
|
}
|
|
|
|
UIEdgeInsets contentInset = [self controllerInsetForInterfaceOrientation:self.interfaceOrientation];
|
|
|
|
bool hasOnScreenNavigation = false;
|
|
if (iosMajorVersion() >= 11)
|
|
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
|
|
|
CGPoint contentOffset = CGPointMake(0, _collectionView.contentSize.height - _collectionView.frame.size.height + contentInset.bottom);
|
|
if (contentOffset.y < -contentInset.top)
|
|
contentOffset.y = -contentInset.top;
|
|
[_collectionView setContentOffset:contentOffset animated:false];
|
|
}
|
|
|
|
- (void)setTopInset:(CGFloat)topInset {
|
|
_topInset = topInset;
|
|
[self layoutControllerForSize:self.view.frame.size duration:0.0];
|
|
}
|
|
|
|
- (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;
|
|
|
|
UIInterfaceOrientation orientation = UIInterfaceOrientationPortrait;
|
|
if (size.width > size.height)
|
|
orientation = UIInterfaceOrientationLandscapeLeft;
|
|
|
|
bool hasOnScreenNavigation = false;
|
|
if (iosMajorVersion() >= 11)
|
|
hasOnScreenNavigation = (self.viewLoaded && self.view.safeAreaInsets.bottom > FLT_EPSILON) || self.context.safeAreaInset.bottom > FLT_EPSILON;
|
|
|
|
UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:hasOnScreenNavigation];
|
|
|
|
CGRect frame = CGRectMake(safeAreaInset.left, _topInset, size.width - safeAreaInset.left - safeAreaInset.right, size.height - _topInset);
|
|
_collectionViewWidth = frame.size.width;
|
|
_collectionView.frame = frame;
|
|
|
|
[_collectionView.collectionViewLayout invalidateLayout];
|
|
[_collectionView layoutSubviews];
|
|
|
|
if (lastInverseOffset < 45)
|
|
{
|
|
[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];
|
|
}
|
|
}
|
|
|
|
#pragma mark - Gallery
|
|
|
|
- (void)_hideCellForItem:(id)item animated:(bool)animated
|
|
{
|
|
_hiddenItem = item;
|
|
|
|
for (TGMediaPickerCell *cell in [_collectionView visibleCells]) {
|
|
if ([cell.item respondsToSelector:@selector(uniqueIdentifier)] && [_hiddenItem respondsToSelector:@selector(uniqueIdentifier)]) {
|
|
[cell setHidden:([[(id)cell.item uniqueIdentifier] isEqual:[_hiddenItem uniqueIdentifier]]) animated:animated];
|
|
} else {
|
|
[cell setHidden:([cell.item isEqual:_hiddenItem]) animated:animated];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)_setupSelectionGesture
|
|
{
|
|
if (_selectionContext == nil)
|
|
return;
|
|
|
|
__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];
|
|
bool success = false;
|
|
[strongSelf->_selectionContext toggleItemSelection:item animated:true sender:nil success:&success];
|
|
if (!success) {
|
|
[strongSelf->_selectionGestureRecognizer cancel];
|
|
}
|
|
};
|
|
}
|
|
|
|
- (BOOL)prefersStatusBarHidden
|
|
{
|
|
if (iosMajorVersion() >= 7)
|
|
{
|
|
if (self.navigationController != nil)
|
|
return self.navigationController.prefersStatusBarHidden;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
@end
|