mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
Build ChatListUI
This commit is contained in:
467
submodules/LegacyComponents/Sources/TGModernGalleryView.m
Normal file
467
submodules/LegacyComponents/Sources/TGModernGalleryView.m
Normal file
@@ -0,0 +1,467 @@
|
||||
#import "TGModernGalleryView.h"
|
||||
|
||||
#import "LegacyComponentsInternal.h"
|
||||
#import "TGColor.h"
|
||||
#import "TGImageUtils.h"
|
||||
#import "TGHacks.h"
|
||||
|
||||
#import <LegacyComponents/TGModernGalleryDefaultInterfaceView.h>
|
||||
#import <LegacyComponents/TGModernGalleryScrollView.h>
|
||||
|
||||
#import <LegacyComponents/TGModernGalleryZoomableScrollViewSwipeGestureRecognizer.h>
|
||||
|
||||
static const CGFloat swipeMinimumVelocity = 600.0f;
|
||||
static const CGFloat swipeVelocityThreshold = 700.0f;
|
||||
static const CGFloat swipeDistanceThreshold = 128.0f;
|
||||
|
||||
@interface TGModernGalleryView () <UIGestureRecognizerDelegate>
|
||||
{
|
||||
CGFloat _itemPadding;
|
||||
|
||||
UIView *_scrollViewContainer;
|
||||
CGFloat _dismissProgress;
|
||||
|
||||
bool _previewMode;
|
||||
CGSize _previewSize;
|
||||
|
||||
CGFloat _scrollViewVerticalOffset;
|
||||
|
||||
UIView *_instantDismissView;
|
||||
id<LegacyComponentsContext> _context;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation TGModernGalleryView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)__unused frame
|
||||
{
|
||||
NSAssert(false, @"use designated initializer");
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame context:(id<LegacyComponentsContext>)context itemPadding:(CGFloat)itemPadding interfaceView:(UIView<TGModernGalleryInterfaceView> *)interfaceView previewMode:(bool)previewMode previewSize:(CGSize)previewSize
|
||||
{
|
||||
_previewMode = previewMode;
|
||||
_previewSize = previewSize;
|
||||
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil)
|
||||
{
|
||||
_context = context;
|
||||
_itemPadding = itemPadding;
|
||||
|
||||
if (iosMajorVersion() >= 11)
|
||||
self.accessibilityIgnoresInvertColors = true;
|
||||
|
||||
self.opaque = false;
|
||||
self.backgroundColor = UIColorRGBA(0x000000, 1.0f);
|
||||
|
||||
CGRect bounds = [self _boundsFrame];
|
||||
|
||||
_scrollViewContainer = [[UIView alloc] initWithFrame:bounds];
|
||||
[self addSubview:_scrollViewContainer];
|
||||
|
||||
_scrollView = [[TGModernGalleryScrollView alloc] initWithFrame:CGRectMake(-_itemPadding, 0.0f, frame.size.width + itemPadding * 2.0f, frame.size.height)];
|
||||
if (iosMajorVersion() >= 11)
|
||||
_scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
[_scrollViewContainer addSubview:_scrollView];
|
||||
|
||||
_interfaceView = interfaceView;
|
||||
_interfaceView.frame = bounds;
|
||||
_interfaceView.hidden = _previewMode;
|
||||
__weak TGModernGalleryView *weakSelf = self;
|
||||
_interfaceView.closePressed = ^
|
||||
{
|
||||
__strong TGModernGalleryView *strongSelf = weakSelf;
|
||||
if (strongSelf.transitionOut)
|
||||
strongSelf.transitionOut(0.0f);
|
||||
};
|
||||
_interfaceView.scrollViewOffsetRequested = ^(CGFloat offset)
|
||||
{
|
||||
__strong TGModernGalleryView *strongSelf = weakSelf;
|
||||
if (strongSelf != nil)
|
||||
[strongSelf setScrollViewVerticalOffset:offset];
|
||||
};
|
||||
[self addSubview:_interfaceView];
|
||||
|
||||
bool hasSwipeGesture = true;
|
||||
if ([interfaceView respondsToSelector:@selector(allowsDismissalWithSwipeGesture)])
|
||||
hasSwipeGesture = [interfaceView allowsDismissalWithSwipeGesture];
|
||||
|
||||
if (hasSwipeGesture)
|
||||
{
|
||||
TGModernGalleryZoomableScrollViewSwipeGestureRecognizer *swipeRecognizer = [[TGModernGalleryZoomableScrollViewSwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGesture:)];
|
||||
swipeRecognizer.delegate = self;
|
||||
swipeRecognizer.delaysTouchesBegan = true;
|
||||
swipeRecognizer.cancelsTouchesInView = false;
|
||||
[_scrollViewContainer addGestureRecognizer:swipeRecognizer];
|
||||
}
|
||||
|
||||
_overlayContainerView = [[UIView alloc] initWithFrame:self.bounds];
|
||||
_overlayContainerView.userInteractionEnabled = false;
|
||||
[self addSubview:_overlayContainerView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (bool)shouldAutorotate
|
||||
{
|
||||
return (_dismissProgress < FLT_EPSILON && (_interfaceView == nil || ![_interfaceView respondsToSelector:@selector(shouldAutorotate)] || [_interfaceView shouldAutorotate]));
|
||||
}
|
||||
|
||||
- (CGRect)_boundsFrame
|
||||
{
|
||||
CGRect bounds = (CGRect){CGPointZero, self.frame.size};
|
||||
if (_previewMode)
|
||||
{
|
||||
bounds.origin.x = floor((_previewSize.width - bounds.size.width) / 2.0f);
|
||||
bounds.origin.y = floor((_previewSize.height - bounds.size.height) / 2.0f);
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
- (void)setFrame:(CGRect)frame
|
||||
{
|
||||
[super setFrame:frame];
|
||||
|
||||
CGRect bounds = [self _boundsFrame];
|
||||
_interfaceView.frame = bounds;
|
||||
_scrollViewContainer.frame = bounds;
|
||||
_overlayContainerView.frame = bounds;
|
||||
|
||||
if (_scrollView != nil) {
|
||||
CGRect scrollViewFrame = CGRectMake(-_itemPadding, _scrollViewVerticalOffset, frame.size.width + _itemPadding * 2.0f, frame.size.height);
|
||||
if (!CGRectEqualToRect(_scrollView.frame, scrollViewFrame))
|
||||
{
|
||||
NSInteger currentItemIndex = (NSInteger)(CGFloor((_scrollView.bounds.origin.x + _scrollView.bounds.size.width / 2.0f) / _scrollView.bounds.size.width));
|
||||
[_scrollView setFrameAndBoundsInTransaction:scrollViewFrame bounds:CGRectMake(currentItemIndex * scrollViewFrame.size.width, 0.0f, scrollViewFrame.size.width, scrollViewFrame.size.height)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setScrollViewVerticalOffset:(CGFloat)offset
|
||||
{
|
||||
_scrollViewVerticalOffset = offset;
|
||||
|
||||
CGRect scrollViewFrame = _scrollView.frame;
|
||||
scrollViewFrame.origin.y = offset;
|
||||
_scrollView.frame = scrollViewFrame;
|
||||
}
|
||||
|
||||
- (bool)isInterfaceHidden
|
||||
{
|
||||
if ([_interfaceView allowsHide])
|
||||
return _interfaceView.alpha < FLT_EPSILON;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
- (void)showHideInterface
|
||||
{
|
||||
if ([_interfaceView allowsHide])
|
||||
{
|
||||
if (_interfaceView.alpha > FLT_EPSILON)
|
||||
{
|
||||
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
|
||||
{
|
||||
_interfaceView.alpha = 0.0f;
|
||||
[_context setApplicationStatusBarAlpha:0.0f];
|
||||
} completion:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
|
||||
{
|
||||
_interfaceView.alpha = 1.0f;
|
||||
if (![_interfaceView prefersStatusBarHidden])
|
||||
[_context setApplicationStatusBarAlpha:1.0f];
|
||||
} completion:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showInterfaceAnimated
|
||||
{
|
||||
if ([_interfaceView allowsHide])
|
||||
{
|
||||
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
|
||||
{
|
||||
_interfaceView.alpha = 1.0f;
|
||||
if (![_interfaceView prefersStatusBarHidden])
|
||||
[_context setApplicationStatusBarAlpha:1.0f];
|
||||
} completion:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)hideInterfaceAnimated
|
||||
{
|
||||
if ([_interfaceView allowsHide])
|
||||
{
|
||||
if (_interfaceView.alpha > FLT_EPSILON)
|
||||
{
|
||||
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
|
||||
{
|
||||
_interfaceView.alpha = 0.0f;
|
||||
[_context setApplicationStatusBarAlpha:0.0f];
|
||||
} completion:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateInterfaceVisibility
|
||||
{
|
||||
if ([_interfaceView allowsHide])
|
||||
{
|
||||
bool showsOnScroll = false;
|
||||
if ([_interfaceView respondsToSelector:@selector(showHiddenInterfaceOnScroll)])
|
||||
showsOnScroll = [_interfaceView showHiddenInterfaceOnScroll];
|
||||
|
||||
if (showsOnScroll)
|
||||
[self showInterfaceAnimated];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addItemHeaderView:(UIView *)itemHeaderView
|
||||
{
|
||||
[_interfaceView addItemHeaderView:itemHeaderView];
|
||||
}
|
||||
|
||||
- (void)removeItemHeaderView:(UIView *)itemHeaderView
|
||||
{
|
||||
[_interfaceView removeItemHeaderView:itemHeaderView];
|
||||
}
|
||||
|
||||
- (void)addItemFooterView:(UIView *)itemFooterView
|
||||
{
|
||||
[_interfaceView addItemFooterView:itemFooterView];
|
||||
}
|
||||
|
||||
- (void)removeItemFooterView:(UIView *)itemFooterView
|
||||
{
|
||||
[_interfaceView removeItemFooterView:itemFooterView];
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizerShouldBegin1:(UIGestureRecognizer *)__unused gestureRecognizer
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)__unused gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)__unused otherGestureRecognizer
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
- (CGFloat)dismissProgressForSwipeDistance:(CGFloat)distance
|
||||
{
|
||||
return MAX(0.0f, MIN(1.0f, ABS(distance / 150.0f)));
|
||||
}
|
||||
|
||||
- (void)swipeGesture:(TGModernGalleryZoomableScrollViewSwipeGestureRecognizer *)recognizer
|
||||
{
|
||||
if (recognizer.state == UIGestureRecognizerStateChanged)
|
||||
{
|
||||
_dismissProgress = [self dismissProgressForSwipeDistance:[recognizer swipeDistance]];
|
||||
[self _updateDismissTransitionWithProgress:_dismissProgress manual:true animated:false];
|
||||
[self _updateDismissTransitionMovementWithDistance:[recognizer swipeDistance] animated:false];
|
||||
}
|
||||
else if (recognizer.state == UIGestureRecognizerStateEnded)
|
||||
{
|
||||
CGFloat swipeVelocity = [recognizer swipeVelocity];
|
||||
if (ABS(swipeVelocity) < swipeMinimumVelocity)
|
||||
swipeVelocity = (swipeVelocity < 0.0f ? -1.0f : 1.0f) * swipeMinimumVelocity;
|
||||
|
||||
if ((ABS(swipeVelocity) < swipeVelocityThreshold && ABS([recognizer swipeDistance]) < swipeDistanceThreshold) || !_transitionOut || !_transitionOut(swipeVelocity))
|
||||
{
|
||||
_dismissProgress = 0.0f;
|
||||
[self _updateDismissTransitionWithProgress:0.0f manual:false animated:true];
|
||||
[self _updateDismissTransitionMovementWithDistance:0.0f animated:true];
|
||||
}
|
||||
}
|
||||
else if (recognizer.state == UIGestureRecognizerStateCancelled)
|
||||
{
|
||||
_dismissProgress = 0.0f;
|
||||
[self _updateDismissTransitionWithProgress:0.0f manual:false animated:true];
|
||||
[self _updateDismissTransitionMovementWithDistance:0.0f animated:true];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_updateDismissTransitionMovementWithDistance:(CGFloat)distance animated:(bool)animated
|
||||
{
|
||||
CGRect scrollViewFrame = (CGRect){{_scrollView.frame.origin.x, distance}, _scrollView.frame.size};
|
||||
if (animated)
|
||||
{
|
||||
[UIView animateWithDuration:0.3 animations:^
|
||||
{
|
||||
_scrollView.frame = scrollViewFrame;
|
||||
}];
|
||||
}
|
||||
else
|
||||
_scrollView.frame = scrollViewFrame;
|
||||
}
|
||||
|
||||
- (void)_updateDismissTransitionWithProgress:(CGFloat)progress animated:(bool)animated
|
||||
{
|
||||
[self _updateDismissTransitionWithProgress:progress manual:false animated:animated];
|
||||
}
|
||||
|
||||
- (void)_updateDismissTransitionWithProgress:(CGFloat)progress manual:(bool)manual animated:(bool)animated
|
||||
{
|
||||
CGFloat alpha = 1.0f - MAX(0.0f, MIN(1.0f, progress * 4.0f));
|
||||
CGFloat transitionProgress = MAX(0.0f, MIN(1.0f, progress * 2.0f));
|
||||
UIColor *backgroundColor = UIColorRGBA(0x000000, alpha);
|
||||
|
||||
if (animated)
|
||||
{
|
||||
[UIView animateWithDuration:0.3 animations:^
|
||||
{
|
||||
self.backgroundColor = backgroundColor;
|
||||
[_interfaceView setTransitionOutProgress:transitionProgress manual:manual];
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
self.backgroundColor = backgroundColor;
|
||||
[_interfaceView setTransitionOutProgress:transitionProgress manual:manual];
|
||||
}
|
||||
|
||||
if (self.transitionProgress != nil)
|
||||
self.transitionProgress(transitionProgress, manual);
|
||||
}
|
||||
|
||||
- (void)simpleTransitionInWithCompletion:(void (^)())completion
|
||||
{
|
||||
CGFloat velocity = 2000.0f;
|
||||
CGFloat distance = (velocity < FLT_EPSILON ? -1.0f : 1.0f) * self.frame.size.height;
|
||||
|
||||
CGRect targetFrame = _scrollView.frame;
|
||||
CGRect targetInterfaceFrame = _interfaceView.frame;
|
||||
CGRect interfaceViewFrame = (CGRect){{_interfaceView.frame.origin.x, distance}, _interfaceView.frame.size};
|
||||
CGRect scrollViewFrame = (CGRect){{_scrollView.frame.origin.x, distance}, _scrollView.frame.size};
|
||||
_interfaceView.frame = interfaceViewFrame;
|
||||
_scrollView.frame = scrollViewFrame;
|
||||
_overlayContainerView.alpha = 0.0f;
|
||||
self.backgroundColor = UIColorRGBA(0x000000, 0.0f);
|
||||
|
||||
[UIView animateWithDuration:ABS(distance / velocity) delay:0.0 options:7 << 16 animations:^{
|
||||
_scrollView.frame = targetFrame;
|
||||
_interfaceView.frame = targetInterfaceFrame;
|
||||
} completion:^(__unused BOOL finished)
|
||||
{
|
||||
if (completion)
|
||||
completion();
|
||||
}];
|
||||
|
||||
[UIView animateWithDuration:ABS(distance / velocity) animations:^
|
||||
{
|
||||
_overlayContainerView.alpha = 1.0f;
|
||||
self.backgroundColor = UIColorRGBA(0x000000, 1.0f);
|
||||
} completion:nil];
|
||||
}
|
||||
|
||||
- (void)simpleTransitionOutWithVelocity:(CGFloat)velocity completion:(void (^)())completion
|
||||
{
|
||||
const CGFloat minVelocity = 2000.0f;
|
||||
if (ABS(velocity) < minVelocity)
|
||||
velocity = (velocity < 0.0f ? -1.0f : 1.0f) * minVelocity;
|
||||
CGFloat distance = (velocity < FLT_EPSILON ? -1.0f : 1.0f) * self.frame.size.height;
|
||||
CGRect interfaceViewFrame = (CGRect){{_interfaceView.frame.origin.x, distance}, _interfaceView.frame.size};
|
||||
CGRect scrollViewFrame = (CGRect){{_scrollView.frame.origin.x, distance}, _scrollView.frame.size};
|
||||
|
||||
[UIView animateWithDuration:ABS(distance / velocity) delay:0.0 options:7 << 16 animations:^{
|
||||
_scrollView.frame = scrollViewFrame;
|
||||
_interfaceView.frame = interfaceViewFrame;
|
||||
} completion:^(__unused BOOL finished)
|
||||
{
|
||||
if (completion)
|
||||
completion();
|
||||
}];
|
||||
|
||||
[UIView animateWithDuration:ABS(distance / velocity) animations:^
|
||||
{
|
||||
_interfaceView.alpha = 0.0f;
|
||||
_overlayContainerView.alpha = 0.0f;
|
||||
self.backgroundColor = UIColorRGBA(0x000000, 0.0f);
|
||||
} completion:nil];
|
||||
}
|
||||
|
||||
- (void)transitionInWithDuration:(NSTimeInterval)duration
|
||||
{
|
||||
_interfaceView.alpha = 0.0f;
|
||||
_overlayContainerView.alpha = 0.0f;
|
||||
self.backgroundColor = UIColorRGBA(0x000000, 0.0f);
|
||||
[UIView animateWithDuration:duration delay:0.0 options:0 animations:^
|
||||
{
|
||||
_interfaceView.alpha = 1.0f;
|
||||
_overlayContainerView.alpha = 1.0f;
|
||||
self.backgroundColor = UIColorRGBA(0x000000, 1.0f);
|
||||
} completion:nil];
|
||||
}
|
||||
|
||||
- (void)transitionOutWithDuration:(NSTimeInterval)duration
|
||||
{
|
||||
[UIView animateWithDuration:duration animations:^
|
||||
{
|
||||
_interfaceView.alpha = 0.0f;
|
||||
_overlayContainerView.alpha = 0.0f;
|
||||
self.backgroundColor = UIColorRGBA(0x000000, 0.0f);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)fadeOutWithDuration:(NSTimeInterval)duration completion:(void (^)(void))completion
|
||||
{
|
||||
[UIView animateWithDuration:duration animations:^
|
||||
{
|
||||
_interfaceView.alpha = 0.0f;
|
||||
_scrollView.alpha = 0.0f;
|
||||
_overlayContainerView.alpha = 0.0f;
|
||||
self.backgroundColor = UIColorRGBA(0x000000, 0.0f);
|
||||
} completion:^(__unused BOOL finished)
|
||||
{
|
||||
if (completion)
|
||||
completion();
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setPreviewMode:(bool)previewMode
|
||||
{
|
||||
_previewMode = previewMode;
|
||||
_interfaceView.hidden = previewMode;
|
||||
|
||||
if (_scrollViewContainer != nil)
|
||||
{
|
||||
CGRect bounds = [self _boundsFrame];
|
||||
_interfaceView.frame = bounds;
|
||||
_scrollViewContainer.frame = bounds;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)enableInstantDismiss {
|
||||
_instantDismissView = [[UIView alloc] initWithFrame:self.bounds];
|
||||
_instantDismissView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[self addSubview:_instantDismissView];
|
||||
[_instantDismissView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(instantDismissViewTap:)]];
|
||||
}
|
||||
|
||||
- (void)disableInstantDismiss
|
||||
{
|
||||
[_instantDismissView removeFromSuperview];
|
||||
_instantDismissView = nil;
|
||||
}
|
||||
|
||||
- (void)instantDismissViewTap:(UITapGestureRecognizer *)recognizer {
|
||||
if (recognizer.state == UIGestureRecognizerStateEnded) {
|
||||
if (_instantDismiss) {
|
||||
_instantDismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
||||
if (_instantDismissView != nil && CGRectContainsPoint(_instantDismissView.frame, point)) {
|
||||
return _instantDismissView;
|
||||
}
|
||||
return [super hitTest:point withEvent:event];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user