Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
overtake 2021-04-08 11:19:51 +04:00
commit a7d322999a
27 changed files with 133 additions and 70 deletions

Binary file not shown.

View File

@ -187,6 +187,7 @@ public struct PresentationGroupCallState: Equatable {
public var title: String? public var title: String?
public var raisedHand: Bool public var raisedHand: Bool
public var scheduleTimestamp: Int32? public var scheduleTimestamp: Int32?
public var subscribedToScheduled: Bool
public init( public init(
myPeerId: PeerId, myPeerId: PeerId,
@ -198,7 +199,8 @@ public struct PresentationGroupCallState: Equatable {
recordingStartTimestamp: Int32?, recordingStartTimestamp: Int32?,
title: String?, title: String?,
raisedHand: Bool, raisedHand: Bool,
scheduleTimestamp: Int32? scheduleTimestamp: Int32?,
subscribedToScheduled: Bool
) { ) {
self.myPeerId = myPeerId self.myPeerId = myPeerId
self.networkState = networkState self.networkState = networkState
@ -210,6 +212,7 @@ public struct PresentationGroupCallState: Equatable {
self.title = title self.title = title
self.raisedHand = raisedHand self.raisedHand = raisedHand
self.scheduleTimestamp = scheduleTimestamp self.scheduleTimestamp = scheduleTimestamp
self.subscribedToScheduled = subscribedToScheduled
} }
} }
@ -323,6 +326,7 @@ public protocol PresentationGroupCall: class {
var memberEvents: Signal<PresentationGroupCallMemberEvent, NoError> { get } var memberEvents: Signal<PresentationGroupCallMemberEvent, NoError> { get }
var reconnectedAsEvents: Signal<Peer, NoError> { get } var reconnectedAsEvents: Signal<Peer, NoError> { get }
func toggleScheduledSubscription(_ subscribe: Bool)
func schedule(timestamp: Int32) func schedule(timestamp: Int32)
func startScheduled() func startScheduled()

View File

@ -160,20 +160,20 @@ public final class CachedChannelData: CachedPeerData {
public var accessHash: Int64 public var accessHash: Int64
public var title: String? public var title: String?
public var scheduleTimestamp: Int32? public var scheduleTimestamp: Int32?
public var subscribed: Bool public var subscribedToScheduled: Bool
public init( public init(
id: Int64, id: Int64,
accessHash: Int64, accessHash: Int64,
title: String?, title: String?,
scheduleTimestamp: Int32?, scheduleTimestamp: Int32?,
subscribed: Bool subscribedToScheduled: Bool
) { ) {
self.id = id self.id = id
self.accessHash = accessHash self.accessHash = accessHash
self.title = title self.title = title
self.scheduleTimestamp = scheduleTimestamp self.scheduleTimestamp = scheduleTimestamp
self.subscribed = subscribed self.subscribedToScheduled = subscribedToScheduled
} }
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
@ -181,7 +181,7 @@ public final class CachedChannelData: CachedPeerData {
self.accessHash = decoder.decodeInt64ForKey("accessHash", orElse: 0) self.accessHash = decoder.decodeInt64ForKey("accessHash", orElse: 0)
self.title = decoder.decodeOptionalStringForKey("title") self.title = decoder.decodeOptionalStringForKey("title")
self.scheduleTimestamp = decoder.decodeOptionalInt32ForKey("scheduleTimestamp") self.scheduleTimestamp = decoder.decodeOptionalInt32ForKey("scheduleTimestamp")
self.subscribed = decoder.decodeBoolForKey("subscribed", orElse: false) self.subscribedToScheduled = decoder.decodeBoolForKey("subscribed", orElse: false)
} }
public func encode(_ encoder: PostboxEncoder) { public func encode(_ encoder: PostboxEncoder) {
@ -197,7 +197,7 @@ public final class CachedChannelData: CachedPeerData {
} else { } else {
encoder.encodeNil(forKey: "scheduleTimestamp") encoder.encodeNil(forKey: "scheduleTimestamp")
} }
encoder.encodeBool(self.subscribed, forKey: "subscribed") encoder.encodeBool(self.subscribedToScheduled, forKey: "subscribed")
} }
} }

View File

@ -406,7 +406,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
strongSelf.joinGroupCall( strongSelf.joinGroupCall(
peerId: groupCallPanelData.peerId, peerId: groupCallPanelData.peerId,
invite: nil, invite: nil,
activeCall: CachedChannelData.ActiveCall(id: groupCallPanelData.info.id, accessHash: groupCallPanelData.info.accessHash, title: groupCallPanelData.info.title, scheduleTimestamp: groupCallPanelData.info.scheduleTimestamp, subscribed: false) activeCall: CachedChannelData.ActiveCall(id: groupCallPanelData.info.id, accessHash: groupCallPanelData.info.accessHash, title: groupCallPanelData.info.title, scheduleTimestamp: groupCallPanelData.info.scheduleTimestamp, subscribedToScheduled: groupCallPanelData.info.subscribedToScheduled)
) )
}) })
if let navigationBar = self.navigationBar { if let navigationBar = self.navigationBar {

View File

@ -505,7 +505,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
transition.updateFrame(node: self.avatarsNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - avatarsSize.width) / 2.0), y: floor((size.height - avatarsSize.height) / 2.0)), size: avatarsSize)) transition.updateFrame(node: self.avatarsNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - avatarsSize.width) / 2.0), y: floor((size.height - avatarsSize.height) / 2.0)), size: avatarsSize))
} }
var joinText = self.strings.VoiceChat_PanelJoin.uppercased() var joinText = self.strings.VoiceChat_PanelJoin
var title = self.strings.VoiceChat_Title var title = self.strings.VoiceChat_Title
var text = self.currentText var text = self.currentText
var isScheduled = false var isScheduled = false
@ -554,7 +554,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
self.updateJoinButton() self.updateJoinButton()
} }
self.joinButtonTitleNode.attributedText = NSAttributedString(string: joinText, font: Font.with(size: 15.0, design: .round, weight: .semibold, traits: [.monospacedNumbers]), textColor: self.theme.chat.inputPanel.actionControlForegroundColor) self.joinButtonTitleNode.attributedText = NSAttributedString(string: joinText.uppercased(), font: Font.with(size: 15.0, design: .round, weight: .semibold, traits: [.monospacedNumbers]), textColor: self.theme.chat.inputPanel.actionControlForegroundColor)
let joinButtonTitleSize = self.joinButtonTitleNode.updateLayout(CGSize(width: 150.0, height: .greatestFiniteMagnitude)) let joinButtonTitleSize = self.joinButtonTitleNode.updateLayout(CGSize(width: 150.0, height: .greatestFiniteMagnitude))
let joinButtonSize = CGSize(width: joinButtonTitleSize.width + 20.0, height: 28.0) let joinButtonSize = CGSize(width: joinButtonTitleSize.width + 20.0, height: 28.0)

View File

@ -78,6 +78,7 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext {
streamDcId: nil, streamDcId: nil,
title: call.title, title: call.title,
scheduleTimestamp: call.scheduleTimestamp, scheduleTimestamp: call.scheduleTimestamp,
subscribedToScheduled: call.subscribedToScheduled,
recordingStartTimestamp: nil, recordingStartTimestamp: nil,
sortAscending: true sortAscending: true
), ),
@ -121,7 +122,7 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext {
} }
return GroupCallPanelData( return GroupCallPanelData(
peerId: peerId, peerId: peerId,
info: GroupCallInfo(id: call.id, accessHash: call.accessHash, participantCount: state.totalCount, clientParams: nil, streamDcId: nil, title: state.title, scheduleTimestamp: state.scheduleTimestamp, recordingStartTimestamp: nil, sortAscending: state.sortAscending), info: GroupCallInfo(id: call.id, accessHash: call.accessHash, participantCount: state.totalCount, clientParams: nil, streamDcId: nil, title: state.title, scheduleTimestamp: state.scheduleTimestamp, subscribedToScheduled: state.subscribedToScheduled, recordingStartTimestamp: nil, sortAscending: state.sortAscending),
topParticipants: topParticipants, topParticipants: topParticipants,
participantCount: state.totalCount, participantCount: state.totalCount,
activeSpeakers: activeSpeakers, activeSpeakers: activeSpeakers,
@ -206,7 +207,7 @@ public final class AccountGroupCallContextCacheImpl: AccountGroupCallContextCach
} }
private extension PresentationGroupCallState { private extension PresentationGroupCallState {
static func initialValue(myPeerId: PeerId, title: String?, scheduleTimestamp: Int32?) -> PresentationGroupCallState { static func initialValue(myPeerId: PeerId, title: String?, scheduleTimestamp: Int32?, subscribedToScheduled: Bool) -> PresentationGroupCallState {
return PresentationGroupCallState( return PresentationGroupCallState(
myPeerId: myPeerId, myPeerId: myPeerId,
networkState: .connecting, networkState: .connecting,
@ -217,7 +218,8 @@ private extension PresentationGroupCallState {
recordingStartTimestamp: nil, recordingStartTimestamp: nil,
title: title, title: title,
raisedHand: false, raisedHand: false,
scheduleTimestamp: scheduleTimestamp scheduleTimestamp: scheduleTimestamp,
subscribedToScheduled: subscribedToScheduled
) )
} }
} }
@ -511,6 +513,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
private let joinDisposable = MetaDisposable() private let joinDisposable = MetaDisposable()
private let requestDisposable = MetaDisposable() private let requestDisposable = MetaDisposable()
private let startDisposable = MetaDisposable() private let startDisposable = MetaDisposable()
private let subscribeDisposable = MetaDisposable()
private var groupCallParticipantUpdatesDisposable: Disposable? private var groupCallParticipantUpdatesDisposable: Disposable?
private let networkStateDisposable = MetaDisposable() private let networkStateDisposable = MetaDisposable()
@ -579,7 +582,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
self.joinAsPeerId = joinAsPeerId ?? accountContext.account.peerId self.joinAsPeerId = joinAsPeerId ?? accountContext.account.peerId
self.schedulePending = initialCall == nil self.schedulePending = initialCall == nil
self.stateValue = PresentationGroupCallState.initialValue(myPeerId: self.joinAsPeerId, title: initialCall?.title, scheduleTimestamp: initialCall?.scheduleTimestamp) self.stateValue = PresentationGroupCallState.initialValue(myPeerId: self.joinAsPeerId, title: initialCall?.title, scheduleTimestamp: initialCall?.scheduleTimestamp, subscribedToScheduled: initialCall?.subscribedToScheduled ?? false)
self.statePromise = ValuePromise(self.stateValue) self.statePromise = ValuePromise(self.stateValue)
self.temporaryJoinTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) self.temporaryJoinTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
@ -734,7 +737,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
addedParticipants.append((ssrc, participantUpdate.jsonParams)) addedParticipants.append((ssrc, participantUpdate.jsonParams))
} }
} }
case let .call(isTerminated, _, _, _): case let .call(isTerminated, _, _, _, _):
if isTerminated { if isTerminated {
strongSelf.markAsCanBeRemoved() strongSelf.markAsCanBeRemoved()
} }
@ -767,7 +770,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
}) })
if let initialCall = initialCall, let temporaryParticipantsContext = (self.accountContext.cachedGroupCallContexts as? AccountGroupCallContextCacheImpl)?.impl.syncWith({ impl in if let initialCall = initialCall, let temporaryParticipantsContext = (self.accountContext.cachedGroupCallContexts as? AccountGroupCallContextCacheImpl)?.impl.syncWith({ impl in
impl.get(account: accountContext.account, peerId: peerId, call: CachedChannelData.ActiveCall(id: initialCall.id, accessHash: initialCall.accessHash, title: initialCall.title, scheduleTimestamp: initialCall.scheduleTimestamp, subscribed: initialCall.subscribed)) impl.get(account: accountContext.account, peerId: peerId, call: CachedChannelData.ActiveCall(id: initialCall.id, accessHash: initialCall.accessHash, title: initialCall.title, scheduleTimestamp: initialCall.scheduleTimestamp, subscribedToScheduled: initialCall.subscribedToScheduled))
}) { }) {
self.switchToTemporaryParticipantsContext(sourceContext: temporaryParticipantsContext.context.participantsContext, oldMyPeerId: self.joinAsPeerId) self.switchToTemporaryParticipantsContext(sourceContext: temporaryParticipantsContext.context.participantsContext, oldMyPeerId: self.joinAsPeerId)
} else { } else {
@ -824,6 +827,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
self.joinDisposable.dispose() self.joinDisposable.dispose()
self.requestDisposable.dispose() self.requestDisposable.dispose()
self.startDisposable.dispose() self.startDisposable.dispose()
self.subscribeDisposable.dispose()
self.groupCallParticipantUpdatesDisposable?.dispose() self.groupCallParticipantUpdatesDisposable?.dispose()
self.leaveDisposable.dispose() self.leaveDisposable.dispose()
self.isMutedDisposable.dispose() self.isMutedDisposable.dispose()
@ -1666,6 +1670,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
streamDcId: nil, streamDcId: nil,
title: state.title, title: state.title,
scheduleTimestamp: state.scheduleTimestamp, scheduleTimestamp: state.scheduleTimestamp,
subscribedToScheduled: false,
recordingStartTimestamp: state.recordingStartTimestamp, recordingStartTimestamp: state.recordingStartTimestamp,
sortAscending: state.sortAscending sortAscending: state.sortAscending
)))) ))))
@ -1987,6 +1992,17 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
self.callContext?.setIsNoiseSuppressionEnabled(isNoiseSuppressionEnabled) self.callContext?.setIsNoiseSuppressionEnabled(isNoiseSuppressionEnabled)
} }
public func toggleScheduledSubscription(_ subscribe: Bool) {
guard case let .active(callInfo) = self.internalState, callInfo.scheduleTimestamp != nil else {
return
}
self.stateValue.subscribedToScheduled = subscribe
self.subscribeDisposable.set((toggleScheduledGroupCallSubscription(account: self.account, peerId: self.peerId, callId: callInfo.id, accessHash: callInfo.accessHash, subscribe: subscribe)
|> deliverOnMainQueue).start())
}
public func schedule(timestamp: Int32) { public func schedule(timestamp: Int32) {
guard self.schedulePending else { guard self.schedulePending else {
return return
@ -2270,7 +2286,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
} }
if let value = value { if let value = value {
strongSelf.initialCall = CachedChannelData.ActiveCall(id: value.id, accessHash: value.accessHash, title: value.title, scheduleTimestamp: nil, subscribed: false) strongSelf.initialCall = CachedChannelData.ActiveCall(id: value.id, accessHash: value.accessHash, title: value.title, scheduleTimestamp: nil, subscribedToScheduled: false)
strongSelf.updateSessionState(internalState: .active(value), audioSessionControl: strongSelf.audioSessionControl) strongSelf.updateSessionState(internalState: .active(value), audioSessionControl: strongSelf.audioSessionControl)
} else { } else {

View File

@ -607,11 +607,11 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
self.maskProgressLayer.lineCap = .round self.maskProgressLayer.lineCap = .round
self.maskProgressLayer.path = path self.maskProgressLayer.path = path
let circleFrame = CGRect(origin: CGPoint(x: (358 - buttonSize.width) / 2.0, y: (358 - buttonSize.height) / 2.0), size: buttonSize).insetBy(dx: -progressLineWidth / 2.0, dy: -progressLineWidth / 2.0) let circleFrame = CGRect(origin: CGPoint(x: (areaSize.width - buttonSize.width) / 2.0, y: (areaSize.height - buttonSize.height) / 2.0), size: buttonSize).insetBy(dx: -progressLineWidth / 2.0, dy: -progressLineWidth / 2.0)
let largerCirclePath = UIBezierPath(roundedRect: CGRect(x: circleFrame.minX, y: circleFrame.minY, width: circleFrame.width, height: circleFrame.height), cornerRadius: circleFrame.width / 2.0).cgPath let largerCirclePath = UIBezierPath(roundedRect: CGRect(x: circleFrame.minX, y: circleFrame.minY, width: circleFrame.width, height: circleFrame.height), cornerRadius: circleFrame.width / 2.0).cgPath
self.maskCircleLayer.fillColor = white.cgColor
self.maskCircleLayer.path = largerCirclePath self.maskCircleLayer.path = largerCirclePath
self.maskCircleLayer.fillColor = white.cgColor
self.maskCircleLayer.isHidden = true self.maskCircleLayer.isHidden = true
updateInHierarchy = { [weak self] value in updateInHierarchy = { [weak self] value in
@ -971,6 +971,7 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
CATransaction.commit() CATransaction.commit()
} }
private var maskIsCircle = true
private func setupButtonAnimation() { private func setupButtonAnimation() {
CATransaction.begin() CATransaction.begin()
CATransaction.setDisableActions(true) CATransaction.setDisableActions(true)
@ -982,6 +983,7 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
let path = UIBezierPath(roundedRect: CGRect(x: 0.0, y: floor((self.bounds.height - buttonHeight) / 2.0), width: self.bounds.width, height: buttonHeight), cornerRadius: 10.0).cgPath let path = UIBezierPath(roundedRect: CGRect(x: 0.0, y: floor((self.bounds.height - buttonHeight) / 2.0), width: self.bounds.width, height: buttonHeight), cornerRadius: 10.0).cgPath
self.maskCircleLayer.path = path self.maskCircleLayer.path = path
self.maskIsCircle = false
CATransaction.commit() CATransaction.commit()
@ -1001,6 +1003,7 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
let previousPath = self.maskCircleLayer.path let previousPath = self.maskCircleLayer.path
self.maskCircleLayer.path = largerCirclePath self.maskCircleLayer.path = largerCirclePath
self.maskIsCircle = true
self.maskCircleLayer.animateSpring(from: previousPath as AnyObject, to: largerCirclePath as AnyObject, keyPath: "path", duration: 0.42, initialVelocity: 0.0, damping: 104.0) self.maskCircleLayer.animateSpring(from: previousPath as AnyObject, to: largerCirclePath as AnyObject, keyPath: "path", duration: 0.42, initialVelocity: 0.0, damping: 104.0)
@ -1144,9 +1147,13 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
self.updateAnimations() self.updateAnimations()
} }
var previousSize: CGSize?
override func layout() { override func layout() {
super.layout() super.layout()
let sizeUpdated = self.previousSize != self.bounds.size
self.previousSize = self.bounds.size
let bounds = CGRect(x: (self.bounds.width - areaSize.width) / 2.0, y: (self.bounds.height - areaSize.height) / 2.0, width: areaSize.width, height: areaSize.height) let bounds = CGRect(x: (self.bounds.width - areaSize.width) / 2.0, y: (self.bounds.height - areaSize.height) / 2.0, width: areaSize.width, height: areaSize.height)
let center = bounds.center let center = bounds.center
@ -1159,7 +1166,17 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
self.growingForegroundCircleLayer.position = center self.growingForegroundCircleLayer.position = center
self.growingForegroundCircleLayer.bounds = self.foregroundCircleLayer.bounds self.growingForegroundCircleLayer.bounds = self.foregroundCircleLayer.bounds
self.maskCircleLayer.frame = self.bounds self.maskCircleLayer.frame = self.bounds
// circleFrame.insetBy(dx: -progressLineWidth / 2.0, dy: -progressLineWidth / 2.0)
if sizeUpdated && self.maskIsCircle {
CATransaction.begin()
CATransaction.setDisableActions(true)
let circleFrame = CGRect(origin: CGPoint(x: (self.bounds.width - buttonSize.width) / 2.0, y: (self.bounds.height - buttonSize.height) / 2.0), size: buttonSize).insetBy(dx: -progressLineWidth / 2.0, dy: -progressLineWidth / 2.0)
let largerCirclePath = UIBezierPath(roundedRect: CGRect(x: circleFrame.minX, y: circleFrame.minY, width: circleFrame.width, height: circleFrame.height), cornerRadius: circleFrame.width / 2.0).cgPath
self.maskCircleLayer.path = largerCirclePath
CATransaction.commit()
}
self.maskProgressLayer.frame = circleFrame.insetBy(dx: -3.0, dy: -3.0) self.maskProgressLayer.frame = circleFrame.insetBy(dx: -3.0, dy: -3.0)
self.foregroundView.frame = self.bounds self.foregroundView.frame = self.bounds
self.foregroundGradientLayer.frame = self.bounds self.foregroundGradientLayer.frame = self.bounds
@ -1543,22 +1560,22 @@ final class VoiceChatActionButtonIconNode: ManagedAnimationNode {
case .subscribe: case .subscribe:
switch state { switch state {
case .unsubscribe: case .unsubscribe:
self.trackTo(item: ManagedAnimationItem(source: .local("VoiceStart"))) self.trackTo(item: ManagedAnimationItem(source: .local("VoiceCancelReminder")))
case .mute: case .mute:
self.trackTo(item: ManagedAnimationItem(source: .local("VoiceStart"))) self.trackTo(item: ManagedAnimationItem(source: .local("VoiceSetReminderToMute")))
case .hand: case .hand:
self.trackTo(item: ManagedAnimationItem(source: .local("VoiceStart"))) self.trackTo(item: ManagedAnimationItem(source: .local("VoiceSetReminderToRaiseHand")))
default: default:
break break
} }
case .unsubscribe: case .unsubscribe:
switch state { switch state {
case .subscribe: case .subscribe:
self.trackTo(item: ManagedAnimationItem(source: .local("VoiceStart"))) self.trackTo(item: ManagedAnimationItem(source: .local("VoiceSetReminder")))
case .mute: case .mute:
self.trackTo(item: ManagedAnimationItem(source: .local("VoiceStart"))) self.trackTo(item: ManagedAnimationItem(source: .local("VoiceCancelReminderToMute")))
case .hand: case .hand:
self.trackTo(item: ManagedAnimationItem(source: .local("VoiceStart"))) self.trackTo(item: ManagedAnimationItem(source: .local("VoiceCancelReminderToRaiseHand")))
default: default:
break break
} }
@ -1574,7 +1591,7 @@ final class VoiceChatActionButtonIconNode: ManagedAnimationNode {
case .mute: case .mute:
self.trackTo(item: ManagedAnimationItem(source: .local("VoiceMute"))) self.trackTo(item: ManagedAnimationItem(source: .local("VoiceMute")))
case .hand: case .hand:
self.trackTo(item: ManagedAnimationItem(source: .local("VoiceHandOff2"))) self.trackTo(item: ManagedAnimationItem(source: .local("VoiceUnmuteToRaiseHand")))
default: default:
break break
} }
@ -1585,7 +1602,11 @@ final class VoiceChatActionButtonIconNode: ManagedAnimationNode {
case .unmute: case .unmute:
self.trackTo(item: ManagedAnimationItem(source: .local("VoiceUnmute"))) self.trackTo(item: ManagedAnimationItem(source: .local("VoiceUnmute")))
case .hand: case .hand:
self.trackTo(item: ManagedAnimationItem(source: .local("VoiceHandOff"))) self.trackTo(item: ManagedAnimationItem(source: .local("VoiceMuteToRaiseHand")))
case .subscribe:
self.trackTo(item: ManagedAnimationItem(source: .local("VoiceSetReminderToRaiseHand"), frames: .range(startFrame: 0, endFrame: 0), duration: 0.001))
case .unsubscribe:
self.trackTo(item: ManagedAnimationItem(source: .local("VoiceCancelReminderToRaiseHand"), frames: .range(startFrame: 0, endFrame: 0), duration: 0.001))
case .empty: case .empty:
self.alpha = 0.0 self.alpha = 0.0
default: default:
@ -1594,7 +1615,7 @@ final class VoiceChatActionButtonIconNode: ManagedAnimationNode {
case .hand: case .hand:
switch state { switch state {
case .mute, .unmute: case .mute, .unmute:
self.trackTo(item: ManagedAnimationItem(source: .local("VoiceHandOn"))) self.trackTo(item: ManagedAnimationItem(source: .local("VoiceRaiseHandToMute")))
default: default:
break break
} }

View File

@ -2438,8 +2438,12 @@ public final class VoiceChatController: ViewController {
@objc func dimTapGesture(_ recognizer: UITapGestureRecognizer) { @objc func dimTapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state { if case .ended = recognizer.state {
self.controller?.dismiss(closing: false) if self.isScheduling {
self.controller?.dismissAllTooltips() self.dismissScheduled()
} else {
self.controller?.dismiss(closing: false)
self.controller?.dismissAllTooltips()
}
} }
} }
@ -2594,7 +2598,7 @@ public final class VoiceChatController: ViewController {
self.call.startScheduled() self.call.startScheduled()
self.transitionToCall() self.transitionToCall()
} else { } else {
self.call.toggleScheduledSubscription(!callState.subscribedToScheduled)
} }
} }
default: default:
@ -2670,8 +2674,6 @@ public final class VoiceChatController: ViewController {
|> deliverOnMainQueue).start(next: { [weak self] inviteLinks in |> deliverOnMainQueue).start(next: { [weak self] inviteLinks in
if let inviteLinks = inviteLinks { if let inviteLinks = inviteLinks {
self?.presentShare(inviteLinks) self?.presentShare(inviteLinks)
} else {
self?.presentShare(GroupCallInviteLinks(listenerLink: "a", speakerLink: nil))
} }
}) })
return return
@ -3199,16 +3201,20 @@ public final class VoiceChatController: ViewController {
let actionButtonSubtitle: String let actionButtonSubtitle: String
var actionButtonEnabled = true var actionButtonEnabled = true
if let callState = self.callState, !self.isScheduling { if let callState = self.callState, !self.isScheduling {
var isScheduled = callState.scheduleTimestamp != nil if callState.scheduleTimestamp != nil {
if isScheduled {
self.ignoreNextConnecting = true self.ignoreNextConnecting = true
if callState.canManageCall { if callState.canManageCall {
actionButtonState = .scheduled(state: .start) actionButtonState = .scheduled(state: .start)
actionButtonTitle = self.presentationData.strings.VoiceChat_StartNow actionButtonTitle = self.presentationData.strings.VoiceChat_StartNow
actionButtonSubtitle = "" actionButtonSubtitle = ""
} else { } else {
actionButtonState = .scheduled(state: .subscribe) if callState.subscribedToScheduled {
actionButtonTitle = self.presentationData.strings.VoiceChat_SetReminder actionButtonState = .scheduled(state: .unsubscribe)
actionButtonTitle = self.presentationData.strings.VoiceChat_CancelReminder
} else {
actionButtonState = .scheduled(state: .subscribe)
actionButtonTitle = self.presentationData.strings.VoiceChat_SetReminder
}
actionButtonSubtitle = "" actionButtonSubtitle = ""
} }
} else { } else {
@ -3681,6 +3687,7 @@ public final class VoiceChatController: ViewController {
@objc func panGesture(_ recognizer: UIPanGestureRecognizer) { @objc func panGesture(_ recognizer: UIPanGestureRecognizer) {
let contentOffset = self.listNode.visibleContentOffset() let contentOffset = self.listNode.visibleContentOffset()
let isScheduling = self.isScheduling || self.callState?.scheduleTimestamp != nil
switch recognizer.state { switch recognizer.state {
case .began: case .began:
let topInset: CGFloat let topInset: CGFloat
@ -3696,7 +3703,7 @@ public final class VoiceChatController: ViewController {
self.controller?.dismissAllTooltips() self.controller?.dismissAllTooltips()
case .changed: case .changed:
var translation = recognizer.translation(in: self.contentContainer.view).y var translation = recognizer.translation(in: self.contentContainer.view).y
if (self.isScheduling || self.callState?.scheduleTimestamp != nil) && translation < 0.0 { if isScheduling && translation < 0.0 {
return return
} }
var topInset: CGFloat = 0.0 var topInset: CGFloat = 0.0
@ -3802,7 +3809,7 @@ public final class VoiceChatController: ViewController {
self.controller?.dismiss(closing: false, manual: true) self.controller?.dismiss(closing: false, manual: true)
} }
dismissing = true dismissing = true
} else if !self.isScheduling && (velocity.y < -300.0 || offset < topInset / 2.0) { } else if !isScheduling && (velocity.y < -300.0 || offset < topInset / 2.0) {
if velocity.y > -1500.0 && !self.isFullscreen { if velocity.y > -1500.0 && !self.isFullscreen {
DispatchQueue.main.async { DispatchQueue.main.async {
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
@ -3819,7 +3826,7 @@ public final class VoiceChatController: ViewController {
self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut), completion: { self.updateFloatingHeaderOffset(offset: self.currentContentOffset ?? 0.0, transition: .animated(duration: 0.3, curve: .easeInOut), completion: {
self.animatingExpansion = false self.animatingExpansion = false
}) })
} else if !self.isScheduling { } else if !isScheduling {
self.updateIsFullscreen(false) self.updateIsFullscreen(false)
self.animatingExpansion = true self.animatingExpansion = true
self.listNode.scroller.setContentOffset(CGPoint(), animated: false) self.listNode.scroller.setContentOffset(CGPoint(), animated: false)

View File

@ -144,8 +144,8 @@ public final class VoiceChatJoinScreen: ViewController {
} else if let cachedData = cachedData as? CachedGroupData { } else if let cachedData = cachedData as? CachedGroupData {
defaultJoinAsPeerId = cachedData.callJoinPeerId defaultJoinAsPeerId = cachedData.callJoinPeerId
} }
let activeCall = CachedChannelData.ActiveCall(id: call.info.id, accessHash: call.info.accessHash, title: call.info.title, scheduleTimestamp: call.info.scheduleTimestamp, subscribed: false) let activeCall = CachedChannelData.ActiveCall(id: call.info.id, accessHash: call.info.accessHash, title: call.info.title, scheduleTimestamp: call.info.scheduleTimestamp, subscribedToScheduled: call.info.subscribedToScheduled)
if availablePeers.count > 0 && defaultJoinAsPeerId == nil { if availablePeers.count > 0 && defaultJoinAsPeerId == nil {
strongSelf.dismiss() strongSelf.dismiss()
strongSelf.join(activeCall) strongSelf.join(activeCall)

View File

@ -136,7 +136,7 @@ final class VoiceChatTimerNode: ASDisplayNode {
self.subtitleNode.attributedText = NSAttributedString(string: subtitle, font: Font.with(size: 21.0, design: .round, weight: .semibold, traits: []), textColor: .white) self.subtitleNode.attributedText = NSAttributedString(string: subtitle, font: Font.with(size: 21.0, design: .round, weight: .semibold, traits: []), textColor: .white)
let subtitleSize = self.subtitleNode.updateLayout(size) let subtitleSize = self.subtitleNode.updateLayout(size)
self.subtitleNode.frame = CGRect(x: floor((size.width - subtitleSize.width) / 2.0), y: 164.0, width: timerSize.width, height: subtitleSize.height) self.subtitleNode.frame = CGRect(x: floor((size.width - subtitleSize.width) / 2.0), y: 164.0, width: subtitleSize.width, height: subtitleSize.height)
self.foregroundView.frame = CGRect(origin: CGPoint(), size: size) self.foregroundView.frame = CGRect(origin: CGPoint(), size: size)
} }

View File

@ -12,6 +12,7 @@ public struct GroupCallInfo: Equatable {
public var streamDcId: Int32? public var streamDcId: Int32?
public var title: String? public var title: String?
public var scheduleTimestamp: Int32? public var scheduleTimestamp: Int32?
public var subscribedToScheduled: Bool
public var recordingStartTimestamp: Int32? public var recordingStartTimestamp: Int32?
public var sortAscending: Bool public var sortAscending: Bool
@ -23,6 +24,7 @@ public struct GroupCallInfo: Equatable {
streamDcId: Int32?, streamDcId: Int32?,
title: String?, title: String?,
scheduleTimestamp: Int32?, scheduleTimestamp: Int32?,
subscribedToScheduled: Bool,
recordingStartTimestamp: Int32?, recordingStartTimestamp: Int32?,
sortAscending: Bool sortAscending: Bool
) { ) {
@ -33,6 +35,7 @@ public struct GroupCallInfo: Equatable {
self.streamDcId = streamDcId self.streamDcId = streamDcId
self.title = title self.title = title
self.scheduleTimestamp = scheduleTimestamp self.scheduleTimestamp = scheduleTimestamp
self.subscribedToScheduled = subscribedToScheduled
self.recordingStartTimestamp = recordingStartTimestamp self.recordingStartTimestamp = recordingStartTimestamp
self.sortAscending = sortAscending self.sortAscending = sortAscending
} }
@ -62,6 +65,7 @@ extension GroupCallInfo {
streamDcId: streamDcId, streamDcId: streamDcId,
title: title, title: title,
scheduleTimestamp: scheduleDate, scheduleTimestamp: scheduleDate,
subscribedToScheduled: (flags & (1 << 8)) != 0,
recordingStartTimestamp: recordStartDate, recordingStartTimestamp: recordStartDate,
sortAscending: (flags & (1 << 6)) != 0 sortAscending: (flags & (1 << 6)) != 0
) )
@ -226,9 +230,9 @@ public func createGroupCall(account: Account, peerId: PeerId, title: String?, sc
return account.postbox.transaction { transaction -> GroupCallInfo in return account.postbox.transaction { transaction -> GroupCallInfo in
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in
if let cachedData = cachedData as? CachedChannelData { if let cachedData = cachedData as? CachedChannelData {
return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: callInfo.scheduleTimestamp, subscribed: false)) return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: callInfo.scheduleTimestamp, subscribedToScheduled: callInfo.subscribedToScheduled))
} else if let cachedData = cachedData as? CachedGroupData { } else if let cachedData = cachedData as? CachedGroupData {
return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: callInfo.scheduleTimestamp, subscribed: false)) return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: callInfo.scheduleTimestamp, subscribedToScheduled: callInfo.subscribedToScheduled))
} else { } else {
return cachedData return cachedData
} }
@ -271,9 +275,9 @@ public func startScheduledGroupCall(account: Account, peerId: PeerId, callId: In
return account.postbox.transaction { transaction -> GroupCallInfo in return account.postbox.transaction { transaction -> GroupCallInfo in
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in
if let cachedData = cachedData as? CachedChannelData { if let cachedData = cachedData as? CachedChannelData {
return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: nil, subscribed: false)) return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: nil, subscribedToScheduled: false))
} else if let cachedData = cachedData as? CachedGroupData { } else if let cachedData = cachedData as? CachedGroupData {
return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: nil, subscribed: false)) return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: nil, subscribedToScheduled: false))
} else { } else {
return cachedData return cachedData
} }
@ -315,9 +319,9 @@ public func toggleScheduledGroupCallSubscription(account: Account, peerId: PeerI
return account.postbox.transaction { transaction in return account.postbox.transaction { transaction in
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in
if let cachedData = cachedData as? CachedChannelData { if let cachedData = cachedData as? CachedChannelData {
return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: callInfo.scheduleTimestamp, subscribed: subscribe)) return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: callInfo.scheduleTimestamp, subscribedToScheduled: callInfo.subscribedToScheduled))
} else if let cachedData = cachedData as? CachedGroupData { } else if let cachedData = cachedData as? CachedGroupData {
return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: callInfo.scheduleTimestamp, subscribed: subscribe)) return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: callInfo.scheduleTimestamp, subscribedToScheduled: callInfo.subscribedToScheduled))
} else { } else {
return cachedData return cachedData
} }
@ -373,19 +377,19 @@ public enum GetGroupCallParticipantsError {
} }
public func getGroupCallParticipants(account: Account, callId: Int64, accessHash: Int64, offset: String, ssrcs: [UInt32], limit: Int32, sortAscending: Bool?) -> Signal<GroupCallParticipantsContext.State, GetGroupCallParticipantsError> { public func getGroupCallParticipants(account: Account, callId: Int64, accessHash: Int64, offset: String, ssrcs: [UInt32], limit: Int32, sortAscending: Bool?) -> Signal<GroupCallParticipantsContext.State, GetGroupCallParticipantsError> {
let sortAscendingValue: Signal<(Bool, Int32?), GetGroupCallParticipantsError> let sortAscendingValue: Signal<(Bool, Int32?, Bool), GetGroupCallParticipantsError>
if let sortAscending = sortAscending { if let sortAscending = sortAscending {
sortAscendingValue = .single((sortAscending, nil)) sortAscendingValue = .single((sortAscending, nil, false))
} else { } else {
sortAscendingValue = getCurrentGroupCall(account: account, callId: callId, accessHash: accessHash) sortAscendingValue = getCurrentGroupCall(account: account, callId: callId, accessHash: accessHash)
|> mapError { _ -> GetGroupCallParticipantsError in |> mapError { _ -> GetGroupCallParticipantsError in
return .generic return .generic
} }
|> mapToSignal { result -> Signal<(Bool, Int32?), GetGroupCallParticipantsError> in |> mapToSignal { result -> Signal<(Bool, Int32?, Bool), GetGroupCallParticipantsError> in
guard let result = result else { guard let result = result else {
return .fail(.generic) return .fail(.generic)
} }
return .single((result.info.sortAscending, result.info.scheduleTimestamp)) return .single((result.info.sortAscending, result.info.scheduleTimestamp, result.info.subscribedToScheduled))
} }
} }
@ -403,7 +407,7 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash
let version: Int32 let version: Int32
let nextParticipantsFetchOffset: String? let nextParticipantsFetchOffset: String?
let (sortAscendingValue, scheduleTimestamp) = sortAscendingAndScheduleTimestamp let (sortAscendingValue, scheduleTimestamp, subscribedToScheduled) = sortAscendingAndScheduleTimestamp
switch result { switch result {
case let .groupParticipants(count, participants, nextOffset, chats, users, apiVersion): case let .groupParticipants(count, participants, nextOffset, chats, users, apiVersion):
@ -492,6 +496,7 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash
recordingStartTimestamp: nil, recordingStartTimestamp: nil,
title: nil, title: nil,
scheduleTimestamp: scheduleTimestamp, scheduleTimestamp: scheduleTimestamp,
subscribedToScheduled: subscribedToScheduled,
totalCount: totalCount, totalCount: totalCount,
version: version version: version
) )
@ -668,9 +673,9 @@ public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, cal
return account.postbox.transaction { transaction -> JoinGroupCallResult in return account.postbox.transaction { transaction -> JoinGroupCallResult in
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in
if let cachedData = cachedData as? CachedChannelData { if let cachedData = cachedData as? CachedChannelData {
return cachedData.withUpdatedCallJoinPeerId(joinAs).withUpdatedActiveCall(CachedChannelData.ActiveCall(id: parsedCall.id, accessHash: parsedCall.accessHash, title: parsedCall.title, scheduleTimestamp: nil, subscribed: false)) return cachedData.withUpdatedCallJoinPeerId(joinAs).withUpdatedActiveCall(CachedChannelData.ActiveCall(id: parsedCall.id, accessHash: parsedCall.accessHash, title: parsedCall.title, scheduleTimestamp: nil, subscribedToScheduled: false))
} else if let cachedData = cachedData as? CachedGroupData { } else if let cachedData = cachedData as? CachedGroupData {
return cachedData.withUpdatedCallJoinPeerId(joinAs).withUpdatedActiveCall(CachedChannelData.ActiveCall(id: parsedCall.id, accessHash: parsedCall.accessHash, title: parsedCall.title, scheduleTimestamp: nil, subscribed: false)) return cachedData.withUpdatedCallJoinPeerId(joinAs).withUpdatedActiveCall(CachedChannelData.ActiveCall(id: parsedCall.id, accessHash: parsedCall.accessHash, title: parsedCall.title, scheduleTimestamp: nil, subscribedToScheduled: false))
} else { } else {
return cachedData return cachedData
} }
@ -1011,6 +1016,7 @@ public final class GroupCallParticipantsContext {
public var recordingStartTimestamp: Int32? public var recordingStartTimestamp: Int32?
public var title: String? public var title: String?
public var scheduleTimestamp: Int32? public var scheduleTimestamp: Int32?
public var subscribedToScheduled: Bool
public var totalCount: Int public var totalCount: Int
public var version: Int32 public var version: Int32
@ -1123,7 +1129,7 @@ public final class GroupCallParticipantsContext {
} }
case state(update: StateUpdate) case state(update: StateUpdate)
case call(isTerminated: Bool, defaultParticipantsAreMuted: State.DefaultParticipantsAreMuted, title: String?, recordingStartTimestamp: Int32?) case call(isTerminated: Bool, defaultParticipantsAreMuted: State.DefaultParticipantsAreMuted, title: String?, recordingStartTimestamp: Int32?, scheduleTimestamp: Int32?)
} }
public final class MemberEvent { public final class MemberEvent {
@ -1313,6 +1319,7 @@ public final class GroupCallParticipantsContext {
recordingStartTimestamp: strongSelf.stateValue.state.recordingStartTimestamp, recordingStartTimestamp: strongSelf.stateValue.state.recordingStartTimestamp,
title: strongSelf.stateValue.state.title, title: strongSelf.stateValue.state.title,
scheduleTimestamp: strongSelf.stateValue.state.scheduleTimestamp, scheduleTimestamp: strongSelf.stateValue.state.scheduleTimestamp,
subscribedToScheduled: strongSelf.stateValue.state.subscribedToScheduled,
totalCount: strongSelf.stateValue.state.totalCount, totalCount: strongSelf.stateValue.state.totalCount,
version: strongSelf.stateValue.state.version version: strongSelf.stateValue.state.version
), ),
@ -1368,11 +1375,12 @@ public final class GroupCallParticipantsContext {
for update in updates { for update in updates {
if case let .state(update) = update { if case let .state(update) = update {
stateUpdates.append(update) stateUpdates.append(update)
} else if case let .call(_, defaultParticipantsAreMuted, title, recordingStartTimestamp) = update { } else if case let .call(_, defaultParticipantsAreMuted, title, recordingStartTimestamp, scheduleTimestamp) = update {
var state = self.stateValue.state var state = self.stateValue.state
state.defaultParticipantsAreMuted = defaultParticipantsAreMuted state.defaultParticipantsAreMuted = defaultParticipantsAreMuted
state.recordingStartTimestamp = recordingStartTimestamp state.recordingStartTimestamp = recordingStartTimestamp
state.title = title state.title = title
state.scheduleTimestamp = scheduleTimestamp
self.stateValue.state = state self.stateValue.state = state
} }
@ -1446,6 +1454,7 @@ public final class GroupCallParticipantsContext {
recordingStartTimestamp: strongSelf.stateValue.state.recordingStartTimestamp, recordingStartTimestamp: strongSelf.stateValue.state.recordingStartTimestamp,
title: strongSelf.stateValue.state.title, title: strongSelf.stateValue.state.title,
scheduleTimestamp: strongSelf.stateValue.state.scheduleTimestamp, scheduleTimestamp: strongSelf.stateValue.state.scheduleTimestamp,
subscribedToScheduled: strongSelf.stateValue.state.subscribedToScheduled,
totalCount: strongSelf.stateValue.state.totalCount, totalCount: strongSelf.stateValue.state.totalCount,
version: strongSelf.stateValue.state.version version: strongSelf.stateValue.state.version
), ),
@ -1662,6 +1671,7 @@ public final class GroupCallParticipantsContext {
let recordingStartTimestamp = strongSelf.stateValue.state.recordingStartTimestamp let recordingStartTimestamp = strongSelf.stateValue.state.recordingStartTimestamp
let title = strongSelf.stateValue.state.title let title = strongSelf.stateValue.state.title
let scheduleTimestamp = strongSelf.stateValue.state.scheduleTimestamp let scheduleTimestamp = strongSelf.stateValue.state.scheduleTimestamp
let subscribedToScheduled = strongSelf.stateValue.state.subscribedToScheduled
updatedParticipants.sort(by: { GroupCallParticipantsContext.Participant.compare(lhs: $0, rhs: $1, sortAscending: strongSelf.stateValue.state.sortAscending) }) updatedParticipants.sort(by: { GroupCallParticipantsContext.Participant.compare(lhs: $0, rhs: $1, sortAscending: strongSelf.stateValue.state.sortAscending) })
@ -1676,6 +1686,7 @@ public final class GroupCallParticipantsContext {
recordingStartTimestamp: recordingStartTimestamp, recordingStartTimestamp: recordingStartTimestamp,
title: title, title: title,
scheduleTimestamp: scheduleTimestamp, scheduleTimestamp: scheduleTimestamp,
subscribedToScheduled: subscribedToScheduled,
totalCount: updatedTotalCount, totalCount: updatedTotalCount,
version: update.version version: update.version
), ),

View File

@ -2982,9 +2982,9 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
if let info = GroupCallInfo(call) { if let info = GroupCallInfo(call) {
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedChannelData { if let current = current as? CachedChannelData {
return current.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash, title: info.title, scheduleTimestamp: info.scheduleTimestamp, subscribed: false)) return current.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash, title: info.title, scheduleTimestamp: info.scheduleTimestamp, subscribedToScheduled: info.subscribedToScheduled))
} else if let current = current as? CachedGroupData { } else if let current = current as? CachedGroupData {
return current.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash, title: info.title, scheduleTimestamp: info.scheduleTimestamp, subscribed: false)) return current.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash, title: info.title, scheduleTimestamp: info.scheduleTimestamp, subscribedToScheduled: info.subscribedToScheduled))
} else { } else {
return current return current
} }
@ -2997,7 +2997,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
let defaultParticipantsAreMuted = GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: isMuted, canChange: canChange) let defaultParticipantsAreMuted = GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: isMuted, canChange: canChange)
updatedGroupCallParticipants.append(( updatedGroupCallParticipants.append((
info.id, info.id,
.call(isTerminated: false, defaultParticipantsAreMuted: defaultParticipantsAreMuted, title: title, recordingStartTimestamp: recordStartDate) .call(isTerminated: false, defaultParticipantsAreMuted: defaultParticipantsAreMuted, title: title, recordingStartTimestamp: recordStartDate, scheduleTimestamp: scheduleDate)
)) ))
default: default:
break break
@ -3006,7 +3006,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
case let .groupCallDiscarded(callId, _, _): case let .groupCallDiscarded(callId, _, _):
updatedGroupCallParticipants.append(( updatedGroupCallParticipants.append((
callId, callId,
.call(isTerminated: true, defaultParticipantsAreMuted: GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: false, canChange: false), title: nil, recordingStartTimestamp: nil) .call(isTerminated: true, defaultParticipantsAreMuted: GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: false, canChange: false), title: nil, recordingStartTimestamp: nil, scheduleTimestamp: nil)
)) ))
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in

View File

@ -306,7 +306,7 @@ public func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId
if let inputCall = chatFull.call { if let inputCall = chatFull.call {
switch inputCall { switch inputCall {
case let .inputGroupCall(id, accessHash): case let .inputGroupCall(id, accessHash):
updatedActiveCall = CachedChannelData.ActiveCall(id: id, accessHash: accessHash, title: previous.activeCall?.title, scheduleTimestamp: previous.activeCall?.scheduleTimestamp, subscribed: previous.activeCall?.subscribed ?? false) updatedActiveCall = CachedChannelData.ActiveCall(id: id, accessHash: accessHash, title: previous.activeCall?.title, scheduleTimestamp: previous.activeCall?.scheduleTimestamp, subscribedToScheduled: previous.activeCall?.subscribedToScheduled ?? false)
} }
} }
@ -516,7 +516,7 @@ public func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId
if let inputCall = inputCall { if let inputCall = inputCall {
switch inputCall { switch inputCall {
case let .inputGroupCall(id, accessHash): case let .inputGroupCall(id, accessHash):
updatedActiveCall = CachedChannelData.ActiveCall(id: id, accessHash: accessHash, title: previous.activeCall?.title, scheduleTimestamp: previous.activeCall?.scheduleTimestamp, subscribed: previous.activeCall?.subscribed ?? false) updatedActiveCall = CachedChannelData.ActiveCall(id: id, accessHash: accessHash, title: previous.activeCall?.title, scheduleTimestamp: previous.activeCall?.scheduleTimestamp, subscribedToScheduled: previous.activeCall?.subscribedToScheduled ?? false)
} }
} }

View File

@ -535,7 +535,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
case .groupPhoneCall, .inviteToGroupPhoneCall: case .groupPhoneCall, .inviteToGroupPhoneCall:
if let activeCall = strongSelf.presentationInterfaceState.activeGroupCallInfo?.activeCall { if let activeCall = strongSelf.presentationInterfaceState.activeGroupCallInfo?.activeCall {
strongSelf.joinGroupCall(peerId: message.id.peerId, invite: nil, activeCall: CachedChannelData.ActiveCall(id: activeCall.id, accessHash: activeCall.accessHash, title: activeCall.title, scheduleTimestamp: activeCall.scheduleTimestamp, subscribed: activeCall.subscribed)) strongSelf.joinGroupCall(peerId: message.id.peerId, invite: nil, activeCall: CachedChannelData.ActiveCall(id: activeCall.id, accessHash: activeCall.accessHash, title: activeCall.title, scheduleTimestamp: activeCall.scheduleTimestamp, subscribedToScheduled: activeCall.subscribedToScheduled))
} else { } else {
var canManageGroupCalls = false var canManageGroupCalls = false
if let channel = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer as? TelegramChannel { if let channel = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer as? TelegramChannel {
@ -569,7 +569,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
strongSelf.joinGroupCall(peerId: message.id.peerId, invite: nil, activeCall: CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash, title: info.title, scheduleTimestamp: info.scheduleTimestamp, subscribed: false)) strongSelf.joinGroupCall(peerId: message.id.peerId, invite: nil, activeCall: CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash, title: info.title, scheduleTimestamp: info.scheduleTimestamp, subscribedToScheduled: info.subscribedToScheduled))
}, error: { [weak self] error in }, error: { [weak self] error in
dismissStatus?() dismissStatus?()

View File

@ -4020,7 +4020,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
} }
strongSelf.context.joinGroupCall(peerId: peerId, invite: nil, requestJoinAsPeerId: { result in strongSelf.context.joinGroupCall(peerId: peerId, invite: nil, requestJoinAsPeerId: { result in
result(joinAsPeerId) result(joinAsPeerId)
}, activeCall: CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash, title: info.title, scheduleTimestamp: nil, subscribed: false)) }, activeCall: CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash, title: info.title, scheduleTimestamp: nil, subscribedToScheduled: false))
}, error: { [weak self] error in }, error: { [weak self] error in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -4199,7 +4199,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|> deliverOnMainQueue).start(completed: { [weak self] in |> deliverOnMainQueue).start(completed: { [weak self] in
if let strongSelf = self, let peer = strongSelf.data?.peer { if let strongSelf = self, let peer = strongSelf.data?.peer {
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
strongSelf.controller?.present(UndoOverlayController(presentationData: presentationData, content: .info(text: presentationData.strings.Conversation_DeletedFromContacts(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root)) let controller = UndoOverlayController(presentationData: presentationData, content: .info(text: presentationData.strings.Conversation_DeletedFromContacts(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false })
controller.keepOnParentDismissal = true
strongSelf.controller?.present(controller, in: .window(.root))
strongSelf.controller?.dismiss() strongSelf.controller?.dismiss()
} }
@ -6642,12 +6644,12 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen {
private func dismissAllTooltips() { private func dismissAllTooltips() {
self.window?.forEachController({ controller in self.window?.forEachController({ controller in
if let controller = controller as? UndoOverlayController { if let controller = controller as? UndoOverlayController, !controller.keepOnParentDismissal {
controller.dismissWithCommitAction() controller.dismissWithCommitAction()
} }
}) })
self.forEachController({ controller in self.forEachController({ controller in
if let controller = controller as? UndoOverlayController { if let controller = controller as? UndoOverlayController, !controller.keepOnParentDismissal {
controller.dismissWithCommitAction() controller.dismissWithCommitAction()
} }
return true return true

View File

@ -56,6 +56,8 @@ public final class UndoOverlayController: ViewController {
private var didPlayPresentationAnimation = false private var didPlayPresentationAnimation = false
private var dismissed = false private var dismissed = false
public var keepOnParentDismissal = false
public init(presentationData: PresentationData, content: UndoOverlayContent, elevatedLayout: Bool, animateInAsReplacement: Bool = false, action: @escaping (UndoOverlayAction) -> Bool) { public init(presentationData: PresentationData, content: UndoOverlayContent, elevatedLayout: Bool, animateInAsReplacement: Bool = false, action: @escaping (UndoOverlayAction) -> Bool) {
self.presentationData = presentationData self.presentationData = presentationData
self.content = content self.content = content