diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 2637c32c50..697721b12d 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -7544,3 +7544,6 @@ Sorry for the inconvenience."; "Premium.Reactions.Proceed" = "Unlock Additional Reactions"; "AccessDenied.LocationPreciseDenied" = "To share your specific location in this chat, please go to Settings > Privacy > Location Services > Telegram and set Precise Location to On."; + +"Chat.MultipleTypingPair" = "%@ and %@ "; +"Chat.MultipleTypingMore" = "%@ and %@ others"; diff --git a/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift b/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift index 9f7fb2ec8f..d3ed4f1898 100644 --- a/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift +++ b/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift @@ -163,6 +163,7 @@ public final class AnimatedStickerNode: ASDisplayNode { public var completed: (Bool) -> Void = { _ in } public var frameUpdated: (Int, Int) -> Void = { _, _ in } public private(set) var currentFrameIndex: Int = 0 + public private(set) var currentFrameCount: Int = 0 private var playFromIndex: Int? private let timer = Atomic(value: nil) @@ -452,6 +453,7 @@ public final class AnimatedStickerNode: ASDisplayNode { strongSelf.frameUpdated(frame.index, frame.totalFrames) strongSelf.currentFrameIndex = frame.index + strongSelf.currentFrameCount = frame.totalFrames if frame.isLastFrame { var stopped = false @@ -556,6 +558,7 @@ public final class AnimatedStickerNode: ASDisplayNode { strongSelf.frameUpdated(frame.index, frame.totalFrames) strongSelf.currentFrameIndex = frame.index + strongSelf.currentFrameCount = frame.totalFrames; if frame.isLastFrame { var stopped = false diff --git a/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift b/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift index c73184dcfb..f53669f298 100644 --- a/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift +++ b/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift @@ -322,7 +322,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS guard let presentationInterfaceState = self.presentationInterfaceState else { return 0.0 } - return self.updateLayout(width: size.width, leftInset: sideInset, rightInset: sideInset, additionalSideInsets: UIEdgeInsets(), maxHeight: size.height, isSecondary: false, transition: .immediate, interfaceState: presentationInterfaceState, metrics: LayoutMetrics(widthClass: .compact, heightClass: .compact)) + return self.updateLayout(width: size.width, leftInset: sideInset, rightInset: sideInset, bottomInset: 0.0, additionalSideInsets: UIEdgeInsets(), maxHeight: size.height, isSecondary: false, transition: .immediate, interfaceState: presentationInterfaceState, metrics: LayoutMetrics(widthClass: .compact, heightClass: .compact)) } public func setCaption(_ caption: NSAttributedString?) { @@ -466,7 +466,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS return minimalHeight } - public func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { + public func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { let hadLayout = self.validLayout != nil let previousAdditionalSideInsets = self.validLayout?.3 self.validLayout = (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary) @@ -1080,7 +1080,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS self.focusUpdated?(true) if self.isCaption, let (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary) = self.validLayout, let presentationInterfaceState = self.presentationInterfaceState { - let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .animated(duration: 0.3, curve: .easeInOut), interfaceState: presentationInterfaceState, metrics: metrics) + let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: 0.0, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .animated(duration: 0.3, curve: .easeInOut), interfaceState: presentationInterfaceState, metrics: metrics) } } @@ -1091,7 +1091,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS self.focusUpdated?(false) if self.isCaption, let (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary) = self.validLayout, let presentationInterfaceState = self.presentationInterfaceState { - let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .animated(duration: 0.3, curve: .easeInOut), interfaceState: presentationInterfaceState, metrics: metrics) + let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: 0.0, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .animated(duration: 0.3, curve: .easeInOut), interfaceState: presentationInterfaceState, metrics: metrics) } } diff --git a/submodules/AttachmentUI/Sources/AttachmentPanel.swift b/submodules/AttachmentUI/Sources/AttachmentPanel.swift index 548cacff7d..80203f71c7 100644 --- a/submodules/AttachmentUI/Sources/AttachmentPanel.swift +++ b/submodules/AttachmentUI/Sources/AttachmentPanel.swift @@ -1096,7 +1096,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate { if textInputPanelNode.frame.width.isZero { panelTransition = .immediate } - let panelHeight = textInputPanelNode.updateLayout(width: layout.size.width, leftInset: insets.left + layout.safeInsets.left, rightInset: insets.right + layout.safeInsets.right, additionalSideInsets: UIEdgeInsets(), maxHeight: layout.size.height / 2.0, isSecondary: false, transition: panelTransition, interfaceState: self.presentationInterfaceState, metrics: layout.metrics) + let panelHeight = textInputPanelNode.updateLayout(width: layout.size.width, leftInset: insets.left + layout.safeInsets.left, rightInset: insets.right + layout.safeInsets.right, bottomInset: 0.0, additionalSideInsets: UIEdgeInsets(), maxHeight: layout.size.height / 2.0, isSecondary: false, transition: panelTransition, interfaceState: self.presentationInterfaceState, metrics: layout.metrics) let panelFrame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: panelHeight) if textInputPanelNode.frame.width.isZero { textInputPanelNode.frame = panelFrame diff --git a/submodules/GalleryUI/Sources/ChatVideoGalleryItemScrubberView.swift b/submodules/GalleryUI/Sources/ChatVideoGalleryItemScrubberView.swift index 22fc7e6b4b..847daf577a 100644 --- a/submodules/GalleryUI/Sources/ChatVideoGalleryItemScrubberView.swift +++ b/submodules/GalleryUI/Sources/ChatVideoGalleryItemScrubberView.swift @@ -22,6 +22,8 @@ final class ChatVideoGalleryItemScrubberView: UIView { private let infoNode: ASTextNode private let scrubberNode: MediaPlayerScrubbingNode + private let hapticFeedback = HapticFeedback() + private var playbackStatus: MediaPlayerStatus? private var chapters: [MediaPlayerScrubbingChapter] = [] @@ -33,6 +35,8 @@ final class ChatVideoGalleryItemScrubberView: UIView { private var rightTimestampNodePushed = false private var infoNodePushed = false + private var currentChapter: MediaPlayerScrubbingChapter? + var hideWhenDurationIsUnknown = false { didSet { if self.hideWhenDurationIsUnknown { @@ -172,20 +176,51 @@ final class ChatVideoGalleryItemScrubberView: UIView { self.chapterDisposable.set((mappedStatus |> deliverOnMainQueue).start(next: { [weak self] status in if let strongSelf = self, status.duration > 1.0, strongSelf.chapters.count > 0 { - var text: String = "" - + let previousChapter = strongSelf.currentChapter + var currentChapter: MediaPlayerScrubbingChapter? for chapter in strongSelf.chapters { if chapter.start > status.timestamp { break } else { - text = chapter.title + currentChapter = chapter } } - strongSelf.infoNode.attributedText = NSAttributedString(string: text, font: textFont, textColor: .white) - - if let (size, leftInset, rightInset) = strongSelf.containerLayout { - strongSelf.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset, transition: .immediate) + if let chapter = currentChapter, chapter != previousChapter { + strongSelf.currentChapter = chapter + + if strongSelf.scrubberNode.isScrubbing { + strongSelf.hapticFeedback.impact(.light) + } + + if let previousChapter = previousChapter, !strongSelf.infoNode.alpha.isZero { + if let snapshotView = strongSelf.infoNode.view.snapshotView(afterScreenUpdates: false) { + snapshotView.frame = strongSelf.infoNode.frame + strongSelf.infoNode.view.superview?.addSubview(snapshotView) + + let offset: CGFloat = 30.0 + let snapshotTargetPosition: CGPoint + let nodeStartPosition: CGPoint + if previousChapter.start < chapter.start { + snapshotTargetPosition = CGPoint(x: -offset, y: 0.0) + nodeStartPosition = CGPoint(x: offset, y: 0.0) + } else { + snapshotTargetPosition = CGPoint(x: offset, y: 0.0) + nodeStartPosition = CGPoint(x: -offset, y: 0.0) + } + snapshotView.layer.animatePosition(from: CGPoint(), to: snapshotTargetPosition, duration: 0.2, removeOnCompletion: false, additive: true) + snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in + snapshotView?.removeFromSuperview() + }) + strongSelf.infoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + strongSelf.infoNode.layer.animatePosition(from: nodeStartPosition, to: CGPoint(), duration: 0.2, additive: true) + } + } + strongSelf.infoNode.attributedText = NSAttributedString(string: chapter.title, font: textFont, textColor: .white) + + if let (size, leftInset, rightInset) = strongSelf.containerLayout { + strongSelf.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset, transition: .immediate) + } } } })) diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintStickersContext.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintStickersContext.h index f8f04b49eb..e2e38a1bf9 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintStickersContext.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintStickersContext.h @@ -20,6 +20,10 @@ - (void)play; - (void)pause; - (void)resetToStart; + +- (void)playFromFrame:(NSInteger)frameIndex; +- (void)copyStickerView:(NSObject *)view; + - (int64_t)documentId; - (UIImage *)image; diff --git a/submodules/LegacyComponents/Sources/TGPhotoEditorTabController.m b/submodules/LegacyComponents/Sources/TGPhotoEditorTabController.m index 3a9492964d..81a052f13d 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoEditorTabController.m +++ b/submodules/LegacyComponents/Sources/TGPhotoEditorTabController.m @@ -298,9 +298,12 @@ const CGFloat TGPhotoEditorToolbarSize = 49.0f; else { bool wasHidden = referenceView.isHidden; + CGRect previousFrame = referenceView.frame; + referenceView.frame = CGRectOffset(referenceView.frame, -1000.0, 0.0); referenceView.hidden = false; toTransitionView = [referenceView snapshotViewAfterScreenUpdates:true]; referenceView.hidden = wasHidden; + referenceView.frame = previousFrame; } [parentView addSubview:toTransitionView]; diff --git a/submodules/LegacyComponents/Sources/TGPhotoEntitiesContainerView.m b/submodules/LegacyComponents/Sources/TGPhotoEntitiesContainerView.m index 7e6e7bcb04..5dda688790 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoEntitiesContainerView.m +++ b/submodules/LegacyComponents/Sources/TGPhotoEntitiesContainerView.m @@ -191,7 +191,6 @@ { TGPhotoStickerEntityView *stickerView = [[TGPhotoStickerEntityView alloc] initWithEntity:entity context:self.stickersContext]; [self _commonEntityViewSetup:stickerView entity:entity]; - [self addSubview:stickerView]; return stickerView; } @@ -202,7 +201,6 @@ [textView sizeToFit]; [self _commonEntityViewSetup:textView entity:entity]; - [self addSubview:textView]; return textView; } diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintController.m b/submodules/LegacyComponents/Sources/TGPhotoPaintController.m index 8a5fa607e9..7d882e38f3 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintController.m +++ b/submodules/LegacyComponents/Sources/TGPhotoPaintController.m @@ -97,6 +97,8 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f; UIView *_settingsView; id _stickersScreen; + double _stickerStartTime; + bool _appeared; bool _skipEntitiesSetup; bool _entitiesReady; @@ -149,6 +151,8 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f; _context = context; _enableStickers = photoEditor.enableStickers; + _stickerStartTime = NAN; + _actionHandle = [[ASHandle alloc] initWithDelegate:self releaseOnMainThread:true]; self.photoEditor = photoEditor; @@ -1196,41 +1200,65 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f; TGPhotoPaintStickerEntity *entity = [[TGPhotoPaintStickerEntity alloc] initWithDocument:document baseSize:[self _stickerBaseSizeForCurrentPainting] animated:animated]; [self _setStickerEntityPosition:entity]; + + TGPhotoStickerEntityView *stickerView = (TGPhotoStickerEntityView *)[_entitiesContainerView createEntityViewWithEntity:entity]; + bool hasStickers = false; + TGPhotoStickerEntityView *existingStickerView; for (TGPhotoPaintEntityView *view in _entitiesContainerView.subviews) { if ([view isKindOfClass:[TGPhotoStickerEntityView class]]) { hasStickers = true; + + if (((TGPhotoStickerEntityView *)view).documentId == stickerView.documentId) { + existingStickerView = (TGPhotoStickerEntityView *)view; + } break; } } - TGPhotoStickerEntityView *stickerView = (TGPhotoStickerEntityView *)[_entitiesContainerView createEntityViewWithEntity:entity]; + [_entitiesContainerView addSubview:stickerView]; [self _commonEntityViewSetup:stickerView]; __weak TGPhotoPaintController *weakSelf = self; - __weak TGPhotoStickerEntityView *weakStickerView = stickerView; stickerView.started = ^(double duration) { __strong TGPhotoPaintController *strongSelf = weakSelf; if (strongSelf != nil) { - TGPhotoEditorController *editorController = (TGPhotoEditorController *)self.parentViewController; + TGPhotoEditorController *editorController = (TGPhotoEditorController *)strongSelf.parentViewController; if (![editorController isKindOfClass:[TGPhotoEditorController class]]) return; if (!hasStickers) { [editorController setMinimalVideoDuration:duration]; } - - NSTimeInterval currentTime = editorController.currentTime; - __strong TGPhotoStickerEntityView *strongStickerView = weakStickerView; - if (strongStickerView != nil) { - if (!isnan(currentTime)) { - [strongStickerView seekTo:currentTime]; - [strongStickerView play]; - } - } } }; + NSTimeInterval currentTime = NAN; + NSTimeInterval stickerStartTime = _stickerStartTime; + TGPhotoEditorController *editorController = (TGPhotoEditorController *)self.parentViewController; + if ([editorController isKindOfClass:[TGPhotoEditorController class]]) { + currentTime = editorController.currentTime; + } + + if (!isnan(currentTime)) { + [stickerView seekTo:currentTime]; + [stickerView play]; + } else { + NSTimeInterval currentTime = CACurrentMediaTime(); + if (!isnan(stickerStartTime)) { + if (existingStickerView != nil) { + [stickerView copyStickerView:existingStickerView]; + } else { + NSTimeInterval position = currentTime - stickerStartTime; + [stickerView seekTo:position]; + [stickerView play]; + } + } else { + _stickerStartTime = currentTime; + [stickerView play]; + } + } + [self selectEntityView:stickerView]; _entitySelectionView.alpha = 0.0f; @@ -1261,6 +1289,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f; entity.angle = [self startRotation]; TGPhotoTextEntityView *textView = (TGPhotoTextEntityView *)[_entitiesContainerView createEntityViewWithEntity:entity]; + [_entitiesContainerView addSubview:textView]; [self _commonEntityViewSetup:textView]; [self selectEntityView:textView]; diff --git a/submodules/LegacyComponents/Sources/TGPhotoStickerEntityView.h b/submodules/LegacyComponents/Sources/TGPhotoStickerEntityView.h index e00badcf5b..92cbdebff1 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoStickerEntityView.h +++ b/submodules/LegacyComponents/Sources/TGPhotoStickerEntityView.h @@ -14,6 +14,8 @@ @property (nonatomic, readonly) TGPhotoPaintStickerEntity *entity; @property (nonatomic, readonly) bool isMirrored; +@property (nonatomic, readonly) int64_t documentId; + - (instancetype)initWithEntity:(TGPhotoPaintStickerEntity *)entity context:(id)context; - (void)mirror; - (UIImage *)image; @@ -23,6 +25,8 @@ - (void)play; - (void)pause; - (void)resetToStart; +- (void)playFromFrame:(NSInteger)frameIndex; +- (void)copyStickerView:(TGPhotoStickerEntityView *)view; - (CGRect)realBounds; diff --git a/submodules/LegacyComponents/Sources/TGPhotoStickerEntityView.m b/submodules/LegacyComponents/Sources/TGPhotoStickerEntityView.m index 9e2712308d..0994747edd 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoStickerEntityView.m +++ b/submodules/LegacyComponents/Sources/TGPhotoStickerEntityView.m @@ -201,6 +201,18 @@ const CGFloat TGPhotoStickerSelectionViewHandleSide = 30.0f; [_stickerView resetToStart]; } +- (void)playFromFrame:(NSInteger)frameIndex { + [_stickerView playFromFrame:frameIndex]; +} + +- (void)copyStickerView:(TGPhotoStickerEntityView *)view { + [_stickerView copyStickerView:view->_stickerView]; +} + +- (int64_t)documentId { + return [_stickerView documentId]; +} + @end diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickerView.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickerView.swift index c7b91175ad..8c9bbe530c 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickerView.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickerView.swift @@ -63,6 +63,7 @@ class LegacyPaintStickerView: UIView, TGPhotoPaintStickerRenderView { if self.file.isAnimatedSticker || self.file.isVideoSticker { if self.animationNode == nil { let animationNode = AnimatedStickerNode() + animationNode.autoplay = false self.animationNode = animationNode animationNode.started = { [weak self, weak animationNode] in self?.imageNode.isHidden = true @@ -79,7 +80,6 @@ class LegacyPaintStickerView: UIView, TGPhotoPaintStickerRenderView { } let dimensions = self.file.dimensions ?? PixelDimensions(width: 512, height: 512) self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: self.context.account.postbox, file: self.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 256.0, height: 256.0)))) - self.updateVisibility() self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, fileReference: stickerPackFileReference(self.file), resource: self.file.resource).start()) } else { if let animationNode = self.animationNode { @@ -110,7 +110,6 @@ class LegacyPaintStickerView: UIView, TGPhotoPaintStickerRenderView { if self.isPlaying != isPlaying { self.isPlaying = isPlaying - self.animationNode?.visibility = isPlaying if isPlaying && !self.didSetUpAnimationNode { self.didSetUpAnimationNode = true let dimensions = self.file.dimensions ?? PixelDimensions(width: 512, height: 512) @@ -121,6 +120,7 @@ class LegacyPaintStickerView: UIView, TGPhotoPaintStickerRenderView { self.cachedDisposable.set((source.cachedDataPath(width: 384, height: 384) |> deliverOn(Queue.concurrentDefaultQueue())).start()) } + self.animationNode?.visibility = isPlaying } } @@ -132,8 +132,7 @@ class LegacyPaintStickerView: UIView, TGPhotoPaintStickerRenderView { func play() { self.isVisible = true - self.isPlaying = true - self.animationNode?.play() + self.updateVisibility() } func pause() { @@ -148,6 +147,21 @@ class LegacyPaintStickerView: UIView, TGPhotoPaintStickerRenderView { self.animationNode?.seekTo(.timestamp(0.0)) } + func play(fromFrame frameIndex: Int) { + self.isVisible = true + self.updateVisibility() + self.animationNode?.play(fromIndex: frameIndex) + } + + func copyStickerView(_ view: TGPhotoPaintStickerRenderView!) { + guard let view = view as? LegacyPaintStickerView, let animationNode = view.animationNode else { + return + } + self.animationNode?.cloneCurrentFrame(from: animationNode) + self.animationNode?.play(fromIndex: animationNode.currentFrameIndex) + self.updateVisibility() + } + override func layoutSubviews() { super.layoutSubviews() diff --git a/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift b/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift index 71ae29d378..3dfcc18fb4 100644 --- a/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift +++ b/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift @@ -18,7 +18,7 @@ private func generateHandleBackground(color: UIColor) -> UIImage? { })?.stretchableImage(withLeftCapWidth: 0, topCapHeight: 2) } -public struct MediaPlayerScrubbingChapter { +public struct MediaPlayerScrubbingChapter: Equatable { public let title: String public let start: Double @@ -37,7 +37,7 @@ private final class MediaPlayerScrubbingNodeButton: ASDisplayNode, UIGestureReco var highlighted: ((Bool) -> Void)? var verticalPanEnabled = false - var hapticFeedback = HapticFeedback() + private let hapticFeedback = HapticFeedback() private var scrubbingMultiplier: Double = 1.0 private var scrubbingStartLocation: CGPoint? @@ -287,6 +287,10 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode { return self._scrubbingPosition.get() } + public var isScrubbing: Bool { + return self.scrubbingTimestampValue != nil + } + public var ignoreSeekId: Int? public var enableScrubbing: Bool = true { @@ -853,20 +857,28 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode { chapterNodesContainer.frame = backgroundFrame + var addedBeginning = false for i in 1 ..< node.chapterNodes.count { let (previousChapter, previousChapterNode) = node.chapterNodes[i - 1] let (chapter, chapterNode) = node.chapterNodes[i] let lineWidth: CGFloat = 1.0 + UIScreenPixel * 2.0 let startPosition: CGFloat - if i == 1 { + if !addedBeginning { startPosition = 0.0 } else { startPosition = floor(backgroundFrame.width * CGFloat(previousChapter.start / duration)) + lineWidth / 2.0 } let endPosition: CGFloat = max(startPosition, floor(backgroundFrame.width * CGFloat(chapter.start / duration)) - lineWidth / 2.0) + let width = endPosition - startPosition + if width < lineWidth * 2.0 { + previousChapterNode.frame = CGRect() + continue + } previousChapterNode.frame = CGRect(x: startPosition, y: 0.0, width: endPosition - startPosition, height: backgroundFrame.size.height) + addedBeginning = true + if i == node.chapterNodes.count - 1 { let startPosition = endPosition + lineWidth chapterNode.frame = CGRect(x: startPosition, y: 0.0, width: backgroundFrame.size.width - startPosition, height: backgroundFrame.size.height) @@ -877,7 +889,6 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode { } } - if let handleNode = node.handleNode { var handleSize: CGSize = CGSize(width: 2.0, height: bounds.size.height) var handleOffset: CGFloat = 0.0 diff --git a/submodules/TelegramUI/Sources/ChatBotStartInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatBotStartInputPanelNode.swift index ddcaf3eb1e..df7ddf406e 100644 --- a/submodules/TelegramUI/Sources/ChatBotStartInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatBotStartInputPanelNode.swift @@ -89,7 +89,7 @@ final class ChatBotStartInputPanelNode: ChatInputPanelNode { self.interfaceInteraction?.sendBotStart(presentationInterfaceState.botStartPayload) } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { if self.presentationInterfaceState != interfaceState { self.presentationInterfaceState = interfaceState } diff --git a/submodules/TelegramUI/Sources/ChatChannelSubscriberInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatChannelSubscriberInputPanelNode.swift index 4f4cf02bf3..b79d0bab44 100644 --- a/submodules/TelegramUI/Sources/ChatChannelSubscriberInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatChannelSubscriberInputPanelNode.swift @@ -127,7 +127,7 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode { private var presentationInterfaceState: ChatPresentationInterfaceState? - private var layoutData: (CGFloat, CGFloat, CGFloat, UIEdgeInsets, CGFloat, Bool, LayoutMetrics)? + private var layoutData: (CGFloat, CGFloat, CGFloat, CGFloat, UIEdgeInsets, CGFloat, Bool, LayoutMetrics)? override init() { self.button = HighlightableButtonNode() @@ -208,8 +208,8 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode { } self.isJoining = true - if let (width, leftInset, rightInset, additionalSideInsets, maxHeight, isSecondary, metrics) = self.layoutData, let presentationInterfaceState = self.presentationInterfaceState { - let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: presentationInterfaceState, metrics: metrics, force: true) + if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, isSecondary, metrics) = self.layoutData, let presentationInterfaceState = self.presentationInterfaceState { + let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: presentationInterfaceState, metrics: metrics, force: true) } self.actionDisposable.set((context.peerChannelMemberCategoriesContextsManager.join(engine: context.engine, peerId: peer.id, hash: nil) |> afterDisposed { [weak self] in @@ -265,12 +265,12 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode { } } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { - return self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: transition, interfaceState: interfaceState, metrics: metrics, force: false) + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { + return self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: transition, interfaceState: interfaceState, metrics: metrics, force: false) } - private func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, force: Bool) -> CGFloat { - self.layoutData = (width, leftInset, rightInset, additionalSideInsets, maxHeight, isSecondary, metrics) + private func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, force: Bool) -> CGFloat { + self.layoutData = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, isSecondary, metrics) if self.presentationInterfaceState != interfaceState || force { let previousState = self.presentationInterfaceState diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index e829a7cf0e..08d4527f84 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -10668,10 +10668,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G photoOnly = true } - let storeEditedPhotos = settings.storeEditedPhotos + let storeCapturedMedia = peer.id.namespace != Namespaces.Peer.SecretChat let inputText = strongSelf.presentationInterfaceState.interfaceState.effectiveInputState.inputText - presentedLegacyCamera(context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, cameraView: cameraView, menuController: nil, parentController: strongSelf, attachmentController: self?.attachmentController, editingMedia: false, saveCapturedPhotos: storeEditedPhotos, mediaGrouping: true, initialCaption: inputText, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, photoOnly: photoOnly, sendMessagesWithSignals: { [weak self] signals, silentPosting, scheduleTime in + presentedLegacyCamera(context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, cameraView: cameraView, menuController: nil, parentController: strongSelf, attachmentController: self?.attachmentController, editingMedia: false, saveCapturedPhotos: storeCapturedMedia, mediaGrouping: true, initialCaption: inputText, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, photoOnly: photoOnly, sendMessagesWithSignals: { [weak self] signals, silentPosting, scheduleTime in if let strongSelf = self { strongSelf.enqueueMediaMessages(signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime > 0 ? scheduleTime : nil) if !inputText.string.isEmpty { @@ -11276,7 +11276,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G photoOnly = true } - presentedLegacyCamera(context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, cameraView: cameraView, menuController: menuController, parentController: strongSelf, editingMedia: editMediaOptions != nil, saveCapturedPhotos: settings.storeEditedPhotos, mediaGrouping: true, initialCaption: inputText, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, photoOnly: photoOnly, sendMessagesWithSignals: { [weak self] signals, silentPosting, scheduleTime in + presentedLegacyCamera(context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, cameraView: cameraView, menuController: menuController, parentController: strongSelf, editingMedia: editMediaOptions != nil, saveCapturedPhotos: peer.id.namespace != Namespaces.Peer.SecretChat, mediaGrouping: true, initialCaption: inputText, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, photoOnly: photoOnly, sendMessagesWithSignals: { [weak self] signals, silentPosting, scheduleTime in if let strongSelf = self { if editMediaOptions != nil { strongSelf.editMessageMediaWithLegacySignals(signals!) diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 1ca0f117be..829c731b86 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -990,7 +990,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { if inputTextPanelNode.isFocused { self.context.sharedContext.mainWindow?.simulateKeyboardDismiss(transition: .animated(duration: 0.5, curve: .spring)) } - let _ = inputTextPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - insets.bottom, isSecondary: false, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics) + let _ = inputTextPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: layout.intrinsicInsets.bottom, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - insets.bottom, isSecondary: false, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics) } if let prevInputPanelNode = self.inputPanelNode, inputPanelNode.canHandleTransition(from: prevInputPanelNode) { inputPanelNodeHandlesTransition = true @@ -1000,7 +1000,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { } else { dismissedInputPanelNode = self.inputPanelNode } - let inputPanelHeight = inputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - insets.bottom, isSecondary: false, transition: inputPanelNode.supernode !== self ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics) + let inputPanelHeight = inputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: layout.intrinsicInsets.bottom, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - insets.bottom, isSecondary: false, transition: inputPanelNode.supernode !== self ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics) inputPanelSize = CGSize(width: layout.size.width, height: inputPanelHeight) self.inputPanelNode = inputPanelNode if inputPanelNode.supernode !== self { @@ -1008,7 +1008,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.inputPanelContainerNode.insertSubnode(inputPanelNode, aboveSubnode: self.inputPanelBackgroundNode) } } else { - let inputPanelHeight = inputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - insets.bottom - 120.0, isSecondary: false, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics) + let inputPanelHeight = inputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: layout.intrinsicInsets.bottom, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - insets.bottom - 120.0, isSecondary: false, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics) inputPanelSize = CGSize(width: layout.size.width, height: inputPanelHeight) } } else { @@ -1019,7 +1019,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { if let secondaryInputPanelNode = inputPanelNodes.secondary, !previewing { if secondaryInputPanelNode !== self.secondaryInputPanelNode { dismissedSecondaryInputPanelNode = self.secondaryInputPanelNode - let inputPanelHeight = secondaryInputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - insets.bottom, isSecondary: true, transition: .immediate, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics) + let inputPanelHeight = secondaryInputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: layout.intrinsicInsets.bottom, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - insets.bottom, isSecondary: true, transition: .immediate, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics) secondaryInputPanelSize = CGSize(width: layout.size.width, height: inputPanelHeight) self.secondaryInputPanelNode = secondaryInputPanelNode if secondaryInputPanelNode.supernode == nil { @@ -1027,7 +1027,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.inputPanelContainerNode.insertSubnode(secondaryInputPanelNode, aboveSubnode: self.inputPanelBackgroundNode) } } else { - let inputPanelHeight = secondaryInputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - insets.bottom, isSecondary: true, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics) + let inputPanelHeight = secondaryInputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: layout.intrinsicInsets.bottom, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - insets.bottom, isSecondary: true, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics) secondaryInputPanelSize = CGSize(width: layout.size.width, height: inputPanelHeight) } } else { diff --git a/submodules/TelegramUI/Sources/ChatFeedNavigationInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatFeedNavigationInputPanelNode.swift index 0a65d48122..a81a9e812e 100644 --- a/submodules/TelegramUI/Sources/ChatFeedNavigationInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatFeedNavigationInputPanelNode.swift @@ -54,7 +54,7 @@ final class ChatFeedNavigationInputPanelNode: ChatInputPanelNode { self.interfaceInteraction?.navigateFeed() } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { if self.presentationInterfaceState != interfaceState { self.presentationInterfaceState = interfaceState } diff --git a/submodules/TelegramUI/Sources/ChatInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatInputPanelNode.swift index 83e77b2e6b..52001cf08b 100644 --- a/submodules/TelegramUI/Sources/ChatInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatInputPanelNode.swift @@ -15,7 +15,7 @@ class ChatInputPanelNode: ASDisplayNode { func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition) { } - func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { + func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { return 0.0 } diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 3703f84e37..3108616ad7 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -1629,10 +1629,10 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } else { let pathPrefix = item.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(resource.id) let additionalAnimationNode = AnimatedStickerNode() - additionalAnimationNode.setup(source: source, width: Int(animationSize.width * 2.5), height: Int(animationSize.height * 2.5), playbackMode: .once, mode: .direct(cachePathPrefix: pathPrefix)) + additionalAnimationNode.setup(source: source, width: Int(animationSize.width * 2), height: Int(animationSize.height * 2), playbackMode: .once, mode: .direct(cachePathPrefix: pathPrefix)) var animationFrame: CGRect if isStickerEffect { - animationFrame = animationNode.frame.offsetBy(dx: incomingMessage ? animationNode.frame.width * 0.66 - 14.0 : -animationNode.frame.width * 0.66 + 14.0, dy: 35.0).insetBy(dx: -animationNode.frame.width * 0.66, dy: -animationNode.frame.height * 0.66) + animationFrame = animationNode.frame.offsetBy(dx: incomingMessage ? animationNode.frame.width * 0.5 : -animationNode.frame.width * 0.5, dy: 35.0).insetBy(dx: -animationNode.frame.width * 0.5, dy: -animationNode.frame.height * 0.5) if incomingMessage { animationNode.transform = CATransform3DMakeScale(-1.0, 1.0, 1.0) } diff --git a/submodules/TelegramUI/Sources/ChatMessageReportInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatMessageReportInputPanelNode.swift index 2b182d3853..39f695d631 100644 --- a/submodules/TelegramUI/Sources/ChatMessageReportInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageReportInputPanelNode.swift @@ -71,7 +71,7 @@ final class ChatMessageReportInputPanelNode: ChatInputPanelNode { } } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { if self.presentationInterfaceState != interfaceState { self.presentationInterfaceState = interfaceState diff --git a/submodules/TelegramUI/Sources/ChatMessageSelectionInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatMessageSelectionInputPanelNode.swift index 9ff0db5f13..043b01a656 100644 --- a/submodules/TelegramUI/Sources/ChatMessageSelectionInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageSelectionInputPanelNode.swift @@ -17,7 +17,7 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode { private let shareButton: HighlightableButtonNode private let separatorNode: ASDisplayNode - private var validLayout: (width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, metrics: LayoutMetrics, isSecondary: Bool)? + private var validLayout: (width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, metrics: LayoutMetrics, isSecondary: Bool)? private var presentationInterfaceState: ChatPresentationInterfaceState? private var actions: ChatAvailableMessageActions? @@ -33,8 +33,8 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode { if self.selectedMessages.isEmpty { self.actions = nil - if let (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary) = self.validLayout, let interfaceState = self.presentationInterfaceState { - let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: interfaceState, metrics: metrics) + if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, metrics, isSecondary) = self.validLayout, let interfaceState = self.presentationInterfaceState { + let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: interfaceState, metrics: metrics) } self.canDeleteMessagesDisposable.set(nil) } else if let context = self.context { @@ -42,8 +42,8 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode { |> deliverOnMainQueue).start(next: { [weak self] actions in if let strongSelf = self { strongSelf.actions = actions - if let (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary) = strongSelf.validLayout, let interfaceState = strongSelf.presentationInterfaceState { - let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: interfaceState, metrics: metrics) + if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, metrics, isSecondary) = strongSelf.validLayout, let interfaceState = strongSelf.presentationInterfaceState { + let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: interfaceState, metrics: metrics) } } })) @@ -154,8 +154,8 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode { } } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { - self.validLayout = (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary) + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { + self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, metrics, isSecondary) let panelHeight = defaultHeight(metrics: metrics) diff --git a/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift index 3ee367b69f..ef4e9a8f36 100644 --- a/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift @@ -135,7 +135,7 @@ final class ChatRecordingPreviewInputPanelNode: ChatInputPanelNode { } } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { if self.presentationInterfaceState != interfaceState { var updateWaveform = false if self.presentationInterfaceState?.recordedMediaPreview != interfaceState.recordedMediaPreview { diff --git a/submodules/TelegramUI/Sources/ChatRestrictedInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatRestrictedInputPanelNode.swift index 2139713830..fe74f4e2d8 100644 --- a/submodules/TelegramUI/Sources/ChatRestrictedInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatRestrictedInputPanelNode.swift @@ -23,7 +23,7 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode { self.addSubnode(self.textNode) } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { if self.presentationInterfaceState != interfaceState { self.presentationInterfaceState = interfaceState } diff --git a/submodules/TelegramUI/Sources/ChatSearchInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatSearchInputPanelNode.swift index ed4e27c6b8..2b8150c7ea 100644 --- a/submodules/TelegramUI/Sources/ChatSearchInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatSearchInputPanelNode.swift @@ -28,7 +28,7 @@ final class ChatSearchInputPanelNode: ChatInputPanelNode { private var needsSearchResultsTooltip = true - private var validLayout: (CGFloat, CGFloat, CGFloat, UIEdgeInsets, CGFloat, LayoutMetrics, Bool)? + private var validLayout: (width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, metrics: LayoutMetrics, isSecondary: Bool)? override var interfaceInteraction: ChatPanelInterfaceInteraction? { didSet { @@ -38,8 +38,8 @@ final class ChatSearchInputPanelNode: ChatInputPanelNode { if let strongSelf = self, strongSelf.displayActivity != value { strongSelf.displayActivity = value strongSelf.activityIndicator.isHidden = !value - if let interfaceState = strongSelf.presentationInterfaceState, let validLayout = strongSelf.validLayout { - let _ = strongSelf.updateLayout(width: validLayout.0, leftInset: validLayout.1, rightInset: validLayout.2, additionalSideInsets: validLayout.3, maxHeight: validLayout.4, isSecondary: validLayout.6, transition: .immediate, interfaceState: interfaceState, metrics: validLayout.5) + if let interfaceState = strongSelf.presentationInterfaceState, let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, metrics, isSecondary) = strongSelf.validLayout { + let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: interfaceState, metrics: metrics) } } })) @@ -127,8 +127,8 @@ final class ChatSearchInputPanelNode: ChatInputPanelNode { } } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { - self.validLayout = (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary) + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { + self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, metrics, isSecondary) if self.presentationInterfaceState != interfaceState { let themeUpdated = self.presentationInterfaceState?.theme !== interfaceState.theme diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index 3c128a0f38..b8cb0c4f2b 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -279,7 +279,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { private var accessoryItemButtons: [(ChatTextInputAccessoryItem, AccessoryItemIconButtonNode)] = [] - private var validLayout: (CGFloat, CGFloat, CGFloat, UIEdgeInsets, CGFloat, LayoutMetrics, Bool)? + private var validLayout: (CGFloat, CGFloat, CGFloat, CGFloat, UIEdgeInsets, CGFloat, LayoutMetrics, Bool)? private var leftMenuInset: CGFloat = 0.0 var displayAttachmentMenu: () -> Void = { } @@ -450,6 +450,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { private var spoilersRevealed = false + private var touchDownGestureRecognizer: TouchDownGestureRecognizer? + init(presentationInterfaceState: ChatPresentationInterfaceState, presentationContext: ChatPresentationContext?, presentController: @escaping (ViewController) -> Void) { self.presentationInterfaceState = presentationInterfaceState @@ -584,15 +586,15 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { } self.actionButtons.micButton.offsetRecordingControls = { [weak self] in if let strongSelf = self, let presentationInterfaceState = strongSelf.presentationInterfaceState { - if let (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary) = strongSelf.validLayout { - let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: presentationInterfaceState, metrics: metrics) + if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, metrics, isSecondary) = strongSelf.validLayout { + let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: presentationInterfaceState, metrics: metrics) } } } self.actionButtons.micButton.updateCancelTranslation = { [weak self] in if let strongSelf = self, let presentationInterfaceState = strongSelf.presentationInterfaceState { - if let (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary) = strongSelf.validLayout { - let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: presentationInterfaceState, metrics: metrics) + if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, metrics, isSecondary) = strongSelf.validLayout { + let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: presentationInterfaceState, metrics: metrics) } } } @@ -739,6 +741,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { } } textInputNode.view.addGestureRecognizer(recognizer) + self.touchDownGestureRecognizer = recognizer textInputNode.textView.accessibilityHint = self.textPlaceholderNode.attributedText?.string } @@ -824,9 +827,17 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { } } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { - let previousAdditionalSideInsets = self.validLayout?.3 - self.validLayout = (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary) + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { + let previousAdditionalSideInsets = self.validLayout?.4 + self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, metrics, isSecondary) + + let textFieldWaitsForTouchUp: Bool + if case .regular = metrics.widthClass, bottomInset.isZero { + textFieldWaitsForTouchUp = true + } else { + textFieldWaitsForTouchUp = false + } + self.touchDownGestureRecognizer?.waitForTouchUp = textFieldWaitsForTouchUp var transition = transition var additionalOffset: CGFloat = 0.0 @@ -2026,7 +2037,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { self.counterTextNode.attributedText = NSAttributedString(string: "", font: counterFont, textColor: .black) } - if let (width, leftInset, rightInset, _, maxHeight, metrics, _) = self.validLayout { + if let (width, leftInset, rightInset, _, _, maxHeight, metrics, _) = self.validLayout { var composeButtonsOffset: CGFloat = 0.0 if self.extendedSearchLayout { composeButtonsOffset = 44.0 @@ -2217,7 +2228,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { } private func updateTextHeight(animated: Bool) { - if let (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, _) = self.validLayout { + if let (width, leftInset, rightInset, _, additionalSideInsets, maxHeight, metrics, _) = self.validLayout { let (_, textFieldHeight) = self.calculateTextFieldMetrics(width: width - leftInset - rightInset - additionalSideInsets.right - self.leftMenuInset, maxHeight: maxHeight, metrics: metrics) let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics) if !self.bounds.size.height.isEqual(to: panelHeight) { diff --git a/submodules/TelegramUI/Sources/ChatTitleView.swift b/submodules/TelegramUI/Sources/ChatTitleView.swift index e50ec52e0d..27cbc1b92c 100644 --- a/submodules/TelegramUI/Sources/ChatTitleView.swift +++ b/submodules/TelegramUI/Sources/ChatTitleView.swift @@ -364,6 +364,17 @@ final class ChatTitleView: UIView, NavigationBarTitleView { stringValue = "" } } else { + if inputActivities.count > 1 { + let peerTitle = EnginePeer(inputActivities[0].0).compactDisplayTitle + if inputActivities.count == 2 { + let secondPeerTitle = EnginePeer(inputActivities[1].0).compactDisplayTitle + stringValue = strings.Chat_MultipleTypingPair(peerTitle, secondPeerTitle).string + } else { + stringValue = strings.Chat_MultipleTypingMore(peerTitle, String(inputActivities.count - 1)).string + } + } else if let (peer, _) = inputActivities.first { + stringValue = EnginePeer(peer).compactDisplayTitle + } for (peer, _) in inputActivities { let title = EnginePeer(peer).compactDisplayTitle if !title.isEmpty { diff --git a/submodules/TelegramUI/Sources/ChatUnblockInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatUnblockInputPanelNode.swift index 7d6c6313ec..3ff6e5ddfe 100644 --- a/submodules/TelegramUI/Sources/ChatUnblockInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatUnblockInputPanelNode.swift @@ -82,7 +82,7 @@ final class ChatUnblockInputPanelNode: ChatInputPanelNode { self.interfaceInteraction?.unblockPeer() } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { if self.presentationInterfaceState != interfaceState { self.presentationInterfaceState = interfaceState diff --git a/submodules/TelegramUI/Sources/DeleteChatInputPanelNode.swift b/submodules/TelegramUI/Sources/DeleteChatInputPanelNode.swift index 23340b9c86..ad0310c571 100644 --- a/submodules/TelegramUI/Sources/DeleteChatInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/DeleteChatInputPanelNode.swift @@ -35,7 +35,7 @@ final class DeleteChatInputPanelNode: ChatInputPanelNode { self.interfaceInteraction?.deleteChat() } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { if self.presentationInterfaceState != interfaceState { self.presentationInterfaceState = interfaceState diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index e936daa865..f2a94e1547 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -366,7 +366,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode { self.separatorNode.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor let interfaceState = ChatPresentationInterfaceState(chatWallpaper: .color(0), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, limitsConfiguration: .defaultValue, fontSize: .regular, bubbleCorners: PresentationChatBubbleCorners(mainRadius: 16.0, auxiliaryRadius: 8.0, mergeBubbleCorners: true), accountPeerId: self.context.account.peerId, mode: .standard(previewing: false), chatLocation: .peer(id: self.peerId), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil) - let panelHeight = self.selectionPanel.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: UIEdgeInsets(), maxHeight: 0.0, isSecondary: false, transition: transition, interfaceState: interfaceState, metrics: layout.metrics) + let panelHeight = self.selectionPanel.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: layout.intrinsicInsets.bottom, additionalSideInsets: UIEdgeInsets(), maxHeight: 0.0, isSecondary: false, transition: transition, interfaceState: interfaceState, metrics: layout.metrics) transition.updateFrame(node: self.selectionPanel, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: panelHeight))) diff --git a/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift b/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift index f2e2069642..90074aa61b 100644 --- a/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift +++ b/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift @@ -489,7 +489,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { if textInputPanelNode.frame.width.isZero { panelTransition = .immediate } - var panelHeight = textInputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: UIEdgeInsets(), maxHeight: layout.size.height / 2.0, isSecondary: false, transition: panelTransition, interfaceState: self.presentationInterfaceState, metrics: layout.metrics) + var panelHeight = textInputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: layout.intrinsicInsets.bottom, additionalSideInsets: UIEdgeInsets(), maxHeight: layout.size.height / 2.0, isSecondary: false, transition: panelTransition, interfaceState: self.presentationInterfaceState, metrics: layout.metrics) if self.searchDisplayController == nil { panelHeight += insets.bottom } else { diff --git a/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift b/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift index 71a718e90d..67053612a4 100644 --- a/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift @@ -44,7 +44,7 @@ final class SecretChatHandshakeStatusInputPanelNode: ChatInputPanelNode { self.interfaceInteraction?.unblockPeer() } - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { + override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { if self.presentationInterfaceState != interfaceState { self.presentationInterfaceState = interfaceState diff --git a/submodules/TouchDownGesture/Sources/TouchDownGestureRecognizer.swift b/submodules/TouchDownGesture/Sources/TouchDownGestureRecognizer.swift index 1f7031455a..2b5a981b6c 100644 --- a/submodules/TouchDownGesture/Sources/TouchDownGestureRecognizer.swift +++ b/submodules/TouchDownGesture/Sources/TouchDownGestureRecognizer.swift @@ -5,6 +5,9 @@ import UIKit.UIGestureRecognizerSubclass public class TouchDownGestureRecognizer: UIGestureRecognizer, UIGestureRecognizerDelegate { public var touchDown: (() -> Void)? + private var touchLocation: CGPoint? + public var waitForTouchUp = false + override public init(target: Any?, action: Selector?) { super.init(target: target, action: action) @@ -18,8 +21,42 @@ public class TouchDownGestureRecognizer: UIGestureRecognizer, UIGestureRecognize override public func touchesBegan(_ touches: Set, with event: UIEvent) { super.touchesBegan(touches, with: event) - if let touchDown = self.touchDown { + if self.waitForTouchUp { + if let touch = touches.first { + self.touchLocation = touch.location(in: self.view) + } + } else if let touchDown = self.touchDown { touchDown() } } + + override public func touchesMoved(_ touches: Set, with event: UIEvent) { + super.touchesMoved(touches, with: event) + + guard let touch = touches.first else { + return + } + + if let touchLocation = self.touchLocation { + let location = touch.location(in: self.view) + let distance = CGPoint(x: location.x - touchLocation.x, y: location.y - touchLocation.y) + if distance.x * distance.x + distance.y * distance.y > 4.0 { + self.state = .cancelled + } + } + } + + override public func touchesEnded(_ touches: Set, with event: UIEvent) { + super.touchesEnded(touches, with: event) + + if let touchDown = self.touchDown, self.waitForTouchUp { + touchDown() + } + } + + override public func reset() { + self.touchLocation = nil + + super.reset() + } }