Merge branch 'master' into beta

This commit is contained in:
Ali 2020-12-12 18:13:11 +04:00
commit 5229966849
13 changed files with 318 additions and 126 deletions

View File

@ -93,6 +93,10 @@ public let listViewAnimationCurveLinear: (CGFloat) -> CGFloat = { t in
return t
}
public let listViewAnimationCurveEaseInOut: (CGFloat) -> CGFloat = { t in
return bezierPoint(0.42, 0.0, 0.58, 1.0, t)
}
#if os(iOS)
public func listViewAnimationCurveFromAnimationOptions(animationOptions: UIView.AnimationOptions) -> (CGFloat) -> CGFloat {
if animationOptions.rawValue == UInt(7 << 16) {

View File

@ -119,6 +119,10 @@ open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode {
final let wantsScrollDynamics: Bool
open var preferredAnimationCurve: (CGFloat) -> CGFloat {
return listViewAnimationCurveSystem
}
public final var wantsTrailingItemSpaceUpdates: Bool = false
public final var scrollPositioningInsets: UIEdgeInsets = UIEdgeInsets()
@ -427,7 +431,7 @@ open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode {
}
public func addHeightAnimation(_ value: CGFloat, duration: Double, beginAt: Double, update: ((CGFloat, CGFloat) -> Void)? = nil) {
let animation = ListViewAnimation(from: self.bounds.height, to: value, duration: duration, curve: listViewAnimationCurveSystem, beginAt: beginAt, update: { [weak self] progress, currentValue in
let animation = ListViewAnimation(from: self.bounds.height, to: value, duration: duration, curve: self.preferredAnimationCurve, beginAt: beginAt, update: { [weak self] progress, currentValue in
if let strongSelf = self {
let frame = strongSelf.frame
strongSelf.frame = CGRect(origin: frame.origin, size: CGSize(width: frame.width, height: currentValue))
@ -461,7 +465,7 @@ open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode {
}
public func addApparentHeightAnimation(_ value: CGFloat, duration: Double, beginAt: Double, update: ((CGFloat, CGFloat) -> Void)? = nil) {
let animation = ListViewAnimation(from: self.apparentHeight, to: value, duration: duration, curve: listViewAnimationCurveSystem, beginAt: beginAt, update: { [weak self] progress, currentValue in
let animation = ListViewAnimation(from: self.apparentHeight, to: value, duration: duration, curve: self.preferredAnimationCurve, beginAt: beginAt, update: { [weak self] progress, currentValue in
if let strongSelf = self {
strongSelf.apparentHeight = currentValue
if let update = update {
@ -494,7 +498,7 @@ open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode {
}
public func addTransitionOffsetAnimation(_ value: CGFloat, duration: Double, beginAt: Double) {
let animation = ListViewAnimation(from: self.transitionOffset, to: value, duration: duration, curve: listViewAnimationCurveSystem, beginAt: beginAt, update: { [weak self] _, currentValue in
let animation = ListViewAnimation(from: self.transitionOffset, to: value, duration: duration, curve: self.preferredAnimationCurve, beginAt: beginAt, update: { [weak self] _, currentValue in
if let strongSelf = self {
strongSelf.transitionOffset = currentValue
}

View File

@ -528,7 +528,18 @@
videoComposition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
}
AVAssetReaderVideoCompositionOutput *output = [[AVAssetReaderVideoCompositionOutput alloc] initWithVideoTracks:[composition tracksWithMediaType:AVMediaTypeVideo] videoSettings:@{ (id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) }];
NSDictionary *settings = [TGMediaVideoConversionPresetSettings videoSettingsForPreset:preset dimensions:outputDimensions];
*outputSettings = settings;
*dimensions = outputDimensions;
NSMutableDictionary *videoSettings = [[NSMutableDictionary alloc] init];
videoSettings[(id)kCVPixelBufferPixelFormatTypeKey] = @(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);
#if TARGET_IPHONE_SIMULATOR
#else
videoSettings[AVVideoColorPropertiesKey] = settings[AVVideoColorPropertiesKey];
#endif
AVAssetReaderVideoCompositionOutput *output = [[AVAssetReaderVideoCompositionOutput alloc] initWithVideoTracks:[composition tracksWithMediaType:AVMediaTypeVideo] videoSettings:videoSettings];
output.videoComposition = videoComposition;
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:composition];
@ -543,9 +554,6 @@
return [context addImageGenerator:imageGenerator];
}];
*outputSettings = [TGMediaVideoConversionPresetSettings videoSettingsForPreset:preset dimensions:outputDimensions];
*dimensions = outputDimensions;
return output;
}
@ -1315,6 +1323,14 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
AVVideoPixelAspectRatioKey: videoAspectRatioSettings
};
NSDictionary *hdVideoProperties = @
{
AVVideoColorPrimariesKey: AVVideoColorPrimaries_ITU_R_709_2,
AVVideoTransferFunctionKey: AVVideoTransferFunction_ITU_R_709_2,
AVVideoYCbCrMatrixKey: AVVideoYCbCrMatrix_ITU_R_709_2,
};
#if TARGET_IPHONE_SIMULATOR
return @
{
AVVideoCodecKey: AVVideoCodecH264,
@ -1322,6 +1338,15 @@ static CGFloat progressOfSampleBufferInTimeRange(CMSampleBufferRef sampleBuffer,
AVVideoWidthKey: @((NSInteger)dimensions.width),
AVVideoHeightKey: @((NSInteger)dimensions.height)
};
#endif
return @
{
AVVideoCodecKey: AVVideoCodecH264,
AVVideoCompressionPropertiesKey: codecSettings,
AVVideoWidthKey: @((NSInteger)dimensions.width),
AVVideoHeightKey: @((NSInteger)dimensions.height),
AVVideoColorPropertiesKey: hdVideoProperties
};
}
+ (NSInteger)_videoBitrateKbpsForPreset:(TGMediaVideoConversionPreset)preset

View File

@ -14,6 +14,7 @@ import AnimatedCountLabelNode
private let blue = UIColor(rgb: 0x0078ff)
private let lightBlue = UIColor(rgb: 0x59c7f8)
private let green = UIColor(rgb: 0x33c659)
private let activeBlue = UIColor(rgb: 0x00a0b9)
private class CallStatusBarBackgroundNode: ASDisplayNode {
private let foregroundView: UIView
@ -46,7 +47,7 @@ private class CallStatusBarBackgroundNode: ASDisplayNode {
let initialColors = self.foregroundGradientLayer.colors
let targetColors: [CGColor]
if let speaking = self.speaking {
targetColors = speaking ? [green.cgColor, blue.cgColor] : [blue.cgColor, lightBlue.cgColor]
targetColors = speaking ? [green.cgColor, activeBlue.cgColor] : [blue.cgColor, lightBlue.cgColor]
} else {
targetColors = [connectingColor.cgColor, connectingColor.cgColor]
}
@ -159,6 +160,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
private let backgroundNode: CallStatusBarBackgroundNode
private let titleNode: ImmediateTextNode
private let subtitleNode: ImmediateAnimatedCountLabelNode
private let speakerNode: ImmediateTextNode
private let audioLevelDisposable = MetaDisposable()
private let stateDisposable = MetaDisposable()
@ -175,6 +177,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
private var currentCallState: PresentationCallState?
private var currentGroupCallState: PresentationGroupCallSummaryState?
private var currentIsMuted = true
private var currentMembers: PresentationGroupCallMembers?
private var currentIsConnected = true
public override init() {
@ -182,12 +185,14 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
self.titleNode = ImmediateTextNode()
self.subtitleNode = ImmediateAnimatedCountLabelNode()
self.subtitleNode.reverseAnimationDirection = true
self.speakerNode = ImmediateTextNode()
super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.titleNode)
self.addSubnode(self.subtitleNode)
self.addSubnode(self.speakerNode)
}
deinit {
@ -264,16 +269,20 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
(combineLatest(
account.postbox.peerView(id: call.peerId),
call.summaryState,
call.isMuted
call.isMuted,
call.members
)
|> deliverOnMainQueue).start(next: { [weak self] view, state, isMuted in
|> deliverOnMainQueue).start(next: { [weak self] view, state, isMuted, members in
if let strongSelf = self {
strongSelf.currentPeer = view.peers[view.peerId]
strongSelf.currentGroupCallState = state
strongSelf.currentMembers = members
var isMuted = isMuted
if let state = state, state.callState.muteState != nil {
isMuted = true
if let state = state, let muteState = state.callState.muteState {
if !muteState.canUnmute {
isMuted = true
}
}
strongSelf.currentIsMuted = isMuted
@ -294,17 +303,18 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
return
}
var effectiveLevel: Float = 0.0
var audioLevels = audioLevels
if !strongSelf.currentIsMuted {
effectiveLevel = myAudioLevel
} else {
effectiveLevel = audioLevels.map { $0.1 }.max() ?? 0.0
audioLevels.append((PeerId(0), myAudioLevel, true))
}
effectiveLevel = audioLevels.map { $0.1 }.max() ?? 0.0
strongSelf.backgroundNode.audioLevel = effectiveLevel
}))
}
}
var title: String = ""
var speakerSubtitle: String = ""
let textFont = Font.regular(13.0)
let textColor = UIColor.white
@ -321,6 +331,21 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
membersCount = 1
}
var speakingPeer: Peer?
if let members = currentMembers {
var speakingPeers: [Peer] = []
for member in members.participants {
if members.speakingParticipants.contains(member.peer.id) {
speakingPeers.append(member.peer)
}
}
speakingPeer = speakingPeers.first
}
if let speakingPeer = speakingPeer {
speakerSubtitle = speakingPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
}
if let membersCount = membersCount {
var membersPart = presentationData.strings.VoiceChat_Status_Members(membersCount)
if let startIndex = membersPart.firstIndex(of: "["), let endIndex = membersPart.firstIndex(of: "]") {
@ -371,15 +396,24 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
self.backgroundNode.connectingColor = color
}
if self.subtitleNode.segments != segments {
if self.subtitleNode.segments != segments && speakerSubtitle.isEmpty {
self.subtitleNode.segments = segments
}
let alphaTransition: ContainedViewLayoutTransition = .animated(duration: 0.2, curve: .easeInOut)
alphaTransition.updateAlpha(node: self.subtitleNode, alpha: !speakerSubtitle.isEmpty ? 0.0 : 1.0)
alphaTransition.updateAlpha(node: self.speakerNode, alpha: !speakerSubtitle.isEmpty ? 1.0 : 0.0)
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(13.0), textColor: .white)
if !speakerSubtitle.isEmpty {
self.speakerNode.attributedText = NSAttributedString(string: speakerSubtitle, font: Font.regular(13.0), textColor: .white)
}
let spacing: CGFloat = 5.0
let titleSize = self.titleNode.updateLayout(CGSize(width: 160.0, height: size.height))
let subtitleSize = self.subtitleNode.updateLayout(size: CGSize(width: 160.0, height: size.height), animated: true)
let speakerSize = self.speakerNode.updateLayout(CGSize(width: 160.0, height: size.height))
let totalWidth = titleSize.width + spacing + subtitleSize.width
let horizontalOrigin: CGFloat = floor((size.width - totalWidth) / 2.0)
@ -391,6 +425,10 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: horizontalOrigin, y: verticalOrigin + floor((contentHeight - titleSize.height) / 2.0)), size: titleSize))
transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(x: horizontalOrigin + titleSize.width + spacing, y: verticalOrigin + floor((contentHeight - subtitleSize.height) / 2.0)), size: subtitleSize))
if !speakerSubtitle.isEmpty {
self.speakerNode.frame = CGRect(origin: CGPoint(x: horizontalOrigin + titleSize.width + spacing, y: verticalOrigin + floor((contentHeight - speakerSize.height) / 2.0)), size: speakerSize)
}
self.backgroundNode.speaking = self.currentIsConnected ? !self.currentIsMuted : nil
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height + 18.0))
}

View File

@ -14,6 +14,7 @@ private let secondaryGreyColor = UIColor(rgb: 0x1c1c1e)
private let blue = UIColor(rgb: 0x0078ff)
private let lightBlue = UIColor(rgb: 0x59c7f8)
private let green = UIColor(rgb: 0x33c659)
private let activeBlue = UIColor(rgb: 0x00a0b9)
private let areaSize = CGSize(width: 440.0, height: 440.0)
private let blobSize = CGSize(width: 244.0, height: 244.0)
@ -205,8 +206,6 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode {
let iconSize = CGSize(width: 90.0, height: 90.0)
self.iconNode.bounds = CGRect(origin: CGPoint(), size: iconSize)
self.iconNode.position = CGPoint(x: size.width / 2.0, y: size.height / 2.0)
self.wasActiveWhenPressed = false
}
private func applyIconParams() {
@ -520,8 +519,10 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
} else {
let previousValue = self.foregroundGradientLayer.startPoint
let newValue: CGPoint
if self.maskBlobView.presentationAudioLevel > 0.15 {
newValue = CGPoint(x: CGFloat.random(in: 0.8 ..< 1.0), y: CGFloat.random(in: 0.1 ..< 0.45))
if self.maskBlobView.presentationAudioLevel > 0.22 {
newValue = CGPoint(x: CGFloat.random(in: 0.9 ..< 1.0), y: CGFloat.random(in: 0.1 ..< 0.35))
} else if self.maskBlobView.presentationAudioLevel > 0.01 {
newValue = CGPoint(x: CGFloat.random(in: 0.77 ..< 0.95), y: CGFloat.random(in: 0.1 ..< 0.35))
} else {
newValue = CGPoint(x: CGFloat.random(in: 0.65 ..< 0.85), y: CGFloat.random(in: 0.1 ..< 0.45))
}
@ -626,7 +627,7 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
let targetScale: CGFloat
if let active = active {
if active {
targetColors = [blue.cgColor, green.cgColor]
targetColors = [activeBlue.cgColor, green.cgColor]
targetScale = 0.89
outerColor = UIColor(rgb: 0x21674f)
} else {

View File

@ -257,4 +257,8 @@ class VoiceChatActionItemNode: ListViewItemNode {
override public func header() -> ListViewItemHeader? {
return nil
}
override var preferredAnimationCurve: (CGFloat) -> CGFloat {
return listViewAnimationCurveEaseInOut
}
}

View File

@ -127,6 +127,8 @@ public final class VoiceChatController: ViewController {
let isLoading: Bool
let isEmpty: Bool
let crossFade: Bool
let count: Int
let isExpanded: Bool
let animated: Bool
}
@ -361,14 +363,14 @@ public final class VoiceChatController: ViewController {
}
}
private func preparedTransition(from fromEntries: [ListEntry], to toEntries: [ListEntry], isLoading: Bool, isEmpty: Bool, crossFade: Bool, context: AccountContext, presentationData: PresentationData, interaction: Interaction) -> ListTransition {
private func preparedTransition(from fromEntries: [ListEntry], to toEntries: [ListEntry], isLoading: Bool, isEmpty: Bool, crossFade: Bool, context: AccountContext, presentationData: PresentationData, interaction: Interaction, isExpanded: Bool) -> ListTransition {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
return ListTransition(deletions: deletions, insertions: insertions, updates: updates, isLoading: isLoading, isEmpty: isEmpty, crossFade: crossFade, animated: fromEntries.count != toEntries.count)
return ListTransition(deletions: deletions, insertions: insertions, updates: updates, isLoading: isLoading, isEmpty: isEmpty, crossFade: crossFade, count: toEntries.count, isExpanded: isExpanded, animated: true)
}
private weak var controller: VoiceChatController?
@ -412,6 +414,9 @@ public final class VoiceChatController: ViewController {
private var currentCallMembers: [GroupCallParticipantsContext.Participant]?
private var currentInvitedPeers: [Peer]?
private var currentSpeakingPeers: Set<PeerId>?
private var currentIsExpanded: Bool = false
private var currentContentOffset: CGFloat?
private var ignoreScrolling = false
private var accountPeer: Peer?
private var currentAudioButtonColor: UIColor?
@ -466,12 +471,11 @@ public final class VoiceChatController: ViewController {
self.backgroundNode = ASDisplayNode()
self.backgroundNode.backgroundColor = secondaryPanelBackgroundColor
self.backgroundNode.clipsToBounds = false
self.listNode = ListView()
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.clipsToBounds = false
@ -482,8 +486,11 @@ public final class VoiceChatController: ViewController {
self.topPanelEdgeNode = ASDisplayNode()
self.topPanelEdgeNode.backgroundColor = panelBackgroundColor
self.topPanelEdgeNode.layer.cornerRadius = 12.0
self.topPanelEdgeNode.cornerRadius = 12.0
self.topPanelEdgeNode.isUserInteractionEnabled = false
if #available(iOS 11.0, *) {
self.topPanelEdgeNode.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
}
self.optionsButton = VoiceChatHeaderButton()
self.optionsButton.setImage(optionsButtonImage(dark: false))
@ -516,10 +523,12 @@ public final class VoiceChatController: ViewController {
self.leftBorderNode = ASDisplayNode()
self.leftBorderNode.backgroundColor = panelBackgroundColor
self.leftBorderNode.isUserInteractionEnabled = false
self.leftBorderNode.clipsToBounds = false
self.rightBorderNode = ASDisplayNode()
self.rightBorderNode.backgroundColor = panelBackgroundColor
self.rightBorderNode.isUserInteractionEnabled = false
self.rightBorderNode.clipsToBounds = false
super.init()
@ -877,7 +886,7 @@ public final class VoiceChatController: ViewController {
}
}
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: callMembers?.participants ?? [], invitedPeers: invitedPeers, speakingPeers: callMembers?.speakingParticipants ?? [])
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: callMembers?.participants ?? [], invitedPeers: invitedPeers, speakingPeers: callMembers?.speakingParticipants ?? [], isExpanded: strongSelf.currentIsExpanded)
let subtitle = strongSelf.presentationData.strings.VoiceChat_Panel_Members(Int32(max(1, callMembers?.totalCount ?? 0)))
strongSelf.currentSubtitle = subtitle
@ -898,7 +907,7 @@ public final class VoiceChatController: ViewController {
}
if !strongSelf.didSetDataReady {
strongSelf.accountPeer = accountPeer
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: strongSelf.currentCallMembers ?? [], invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? Set())
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: strongSelf.currentCallMembers ?? [], invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? Set(), isExpanded: strongSelf.currentIsExpanded)
if let peer = peerViewMainPeer(view), let channel = peer as? TelegramChannel {
let addressName = channel.addressName ?? ""
@ -1090,6 +1099,7 @@ public final class VoiceChatController: ViewController {
self.listNode.updateFloatingHeaderOffset = { [weak self] offset, transition in
if let strongSelf = self {
strongSelf.currentContentOffset = offset
strongSelf.updateFloatingHeaderOffset(offset: offset, transition: transition)
}
}
@ -1098,10 +1108,27 @@ public final class VoiceChatController: ViewController {
guard let strongSelf = self else {
return
}
switch strongSelf.listNode.visibleContentOffset() {
if strongSelf.ignoreScrolling {
Queue.mainQueue().after(0.5) {
strongSelf.ignoreScrolling = false
}
}
}
self.listNode.visibleContentOffsetChanged = { [weak self] offset in
guard let strongSelf = self else {
return
}
switch offset {
case let .known(value):
if value <= -10.0 {
// strongSelf.controller?.dismiss()
// strongSelf.updateFloatingHeaderOffset(offset: -value + strongSelf.listNode.insets.top, transition: strongSelf.listNode.isTracking ? .immediate : .animated(duration: 0.4, curve: .linear))
if value > 5, !strongSelf.currentIsExpanded && strongSelf.listNode.isTracking && !strongSelf.ignoreScrolling {
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers:strongSelf.currentCallMembers ?? [], invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? Set(), isExpanded: true)
strongSelf.ignoreScrolling = true
} else if value < -5, strongSelf.currentIsExpanded && strongSelf.listNode.isTracking && !strongSelf.ignoreScrolling {
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: strongSelf.currentCallMembers ?? [], invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? [], isExpanded: false)
strongSelf.ignoreScrolling = true
}
default:
break
@ -1196,7 +1223,7 @@ public final class VoiceChatController: ViewController {
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .spring))
}
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? [], invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set())
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? [], invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set(), isExpanded: self.currentIsExpanded)
}
@objc private func actionButtonPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) {
@ -1241,7 +1268,7 @@ public final class VoiceChatController: ViewController {
if let (layout, navigationHeight) = self.validLayout {
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .spring))
}
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? [], invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set())
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? [], invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set(), isExpanded: self.currentIsExpanded)
default:
break
}
@ -1315,82 +1342,82 @@ public final class VoiceChatController: ViewController {
}
private func updateFloatingHeaderOffset(offset: CGFloat, transition: ContainedViewLayoutTransition) {
guard let (validLayout, _) = self.validLayout else {
guard let (layout, _) = self.validLayout else {
return
}
self.floatingHeaderOffset = offset
let layoutTopInset: CGFloat = max(validLayout.statusBarHeight ?? 0.0, validLayout.safeInsets.top)
let layoutTopInset: CGFloat = max(layout.statusBarHeight ?? 0.0, layout.safeInsets.top)
let topPanelHeight: CGFloat = 63.0
let listTopInset = layoutTopInset + topPanelHeight
let bottomAreaHeight: CGFloat = 268.0
let bottomPanelHeight = bottomAreaHeight + layout.intrinsicInsets.bottom
let listSize = CGSize(width: layout.size.width, height: layout.size.height - listTopInset - bottomPanelHeight)
let topInset = self.topInset ?? listSize.height
var offset = offset + topInset
self.floatingHeaderOffset = offset
let rawPanelOffset = offset + listTopInset - topPanelHeight
let panelOffset = max(layoutTopInset, rawPanelOffset)
let topPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: panelOffset), size: CGSize(width: validLayout.size.width, height: topPanelHeight))
let topPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: panelOffset), size: CGSize(width: layout.size.width, height: topPanelHeight))
let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: topPanelFrame.maxY), size: CGSize(width: layout.size.width, height: layout.size.height))
let sideInset: CGFloat = 16.0
let leftBorderFrame = CGRect(origin: CGPoint(x: 0.0, y: topPanelFrame.maxY - 16.0), size: CGSize(width: sideInset, height: layout.size.height))
let rightBorderFrame = CGRect(origin: CGPoint(x: layout.size.width - sideInset, y: topPanelFrame.maxY - 16.0), size: CGSize(width: sideInset, height: layout.size.height))
let previousTopPanelFrame = self.topPanelNode.frame
let previousBackgroundFrame = self.backgroundNode.frame
let previousLeftBorderFrame = self.leftBorderNode.frame
let previousRightBorderFrame = self.rightBorderNode.frame
if !topPanelFrame.equalTo(previousTopPanelFrame) {
self.topPanelNode.frame = topPanelFrame
let positionDelta = CGPoint(x: topPanelFrame.minX - previousTopPanelFrame.minX, y: topPanelFrame.minY - previousTopPanelFrame.minY)
let positionDelta = CGPoint(x: 0.0, y: topPanelFrame.minY - previousTopPanelFrame.minY)
transition.animateOffsetAdditive(node: self.topPanelNode, offset: positionDelta.y)
self.backgroundNode.frame = backgroundFrame
let backgroundPositionDelta = CGPoint(x: 0.0, y: previousBackgroundFrame.minY - backgroundFrame.minY)
transition.animatePositionAdditive(node: self.backgroundNode, offset: backgroundPositionDelta)
self.leftBorderNode.frame = leftBorderFrame
let leftBorderPositionDelta = CGPoint(x: 0.0, y: previousLeftBorderFrame.minY - leftBorderFrame.minY)
transition.animatePositionAdditive(node: self.leftBorderNode, offset: leftBorderPositionDelta)
self.rightBorderNode.frame = rightBorderFrame
let rightBorderPositionDelta = CGPoint(x: 0.0, y: previousRightBorderFrame.minY - rightBorderFrame.minY)
transition.animatePositionAdditive(node: self.rightBorderNode, offset: rightBorderPositionDelta)
}
self.topPanelBackgroundNode.frame = CGRect(x: 0.0, y: topPanelHeight - 24.0, width: validLayout.size.width, height: 24.0)
self.topPanelEdgeNode.frame = CGRect(x: 0.0, y: 0.0, width: validLayout.size.width, height: topPanelHeight)
let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: topPanelFrame.maxY), size: CGSize(width: validLayout.size.width, height: validLayout.size.height))
let sideInset: CGFloat = 16.0
let leftBorderFrame = CGRect(origin: CGPoint(x: 0.0, y: topPanelFrame.maxY - 16.0), size: CGSize(width: sideInset, height: validLayout.size.height))
let rightBorderFrame = CGRect(origin: CGPoint(x: validLayout.size.width - sideInset, y: topPanelFrame.maxY - 16.0), size: CGSize(width: sideInset, height: validLayout.size.height))
self.topPanelBackgroundNode.frame = CGRect(x: 0.0, y: topPanelHeight - 24.0, width: layout.size.width, height: 24.0)
var bottomEdge: CGFloat = 0.0
self.listNode.forEachItemNode { itemNode in
if let itemNode = itemNode as? ListViewItemNode {
let convertedFrame = self.listNode.view.convert(itemNode.apparentFrame, to: self.view)
let convertedFrame = self.listNode.view.convert(itemNode.frame, to: self.view)
if convertedFrame.maxY > bottomEdge {
bottomEdge = convertedFrame.maxY
}
}
}
let listMaxY = listTopInset + listSize.height
if bottomEdge.isZero {
bottomEdge = listMaxY
}
var bottomOffset: CGFloat = 0.0
if bottomEdge < self.listNode.frame.maxY {
bottomOffset = bottomEdge - self.listNode.frame.maxY
if bottomEdge < listMaxY {
bottomOffset = bottomEdge - listMaxY
}
let bottomCornersFrame = CGRect(origin: CGPoint(x: sideInset, y: -50.0 + bottomOffset), size: CGSize(width: validLayout.size.width - sideInset * 2.0, height: 50.0))
let bottomCornersFrame = CGRect(origin: CGPoint(x: sideInset, y: -50.0 + bottomOffset), size: CGSize(width: layout.size.width - sideInset * 2.0, height: 50.0))
let previousBottomCornersFrame = self.bottomCornersNode.frame
if !bottomCornersFrame.equalTo(previousBottomCornersFrame) {
self.bottomCornersNode.frame = bottomCornersFrame
self.bottomPanelBackgroundNode.frame = CGRect(x: 0.0, y: bottomOffset, width: validLayout.size.width, height: 2000.0)
self.bottomPanelBackgroundNode.frame = CGRect(x: 0.0, y: bottomOffset, width: layout.size.width, height: 2000.0)
let positionDelta = CGPoint(x: bottomCornersFrame.minX - previousBottomCornersFrame.minX, y: bottomCornersFrame.minY - previousBottomCornersFrame.minY)
transition.animateOffsetAdditive(node: self.bottomCornersNode, offset: positionDelta.y)
transition.animateOffsetAdditive(node: self.bottomPanelBackgroundNode, offset: positionDelta.y)
}
let previousBackgroundFrame = self.backgroundNode.frame
let previousLeftBorderFrame = self.leftBorderNode.frame
let previousRightBorderFrame = self.rightBorderNode.frame
self.updateColors(fullscreen: abs(panelOffset - layoutTopInset) < 1.0)
if !backgroundFrame.equalTo(previousBackgroundFrame) {
self.backgroundNode.frame = backgroundFrame
self.leftBorderNode.frame = leftBorderFrame
self.rightBorderNode.frame = rightBorderFrame
let backgroundPositionDelta = CGPoint(x: backgroundFrame.minX - previousBackgroundFrame.minX, y: backgroundFrame.minY - previousBackgroundFrame.minY)
transition.animateOffsetAdditive(node: self.backgroundNode, offset: backgroundPositionDelta.y)
let leftBorderPositionDelta = CGPoint(x: leftBorderFrame.minX - previousLeftBorderFrame.minX, y: leftBorderFrame.minY - previousLeftBorderFrame.minY)
transition.animateOffsetAdditive(node: self.leftBorderNode, offset: leftBorderPositionDelta.y)
let rightBorderPositionDelta = CGPoint(x: rightBorderFrame.minX - previousRightBorderFrame.minX, y: rightBorderFrame.minY - previousRightBorderFrame.minY)
transition.animateOffsetAdditive(node: self.rightBorderNode, offset: rightBorderPositionDelta.y)
let positionDelta = CGPoint(x: 0.0, y: previousBottomCornersFrame.minY - bottomCornersFrame.minY)
transition.animatePositionAdditive(node: self.bottomCornersNode, offset: positionDelta)
transition.animatePositionAdditive(node: self.bottomPanelBackgroundNode, offset: positionDelta)
}
}
@ -1405,8 +1432,22 @@ public final class VoiceChatController: ViewController {
let transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .linear)
// transition.updateCornerRadius(node: self.topPanelEdgeNode, cornerRadius: fullscreen ? layout.deviceMetrics.screenCornerRadius : 12.0)
transition.updateBackgroundColor(node: self.dimNode, color: fullscreen ? fullscreenBackgroundColor : dimColor)
let topPanelHeight: CGFloat = 63.0
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: layout.size.width, height: topPanelHeight + offset)
} else {
topEdgeFrame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: topPanelHeight)
}
transition.updateFrame(node: self.topPanelEdgeNode, frame: topEdgeFrame)
transition.updateCornerRadius(node: self.topPanelEdgeNode, cornerRadius: fullscreen ? layout.deviceMetrics.screenCornerRadius - 0.5 : 12.0)
// transition.updateBackgroundColor(node: self.dimNode, color: fullscreen ? fullscreenBackgroundColor : dimColor)
transition.updateBackgroundColor(node: self.topPanelBackgroundNode, color: fullscreen ? fullscreenBackgroundColor : panelBackgroundColor)
transition.updateBackgroundColor(node: self.topPanelEdgeNode, color: fullscreen ? fullscreenBackgroundColor : panelBackgroundColor)
transition.updateBackgroundColor(node: self.backgroundNode, color: fullscreen ? panelBackgroundColor : secondaryPanelBackgroundColor)
@ -1541,13 +1582,26 @@ public final class VoiceChatController: ViewController {
insets.left = layout.safeInsets.left + sideInset
insets.right = layout.safeInsets.right + sideInset
let topPanelHeight: CGFloat = 63.0
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: layout.size.width, height: topPanelHeight + offset)
} else {
topEdgeFrame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: topPanelHeight)
}
transition.updateFrame(node: self.topPanelEdgeNode, frame: topEdgeFrame)
let bottomPanelHeight = bottomAreaHeight + layout.intrinsicInsets.bottom
let listTopInset = layoutTopInset + 63.0
let listTopInset = layoutTopInset + topPanelHeight
let listSize = CGSize(width: layout.size.width, height: layout.size.height - listTopInset - bottomPanelHeight)
insets.top = max(0.0, listSize.height - 44.0 - floor(56.0 * 3.5))
transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(x: 0.0, y: listTopInset), size: listSize))
transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(x: 0.0, y: listTopInset + (self.topInset ?? listSize.height)), size: listSize))
let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition)
let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: listSize, insets: insets, duration: duration, curve: curve)
@ -1671,7 +1725,7 @@ public final class VoiceChatController: ViewController {
let topPanelFrame = self.topPanelNode.view.convert(self.topPanelNode.bounds, to: self.view)
self.contentContainer.layer.animateBoundsOriginYAdditive(from: self.contentContainer.bounds.origin.y, to: -(layout.size.height - topPanelFrame.minY), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
self.contentContainer.layer.animateBoundsOriginYAdditive(from: self.contentContainer.bounds.origin.y, to: -(layout.size.height - topPanelFrame.minY) - 44.0, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
offsetCompleted = true
internalCompletion()
})
@ -1688,15 +1742,18 @@ public final class VoiceChatController: ViewController {
}
}
private var topInset: CGFloat?
private var isFirstTime = true
private func dequeueTransition() {
guard let _ = self.validLayout, let transition = self.enqueuedTransitions.first else {
guard let (layout, _) = self.validLayout, let transition = self.enqueuedTransitions.first else {
return
}
self.enqueuedTransitions.remove(at: 0)
var options = ListViewDeleteAndInsertOptions()
if !isFirstTime {
if self.isFirstTime {
self.isFirstTime = false
} else {
if transition.crossFade {
options.insert(.AnimateCrossfade)
}
@ -1707,13 +1764,38 @@ public final class VoiceChatController: ViewController {
options.insert(.LowLatency)
options.insert(.PreferSynchronousResourceLoading)
var scrollToItem: ListViewScrollToItem?
if self.isFirstTime {
self.isFirstTime = false
scrollToItem = ListViewScrollToItem(index: 0, position: .bottom(0), animated: false, curve: .Default(duration: nil), directionHint: .Up)
}
var itemsHeight: CGFloat = 46.0 + CGFloat(transition.count - 1) * 56.0
let bottomAreaHeight: CGFloat = 268.0
let layoutTopInset: CGFloat = max(layout.statusBarHeight ?? 0.0, layout.safeInsets.top)
self.listNode.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, scrollToItem: scrollToItem, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { [weak self] _ in
let sideInset: CGFloat = 16.0
var insets = UIEdgeInsets()
insets.left = layout.safeInsets.left + sideInset
insets.right = layout.safeInsets.right + sideInset
let bottomPanelHeight = bottomAreaHeight + layout.intrinsicInsets.bottom
let listTopInset = layoutTopInset + 63.0
let listSize = CGSize(width: layout.size.width, height: layout.size.height - listTopInset - bottomPanelHeight)
let previousIsExpanded = self.currentIsExpanded
self.currentIsExpanded = transition.isExpanded
self.topInset = max(0.0, transition.isExpanded ? 0.0 : max(listSize.height - itemsHeight, listSize.height - 46.0 - floor(56.0 * 3.5)))
let frameTransition: ContainedViewLayoutTransition
if previousIsExpanded != self.currentIsExpanded {
frameTransition = .animated(duration: 0.4, curve: .spring)
} else {
frameTransition = .animated(duration: 0.4, curve: .easeInOut)
}
frameTransition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(x: 0.0, y: listTopInset + (self.topInset ?? listSize.height)), size: listSize))
let (duration, curve) = listViewAnimationDurationAndCurve(transition: frameTransition)
let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: listSize, insets: insets, duration: duration, curve: curve)
self.updateColors(fullscreen: transition.isExpanded)
self.listNode.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, updateOpaqueState: nil, completion: { [weak self] _ in
guard let strongSelf = self else {
return
}
@ -1722,9 +1804,12 @@ public final class VoiceChatController: ViewController {
strongSelf.controller?.contentsReady.set(true)
}
})
if previousIsExpanded != self.currentIsExpanded {
self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: frameTransition)
}
}
private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, callMembers: [GroupCallParticipantsContext.Participant], invitedPeers: [Peer], speakingPeers: Set<PeerId>) {
private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, callMembers: [GroupCallParticipantsContext.Participant], invitedPeers: [Peer], speakingPeers: Set<PeerId>, isExpanded: Bool) {
self.currentCallMembers = callMembers
self.currentSpeakingPeers = speakingPeers
self.currentInvitedPeers = invitedPeers
@ -1789,7 +1874,7 @@ public final class VoiceChatController: ViewController {
self.currentEntries = entries
let presentationData = self.presentationData.withUpdated(theme: self.darkTheme)
let transition = preparedTransition(from: previousEntries, to: entries, isLoading: false, isEmpty: false, crossFade: false, context: self.context, presentationData: presentationData, interaction: self.itemInteraction!)
let transition = preparedTransition(from: previousEntries, to: entries, isLoading: false, isEmpty: false, crossFade: false, context: self.context, presentationData: presentationData, interaction: self.itemInteraction!, isExpanded: isExpanded ?? self.currentIsExpanded)
self.enqueueTransition(transition)
}

View File

@ -56,20 +56,24 @@ public final class VoiceChatOverlayController: ViewController {
transition.updateSublayerTransformOffset(layer: actionButton.layer, offset: CGPoint(x: slideOffset, y: 0.0))
} else {
actionButton.layer.removeAllAnimations()
actionButton.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, completion: { [weak actionButton] _ in
actionButton?.isHidden = true
actionButton.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, completion: { [weak actionButton] finished in
if finished {
actionButton?.isHidden = true
}
})
}
} else {
actionButton.isHidden = false
if slide {
transition.updateSublayerTransformOffset(layer: actionButton.layer, offset: CGPoint())
} else {
actionButton.layer.removeAllAnimations()
actionButton.isHidden = false
actionButton.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4)
}
}
} else {
actionButton.isHidden = hidden
actionButton.layer.removeAllAnimations()
if hidden {
if slide {
actionButton.layer.sublayerTransform = CATransform3DMakeTranslation(slideOffset, 0.0, 0.0)

View File

@ -18,8 +18,8 @@ import AccountContext
import LegacyComponents
import AudioBlob
public final class VoiceChatParticipantItem: ListViewItem {
public enum ParticipantText {
final class VoiceChatParticipantItem: ListViewItem {
enum ParticipantText {
public enum TextColor {
case generic
case accent
@ -31,25 +31,25 @@ public final class VoiceChatParticipantItem: ListViewItem {
case none
}
public enum Icon {
enum Icon {
case none
case microphone(Bool, UIColor)
case invite(Bool)
}
public struct RevealOption {
public enum RevealOptionType {
struct RevealOption {
enum RevealOptionType {
case neutral
case warning
case destructive
case accent
}
public var type: RevealOptionType
public var title: String
public var action: () -> Void
var type: RevealOptionType
var title: String
var action: () -> Void
public init(type: RevealOptionType, title: String, action: @escaping () -> Void) {
init(type: RevealOptionType, title: String, action: @escaping () -> Void) {
self.type = type
self.title = title
self.action = action
@ -138,7 +138,7 @@ public final class VoiceChatParticipantItem: ListViewItem {
private let avatarFont = avatarPlaceholderFont(size: floor(40.0 * 16.0 / 37.0))
public class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
private let topStripeNode: ASDisplayNode
private let bottomStripeNode: ASDisplayNode
private let highlightedBackgroundNode: ASDisplayNode
@ -170,7 +170,7 @@ public class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
private var peerPresenceManager: PeerPresenceStatusManager?
private var layoutParams: (VoiceChatParticipantItem, ListViewItemLayoutParams, Bool, Bool)?
public init() {
init() {
self.topStripeNode = ASDisplayNode()
self.topStripeNode.isLayerBacked = true
@ -281,7 +281,7 @@ public class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
self.audioLevelDisposable.dispose()
}
public func asyncLayout() -> (_ item: VoiceChatParticipantItem, _ params: ListViewItemLayoutParams, _ first: Bool, _ last: Bool) -> (ListViewItemNodeLayout, (Bool, Bool) -> Void) {
func asyncLayout() -> (_ item: VoiceChatParticipantItem, _ params: ListViewItemLayoutParams, _ first: Bool, _ last: Bool) -> (ListViewItemNodeLayout, (Bool, Bool) -> Void) {
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
let makeStatusLayout = TextNode.asyncLayout(self.statusNode)
var currentDisabledOverlayNode = self.disabledOverlayNode
@ -706,7 +706,7 @@ public class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
}
}
override public func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
override func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
super.setHighlighted(highlighted, at: point, animated: animated)
self.isHighlighted = highlighted
@ -714,20 +714,19 @@ public class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
self.updateIsHighlighted(transition: (animated && !highlighted) ? .animated(duration: 0.3, curve: .easeInOut) : .immediate)
}
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
}
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
}
override public func header() -> ListViewItemHeader? {
override func header() -> ListViewItemHeader? {
return nil
}
override public func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
override func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
var rect = rect
rect.origin.y += self.insets.top
self.absoluteLocation = (rect, containerSize)
@ -739,7 +738,7 @@ public class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
}
}
override public func updateRevealOffset(offset: CGFloat, transition: ContainedViewLayoutTransition) {
override func updateRevealOffset(offset: CGFloat, transition: ContainedViewLayoutTransition) {
super.updateRevealOffset(offset: offset, transition: transition)
if let _ = self.layoutParams?.0, let params = self.layoutParams?.1 {
@ -761,19 +760,19 @@ public class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
}
}
override public func revealOptionsInteractivelyOpened() {
override func revealOptionsInteractivelyOpened() {
if let item = self.layoutParams?.0 {
item.setPeerIdWithRevealedOptions(item.peer.id, nil)
}
}
override public func revealOptionsInteractivelyClosed() {
override func revealOptionsInteractivelyClosed() {
if let item = self.layoutParams?.0 {
item.setPeerIdWithRevealedOptions(nil, item.peer.id)
}
}
override public func revealOptionSelected(_ option: ItemListRevealOption, animated: Bool) {
override func revealOptionSelected(_ option: ItemListRevealOption, animated: Bool) {
if let item = self.layoutParams?.0 {
item.revealOptions[Int(option.key)].action()
}
@ -781,4 +780,8 @@ public class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
self.setRevealOptionsOpened(false, animated: true)
self.revealOptionsInteractivelyClosed()
}
override var preferredAnimationCurve: (CGFloat) -> CGFloat {
return listViewAnimationCurveEaseInOut
}
}

View File

@ -955,6 +955,8 @@ public final class GroupCallParticipantsContext {
}
}
updatedTotalCount = max(updatedTotalCount, updatedParticipants.count)
var updatedOverlayState = strongSelf.stateValue.overlayState
for peerId in update.removePendingMuteStates {
updatedOverlayState.pendingMuteStateChanges.removeValue(forKey: peerId)

View File

@ -7071,7 +7071,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let controller = voiceChatOverlayController {
var hidden = false
if self.presentationInterfaceState.interfaceState.editMessage != nil || self.presentationInterfaceState.interfaceState.composeInputState.inputText.string.count > 0 {
if self.presentationInterfaceState.interfaceState.editMessage != nil || self.presentationInterfaceState.interfaceState.forwardMessageIds != nil || self.presentationInterfaceState.interfaceState.composeInputState.inputText.string.count > 0 {
hidden = true
}
controller.update(hidden: hidden, slide: false, animated: true)

View File

@ -12,6 +12,7 @@ import AccountContext
import StickerResources
import ContextUI
import Markdown
import ShimmerEffect
private let nameFont = Font.medium(14.0)
private let inlineBotPrefixFont = Font.regular(14.0)
@ -21,6 +22,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
private let contextSourceNode: ContextExtractedContentContainingNode
private let containerNode: ContextControllerSourceNode
let imageNode: TransformImageNode
private var placeholderNode: StickerShimmerEffectNode?
var textNode: TextNode?
private var swipeToReplyNode: ChatMessageSwipeToReplyNode?
@ -50,6 +52,8 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
self.contextSourceNode = ContextExtractedContentContainingNode()
self.containerNode = ContextControllerSourceNode()
self.imageNode = TransformImageNode()
self.placeholderNode = StickerShimmerEffectNode()
self.placeholderNode?.isUserInteractionEnabled = false
self.dateAndStatusNode = ChatMessageDateAndStatusNode()
super.init(layerBacked: false)
@ -96,6 +100,9 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
self.containerNode.addSubnode(self.contextSourceNode)
self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode
self.addSubnode(self.containerNode)
if let placeholderNode = self.placeholderNode {
self.contextSourceNode.contentNode.addSubnode(placeholderNode)
}
self.contextSourceNode.contentNode.addSubnode(self.imageNode)
self.contextSourceNode.contentNode.addSubnode(self.dateAndStatusNode)
@ -115,6 +122,21 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
self.fetchDisposable.dispose()
}
private func removePlaceholder(animated: Bool) {
if let placeholderNode = self.placeholderNode {
self.placeholderNode = nil
if !animated {
placeholderNode.removeFromSupernode()
} else {
placeholderNode.alpha = 0.0
placeholderNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak placeholderNode] _ in
placeholderNode?.removeFromSupernode()
})
}
}
}
override func didLoad() {
super.didLoad()

@ -1 +1 @@
Subproject commit f15d2311eb3998e38000eff15a634b74b4358655
Subproject commit 982b3456d0b18369f36e2b1e1438f40235a12eae