diff --git a/submodules/CallListUI/Sources/CallListControllerNode.swift b/submodules/CallListUI/Sources/CallListControllerNode.swift index df4356f9b6..db7cf53b83 100644 --- a/submodules/CallListUI/Sources/CallListControllerNode.swift +++ b/submodules/CallListUI/Sources/CallListControllerNode.swift @@ -678,7 +678,7 @@ final class CallListControllerNode: ASDisplayNode { self.emptyAnimationNode.alpha = alpha self.emptyAnimationNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.2, completion: { [weak self] _ in if let strongSelf = self { - if !previousAlpha.isZero && alpha.isZero { + if !previousAlpha.isZero && strongSelf.emptyAnimationNode.alpha.isZero { strongSelf.emptyAnimationNode.visibility = false } } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index ef3252e425..3db6213a06 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -664,7 +664,11 @@ public final class VoiceChatController: ViewController { if case .list = peerEntry.style { interaction.peerContextAction(peerEntry, node, nil) } else { - interaction.pinPeer(peer.id, peerEntry.ssrc) + if peerEntry.pinned { + interaction.peerContextAction(peerEntry, node, nil) + } else { + interaction.pinPeer(peer.id, peerEntry.ssrc) + } } }, contextAction: peerEntry.style == .list ? { node, gesture in interaction.peerContextAction(peerEntry, node, gesture) @@ -703,6 +707,7 @@ public final class VoiceChatController: ViewController { private let mainVideoClippingNode: ASDisplayNode private var mainVideoContainerNode: MainVideoContainerNode? private var mainParticipantNode: VoiceChatParticipantItemNode + private var minimizeButton: HighlightTrackingButtonNode private let listNode: ListView private let tileListNode: ListView private let topPanelNode: ASDisplayNode @@ -869,7 +874,10 @@ public final class VoiceChatController: ViewController { } self.mainParticipantNode = VoiceChatParticipantItemNode() + self.minimizeButton = HighlightTrackingButtonNode() + self.minimizeButton.alpha = 0.65 + self.minimizeButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/Minimize"), color: .white), for: .normal) self.listNode = ListView() self.listNode.alpha = self.isScheduling ? 0.0 : 1.0 self.listNode.isUserInteractionEnabled = !self.isScheduling @@ -1665,6 +1673,7 @@ public final class VoiceChatController: ViewController { self.contentContainer.addSubnode(self.mainVideoClippingNode) self.mainVideoClippingNode.addSubnode(mainVideoContainer) self.mainVideoClippingNode.addSubnode(self.mainParticipantNode) + self.mainVideoClippingNode.addSubnode(self.minimizeButton) } self.contentContainer.addSubnode(self.listNode) self.contentContainer.addSubnode(self.topPanelNode) @@ -1677,6 +1686,8 @@ public final class VoiceChatController: ViewController { self.contentContainer.addSubnode(self.tileListNode) self.addSubnode(self.transitionContainerNode) + self.minimizeButton.addTarget(self, action: #selector(self.minimizePressed), forControlEvents: .touchUpInside) + let invitedPeers: Signal<[Peer], NoError> = self.call.invitedPeers |> mapToSignal { ids -> Signal<[Peer], NoError> in return context.account.postbox.transaction { transaction -> [Peer] in @@ -2162,6 +2173,18 @@ public final class VoiceChatController: ViewController { strongSelf.dismissScheduled() } } + + self.minimizeButton.highligthedChanged = { [weak self] highlighted in + if let strongSelf = self { + if highlighted { + strongSelf.minimizeButton.layer.removeAnimation(forKey: "opacity") + strongSelf.minimizeButton.alpha = 0.26 + } else { + strongSelf.minimizeButton.alpha = 0.65 + strongSelf.minimizeButton.layer.animateAlpha(from: 0.26, to: 0.65, duration: 0.2) + } + } + } } deinit { @@ -2182,6 +2205,11 @@ public final class VoiceChatController: ViewController { self.updateAvatarDisposable.dispose() self.ignoreConnectingTimer?.invalidate() } + + @objc private func minimizePressed() { + self.displayMode = .fullscreen(controlsHidden: true) + self.mainVideoContainerNode?.tapped?() + } private func openContextMenu(sourceNode: ASDisplayNode, gesture: ContextGesture?) { let canManageCall = !self.optionsButtonIsAvatar @@ -3285,27 +3313,25 @@ public final class VoiceChatController: ViewController { let offset: CGFloat var mainParticipantNodeWidth = videoClippingFrame.width - if case let .fullscreen(controlsHidden) = effectiveDisplayMode, !isLandscape { - offset = controlsHidden ? 66.0 : 140.0 - mainParticipantNodeWidth -= 50.0 - } else { + if case let .fullscreen(controlsHidden) = effectiveDisplayMode { if isLandscape { - mainParticipantNodeWidth -= 50.0 offset = 56.0 + 6.0 + layout.intrinsicInsets.bottom + mainParticipantNodeWidth -= controlsHidden ? 66.0 : 140.0 } else { - offset = 56.0 + 6.0 + offset = controlsHidden ? 66.0 : 140.0 + mainParticipantNodeWidth -= 50.0 } + } else { + offset = 56.0 + 6.0 } - - transition.updateFrame(node: self.mainParticipantNode, frame: CGRect(x: 0.0, y: videoClippingFrame.height - offset, width: mainParticipantNodeWidth, height: 56.0)) - + if let entry = self.pinnedEntry, let interaction = self.itemInteraction { self.mainParticipantNode.isHidden = false let item = entry.item(context: self.context, presentationData: self.presentationData, interaction: interaction, transparent: true) let itemNode = self.mainParticipantNode item.updateNode(async: { $0() }, node: { return itemNode - }, params: ListViewItemLayoutParams(width: mainParticipantNodeWidth, leftInset: 0.0, rightInset: 0.0, availableHeight: self.bounds.height), previousItem: nil, nextItem: nil, animation: .Crossfade, completion: { (layout, apply) in + }, params: ListViewItemLayoutParams(width: mainParticipantNodeWidth, leftInset: 0.0, rightInset: 0.0, availableHeight: self.bounds.height), previousItem: nil, nextItem: nil, animation: .None, completion: { (layout, apply) in itemNode.contentSize = layout.contentSize itemNode.insets = layout.insets itemNode.isUserInteractionEnabled = false @@ -3316,6 +3342,9 @@ public final class VoiceChatController: ViewController { self.mainParticipantNode.isHidden = true } + transition.updateFrame(node: self.mainParticipantNode, frame: CGRect(x: 0.0, y: videoClippingFrame.height - offset, width: mainParticipantNodeWidth, height: 56.0)) + transition.updateFrame(node: self.minimizeButton, frame: CGRect(x: mainParticipantNodeWidth + 1.0, y: videoClippingFrame.height - offset + 7.0, width: 44.0, height: 44.0)) + transition.updateFrame(node: self.mainVideoClippingNode, frame: videoClippingFrame) transition.updateFrame(node: mainVideoContainer, frame: videoContainerFrame, completion: { [weak self] _ in if let strongSelf = self { diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift b/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift index abec8b3bb6..c3d257dc93 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift @@ -164,13 +164,17 @@ private let tileSize = CGSize(width: 84.0, height: 84.0) private let backgroundCornerRadius: CGFloat = 14.0 private let avatarSize: CGFloat = 40.0 +private let accentColor: UIColor = UIColor(rgb: 0x007aff) +private let constructiveColor: UIColor = UIColor(rgb: 0x34c759) +private let destructiveColor: UIColor = UIColor(rgb: 0xff3b30) + private let borderLineWidth: CGFloat = 2.0 private let borderImage = generateImage(CGSize(width: tileSize.width, height: tileSize.height), rotatedContext: { size, context in let bounds = CGRect(origin: CGPoint(), size: size) context.clear(bounds) context.setLineWidth(borderLineWidth) - context.setStrokeColor(UIColor(rgb: 0x007aff).cgColor) + context.setStrokeColor(accentColor.cgColor) context.addPath(UIBezierPath(roundedRect: bounds.insetBy(dx: (borderLineWidth - UIScreenPixel) / 2.0, dy: (borderLineWidth - UIScreenPixel) / 2.0), cornerRadius: backgroundCornerRadius - UIScreenPixel).cgPath) context.strokePath() @@ -841,6 +845,23 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { if item.transparent && item.style == .list { titleFont = Font.semibold(17.0) titleColor = UIColor(rgb: 0xffffff, alpha: 0.65) + } else if case .tile = item.style { + switch item.text { + case let .text(_, textColor): + switch textColor { + case .generic: + titleColor = item.presentationData.theme.list.itemPrimaryTextColor + case .accent: + titleColor = item.presentationData.theme.list.itemAccentColor + case .constructive: + titleColor = constructiveColor + case .destructive: + titleColor = destructiveColor + } + default: + break + } + } let currentBoldFont: UIFont = titleFont @@ -862,14 +883,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { } titleAttributedString = string case .tile: - let textColor: UIColor - switch item.icon { - case .wantsToSpeak: - textColor = item.presentationData.theme.list.itemAccentColor - default: - textColor = titleColor - } - titleAttributedString = NSAttributedString(string: firstName, font: titleFont, textColor: textColor) + titleAttributedString = NSAttributedString(string: firstName, font: titleFont, textColor: titleColor) } } else if let firstName = user.firstName, !firstName.isEmpty { titleAttributedString = NSAttributedString(string: firstName, font: currentBoldFont, textColor: titleColor) @@ -914,9 +928,9 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { textColorValue = item.presentationData.theme.list.itemAccentColor wavesColor = textColorValue case .constructive: - textColorValue = UIColor(rgb: 0x34c759) + textColorValue = constructiveColor case .destructive: - textColorValue = UIColor(rgb: 0xff3b30) + textColorValue = destructiveColor wavesColor = textColorValue } if item.transparent && item.style == .list { @@ -935,9 +949,9 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { case .accent: textColorValue = item.presentationData.theme.list.itemAccentColor case .constructive: - textColorValue = UIColor(rgb: 0x34c759) + textColorValue = constructiveColor case .destructive: - textColorValue = UIColor(rgb: 0xff3b30) + textColorValue = destructiveColor } expandedStatusAttributedString = NSAttributedString(string: text, font: statusFont, textColor: textColorValue) } else { @@ -1167,10 +1181,14 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { if updatedTitle, let snapshotView = strongSelf.titleNode.view.snapshotContentTree() { strongSelf.titleNode.view.superview?.insertSubview(snapshotView, aboveSubview: strongSelf.titleNode.view) + if item.transparent { + snapshotView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -20.0), duration: 0.2, removeOnCompletion: false, additive: true) + strongSelf.titleNode.layer.animatePosition(from: CGPoint(x: 0.0, y: 20.0), to: CGPoint(), duration: 0.2, additive: true) + } + snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in snapshotView?.removeFromSuperview() }) - strongSelf.titleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) }