From 8d39e8d3f5e19c0b0469b4adf0ffcb4d72bb88d6 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Fri, 30 Apr 2021 14:54:11 +0400 Subject: [PATCH] Video Chat Improvements --- .../Sources/VoiceChatController.swift | 193 ++++++++++-------- .../Sources/VoiceChatTitleNode.swift | 3 + .../Contents.json | 13 +- .../airpods-b515@3x.png | Bin 4642 -> 0 bytes .../ic_call_airpodsmax.pdf | Bin 0 -> 4959 bytes 5 files changed, 113 insertions(+), 96 deletions(-) delete mode 100644 submodules/TelegramUI/Images.xcassets/Call/CallAirpodsMaxButton.imageset/airpods-b515@3x.png create mode 100644 submodules/TelegramUI/Images.xcassets/Call/CallAirpodsMaxButton.imageset/ic_call_airpodsmax.pdf diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 5619b8498e..5c094f0ebe 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -749,7 +749,6 @@ public final class VoiceChatController: ViewController { private var enqueuedTransitions: [ListTransition] = [] private var enqueuedTileTransitions: [ListTransition] = [] - private var floatingHeaderOffset: CGFloat? private var validLayout: (ContainerViewLayout, CGFloat)? private var didSetContentsReady: Bool = false @@ -1054,7 +1053,7 @@ public final class VoiceChatController: ViewController { if let (layout, navigationHeight) = strongSelf.validLayout { strongSelf.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut)) } - strongSelf.updateFloatingHeaderOffset(offset: strongSelf.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut), completion: { + strongSelf.updateDecorationsLayout(transition: .animated(duration: 0.3, curve: .easeInOut), completion: { strongSelf.animatingExpansion = false }) } @@ -1663,8 +1662,6 @@ public final class VoiceChatController: ViewController { self.topPanelNode.addSubnode(self.closeButton) self.topPanelNode.addSubnode(self.topCornersNode) - self.bottomPanelNode.addSubnode(self.bottomCornersNode) - self.bottomPanelNode.addSubnode(self.bottomPanelBackgroundNode) self.bottomPanelNode.addSubnode(self.audioButton) if let _ = self.mainVideoContainerNode { self.bottomPanelNode.addSubnode(self.cameraButton) @@ -1689,6 +1686,8 @@ public final class VoiceChatController: ViewController { self.contentContainer.addSubnode(self.leftBorderNode) self.contentContainer.addSubnode(self.rightBorderNode) self.contentContainer.addSubnode(self.bottomPanelCoverNode) + self.contentContainer.addSubnode(self.bottomCornersNode) + self.contentContainer.addSubnode(self.bottomPanelBackgroundNode) self.contentContainer.addSubnode(self.bottomPanelNode) self.contentContainer.addSubnode(self.timerNode) self.contentContainer.addSubnode(self.scheduleTextNode) @@ -1895,7 +1894,7 @@ public final class VoiceChatController: ViewController { if let strongSelf = self { strongSelf.currentContentOffset = offset if !strongSelf.animatingExpansion && !strongSelf.animatingInsertion && strongSelf.panGestureArguments == nil && !strongSelf.animatingAppearance { - strongSelf.updateFloatingHeaderOffset(offset: offset, transition: transition) + strongSelf.updateDecorationsLayout(transition: transition) } } } @@ -2028,7 +2027,7 @@ public final class VoiceChatController: ViewController { })) self.titleNode.tapped = { [weak self] in - if let strongSelf = self { + if let strongSelf = self, !strongSelf.isScheduling { if strongSelf.callState?.canManageCall ?? false { strongSelf.openTitleEditing() } else if !strongSelf.titleNode.recordingIconNode.isHidden { @@ -2110,7 +2109,7 @@ public final class VoiceChatController: ViewController { if let (layout, navigationHeight) = strongSelf.validLayout { strongSelf.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut)) - strongSelf.updateFloatingHeaderOffset(offset: strongSelf.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut)) + strongSelf.updateDecorationsLayout(transition: .animated(duration: 0.3, curve: .easeInOut)) } } if let (peerId, _) = minimalVisiblePeerid { @@ -2158,7 +2157,7 @@ public final class VoiceChatController: ViewController { if let (layout, navigationHeight) = strongSelf.validLayout { strongSelf.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut)) - strongSelf.updateFloatingHeaderOffset(offset: strongSelf.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut)) + strongSelf.updateDecorationsLayout(transition: .animated(duration: 0.3, curve: .easeInOut)) } } if let (peerId, _) = minimalVisiblePeerid { @@ -2182,7 +2181,7 @@ public final class VoiceChatController: ViewController { if let (layout, navigationHeight) = strongSelf.validLayout { strongSelf.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut)) - strongSelf.updateFloatingHeaderOffset(offset: strongSelf.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut)) + strongSelf.updateDecorationsLayout(transition: .animated(duration: 0.3, curve: .easeInOut)) } } } @@ -3222,20 +3221,11 @@ public final class VoiceChatController: ViewController { } private var bringVideoToBackOnCompletion = false - private func updateFloatingHeaderOffset(offset: CGFloat, transition: ContainedViewLayoutTransition, completion: (() -> Void)? = nil) { + private func updateDecorationsLayout(transition: ContainedViewLayoutTransition, completion: (() -> Void)? = nil) { guard let (layout, _) = self.validLayout else { return } - - let layoutTopInset: CGFloat = max(layout.statusBarHeight ?? 0.0, layout.safeInsets.top) - let listTopInset = layoutTopInset + topPanelHeight - let bottomPanelHeight = self.effectiveBottomAreaHeight + layout.intrinsicInsets.bottom - - var size = layout.size - if case .regular = layout.metrics.widthClass { - size.width = floor(min(size.width, size.height) * 0.5) - } - + var isLandscape = false var effectiveDisplayMode = self.displayMode if case .compact = layout.metrics.widthClass, layout.size.width > layout.size.height { @@ -3246,7 +3236,24 @@ public final class VoiceChatController: ViewController { } } - let listSize = CGSize(width: size.width, height: layout.size.height - listTopInset - bottomPanelHeight) + let layoutTopInset: CGFloat = max(layout.statusBarHeight ?? 0.0, layout.safeInsets.top) + let listTopInset = isLandscape ? topPanelHeight : layoutTopInset + topPanelHeight + let bottomPanelHeight = isLandscape ? layout.intrinsicInsets.bottom : self.effectiveBottomAreaHeight + layout.intrinsicInsets.bottom + + var size = layout.size + if case .regular = layout.metrics.widthClass { + size.width = floor(min(size.width, size.height) * 0.5) + } + + let contentWidth: CGFloat + if case .regular = layout.metrics.widthClass { + size.width = floor(min(size.width, size.height) * 0.5) + contentWidth = size.width + } else { + contentWidth = isLandscape ? min(530.0, size.width - 210.0) : size.width + } + + let listSize = CGSize(width: contentWidth, height: layout.size.height - listTopInset - bottomPanelHeight) let topInset: CGFloat if let (panInitialTopInset, panOffset) = self.panGestureArguments { if self.isExpanded { @@ -3270,9 +3277,8 @@ public final class VoiceChatController: ViewController { } } - - let offset = (bottomEdge.isZero ? 0.0 : offset) + topInset - self.floatingHeaderOffset = offset + let currentContentOffset = self.currentContentOffset ?? 0.0 + let offset = (bottomEdge.isZero ? 0.0 : currentContentOffset) + topInset if bottomEdge.isZero { bottomEdge = self.listNode.frame.minY + 46.0 + 56.0 @@ -3282,7 +3288,7 @@ public final class VoiceChatController: ViewController { let panelOffset = max(layoutTopInset, rawPanelOffset) let topPanelFrame: CGRect if isLandscape { - topPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: 0.0)) + topPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: topPanelHeight)) } else { topPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: panelOffset), size: CGSize(width: size.width, height: topPanelHeight)) } @@ -3374,8 +3380,8 @@ public final class VoiceChatController: ViewController { let leftBorderFrame: CGRect let rightBorderFrame: CGRect if isLandscape { - leftBorderFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.safeInsets.left, height: layout.size.height)) - rightBorderFrame = CGRect(origin: CGPoint(x: size.width - layout.safeInsets.right, y: 0.0), size: CGSize(width: layout.safeInsets.right, height: layout.size.height)) + leftBorderFrame = CGRect(origin: CGPoint(x: 0.0, y: topPanelFrame.maxY - 16.0), size: CGSize(width: (size.width - contentWidth) / 2.0 + sideInset, height: layout.size.height)) + rightBorderFrame = CGRect(origin: CGPoint(x: size.width - (size.width - contentWidth) / 2.0 - sideInset, y: topPanelFrame.maxY - 16.0), size: CGSize(width: layout.safeInsets.right + (size.width - contentWidth) / 2.0 + sideInset, height: layout.size.height)) } else { leftBorderFrame = CGRect(origin: CGPoint(x: 0.0, y: topPanelFrame.maxY - 16.0), size: CGSize(width: sideInset, height: layout.size.height)) rightBorderFrame = CGRect(origin: CGPoint(x: size.width - sideInset, y: topPanelFrame.maxY - 16.0), size: CGSize(width: sideInset, height: layout.size.height)) @@ -3409,10 +3415,15 @@ public final class VoiceChatController: ViewController { self.topPanelBackgroundNode.frame = CGRect(x: 0.0, y: topPanelHeight - 24.0, width: size.width, height: min(topPanelFrame.height, 24.0)) let listMaxY = listTopInset + listSize.height - let bottomOffset: CGFloat = min(0.0, bottomEdge - listMaxY) + var bottomOffset: CGFloat = min(0.0, bottomEdge - listMaxY) let bottomDelta = self.effectiveBottomAreaHeight - bottomAreaHeight - let bottomCornersFrame = CGRect(origin: CGPoint(x: sideInset, y: -50.0 + bottomOffset + bottomDelta), size: CGSize(width: size.width - sideInset * 2.0, height: 50.0)) + bottomOffset += layout.size.height - bottomPanelHeight + + var bottomCornersFrame = CGRect(origin: CGPoint(x: sideInset + floorToScreenPixels((size.width - contentWidth) / 2.0), y: -50.0 + bottomOffset + bottomDelta), size: CGSize(width: contentWidth - sideInset * 2.0, height: 50.0)) + + + let previousBottomCornersFrame = self.bottomCornersNode.frame if !bottomCornersFrame.equalTo(previousBottomCornersFrame) { self.bottomCornersNode.frame = bottomCornersFrame @@ -3451,8 +3462,10 @@ public final class VoiceChatController: ViewController { topEdgeFrame = CGRect(x: 0.0, y: 0.0, width: size.width, height: topPanelHeight) } + var isLandscape = false var effectiveDisplayMode = self.displayMode if case .compact = layout.metrics.widthClass, layout.size.width > layout.size.height { + isLandscape = true if case .fullscreen = effectiveDisplayMode { } else { effectiveDisplayMode = .fullscreen(controlsHidden: false) @@ -3461,7 +3474,11 @@ public final class VoiceChatController: ViewController { let backgroundColor: UIColor if case .fullscreen = effectiveDisplayMode { - backgroundColor = fullscreenBackgroundColor + if isLandscape { + backgroundColor = isFullscreen ? panelBackgroundColor : secondaryPanelBackgroundColor + } else { + backgroundColor = fullscreenBackgroundColor + } } else if self.isScheduling || self.callState?.scheduleTimestamp != nil { backgroundColor = panelBackgroundColor } else { @@ -3507,7 +3524,7 @@ public final class VoiceChatController: ViewController { } private func updateTitle(slide: Bool = false, transition: ContainedViewLayoutTransition) { - guard let (layout, _) = self.validLayout else { + guard let _ = self.validLayout else { return } var title = self.currentTitle @@ -3534,12 +3551,7 @@ public final class VoiceChatController: ViewController { } } - var size = layout.size - if case .regular = layout.metrics.widthClass { - size.width = floor(min(size.width, size.height) * 0.5) - } - - self.titleNode.update(size: CGSize(width: size.width, height: 44.0), title: title, subtitle: subtitle, slide: slide, transition: transition) + self.titleNode.update(size: CGSize(width: self.titleNode.bounds.width, height: 44.0), title: title, subtitle: subtitle, slide: slide, transition: transition) } private func updateButtons(animated: Bool) { @@ -3660,8 +3672,12 @@ public final class VoiceChatController: ViewController { self.validLayout = (layout, navigationHeight) var size = layout.size + let contentWidth: CGFloat if case .regular = layout.metrics.widthClass { size.width = floor(min(size.width, size.height) * 0.5) + contentWidth = size.width + } else { + contentWidth = isLandscape ? min(530.0, size.width - 210.0) : size.width } let isScheduled = self.isScheduling || self.callState?.scheduleTimestamp != nil @@ -3679,7 +3695,7 @@ public final class VoiceChatController: ViewController { if !self.isFullscreen { self.isExpanded = true self.updateIsFullscreen(true) - self.tileListNode.isHidden = false +// self.tileListNode.isHidden = false } if case .fullscreen = effectiveDisplayMode { } else { @@ -3703,34 +3719,37 @@ public final class VoiceChatController: ViewController { } } } - + + transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - contentWidth) / 2.0), y: 10.0), size: CGSize(width: contentWidth, height: 44.0))) self.updateTitle(transition: transition) - transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 10.0), size: CGSize(width: size.width, height: 44.0))) - transition.updateFrame(node: self.optionsButton, frame: CGRect(origin: CGPoint(x: 20.0, y: 18.0), size: CGSize(width: 28.0, height: 28.0))) - transition.updateFrame(node: self.closeButton, frame: CGRect(origin: CGPoint(x: size.width - 20.0 - 28.0, y: 18.0), size: CGSize(width: 28.0, height: 28.0))) + + transition.updateFrame(node: self.optionsButton, frame: CGRect(origin: CGPoint(x: 20.0 + floorToScreenPixels((size.width - contentWidth) / 2.0), y: 18.0), size: CGSize(width: 28.0, height: 28.0))) + transition.updateFrame(node: self.closeButton, frame: CGRect(origin: CGPoint(x: size.width - floorToScreenPixels((size.width - contentWidth) / 2.0) - 20.0 - 28.0, y: 18.0), size: CGSize(width: 28.0, height: 28.0))) transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(), size: layout.size)) transition.updateFrame(node: self.contentContainer, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - size.width) / 2.0), y: 0.0), size: size)) let layoutTopInset: CGFloat = max(layout.statusBarHeight ?? 0.0, layout.safeInsets.top) let sideInset: CGFloat = 16.0 + var insets = UIEdgeInsets() - insets.left = layout.safeInsets.left + sideInset - insets.right = layout.safeInsets.right + sideInset + insets.left = sideInset + (isLandscape ? 0.0 : layout.safeInsets.left) + insets.right = sideInset + (isLandscape ? 0.0 : layout.safeInsets.right) + + let topEdgeOffset: CGFloat + if let statusBarHeight = layout.statusBarHeight { + topEdgeOffset = statusBarHeight + } else { + topEdgeOffset = 44.0 + } if isLandscape { - transition.updateFrame(node: self.topPanelEdgeNode, frame: CGRect(x: 0.0, y: 0.0, width: size.width, height: 0.0)) + transition.updateFrame(node: self.topPanelEdgeNode, frame: CGRect(x: 0.0, y: -topEdgeOffset, width: size.width, height: topPanelHeight + topEdgeOffset)) } else if let _ = self.panGestureArguments { } else { let topEdgeFrame: CGRect if self.isFullscreen { - let offset: CGFloat - if let statusBarHeight = layout.statusBarHeight { - offset = statusBarHeight - } else { - offset = 44.0 - } - topEdgeFrame = CGRect(x: 0.0, y: -offset, width: size.width, height: topPanelHeight + offset) + topEdgeFrame = CGRect(x: 0.0, y: -topEdgeOffset, width: size.width, height: topPanelHeight + topEdgeOffset) } else { topEdgeFrame = CGRect(x: 0.0, y: 0.0, width: size.width, height: topPanelHeight) } @@ -3741,15 +3760,15 @@ public final class VoiceChatController: ViewController { var listTopInset = layoutTopInset + topPanelHeight var topCornersY = topPanelHeight if isLandscape { - listTopInset = 0.0 - topCornersY = -50.0 + listTopInset = topPanelHeight +// topCornersY = -50.0 } else if self.mainVideoContainerNode != nil && self.isFullscreen { let videoContainerHeight = min(mainVideoHeight, layout.size.width) listTopInset += videoContainerHeight topCornersY += videoContainerHeight } - let listSize = CGSize(width: size.width, height: layout.size.height - listTopInset - bottomPanelHeight) - + + let listSize = CGSize(width: contentWidth, height: layout.size.height - listTopInset - (isLandscape ? layout.intrinsicInsets.bottom : bottomPanelHeight)) let topInset: CGFloat if let (panInitialTopInset, panOffset) = self.panGestureArguments { if self.isExpanded { @@ -3763,7 +3782,7 @@ public final class VoiceChatController: ViewController { topInset = listSize.height - 46.0 - floor(56.0 * 3.5) } - transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(x: 0.0, y: listTopInset + topInset), size: listSize)) + transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - contentWidth) / 2.0), y: listTopInset + topInset), size: listSize)) let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition) self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: listSize, insets: insets, duration: duration, curve: curve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) @@ -3796,20 +3815,20 @@ public final class VoiceChatController: ViewController { self.tileListNode.transform = tileListTransform self.tileListNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: tileListUpdateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) - transition.updateFrame(node: self.topCornersNode, frame: CGRect(origin: CGPoint(x: sideInset, y: topCornersY), size: CGSize(width: size.width - sideInset * 2.0, height: 50.0))) + transition.updateFrame(node: self.topCornersNode, frame: CGRect(origin: CGPoint(x: sideInset + floorToScreenPixels((size.width - contentWidth) / 2.0), y: topCornersY), size: CGSize(width: contentWidth - sideInset * 2.0, height: 50.0))) var bottomPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - bottomPanelHeight), size: CGSize(width: size.width, height: bottomPanelHeight)) let bottomPanelCoverHeight = bottomAreaHeight + layout.intrinsicInsets.bottom let bottomPanelCoverFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - bottomPanelCoverHeight), size: CGSize(width: size.width, height: bottomPanelCoverHeight)) if isLandscape { - transition.updateAlpha(node: self.closeButton, alpha: 0.0) - transition.updateAlpha(node: self.optionsButton, alpha: 0.0) - transition.updateAlpha(node: self.titleNode, alpha: 0.0) +// transition.updateAlpha(node: self.closeButton, alpha: 0.0) +// transition.updateAlpha(node: self.optionsButton, alpha: 0.0) +// transition.updateAlpha(node: self.titleNode, alpha: 0.0) bottomPanelFrame = CGRect(origin: CGPoint(x: layout.size.width - fullscreenBottomAreaHeight - layout.safeInsets.right, y: 0.0), size: CGSize(width: fullscreenBottomAreaHeight + layout.safeInsets.right, height: layout.size.height)) } else { - transition.updateAlpha(node: self.closeButton, alpha: 1.0) - transition.updateAlpha(node: self.optionsButton, alpha: self.optionsButton.isUserInteractionEnabled ? 1.0 : 0.0) - transition.updateAlpha(node: self.titleNode, alpha: 1.0) +// transition.updateAlpha(node: self.closeButton, alpha: 1.0) +// transition.updateAlpha(node: self.optionsButton, alpha: self.optionsButton.isUserInteractionEnabled ? 1.0 : 0.0) +// transition.updateAlpha(node: self.titleNode, alpha: 1.0) } transition.updateFrame(node: self.bottomPanelCoverNode, frame: bottomPanelCoverFrame) transition.updateFrame(node: self.bottomPanelNode, frame: bottomPanelFrame) @@ -3856,16 +3875,26 @@ public final class VoiceChatController: ViewController { forthButtonFrame = rightButtonFrame case let .fullscreen(controlsHidden): smallButtons = true - let sideInset: CGFloat = 26.0 + if isLandscape { - let spacing = floor((layout.size.height - sideInset * 2.0 - sideButtonSize.height * 4.0) / 3.0) + let sideInset: CGFloat + let buttonsCount: Int + if self.mainVideoContainerNode == nil { + sideInset = 42.0 + buttonsCount = 3 + } else { + sideInset = 26.0 + buttonsCount = 4 + } + let spacing = floor((layout.size.height - sideInset * 2.0 - sideButtonSize.height * CGFloat(buttonsCount)) / (CGFloat(buttonsCount - 1))) let x = controlsHidden ? fullscreenBottomAreaHeight + layout.safeInsets.right + 30.0: floor((fullscreenBottomAreaHeight - sideButtonSize.width) / 2.0) forthButtonFrame = CGRect(origin: CGPoint(x: x, y: sideInset), size: sideButtonSize) let thirdButtonPreFrame = CGRect(origin: CGPoint(x: x, y: sideInset + sideButtonSize.height + spacing), size: sideButtonSize) thirdButtonFrame = CGRect(origin: CGPoint(x: floor(thirdButtonPreFrame.midX - centralButtonSize.width / 2.0), y: floor(thirdButtonPreFrame.midY - centralButtonSize.height / 2.0)), size: centralButtonSize) - secondButtonFrame = CGRect(origin: CGPoint(x: x, y: layout.size.height - sideInset - sideButtonSize.height - spacing - sideButtonSize.height), size: sideButtonSize) + secondButtonFrame = CGRect(origin: CGPoint(x: x, y: thirdButtonPreFrame.maxY + spacing), size: sideButtonSize) firstButtonFrame = CGRect(origin: CGPoint(x: x, y: layout.size.height - sideInset - sideButtonSize.height), size: sideButtonSize) } else { + let sideInset: CGFloat = 26.0 let spacing = floor((layout.size.width - sideInset * 2.0 - sideButtonSize.width * 4.0) / 3.0) let y = controlsHidden ? self.effectiveBottomAreaHeight + layout.intrinsicInsets.bottom + 30.0: floor((self.effectiveBottomAreaHeight - sideButtonSize.height) / 2.0) firstButtonFrame = CGRect(origin: CGPoint(x: sideInset, y: y), size: sideButtonSize) @@ -3998,7 +4027,7 @@ public final class VoiceChatController: ViewController { guard let (layout, navigationHeight) = self.validLayout else { return } - self.updateFloatingHeaderOffset(offset: 0.0, transition: .immediate) + self.updateDecorationsLayout(transition: .immediate) self.animatingAppearance = true @@ -4123,9 +4152,7 @@ public final class VoiceChatController: ViewController { itemsCount -= 1 } itemsHeight += CGFloat(itemsCount) * 56.0 - - let layoutTopInset: CGFloat = max(layout.statusBarHeight ?? 0.0, layout.safeInsets.top) - + let sideInset: CGFloat = 16.0 var insets = UIEdgeInsets() insets.left = layout.safeInsets.left + sideInset @@ -4136,7 +4163,8 @@ public final class VoiceChatController: ViewController { size.width = floor(min(size.width, size.height) * 0.5) } - let bottomPanelHeight = self.effectiveBottomAreaHeight + layout.intrinsicInsets.bottom + let bottomPanelHeight = self.isLandscape ? layout.intrinsicInsets.bottom : self.effectiveBottomAreaHeight + layout.intrinsicInsets.bottom + let layoutTopInset: CGFloat = max(layout.statusBarHeight ?? 0.0, layout.safeInsets.top) let listTopInset = layoutTopInset + topPanelHeight let listSize = CGSize(width: size.width, height: layout.size.height - listTopInset - bottomPanelHeight) @@ -4158,9 +4186,9 @@ public final class VoiceChatController: ViewController { return } if isFirstTime { - strongSelf.updateFloatingHeaderOffset(offset: strongSelf.currentContentOffset ?? 0.0, transition: .immediate) + strongSelf.updateDecorationsLayout(transition: .immediate) } else if strongSelf.animatingInsertion { - strongSelf.updateFloatingHeaderOffset(offset: strongSelf.currentContentOffset ?? 0.0, transition: .animated(duration: 0.2, curve: .easeInOut)) + strongSelf.updateDecorationsLayout(transition: .animated(duration: 0.2, curve: .easeInOut)) } strongSelf.animatingInsertion = false if !strongSelf.didSetContentsReady { @@ -4226,12 +4254,7 @@ public final class VoiceChatController: ViewController { entries.append(.invite(self.presentationData.theme, self.presentationData.strings, inviteIsLink ? self.presentationData.strings.VoiceChat_Share : self.presentationData.strings.VoiceChat_InviteMember, inviteIsLink)) } - if let _ = self.effectiveSpeakerWithVideo { - index += 1 - } - var pinnedEntry: ListEntry? - for member in callMembers.0 { if processedPeerIds.contains(member.peer.id) { continue @@ -4520,7 +4543,7 @@ public final class VoiceChatController: ViewController { if let (layout, navigationHeight) = self.validLayout { self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .immediate) - self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: .immediate) + self.updateDecorationsLayout(transition: .immediate) } if !self.isExpanded { @@ -4568,7 +4591,7 @@ public final class VoiceChatController: ViewController { if let (layout, navigationHeight) = self.validLayout { self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut)) } - self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut), completion: { + self.updateDecorationsLayout(transition: .animated(duration: 0.3, curve: .easeInOut), completion: { self.animatingExpansion = false }) } else { @@ -4578,7 +4601,7 @@ public final class VoiceChatController: ViewController { if let (layout, navigationHeight) = self.validLayout { self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut)) } - self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut), completion: { + self.updateDecorationsLayout(transition: .animated(duration: 0.3, curve: .easeInOut), completion: { self.animatingExpansion = false }) } @@ -4606,7 +4629,7 @@ public final class VoiceChatController: ViewController { if let (layout, navigationHeight) = self.validLayout { self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut)) } - self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut), completion: { + self.updateDecorationsLayout(transition: .animated(duration: 0.3, curve: .easeInOut), completion: { self.animatingExpansion = false }) } else if !isScheduling { @@ -4617,7 +4640,7 @@ public final class VoiceChatController: ViewController { if let (layout, navigationHeight) = self.validLayout { self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut)) } - self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut), completion: { + self.updateDecorationsLayout(transition: .animated(duration: 0.3, curve: .easeInOut), completion: { self.animatingExpansion = false }) } @@ -4641,7 +4664,7 @@ public final class VoiceChatController: ViewController { if let (layout, navigationHeight) = self.validLayout { self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut)) } - self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut), completion: { + self.updateDecorationsLayout(transition: .animated(duration: 0.3, curve: .easeInOut), completion: { self.animatingExpansion = false }) default: diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatTitleNode.swift b/submodules/TelegramCallsUI/Sources/VoiceChatTitleNode.swift index 853a0128e5..5d2569a4d3 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatTitleNode.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatTitleNode.swift @@ -66,6 +66,9 @@ final class VoiceChatTitleNode: ASDisplayNode { } func update(size: CGSize, title: String, subtitle: String, slide: Bool, transition: ContainedViewLayoutTransition) { + guard !size.width.isZero else { + return + } var titleUpdated = false if let previousTitle = self.titleNode.attributedText?.string { titleUpdated = previousTitle != title diff --git a/submodules/TelegramUI/Images.xcassets/Call/CallAirpodsMaxButton.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Call/CallAirpodsMaxButton.imageset/Contents.json index 360b4f2588..795a18ba91 100644 --- a/submodules/TelegramUI/Images.xcassets/Call/CallAirpodsMaxButton.imageset/Contents.json +++ b/submodules/TelegramUI/Images.xcassets/Call/CallAirpodsMaxButton.imageset/Contents.json @@ -1,17 +1,8 @@ { "images" : [ { - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "filename" : "airpods-b515@3x.png", - "idiom" : "universal", - "scale" : "3x" + "filename" : "ic_call_airpodsmax.pdf", + "idiom" : "universal" } ], "info" : { diff --git a/submodules/TelegramUI/Images.xcassets/Call/CallAirpodsMaxButton.imageset/airpods-b515@3x.png b/submodules/TelegramUI/Images.xcassets/Call/CallAirpodsMaxButton.imageset/airpods-b515@3x.png deleted file mode 100644 index cf735b34c9a9ae76a30865d2438810cf7d869ac2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4642 zcmX|^WmFX0*TshhN$HNEq?@682uYEY9J-X290`dT5DAeIWGImiham-28mXa?E*Vm! z`^Epe)^peToxSf_XWjc{e>rd?11-`Aj1K?+0I80)hVi|M-lIT>dtVd!4}fT=7eouWMj?P-nFP#0{9ku)*AzF~<&mrP=;sAg}Y>7F6^}A`>j-@_8T5ai@ z+EiziD1bOnB663b38upyMd5&ty{eW#Q)$I4!_S}a%$g=j?n$EAc25<#M;T(mK}fi= z{R1vV#a`IKS^M>V(A|>a?|J`W#or&pa3c3L-)aEWumB+r&62>>_ey+| zaDos+D+64W=jZf&*j*P6O6Th#zBudyw>cmDstqxB=M=%=40NZw5P{YHrVs%88W#Hp zUv6Vr0OPymrai%C4Y)45bf3NfNmQ`xdI8A*KU)Q1dzJ`|ALgO4!9&I9cbUBfVJ%_k zwUP@j}jXbu*tJ%!Z?SBrUE~g_-b>B?@Q^@5PGDrY24sXP160!vj)&#^;ISn-Q$( zmHUkDl-ry(4Xci-O9)%Zia|mi#-@8j^dU6Gp>CG&=j$P8Iw@zUu zs^jhI_jC6voMUwe$q>yY^_A&r#Y6XLG<0++!L{GJ`si!#GrL>Fgz9U@8iO4Y=Csf+ z+hxGA%0C~XaZ(a|0Bq~88U766IgAo*so=*TRATF~2-d%8#?v-^r^RaSs@36$Cs{9- zDMol^DRC8~`{Gb)4-#0WnB#KC_h2FkT#a=3UHjwpFG_Not)zNbCbr0|U>jtJNIUFN zVhlEnCz@~T{XilRMPms~2$SYycQyCpDQ(dZ=agRyP5;R6_zr-0@#jT|examoI_ZtgZ zV=&$fVZ!VMucdpYPo+h`wo6e^=ET8+{0z{YkCkvhxiVfE454@6) zSIdUXe`7%u4-okKtlKhRBs?`F)34P%vyMO)isJFF%m8oa*n3-~t zt(*Ay;NRR-Bp)ZYnS}B%XEPDfY{vO$kX~5t6-FSZjS-a;KaKkbO(s<<)82)rFNvE@ zMsxN#nUW|wGL0o~X_Iiuy&6>~;nt-50XZmO=6%bdsk&RS{$0qIJeRb>iW#vcI8RK@ z+O?ekGC4AN(*2rUih{g5dw}s`%wYLe%TQ}yEqFTRhSX)) z1@h<38=QX8`f)@cwp$W)^>ZQ%zn**iGBjYvum_@D8%Bj2iKKO#=jd^c9+CM`!Lq&YZRvL%Pa zUr3Zjl#UX+$L>)s20QCT`K0M8I?HPrD_PB=%yt>4qD~xY ze1X-;;VFK}Jh2iO&i7j6zChu?5f_NT9_Jz(!nmEn>t z%SC=fW(GtDyq^Gvf~SC1sfzt8>m>DA){m=!2Rv-NcHGK9aAy|*C!-kkh7bc~x@CbA;}ZlE=917H`6T_dvCXk^ zcT!{pvUHAd?sQIY&wZ|Y&U7vwDdK*%?Y1Se6|?0Nu(@rrBZ--xz)Vk0pNuAr4~^Rt zwpyLFy=Y|B8BrC{OD;A4)Tn=eTvUhZEtx56v%HnES=+Y)Q*SJSbN;HE@l9S++O*lk2!F7yZlbh?+H_Y-Rf85Dy%21~Zd81cx39S`wqLTZHJ|^s zj_IA4OLx|k*a5vQ$wP&u{m`utjga(E$*}8v%x?clC)@CxnI)0M

n&G3H&n zuy?63eOrArsi0X}FX7g=3v?S)QoP%GlH789q3XwmV#8wStWEe<*JpSI&thUjGEFZl z9LIOJ$<+63jb+WXCn8ft4`%q;;GBDmvyQ7yN=Ml}6un znUx$vI*vD#`hQ{@;BxxpygwX12w$7~kM7!H z;E|2xW$$-n?2t39^U)ydtA~f(AN`&+Bd<4scVMgbt`6!~A-;z*-8*z070agAM*W{F z%fnk^TG!)i6xyGiOWT;-*`h*ZeVcJ6PGrSSAy}3MeVkL+& zc@c8d@Mp)$iW4P0Av0m}ob!di%<16i#9ozrmi)HIkcWWh-8|poY@LAbbhcc6OUuG$ zYv!Kn*`w3r-MspG*Y*A5J+^S6}wWM{+p zuO@zEV1$AU4dtLWdf&4XU5iFOUMXE)jaOApQT@gqW>Gu{YR3?4l4}VE+qtc$ z1zgSMMa$y^{r-^%?S|%EnUeoxo4EEo?l=t$4r1OR+4H*M!<4p?Hh0Kg&h4=iwonEic|*t^>AZHk_|H&2b3kY z6ce^2=sqZPsvAwwBQr37tBK2KY~`1{MkFq@Ak`3IF7AyeAj{*21l*6oqeuPI?9J=K zi#B-)2aWS*Z6il*OJC0x3C?_%qV9@u6yKyk^7NJdqzVlP{#~zL+~Z@q?vmbt;ZzlE z?$gm|-c|jS$#;4QP6|qYgsMzS$q|=seG@A{xkj3K4T*1{U7G@e%|b+aXuLz{k$s{| z0WBl-KF?n6n|0S;4Ev-|KF#$RuK0BE;HX#|ZAh&vP+nS`5@MF~X4-*GVy{snL1Ju> zlFnijY4K4_cNVWM!GTTp{a+^(SDGAjAsj86H(_`zQA){eP|_9{%vM|a*35!urS~fC zT}mNvgB1$O+WCRfHnsgcqRPo{YP!Am;(HsRv`A~f*AH`P^#vngsSeEiH?c6f6*GnJ z=CaI`{;sroH*dnwyg6d5cpy}_xBsneW3hLoIZN%vy7-*LrwN^SVQxeB*=odAt@p9M0pWRoirUezMYNbnrGj)P(kdDseUr}j1tAolQPugK2_|;Qx0CoRo`bF#6Q=0@~^HZzF=n+%8A?F6lAGwcSKr`!s4d=7oAv4sf`NVPjP&IG#8lOgX zK>kp)HtpDcp|N{!;V53{F7aCYjaO)2qFX1pM4a8pmiaOk60EiS*lAFCzM4poI0Ssd zqF800rqZ4B0|9mye{>pR@;Tq+Gi&2YYG17Om#s>5%0QsN1b0KS8`Z!AS0d9|;Z=^r z2WcD}QybT=IGu_;PgW`9;%Ne8edx@bB8j&j!{jTeKM~GNa|r1P=_P)xzDrks7Hg*9 z1M{r20HasaEZ*-+Ns+rXG{Ly^XMSX4y|LJZ1)wxmh9}Y{(=LyKMWp2juC5PcRXDy2 z6;32BcmIZH#c8MN>jcK1Iv=OGQSKTadnmCskQ_z?cR{3S!3CAC%8Fck z)c3gqm?RmTqSeTICwX78vP=ZnFaG36q$=o{y>YJ9I!p~&2#jaVZz|*R(QrA)td8#X z-5+!<_K5#hu^}kgrZ4r=A*+Xvb`+iBCbsZY9eS5^?R_WkC&+x6nC#2>EN;?M`uo%X Nbif80)oS+9{|AHDxLyDN diff --git a/submodules/TelegramUI/Images.xcassets/Call/CallAirpodsMaxButton.imageset/ic_call_airpodsmax.pdf b/submodules/TelegramUI/Images.xcassets/Call/CallAirpodsMaxButton.imageset/ic_call_airpodsmax.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3661b17240ce5050f0d2dc654f9c0e529920adf1 GIT binary patch literal 4959 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