#import "TGModernConversationAlphacodeAssociatedPanel.h" #import "LegacyComponentsInternal.h" #import "TGColor.h" #import "TGImageUtils.h" #import "TGFont.h" #import "TGViewController.h" #import "TGAlphacodePanelCell.h" #import "TGAlphacode.h" @interface TGModernConversationAlphacodeAssociatedPanel () { SMetaDisposable *_disposable; NSArray *_codeList; UIView *_backgroundView; UIView *_effectView; UITableView *_tableView; UIView *_stripeView; UIView *_separatorView; UIView *_bottomView; UIView *_tableViewBackground; UIView *_tableViewSeparator; bool _resetOffsetOnLayout; bool _animatingOut; } @end @implementation TGModernConversationAlphacodeAssociatedPanel - (instancetype)initWithStyle:(TGModernConversationAssociatedInputPanelStyle)style { self = [super initWithStyle:style]; if (self != nil) { _disposable = [[SMetaDisposable alloc] init]; UIColor *backgroundColor = [UIColor whiteColor]; UIColor *bottomColor = UIColorRGBA(0xfafafa, 0.98f); UIColor *separatorColor = UIColorRGB(0xc5c7d0); UIColor *cellSeparatorColor = UIColorRGB(0xdbdbdb); self.clipsToBounds = true; if (self.style == TGModernConversationAssociatedInputPanelDarkStyle) { backgroundColor = UIColorRGB(0x171717); bottomColor = backgroundColor; separatorColor = UIColorRGB(0x292929); cellSeparatorColor = separatorColor; } else if (self.style == TGModernConversationAssociatedInputPanelDarkBlurredStyle) { backgroundColor = [UIColor clearColor]; separatorColor = UIColorRGBA(0xb2b2b2, 0.7f); cellSeparatorColor = UIColorRGBA(0xb2b2b2, 0.4f); bottomColor = [UIColor clearColor]; CGFloat backgroundAlpha = 0.8f; if (iosMajorVersion() >= 8) { UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]]; blurEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; blurEffectView.frame = self.bounds; [self addSubview:blurEffectView]; _effectView = blurEffectView; backgroundAlpha = 0.4f; } _backgroundView = [[UIView alloc] initWithFrame:self.bounds]; _backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; _backgroundView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:backgroundAlpha]; [self addSubview:_backgroundView]; } _bottomView = [[UIView alloc] init]; _bottomView.backgroundColor = bottomColor; [self addSubview:_bottomView]; _tableViewBackground = [[UIView alloc] init]; _tableViewBackground.backgroundColor = backgroundColor; [self addSubview:_tableViewBackground]; _tableView = [[UITableView alloc] init]; _tableView.delegate = self; _tableView.dataSource = self; _tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; _tableView.tableFooterView = [[UIView alloc] init]; if (iosMajorVersion() >= 7) { _tableView.separatorColor = cellSeparatorColor; _tableView.separatorInset = UIEdgeInsetsMake(0.0f, 40.0f, 0.0f, 0.0f); } _tableView.backgroundColor = nil; _tableView.opaque = false; _tableView.showsVerticalScrollIndicator = false; _tableView.showsHorizontalScrollIndicator = false; [self addSubview:_tableView]; _tableViewSeparator = [[UIView alloc] init]; _tableViewSeparator.backgroundColor = separatorColor; [self addSubview:_tableViewSeparator]; _stripeView = [[UIView alloc] init]; _stripeView.backgroundColor = separatorColor; [self addSubview:_stripeView]; if (self.style != TGModernConversationAssociatedInputPanelDarkBlurredStyle) { _separatorView = [[UIView alloc] init]; _separatorView.backgroundColor = separatorColor; [self addSubview:_separatorView]; } } return self; } - (void)dealloc { [_disposable dispose]; } - (void)setPallete:(TGConversationAssociatedInputPanelPallete *)pallete { [super setPallete:pallete]; if (self.pallete == nil) return; _bottomView.backgroundColor = pallete.barBackgroundColor; _tableViewBackground.backgroundColor = pallete.backgroundColor; _tableViewSeparator.backgroundColor = pallete.barSeparatorColor; _tableView.separatorColor = pallete.separatorColor; _stripeView.backgroundColor = pallete.barSeparatorColor; _separatorView.backgroundColor = pallete.barSeparatorColor; } - (void)setFrame:(CGRect)frame { [super setFrame:frame]; self.alpha = frame.size.height >= FLT_EPSILON; } - (bool)fillsAvailableSpace { return true;//iosMajorVersion() >= 9; } - (CGFloat)preferredHeight { return [self preferredHeightAndOverlayHeight:NULL]; } - (CGFloat)preferredHeightAndOverlayHeight:(CGFloat *)overlayHeight { CGFloat height = 0.0f; CGFloat lastHeight = 0.0f; NSInteger lastIndex = MIN([TGViewController isWidescreen] ? 4 : 3, (NSInteger)_codeList.count - 1); for (NSInteger i = 0; i <= lastIndex; i++) { CGFloat rowHeight = [self tableView:_tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]]; if (i == lastIndex) { lastHeight = rowHeight; } else { height += rowHeight; } } CGFloat completeHeight = 0.0f; for (NSInteger i = 0; i < (NSInteger)_codeList.count; i++) { CGFloat rowHeight = [self tableView:_tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]]; completeHeight += rowHeight; } CGFloat maxHeight = CGFloor(self.frame.size.height * 2.0f / 3.0f); height = completeHeight; CGFloat overlayHeightValue = 0.0f; if (height + self.barInset < self.frame.size.height) { overlayHeightValue = self.barInset; } if (overlayHeight) { *overlayHeight = overlayHeightValue; } height += overlayHeightValue; if (lastIndex > 0) { return MIN(maxHeight, CGFloor(height)); } else { return MIN(maxHeight, height); } } - (void)setAlphacodeListSignal:(SSignal *)alphacodeListSignal { if (alphacodeListSignal == nil) { [_disposable setDisposable:nil]; [self setCodeList:@[]]; } else { __weak TGModernConversationAlphacodeAssociatedPanel *weakSelf = self; [_disposable setDisposable:[[alphacodeListSignal deliverOn:[SQueue mainQueue]] startWithNext:^(NSArray *userList) { __strong TGModernConversationAlphacodeAssociatedPanel *strongSelf = weakSelf; if (strongSelf != nil) [strongSelf setCodeList:userList]; }]]; } } - (void)setCodeList:(NSArray *)codeList { bool wasEmpty = _codeList.count == 0; _codeList = codeList; if (iosMajorVersion() >= 7) { _tableView.separatorStyle = _codeList.count <= 1 ? UITableViewCellSeparatorStyleNone : UITableViewCellSeparatorStyleSingleLine; } [_tableView reloadData]; [self setNeedsPreferredHeightUpdate]; _stripeView.hidden = _codeList.count == 0; _separatorView.hidden = _codeList.count == 0; _bottomView.hidden = _codeList.count == 0; [self scrollViewDidScroll:_tableView]; if (_codeList.count != 0 && wasEmpty) { [self animateIn]; } else { [self layoutSubviews]; } } - (NSInteger)tableView:(UITableView *)__unused tableView numberOfRowsInSection:(NSInteger)__unused section { return _codeList.count; } - (CGFloat)tableView:(UITableView *)__unused tableView heightForRowAtIndexPath:(NSIndexPath *)__unused indexPath { return 41.0f; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { TGAlphacodePanelCell *cell = (TGAlphacodePanelCell *)[tableView dequeueReusableCellWithIdentifier:TGAlphacodePanelCellKind]; if (cell == nil) cell = [[TGAlphacodePanelCell alloc] initWithStyle:self.style]; cell.pallete = self.pallete; TGAlphacodeEntry *entry = _codeList[indexPath.row]; [cell setEmoji:entry.emoji label:entry.code]; return cell; } - (void)tableView:(UITableView *)__unused tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { TGAlphacodeEntry *entry = _codeList[indexPath.row]; if (_alphacodeSelected) { _alphacodeSelected(entry); } } - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView == _tableView) { [self updateTableBackground]; } } - (void)layoutSubviews { [super layoutSubviews]; if (_animatingOut) { return; } _backgroundView.frame = CGRectMake(-1000, 0, self.frame.size.width + 2000, self.frame.size.height); _effectView.frame = CGRectMake(-1000, 0, self.frame.size.width + 2000, self.frame.size.height); CGFloat separatorHeight = TGScreenPixel; _separatorView.frame = CGRectMake(0.0f, self.frame.size.height - separatorHeight, self.frame.size.width, separatorHeight); UIEdgeInsets previousInset = _tableView.contentInset; _tableView.frame = CGRectMake(0.0f, 0.0f, self.frame.size.width, self.frame.size.height); if ([self fillsAvailableSpace]) { CGFloat overlayHeight = 0.0; CGFloat preferredHeight = [self preferredHeightAndOverlayHeight:&overlayHeight]; CGFloat topInset = MAX(0.0f, self.frame.size.height - preferredHeight); CGFloat insetDifference = topInset - _tableView.contentInset.top; UIEdgeInsets finalInset = UIEdgeInsetsMake(topInset, 0.0f, MAX(0.0f, overlayHeight - 1.0f / TGScreenScaling()), 0.0f); if (_resetOffsetOnLayout) { _resetOffsetOnLayout = false; _tableView.contentInset = finalInset; [_tableView setContentOffset:CGPointMake(0.0f, -_tableView.contentInset.top) animated:false]; } else if (ABS(insetDifference) > FLT_EPSILON) { //if (ABS(insetDifference) <= 36.0f + 0.1) { { [self _autoAdjustInsetsForScrollView:_tableView finalInset:finalInset previousInset:previousInset]; //contentOffset.y -= insetDifference; //_tableView.contentOffset = contentOffset; } } } else { _tableView.contentInset = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f); } _bottomView.frame = CGRectMake(0.0f, self.frame.size.height, self.frame.size.width, 4.0f); [self updateTableBackground]; } - (void)_autoAdjustInsetsForScrollView:(UIScrollView *)scrollView finalInset:(UIEdgeInsets)finalInset previousInset:(UIEdgeInsets)previousInset { CGPoint contentOffset = scrollView.contentOffset; scrollView.contentInset = finalInset; if (iosMajorVersion() <= 8 && scrollView.subviews.count != 0) { if ([NSStringFromClass([scrollView.subviews.firstObject class]) hasPrefix:@"UITableViewWra"]) { CGRect frame = scrollView.subviews.firstObject.frame; frame.origin = CGPointZero; scrollView.subviews.firstObject.frame = frame; } } if (!UIEdgeInsetsEqualToEdgeInsets(previousInset, UIEdgeInsetsZero)) { CGFloat maxOffset = scrollView.contentSize.height - (scrollView.frame.size.height - finalInset.bottom); contentOffset.y += previousInset.top - finalInset.top; contentOffset.y = MAX(-finalInset.top, MIN(contentOffset.y, maxOffset)); [scrollView setContentOffset:contentOffset animated:false]; } else if (contentOffset.y < finalInset.top) { contentOffset.y = -finalInset.top; [scrollView setContentOffset:contentOffset animated:false]; } } - (void)updateTableBackground { if (_animatingOut) { return; } CGFloat backgroundOriginY = MAX(0.0f, -_tableView.contentOffset.y); _tableViewBackground.frame = CGRectMake(0.0f, backgroundOriginY, self.frame.size.width, self.frame.size.height - backgroundOriginY); _tableViewSeparator.frame = CGRectMake(0.0f, backgroundOriginY - 0.5f, self.frame.size.width, 0.5f); _tableView.scrollIndicatorInsets = UIEdgeInsetsMake(backgroundOriginY, 0.0f, 0.0f, 0.0f); self.overlayBarOffset = _tableView.contentOffset.y + _tableView.contentInset.top; if (self.updateOverlayBarOffset) { self.updateOverlayBarOffset(self.overlayBarOffset); } } - (CGRect)tableBackgroundFrame { return _tableViewBackground.frame; } - (bool)hasSelectedItem { return _tableView.indexPathForSelectedRow != nil; } - (void)selectPreviousItem { if ([self tableView:_tableView numberOfRowsInSection:0] == 0) return; NSIndexPath *newIndexPath = _tableView.indexPathForSelectedRow; if (newIndexPath == nil) newIndexPath = [NSIndexPath indexPathForRow:0 inSection:0]; else if (newIndexPath.row > 0) newIndexPath = [NSIndexPath indexPathForRow:newIndexPath.row - 1 inSection:0]; if (_tableView.indexPathForSelectedRow != nil) [_tableView deselectRowAtIndexPath:_tableView.indexPathForSelectedRow animated:false]; if (newIndexPath != nil) [_tableView selectRowAtIndexPath:newIndexPath animated:false scrollPosition:UITableViewScrollPositionBottom]; } - (void)selectNextItem { if ([self tableView:_tableView numberOfRowsInSection:0] == 0) return; NSIndexPath *newIndexPath = _tableView.indexPathForSelectedRow; if (newIndexPath == nil) newIndexPath = [NSIndexPath indexPathForRow:0 inSection:0]; else if (newIndexPath.row < [self tableView:_tableView numberOfRowsInSection:newIndexPath.section] - 1) newIndexPath = [NSIndexPath indexPathForRow:newIndexPath.row + 1 inSection:0]; if (_tableView.indexPathForSelectedRow != nil) [_tableView deselectRowAtIndexPath:_tableView.indexPathForSelectedRow animated:false]; if (newIndexPath != nil) [_tableView selectRowAtIndexPath:newIndexPath animated:false scrollPosition:UITableViewScrollPositionBottom]; } - (void)commitSelectedItem { if ([self tableView:_tableView numberOfRowsInSection:0] == 0) return; NSIndexPath *selectedIndexPath = _tableView.indexPathForSelectedRow; if (selectedIndexPath == nil) selectedIndexPath = [NSIndexPath indexPathForRow:0 inSection:0]; [self tableView:_tableView didSelectRowAtIndexPath:selectedIndexPath]; } - (void)animateIn { [self layoutSubviews]; CGFloat offset = [self preferredHeight]; CGRect normalFrame = _tableView.frame; _tableView.frame = CGRectMake(normalFrame.origin.x, normalFrame.origin.y + offset, normalFrame.size.width, normalFrame.size.height); CGRect normalBackgroundFrame = _tableViewBackground.frame; _tableViewBackground.frame = CGRectMake(normalBackgroundFrame.origin.x, normalBackgroundFrame.origin.y + offset, normalBackgroundFrame.size.width, normalBackgroundFrame.size.height); CGRect normalSeparatorFrame = _tableViewSeparator.frame; _tableViewSeparator.frame = CGRectMake(normalSeparatorFrame.origin.x, normalSeparatorFrame.origin.y + offset, normalSeparatorFrame.size.width, normalSeparatorFrame.size.height); [UIView animateWithDuration:0.3 delay:0.0 options:7 << 16 animations:^{ _tableView.frame = normalFrame; _tableViewBackground.frame = normalBackgroundFrame; _tableViewSeparator.frame = normalSeparatorFrame; } completion:nil]; } - (void)animateOut:(void (^)())completion { CGFloat offset = self.frame.size.height - _tableViewBackground.frame.origin.y; CGRect normalFrame = _tableView.frame; CGRect normalBackgroundFrame = _tableViewBackground.frame; CGRect normalSeparatorFrame = _tableViewSeparator.frame; _animatingOut = true; [UIView animateWithDuration:0.15 delay:0.0 options:0 animations:^{ _tableView.frame = CGRectMake(normalFrame.origin.x, normalFrame.origin.y + offset, normalFrame.size.width, normalFrame.size.height); _tableViewBackground.frame = CGRectMake(normalBackgroundFrame.origin.x, normalBackgroundFrame.origin.y + offset, normalBackgroundFrame.size.width, normalBackgroundFrame.size.height); _tableViewSeparator.frame = CGRectMake(normalSeparatorFrame.origin.x, normalSeparatorFrame.origin.y + offset, normalSeparatorFrame.size.width, normalSeparatorFrame.size.height); } completion:^(__unused BOOL finished) { completion(); }]; } - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { if (CGRectContainsPoint(_tableViewBackground.frame, point)) { return [super hitTest:point withEvent:event]; } return nil; } - (void)setBarInset:(CGFloat)barInset animated:(bool)animated { if (ABS(barInset - self.barInset) > FLT_EPSILON) { [super setBarInset:barInset animated:animated]; if (animated) { [self layoutSubviews]; } else { [UIView animateWithDuration:0.3 animations:^{ [self layoutSubviews]; }]; } } } @end