diff --git a/submodules/TelegramCallsUI/Sources/VideoChatParticipantsComponent.swift b/submodules/TelegramCallsUI/Sources/VideoChatParticipantsComponent.swift index 2174d6f161..18cd09bd5d 100644 --- a/submodules/TelegramCallsUI/Sources/VideoChatParticipantsComponent.swift +++ b/submodules/TelegramCallsUI/Sources/VideoChatParticipantsComponent.swift @@ -26,11 +26,13 @@ final class VideoChatParticipantsComponent: Component { var videoColumn: Column? var mainColumn: Column var columnSpacing: CGFloat + var isMainColumnHidden: Bool - init(videoColumn: Column?, mainColumn: Column, columnSpacing: CGFloat) { + init(videoColumn: Column?, mainColumn: Column, columnSpacing: CGFloat, isMainColumnHidden: Bool) { self.videoColumn = videoColumn self.mainColumn = mainColumn self.columnSpacing = columnSpacing + self.isMainColumnHidden = isMainColumnHidden } } @@ -126,7 +128,7 @@ final class VideoChatParticipantsComponent: Component { let safeInsets: UIEdgeInsets let interfaceOrientation: UIInterfaceOrientation let openParticipantContextMenu: (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void - let updateMainParticipant: (VideoParticipantKey?) -> Void + let updateMainParticipant: (VideoParticipantKey?, Bool?) -> Void let updateIsMainParticipantPinned: (Bool) -> Void let updateIsExpandedUIHidden: (Bool) -> Void let openInviteMembers: () -> Void @@ -143,7 +145,7 @@ final class VideoChatParticipantsComponent: Component { safeInsets: UIEdgeInsets, interfaceOrientation: UIInterfaceOrientation, openParticipantContextMenu: @escaping (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void, - updateMainParticipant: @escaping (VideoParticipantKey?) -> Void, + updateMainParticipant: @escaping (VideoParticipantKey?, Bool?) -> Void, updateIsMainParticipantPinned: @escaping (Bool) -> Void, updateIsExpandedUIHidden: @escaping (Bool) -> Void, openInviteMembers: @escaping () -> Void @@ -422,7 +424,11 @@ final class VideoChatParticipantsComponent: Component { let gridSideInset: CGFloat let gridContainerHeight: CGFloat if let videoColumn = layout.videoColumn { - gridWidth = videoColumn.width + if layout.isMainColumnHidden { + gridWidth = videoColumn.width + layout.columnSpacing + layout.mainColumn.width + } else { + gridWidth = videoColumn.width + } gridSideInset = videoColumn.insets.left gridContainerHeight = containerSize.height - videoColumn.insets.top - videoColumn.insets.bottom } else { @@ -435,7 +441,7 @@ final class VideoChatParticipantsComponent: Component { self.list = List(containerSize: CGSize(width: listWidth, height: containerSize.height), sideInset: layout.mainColumn.insets.left, itemCount: listItemCount, itemHeight: listItemHeight, trailingItemHeight: listTrailingItemHeight) self.spacing = 4.0 - if let videoColumn = layout.videoColumn, !isUIHidden { + if let videoColumn = layout.videoColumn, !isUIHidden && !layout.isMainColumnHidden { self.expandedGrid = ExpandedGrid(containerSize: CGSize(width: videoColumn.width + expandedInsets.left, height: containerSize.height), layout: layout, expandedInsets: UIEdgeInsets(top: expandedInsets.top, left: expandedInsets.left, bottom: expandedInsets.bottom, right: 0.0), isUIHidden: isUIHidden) } else { self.expandedGrid = ExpandedGrid(containerSize: containerSize, layout: layout, expandedInsets: expandedInsets, isUIHidden: isUIHidden) @@ -459,8 +465,8 @@ final class VideoChatParticipantsComponent: Component { var separateVideoGridFrame = CGRect(origin: CGPoint(x: floor((containerSize.width - columnsWidth) * 0.5), y: 0.0), size: CGSize(width: gridWidth, height: containerSize.height)) var listFrame = CGRect(origin: CGPoint(x: separateVideoGridFrame.maxX + layout.columnSpacing, y: 0.0), size: CGSize(width: listWidth, height: containerSize.height)) - if isUIHidden { - listFrame.origin.x += columnsSideInset + layout.mainColumn.width + if isUIHidden || layout.isMainColumnHidden { + listFrame.origin.x = containerSize.width + columnsSideInset separateVideoGridFrame = CGRect(origin: CGPoint(x: floor((containerSize.width - columnsWidth) * 0.5), y: 0.0), size: CGSize(width: columnsWidth, height: containerSize.height)) } @@ -597,12 +603,13 @@ final class VideoChatParticipantsComponent: Component { private let separateVideoScrollViewClippingContainer: SolidRoundedCornersContainer private let separateVideoScrollView: ScrollView - private var component: VideoChatParticipantsComponent? + private(set) var component: VideoChatParticipantsComponent? private weak var state: EmptyComponentState? private var isUpdating: Bool = false private var ignoreScrolling: Bool = false + //TODO:release private var gridParticipants: [VideoParticipant] = [] private var listParticipants: [GroupCallParticipantsContext.Participant] = [] @@ -703,9 +710,19 @@ final class VideoChatParticipantsComponent: Component { if component.expandedVideoState != nil { if let result = self.expandedGridItemContainer.hitTest(self.convert(point, to: self.expandedGridItemContainer), with: event) { return result - } else { - return self } + + if component.layout.videoColumn != nil { + if let result = self.scrollViewClippingContainer.hitTest(self.convert(point, to: self.scrollViewClippingContainer), with: event) { + return result + } + } + + if !self.expandedGridItemContainer.bounds.contains(self.convert(point, to: self.expandedGridItemContainer)) && !self.scrollViewClippingContainer.bounds.contains(self.convert(point, to: self.scrollViewClippingContainer)) { + return nil + } + + return self } else { if let result = self.scrollViewClippingContainer.hitTest(self.convert(point, to: self.scrollViewClippingContainer), with: event) { return result @@ -737,7 +754,7 @@ final class VideoChatParticipantsComponent: Component { let velocity = recognizer.velocity(in: self) if abs(velocity.y) > 100.0 || abs(fraction) >= 0.5 { - component.updateMainParticipant(nil) + component.updateMainParticipant(nil, nil) } else { self.state?.updated(transition: .spring(duration: 0.4)) } @@ -935,10 +952,19 @@ final class VideoChatParticipantsComponent: Component { guard let self, let component = self.component else { return } - if let expandedVideoState = component.expandedVideoState, expandedVideoState.mainParticipant == videoParticipantKey { - component.updateIsExpandedUIHidden(!expandedVideoState.isUIHidden) + + if self.gridParticipants.count == 1, component.layout.videoColumn != nil { + if let expandedVideoState = component.expandedVideoState, expandedVideoState.mainParticipant == videoParticipantKey { + component.updateMainParticipant(nil, false) + } else { + component.updateMainParticipant(videoParticipantKey, true) + } } else { - component.updateMainParticipant(videoParticipantKey) + if let expandedVideoState = component.expandedVideoState, expandedVideoState.mainParticipant == videoParticipantKey { + component.updateIsExpandedUIHidden(!expandedVideoState.isUIHidden) + } else { + component.updateMainParticipant(videoParticipantKey, nil) + } } } )), @@ -1254,7 +1280,7 @@ final class VideoChatParticipantsComponent: Component { guard let self, let component = self.component else { return } - component.updateMainParticipant(VideoParticipantKey(id: key.id, isPresentation: key.isPresentation)) + component.updateMainParticipant(VideoParticipantKey(id: key.id, isPresentation: key.isPresentation), nil) } )), environment: {}, @@ -1302,7 +1328,7 @@ final class VideoChatParticipantsComponent: Component { guard let self, let component = self.component else { return } - component.updateMainParticipant(nil) + component.updateMainParticipant(nil, nil) }, pinAction: { [weak self] in guard let self, let component = self.component else { diff --git a/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift b/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift index 306499852f..2ca6153719 100644 --- a/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift +++ b/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift @@ -107,6 +107,7 @@ private final class VideoChatScreenComponent: Component { private var applicationStateDisposable: Disposable? private var expandedParticipantsVideoState: VideoChatParticipantsComponent.ExpandedVideoState? + private var isTwoColumnSidebarHidden: Bool = false private let inviteDisposable = MetaDisposable() private let currentAvatarMixin = Atomic(value: nil) @@ -2175,6 +2176,23 @@ private final class VideoChatScreenComponent: Component { self.members = members + if let members, let _ = self.expandedParticipantsVideoState { + var videoCount = 0 + for participant in members.participants { + if participant.presentationDescription != nil { + videoCount += 1 + } + if participant.videoDescription != nil { + videoCount += 1 + } + } + if videoCount == 1, let participantsView = self.participants.view as? VideoChatParticipantsComponent.View, let participantsComponent = participantsView.component { + if participantsComponent.layout.videoColumn != nil { + self.expandedParticipantsVideoState = nil + } + } + } + if let expandedParticipantsVideoState = self.expandedParticipantsVideoState, let members { if !expandedParticipantsVideoState.isMainParticipantPinned, let participant = members.participants.first(where: { participant in if let callState = self.callState, participant.peer.id == callState.myPeerId { @@ -2443,6 +2461,7 @@ private final class VideoChatScreenComponent: Component { size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter) )), effectAlignment: .center, + minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), action: { [weak self] in guard let self else { return @@ -2465,6 +2484,7 @@ private final class VideoChatScreenComponent: Component { size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter) )), effectAlignment: .center, + minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), action: { [weak self] in guard let self else { return @@ -2492,7 +2512,7 @@ private final class VideoChatScreenComponent: Component { transition.setFrame(view: navigationRightButtonView, frame: navigationRightButtonFrame) } - if isTwoColumnLayout, !"".isEmpty { + if isTwoColumnLayout { var navigationSidebarButtonTransition = transition let navigationSidebarButton: ComponentView if let current = self.navigationSidebarButton { @@ -2509,25 +2529,19 @@ private final class VideoChatScreenComponent: Component { name: "Call/PanelIcon", tintColor: .white )), - background: AnyComponent(Circle( - fillColor: UIColor(white: 1.0, alpha: 0.1), - size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter) + background: AnyComponent(FilledRoundedRectangleComponent( + color: UIColor(white: 1.0, alpha: 0.1), + cornerRadius: navigationButtonDiameter * 0.5, + smoothCorners: false )), effectAlignment: .center, + minSize: CGSize(width: navigationButtonDiameter + 10.0, height: navigationButtonDiameter), action: { [weak self] in guard let self else { return } - if let expandedParticipantsVideoState = self.expandedParticipantsVideoState { - self.expandedParticipantsVideoState = VideoChatParticipantsComponent.ExpandedVideoState( - mainParticipant: expandedParticipantsVideoState.mainParticipant, - isMainParticipantPinned: expandedParticipantsVideoState.isMainParticipantPinned, - isUIHidden: !expandedParticipantsVideoState.isUIHidden - ) - self.state?.updated(transition: .spring(duration: 0.4)) - } else { - - } + self.isTwoColumnSidebarHidden = !self.isTwoColumnSidebarHidden + self.state?.updated(transition: .spring(duration: 0.4)) } )), environment: {}, @@ -2535,12 +2549,18 @@ private final class VideoChatScreenComponent: Component { ) let navigationSidebarButtonFrame = CGRect(origin: CGPoint(x: navigationRightButtonFrame.minX - 32.0 - navigationSidebarButtonSize.width, y: topInset + floor((navigationBarHeight - navigationSidebarButtonSize.height) * 0.5)), size: navigationSidebarButtonSize) if let navigationSidebarButtonView = navigationSidebarButton.view { + var animateIn = false if navigationSidebarButtonView.superview == nil { + animateIn = true if let navigationRightButtonView = self.navigationRightButton.view { self.containerView.insertSubview(navigationSidebarButtonView, aboveSubview: navigationRightButtonView) } } - transition.setFrame(view: navigationSidebarButtonView, frame: navigationSidebarButtonFrame) + navigationSidebarButtonTransition.setFrame(view: navigationSidebarButtonView, frame: navigationSidebarButtonFrame) + if animateIn { + transition.animateScale(view: navigationSidebarButtonView, from: 0.001, to: 1.0) + transition.animateAlpha(view: navigationSidebarButtonView, from: 0.0, to: 1.0) + } } } else if let navigationSidebarButton = self.navigationSidebarButton { self.navigationSidebarButton = nil @@ -2572,6 +2592,7 @@ private final class VideoChatScreenComponent: Component { let titleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) * 0.5), y: topInset + floor((navigationBarHeight - titleSize.height) * 0.5)), size: titleSize) if let titleView = self.title.view { if titleView.superview == nil { + titleView.isUserInteractionEnabled = false self.containerView.addSubview(titleView) } transition.setFrame(view: titleView, frame: titleFrame) @@ -2629,8 +2650,18 @@ private final class VideoChatScreenComponent: Component { var collapsedMicrophoneButtonFrame: CGRect = CGRect(origin: CGPoint(x: floor((availableSize.width - collapsedMicrophoneButtonDiameter) * 0.5), y: availableSize.height - 48.0 - environment.safeInsets.bottom - collapsedMicrophoneButtonDiameter), size: CGSize(width: collapsedMicrophoneButtonDiameter, height: collapsedMicrophoneButtonDiameter)) var expandedMicrophoneButtonFrame: CGRect = CGRect(origin: CGPoint(x: floor((availableSize.width - expandedMicrophoneButtonDiameter) * 0.5), y: availableSize.height - environment.safeInsets.bottom - expandedMicrophoneButtonDiameter - 12.0), size: CGSize(width: expandedMicrophoneButtonDiameter, height: expandedMicrophoneButtonDiameter)) + + var isMainColumnHidden = false if isTwoColumnLayout { if let expandedParticipantsVideoState = self.expandedParticipantsVideoState, expandedParticipantsVideoState.isUIHidden { + isMainColumnHidden = true + } else if self.isTwoColumnSidebarHidden { + isMainColumnHidden = true + } + } + + if isTwoColumnLayout { + if isMainColumnHidden { collapsedMicrophoneButtonFrame.origin.x = availableSize.width - sideInset - mainColumnWidth + floor((mainColumnWidth - collapsedMicrophoneButtonDiameter) * 0.5) + sideInset + mainColumnWidth } else { collapsedMicrophoneButtonFrame.origin.x = availableSize.width - sideInset - mainColumnWidth + floor((mainColumnWidth - collapsedMicrophoneButtonDiameter) * 0.5) @@ -2682,7 +2713,8 @@ private final class VideoChatScreenComponent: Component { width: mainColumnWidth, insets: mainColumnInsets ), - columnSpacing: columnSpacing + columnSpacing: columnSpacing, + isMainColumnHidden: self.isTwoColumnSidebarHidden ) } else { let mainColumnInsets: UIEdgeInsets = UIEdgeInsets(top: navigationHeight, left: mainColumnSideInset, bottom: availableSize.height - collapsedParticipantsClippingY, right: mainColumnSideInset) @@ -2692,7 +2724,8 @@ private final class VideoChatScreenComponent: Component { width: mainColumnWidth, insets: mainColumnInsets ), - columnSpacing: columnSpacing + columnSpacing: columnSpacing, + isMainColumnHidden: false ) } @@ -2738,7 +2771,7 @@ private final class VideoChatScreenComponent: Component { } self.openParticipantContextMenu(id: id, sourceView: sourceView, gesture: gesture) }, - updateMainParticipant: { [weak self] key in + updateMainParticipant: { [weak self] key, alsoSetIsUIHidden in guard let self else { return } @@ -2746,7 +2779,13 @@ private final class VideoChatScreenComponent: Component { if let expandedParticipantsVideoState = self.expandedParticipantsVideoState, expandedParticipantsVideoState.mainParticipant == key { return } - self.expandedParticipantsVideoState = VideoChatParticipantsComponent.ExpandedVideoState(mainParticipant: key, isMainParticipantPinned: false, isUIHidden: self.expandedParticipantsVideoState?.isUIHidden ?? false) + + var isUIHidden = self.expandedParticipantsVideoState?.isUIHidden ?? false + if let alsoSetIsUIHidden { + isUIHidden = alsoSetIsUIHidden + } + + self.expandedParticipantsVideoState = VideoChatParticipantsComponent.ExpandedVideoState(mainParticipant: key, isMainParticipantPinned: false, isUIHidden: isUIHidden) self.state?.updated(transition: .spring(duration: 0.4)) } else if self.expandedParticipantsVideoState != nil { self.expandedParticipantsVideoState = nil