From a98e69cfa01cb095d980bc29d9f12d333123a30e Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 18 Nov 2022 18:17:24 +0400 Subject: [PATCH] Inline forum improvements --- .../Sources/ChatListController.swift | 19 +++++-- .../Sources/ChatListControllerNode.swift | 2 + .../Sources/Node/ChatListBadgeNode.swift | 2 +- .../Sources/Node/ChatListItem.swift | 54 +++++++++++++------ .../Sources/CallKitIntegration.swift | 6 --- .../Sources/PresentationCall.swift | 10 ++++ .../Sources/ChatListHeaderComponent.swift | 10 +++- .../Sources/OngoingCallThreadLocalContext.mm | 6 +-- 8 files changed, 75 insertions(+), 34 deletions(-) diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index cf8fd86738..e967760287 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -366,7 +366,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController case let .known(offset): let isFirstFilter = strongSelf.chatListDisplayNode.containerNode.currentItemNode.chatListFilter == strongSelf.chatListDisplayNode.containerNode.availableFilters.first?.filter - if offset <= navigationBarSearchContentHeight + 1.0 && !isFirstFilter { + if offset <= navigationBarSearchContentHeight + 1.0 && strongSelf.chatListDisplayNode.inlineStackContainerNode != nil { + strongSelf.setInlineChatList(location: nil) + } else if offset <= navigationBarSearchContentHeight + 1.0 && !isFirstFilter { let firstFilter = strongSelf.chatListDisplayNode.containerNode.availableFilters.first ?? .all let targetTab: ChatListFilterTabEntryId switch firstFilter { @@ -380,7 +382,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController if let searchContentNode = strongSelf.searchContentNode { searchContentNode.updateExpansionProgress(1.0, animated: true) } - strongSelf.chatListDisplayNode.containerNode.currentItemNode.scrollToPosition(.top) + if let inlineStackContainerNode = strongSelf.chatListDisplayNode.inlineStackContainerNode { + inlineStackContainerNode.currentItemNode.scrollToPosition(.top) + } else { + strongSelf.chatListDisplayNode.containerNode.currentItemNode.scrollToPosition(.top) + } } } } @@ -949,7 +955,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController if case let .channel(channel) = peer, channel.flags.contains(.isForum), threadId == nil { strongSelf.chatListDisplayNode.clearHighlightAnimated(true) - strongSelf.setInlineChatList(location: .forum(peerId: channel.id)) + if strongSelf.chatListDisplayNode.inlineStackContainerNode?.location == .forum(peerId: channel.id) { + strongSelf.setInlineChatList(location: nil) + } else { + strongSelf.setInlineChatList(location: .forum(peerId: channel.id)) + } } else { if let threadId = threadId { let _ = strongSelf.context.sharedContext.navigateToForumThread(context: strongSelf.context, peerId: peer.id, threadId: threadId, messageId: nil, navigationController: navigationController, activateInput: nil, keepStack: .never).start() @@ -2633,6 +2643,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController if strongSelf.chatListDisplayNode.containerNode.currentItemNode.chatListFilter?.id == updatedFilter?.id { strongSelf.scrollToTop?() } else { + if strongSelf.chatListDisplayNode.inlineStackContainerNode != nil { + strongSelf.setInlineChatList(location: nil) + } strongSelf.chatListDisplayNode.containerNode.switchToFilter(id: updatedFilter.flatMap { .filter($0.id) } ?? .all) } }) diff --git a/submodules/ChatListUI/Sources/ChatListControllerNode.swift b/submodules/ChatListUI/Sources/ChatListControllerNode.swift index 33931cb0ef..7832dd34cf 100644 --- a/submodules/ChatListUI/Sources/ChatListControllerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListControllerNode.swift @@ -1702,6 +1702,8 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { func scrollToTop() { if let searchDisplayController = self.searchDisplayController { searchDisplayController.contentNode.scrollToTop() + } else if let inlineStackContainerNode = self.inlineStackContainerNode { + inlineStackContainerNode.scrollToTop() } else { self.containerNode.scrollToTop() } diff --git a/submodules/ChatListUI/Sources/Node/ChatListBadgeNode.swift b/submodules/ChatListUI/Sources/Node/ChatListBadgeNode.swift index c5246a2db1..e99291b98c 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListBadgeNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListBadgeNode.swift @@ -191,7 +191,7 @@ final class ChatListBadgeNode: ASDisplayNode { let backgroundFrame = CGRect(x: 0.0, y: 0.0, width: badgeWidth, height: strongSelf.backgroundNode.image?.size.height ?? 0.0) if let (textLayout, _) = textLayoutAndApply { - let badgeTextFrame = CGRect(origin: CGPoint(x: backgroundFrame.midX - textLayout.size.width / 2.0, y: backgroundFrame.minY + floorToScreenPixels((backgroundFrame.height - textLayout.size.height) / 2.0)), size: textLayout.size) + let badgeTextFrame = CGRect(origin: CGPoint(x: backgroundFrame.midX - textLayout.size.width / 2.0, y: backgroundFrame.minY + UIScreenPixel + floorToScreenPixels((backgroundFrame.height - textLayout.size.height) / 2.0)), size: textLayout.size) strongSelf.textNode.position = badgeTextFrame.center strongSelf.textNode.bounds = CGRect(origin: CGPoint(), size: badgeTextFrame.size) if animateTextNode { diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index dc2282f50d..04f2ec1838 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -790,6 +790,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { let contextContainer: ContextControllerSourceNode let mainContentContainerNode: ASDisplayNode + let avatarContainerNode: ASDisplayNode let avatarNode: AvatarNode var avatarIconView: ComponentHostView? var avatarIconComponent: EmojiStatusComponent? @@ -1037,6 +1038,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { self.backgroundNode.isLayerBacked = true self.backgroundNode.displaysAsynchronously = false + self.avatarContainerNode = ASDisplayNode() self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 26.0)) self.highlightedBackgroundNode = ASDisplayNode() @@ -1096,7 +1098,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { self.addSubnode(self.contextContainer) self.contextContainer.addSubnode(self.mainContentContainerNode) - self.contextContainer.addSubnode(self.avatarNode) + self.avatarContainerNode.addSubnode(self.avatarNode) + self.contextContainer.addSubnode(self.avatarContainerNode) self.contextContainer.addSubnode(self.onlineNode) self.mainContentContainerNode.addSubnode(self.titleNode) @@ -1122,10 +1125,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } if item.interaction.inlineNavigationLocation != nil { - return false - } - - if let value = strongSelf.hitTest(location, with: nil), value === strongSelf.compoundTextButtonNode?.view { + strongSelf.contextContainer.targetNodeForActivationProgress = strongSelf.avatarContainerNode + } else if let value = strongSelf.hitTest(location, with: nil), value === strongSelf.compoundTextButtonNode?.view { strongSelf.contextContainer.targetNodeForActivationProgress = strongSelf.compoundHighlightingNode } else { strongSelf.contextContainer.targetNodeForActivationProgress = nil @@ -1293,6 +1294,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { reallyHighlighted = true } } + if item.interaction.inlineNavigationLocation != nil { + reallyHighlighted = false + } } return reallyHighlighted } @@ -1944,7 +1948,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } else { let badgeTextColor: UIColor if unreadCount.muted { - if unreadCount.isProvisonal { + if unreadCount.isProvisonal, case .forum = item.chatListLocation { badgeTextColor = theme.unreadBadgeInactiveBackgroundColor currentBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundInactiveProvisional(item.presentationData.theme, diameter: badgeDiameter) currentAvatarBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundInactiveProvisional(item.presentationData.theme, diameter: avatarBadgeDiameter) @@ -1954,7 +1958,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { currentAvatarBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundInactive(item.presentationData.theme, diameter: avatarBadgeDiameter) } } else { - if unreadCount.isProvisonal { + if unreadCount.isProvisonal, case .forum = item.chatListLocation { badgeTextColor = theme.unreadBadgeActiveBackgroundColor currentBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundActiveProvisional(item.presentationData.theme, diameter: badgeDiameter) currentAvatarBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundActiveProvisional(item.presentationData.theme, diameter: avatarBadgeDiameter) @@ -2186,9 +2190,18 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { case .chatList: maxTitleLines = 1 } + + var titleLeftCutout: CGFloat = 0.0 + if item.interaction.isInlineMode { + titleLeftCutout = 22.0 + } let titleRectWidth = rawContentWidth - dateLayout.size.width - 10.0 - statusWidth - titleIconsWidth - let (titleLayout, titleApply) = titleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: maxTitleLines, truncationType: .end, constrainedSize: CGSize(width: titleRectWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + var titleCutout: TextNodeCutout? + if !titleLeftCutout.isZero { + titleCutout = TextNodeCutout(topLeft: CGSize(width: titleLeftCutout, height: 10.0), topRight: nil, bottomRight: nil) + } + let (titleLayout, titleApply) = titleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: maxTitleLines, truncationType: .end, constrainedSize: CGSize(width: titleRectWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: titleCutout, insets: UIEdgeInsets())) var inputActivitiesSize: CGSize? var inputActivitiesApply: (() -> Void)? @@ -2221,8 +2234,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } } - let peerRevealOptions: [ItemListRevealOption] - let peerLeftRevealOptions: [ItemListRevealOption] + var peerRevealOptions: [ItemListRevealOption] + var peerLeftRevealOptions: [ItemListRevealOption] switch item.content { case let .peer(_, renderedPeer, _, _, _, presence, _, _, _, _, _, _, displayAsMessage, _, _, _): if !displayAsMessage { @@ -2300,6 +2313,11 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { peerLeftRevealOptions = [] } + if item.interaction.inlineNavigationLocation != nil { + peerRevealOptions = [] + peerLeftRevealOptions = [] + } + let (onlineLayout, onlineApply) = onlineLayout(online, onlineIsVoiceChat) var animateContent = false if let currentItem = currentItem, currentItem.content.chatLocation == item.content.chatLocation { @@ -2466,7 +2484,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { let targetAvatarScaleOffset: CGFloat = -(avatarFrame.width - avatarFrame.width * avatarScale) * 0.5 avatarScaleOffset = targetAvatarScaleOffset * inlineNavigationLocation.progress } - transition.updatePosition(node: strongSelf.avatarNode, position: avatarFrame.center.offsetBy(dx: avatarScaleOffset, dy: 0.0)) + transition.updateFrame(node: strongSelf.avatarContainerNode, frame: avatarFrame) + transition.updatePosition(node: strongSelf.avatarNode, position: avatarFrame.offsetBy(dx: -avatarFrame.minX, dy: -avatarFrame.minY).center.offsetBy(dx: avatarScaleOffset, dy: 0.0)) transition.updateBounds(node: strongSelf.avatarNode, bounds: CGRect(origin: CGPoint(), size: avatarFrame.size)) transition.updateTransformScale(node: strongSelf.avatarNode, scale: avatarScale) strongSelf.avatarNode.updateSize(size: avatarFrame.size) @@ -2610,9 +2629,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } if case .forum = item.index { - strongSelf.avatarNode.isHidden = true + strongSelf.avatarContainerNode.isHidden = true } else { - strongSelf.avatarNode.isHidden = false + strongSelf.avatarContainerNode.isHidden = false } let onlineFrame: CGRect @@ -2623,6 +2642,10 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } transition.updateFrame(node: strongSelf.onlineNode, frame: onlineFrame) + let onlineInlineNavigationFraction: CGFloat = item.interaction.inlineNavigationLocation?.progress ?? 0.0 + transition.updateAlpha(node: strongSelf.onlineNode, alpha: 1.0 - onlineInlineNavigationFraction) + transition.updateSublayerTransformScale(node: strongSelf.onlineNode, scale: (1.0 - onlineInlineNavigationFraction) * 1.0 + onlineInlineNavigationFraction * 0.001) + let onlineIcon: UIImage? if strongSelf.reallyHighlighted { onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .highlighted, voiceChat: onlineIsVoiceChat) @@ -2726,9 +2749,6 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } var titleOffset: CGFloat = 0.0 - if item.interaction.isInlineMode { - titleOffset += 22.0 - } if let currentSecretIconImage = currentSecretIconImage { let iconNode: ASImageNode if let current = strongSelf.secretIconNode { @@ -3039,7 +3059,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { if let currentMutedIconImage = currentMutedIconImage { strongSelf.mutedIconNode.image = currentMutedIconImage strongSelf.mutedIconNode.isHidden = false - transition.updateFrame(node: strongSelf.mutedIconNode, frame: CGRect(origin: CGPoint(x: nextTitleIconOrigin - 5.0, y: titleFrame.minY - 1.0 - UIScreenPixel), size: currentMutedIconImage.size)) + transition.updateFrame(node: strongSelf.mutedIconNode, frame: CGRect(origin: CGPoint(x: nextTitleIconOrigin - 5.0, y: titleFrame.maxY - currentMutedIconImage.size.height + 0.0 + UIScreenPixel), size: currentMutedIconImage.size)) nextTitleIconOrigin += currentMutedIconImage.size.width + 1.0 } else { strongSelf.mutedIconNode.image = nil diff --git a/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift b/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift index dc78dd3ef6..a17e0eabee 100644 --- a/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift +++ b/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift @@ -260,12 +260,6 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { OngoingCallContext.setupAudioSession() - /*do { - try AVAudioSession.sharedInstance().setMode(.voiceChat) - } catch let e { - print("AVAudioSession.sharedInstance().setMode(.voiceChat) error \(e)") - }*/ - self.provider.reportNewIncomingCall(with: uuid, update: update, completion: { error in completion?(error as NSError?) }) diff --git a/submodules/TelegramCallsUI/Sources/PresentationCall.swift b/submodules/TelegramCallsUI/Sources/PresentationCall.swift index e4084d3cf1..ee9d590d12 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationCall.swift @@ -536,6 +536,8 @@ public final class PresentationCallImpl: PresentationCall { } } + #if DEBUG + #else if let audioSessionControl = audioSessionControl, previous == nil || previousControl == nil { if let callKitIntegration = self.callKitIntegration { callKitIntegration.applyVoiceChatOutputMode(outputMode: .custom(self.currentAudioOutputValue)) @@ -544,6 +546,7 @@ public final class PresentationCallImpl: PresentationCall { audioSessionControl.setup(synchronous: true) } } + #endif let mappedVideoState: PresentationCallState.VideoState let mappedRemoteVideoState: PresentationCallState.RemoteVideoState @@ -866,9 +869,13 @@ public final class PresentationCallImpl: PresentationCall { } if tone != self.toneRenderer?.tone { if let tone = tone { + #if DEBUG + let _ = tone + #else let toneRenderer = PresentationCallToneRenderer(tone: tone) self.toneRenderer = toneRenderer toneRenderer.setAudioSessionActive(self.isAudioSessionActive) + #endif } else { self.toneRenderer = nil } @@ -1045,6 +1052,8 @@ public final class PresentationCallImpl: PresentationCall { |> delay(1.0, queue: Queue.mainQueue()) )) + #if DEBUG + #else if let audioSessionControl = self.audioSessionControl { if let callKitIntegration = self.callKitIntegration { callKitIntegration.applyVoiceChatOutputMode(outputMode: .custom(self.currentAudioOutputValue)) @@ -1052,6 +1061,7 @@ public final class PresentationCallImpl: PresentationCall { audioSessionControl.setOutputMode(.custom(output)) } } + #endif } public func debugInfo() -> Signal<(String, String), NoError> { diff --git a/submodules/TelegramUI/Components/ChatListHeaderComponent/Sources/ChatListHeaderComponent.swift b/submodules/TelegramUI/Components/ChatListHeaderComponent/Sources/ChatListHeaderComponent.swift index 496bd0297c..2759827ef1 100644 --- a/submodules/TelegramUI/Components/ChatListHeaderComponent/Sources/ChatListHeaderComponent.swift +++ b/submodules/TelegramUI/Components/ChatListHeaderComponent/Sources/ChatListHeaderComponent.swift @@ -326,11 +326,17 @@ public final class ChatListHeaderComponent: Component { }) transition.setAlpha(view: self.rightButtonOffsetContainer, alpha: pow(1.0 - fraction, 2.0)) + if let backButtonView = self.backButtonView { + transition.setBounds(view: backButtonView, bounds: CGRect(origin: CGPoint(x: fraction * self.bounds.width * 0.5, y: 0.0), size: backButtonView.bounds.size), completion: { _ in + completion() + }) + } + if let chatListTitleView = self.chatListTitleView, let nextBackButtonView = nextView.backButtonView { let titleFrame = chatListTitleView.titleNode.view.convert(chatListTitleView.titleNode.bounds, to: self.titleOffsetContainer) let backButtonTitleFrame = nextBackButtonView.convert(nextBackButtonView.titleView.frame, to: nextView) - let totalOffset = titleFrame.midX - backButtonTitleFrame.midX + let totalOffset = titleFrame.minX - backButtonTitleFrame.minX transition.setBounds(view: self.titleOffsetContainer, bounds: CGRect(origin: CGPoint(x: totalOffset * fraction, y: 0.0), size: self.titleOffsetContainer.bounds.size)) transition.setAlpha(view: self.titleOffsetContainer, alpha: (1.0 - fraction)) @@ -350,7 +356,7 @@ public final class ChatListHeaderComponent: Component { let previousTitleFrame = previousChatListTitleView.titleNode.view.convert(previousChatListTitleView.titleNode.bounds, to: previousView.titleOffsetContainer) let backButtonTitleFrame = backButtonView.convert(backButtonView.titleView.frame, to: self) - let totalOffset = previousTitleFrame.midX - backButtonTitleFrame.midX + let totalOffset = previousTitleFrame.minX - backButtonTitleFrame.minX transition.setBounds(view: backButtonView.titleOffsetContainer, bounds: CGRect(origin: CGPoint(x: -totalOffset * (1.0 - fraction), y: 0.0), size: backButtonView.titleOffsetContainer.bounds.size)) transition.setAlpha(view: backButtonView.titleOffsetContainer, alpha: fraction) diff --git a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm index b3ac7582b2..13dbe2c062 100644 --- a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm +++ b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm @@ -890,11 +890,7 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; #ifdef WEBRTC_IOS RTCAudioSessionConfiguration *sharedConfiguration = [RTCAudioSessionConfiguration webRTCConfiguration]; - if (useManualAudioSessionControl) { - sharedConfiguration.mode = AVAudioSessionModeVoiceChat; - } else { - sharedConfiguration.mode = AVAudioSessionModeVoiceChat; - } + sharedConfiguration.mode = AVAudioSessionModeVoiceChat; sharedConfiguration.categoryOptions |= AVAudioSessionCategoryOptionMixWithOthers; sharedConfiguration.categoryOptions |= AVAudioSessionCategoryOptionAllowBluetoothA2DP; sharedConfiguration.outputNumberOfChannels = 1;