From e0aacc155ca6fe6a840048706cf16850f979f021 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Fri, 4 Dec 2020 20:30:51 +0400 Subject: [PATCH] Voice Chat UI improvements --- .../Sources/Node/ChatListItem.swift | 6 ++-- submodules/Display/Source/ListView.swift | 5 +++ .../Sources/HorizontalPeerItem.swift | 2 +- .../Sources/PeerOnlineMarkerNode.swift | 12 ++++++- .../Sources/SelectablePeerNode.swift | 2 +- .../Sources/VoiceChatActionButton.swift | 33 +++++++++++++++++++ .../Sources/VoiceChatController.swift | 17 +++++++--- 7 files changed, 66 insertions(+), 11 deletions(-) diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index 899fa9186f..05220ae6fe 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -697,7 +697,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { transition.updateAlpha(layer: self.highlightedBackgroundNode.layer, alpha: highlightProgress) if let item = self.item { - self.onlineNode.setImage(PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .highlighted, voiceChat: self.onlineIsVoiceChat), color: nil) + self.onlineNode.setImage(PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .highlighted, voiceChat: self.onlineIsVoiceChat), color: nil, transition: transition) } } else { if self.highlightedBackgroundNode.supernode != nil { @@ -717,7 +717,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } else { onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .regular, voiceChat: self.onlineIsVoiceChat) } - self.onlineNode.setImage(onlineIcon, color: nil) + self.onlineNode.setImage(onlineIcon, color: nil, transition: transition) } } } @@ -1543,7 +1543,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } else { onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .regular, voiceChat: onlineIsVoiceChat) } - strongSelf.onlineNode.setImage(onlineIcon, color: item.presentationData.theme.list.itemCheckColors.foregroundColor) + strongSelf.onlineNode.setImage(onlineIcon, color: item.presentationData.theme.list.itemCheckColors.foregroundColor, transition: .immediate) let _ = measureApply() let _ = dateApply() diff --git a/submodules/Display/Source/ListView.swift b/submodules/Display/Source/ListView.swift index c31201b1d0..da11f541e3 100644 --- a/submodules/Display/Source/ListView.swift +++ b/submodules/Display/Source/ListView.swift @@ -1426,11 +1426,16 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture } if self.stackFromBottom { + let previousCompleteHeight = completeHeight let updatedCompleteHeight = max(completeHeight, self.visibleSize.height) let deltaCompleteHeight = updatedCompleteHeight - completeHeight topItemEdge -= deltaCompleteHeight bottomItemEdge -= deltaCompleteHeight completeHeight = updatedCompleteHeight + + if let _ = self.keepMinimalScrollHeightWithTopInset { + completeHeight += effectiveInsets.top + previousCompleteHeight + } } } } diff --git a/submodules/HorizontalPeerItem/Sources/HorizontalPeerItem.swift b/submodules/HorizontalPeerItem/Sources/HorizontalPeerItem.swift index 15625961bd..c503696c27 100644 --- a/submodules/HorizontalPeerItem/Sources/HorizontalPeerItem.swift +++ b/submodules/HorizontalPeerItem/Sources/HorizontalPeerItem.swift @@ -209,7 +209,7 @@ public final class HorizontalPeerItemNode: ListViewItemNode { strongSelf.badgeBackgroundNode.isHidden = true } - strongSelf.onlineNode.setImage(PresentationResourcesChatList.recentStatusOnlineIcon(item.theme, state: .regular), color: nil) + strongSelf.onlineNode.setImage(PresentationResourcesChatList.recentStatusOnlineIcon(item.theme, state: .regular), color: nil, transition: .immediate) strongSelf.onlineNode.frame = CGRect(x: itemLayout.size.width - onlineLayout.width - 18.0, y: itemLayout.size.height - onlineLayout.height - 18.0, width: onlineLayout.width, height: onlineLayout.height) let _ = badgeApply() diff --git a/submodules/PeerOnlineMarkerNode/Sources/PeerOnlineMarkerNode.swift b/submodules/PeerOnlineMarkerNode/Sources/PeerOnlineMarkerNode.swift index 740b1154bf..6eac978ed7 100644 --- a/submodules/PeerOnlineMarkerNode/Sources/PeerOnlineMarkerNode.swift +++ b/submodules/PeerOnlineMarkerNode/Sources/PeerOnlineMarkerNode.swift @@ -123,7 +123,17 @@ public final class PeerOnlineMarkerNode: ASDisplayNode { self.addSubnode(self.iconNode) } - public func setImage(_ image: UIImage?, color: UIColor?) { + public func setImage(_ image: UIImage?, color: UIColor?, transition: ContainedViewLayoutTransition) { + if case let .animated(duration, curve) = transition { + if let snapshotLayer = self.iconNode.layer.snapshotContentTree() { + snapshotLayer.frame = self.iconNode.frame + self.iconNode.layer.insertSublayer(snapshotLayer, at: 0) + + snapshotLayer.animateAlpha(from: 1.0, to: 0.0, duration: duration, timingFunction: curve.timingFunction, removeOnCompletion: false, completion: { [weak snapshotLayer] _ in + snapshotLayer?.removeFromSuperlayer() + }) + } + } self.iconNode.image = image if let color = color { self.color = color diff --git a/submodules/SelectablePeerNode/Sources/SelectablePeerNode.swift b/submodules/SelectablePeerNode/Sources/SelectablePeerNode.swift index ba610aab9e..f1d0eab69e 100644 --- a/submodules/SelectablePeerNode/Sources/SelectablePeerNode.swift +++ b/submodules/SelectablePeerNode/Sources/SelectablePeerNode.swift @@ -166,7 +166,7 @@ public final class SelectablePeerNode: ASDisplayNode { let (onlineSize, onlineApply) = onlineLayout(online, false) let _ = onlineApply(false) - self.onlineNode.setImage(PresentationResourcesChatList.recentStatusOnlineIcon(theme, state: .panel), color: nil) + self.onlineNode.setImage(PresentationResourcesChatList.recentStatusOnlineIcon(theme, state: .panel), color: nil, transition: .immediate) self.onlineNode.frame = CGRect(origin: CGPoint(), size: onlineSize) self.setNeedsLayout() diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift b/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift index 129e0636ce..aa5b03b77b 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift @@ -411,6 +411,12 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { self.maskView.addSubview(self.maskBlobView) self.maskView.layer.addSublayer(self.maskCircleLayer) + + self.maskBlobView.scaleUpdated = { [weak self] scale in + if let strongSelf = self { + strongSelf.updateGlowScale(strongSelf.isActive ? scale : nil) + } + } } private func setupGradientAnimations() { @@ -483,6 +489,18 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { } } + func updateGlowScale(_ scale: CGFloat?) { + return + if let scale = scale { + self.maskGradientLayer.transform = CATransform3DMakeScale(0.89 + 0.11 * scale, 0.89 + 0.11 * scale, 1.0) + } else { +// let initialScale: CGFloat = ((self.maskGradientLayer.value(forKeyPath: "presentationLayer.transform.scale.x") as? NSNumber)?.floatValue).flatMap({ CGFloat($0) }) ?? (((self.maskGradientLayer.value(forKeyPath: "transform.scale.x") as? NSNumber)?.floatValue).flatMap({ CGFloat($0) }) ?? (effectivePreviousActive ? 0.95 : 0.8)) +// let targetScale: CGFloat = self.isActive ? 0.89 : 0.85 +// self.maskGradientLayer.transform = CATransform3DMakeScale(targetScale, targetScale, 1.0) +// self.maskGradientLayer.animateScale(from: initialScale, to: targetScale, duration: 0.3) + } + } + func updateGlowAndGradientAnimations(active: Bool?, previousActive: Bool? = nil) { let effectivePreviousActive = previousActive ?? false @@ -587,6 +605,7 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { CATransaction.commit() } + var isActive = false func updateAnimations() { if !self.isCurrentlyInHierarchy { self.foregroundGradientLayer.removeAllAnimations() @@ -601,10 +620,12 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { case .connecting: self.updatedActive?(false) self.setupProgressAnimations() + self.isActive = false case let .blob(newActive): if let transition = self.transition { if transition == .connecting { self.playConnectionAnimation(active: newActive) { [weak self] in + self?.isActive = newActive self?.transition = nil } } else if transition == .disabled { @@ -612,11 +633,14 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { } else if case let .blob(previousActive) = transition { updateGlowAndGradientAnimations(active: newActive, previousActive: previousActive) self.transition = nil + self.isActive = newActive } } else { self.maskBlobView.startAnimating() } case .disabled: + self.isActive = false + self.updateGlowScale(nil) break } } @@ -684,6 +708,12 @@ private final class VoiceBlobView: UIView { private var audioLevel: CGFloat = 0.0 var presentationAudioLevel: CGFloat = 0.0 + var scaleUpdated: ((CGFloat) -> Void)? { + didSet { + self.bigBlob.scaleUpdated = self.scaleUpdated + } + } + private(set) var isAnimating = false public typealias BlobRange = (min: CGFloat, max: CGFloat) @@ -805,12 +835,15 @@ final class BlobView: UIView { let minScale: CGFloat let maxScale: CGFloat + var scaleUpdated: ((CGFloat) -> Void)? + var level: CGFloat = 0 { didSet { CATransaction.begin() CATransaction.setDisableActions(true) let lv = minScale + (maxScale - minScale) * level shapeLayer.transform = CATransform3DMakeScale(lv, lv, 1) + self.scaleUpdated?(level) CATransaction.commit() } } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 79be30b861..4ca52c08af 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -456,6 +456,7 @@ public final class VoiceChatController: ViewController { self.listNode.verticalScrollIndicatorColor = UIColor(white: 1.0, alpha: 0.3) self.listNode.clipsToBounds = true self.listNode.stackFromBottom = true + self.listNode.keepMinimalScrollHeightWithTopInset = 0 self.topPanelNode = ASDisplayNode() self.topPanelNode.backgroundColor = panelBackgroundColor @@ -1360,7 +1361,7 @@ public final class VoiceChatController: ViewController { actionButtonState = .connecting actionButtonTitle = self.presentationData.strings.VoiceChat_Connecting actionButtonSubtitle = "" - audioButtonAppearance = .color(.custom(0x1c1c1e)) + audioButtonAppearance = .color(.custom(0x2c2c2e)) actionButtonEnabled = false case .connected: if let muteState = callState.muteState, !self.pushingToTalk { @@ -1506,6 +1507,7 @@ public final class VoiceChatController: ViewController { } } + private var isFirstTime = true private func dequeueTransition() { guard let _ = self.validLayout, let transition = self.enqueuedTransitions.first else { return @@ -1522,7 +1524,14 @@ public final class VoiceChatController: ViewController { options.insert(.LowLatency) options.insert(.PreferSynchronousResourceLoading) - self.listNode.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { [weak self] _ in + + var scrollToItem: ListViewScrollToItem? + if self.isFirstTime { + self.isFirstTime = false + scrollToItem = ListViewScrollToItem(index: 0, position: .bottom(0), animated: false, curve: .Default(duration: nil), directionHint: .Up) + } + + self.listNode.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, scrollToItem: scrollToItem, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { [weak self] _ in guard let strongSelf = self else { return } @@ -1638,7 +1647,6 @@ public final class VoiceChatController: ViewController { if let gestureRecognizers = view.gestureRecognizers, view != self.view { for gestureRecognizer in gestureRecognizers { if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer, gestureRecognizer.isEnabled { - print(view) if panGestureRecognizer.state != .began { panGestureRecognizer.isEnabled = false panGestureRecognizer.isEnabled = true @@ -1690,8 +1698,7 @@ public final class VoiceChatController: ViewController { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let result = super.hitTest(point, with: event) - - print("actually hitting") + if result === self.topPanelNode.view || result === self.bottomPanelNode.view { return self.view }