diff --git a/Telegram/BUILD b/Telegram/BUILD index ee3013f71b..f22af48910 100644 --- a/Telegram/BUILD +++ b/Telegram/BUILD @@ -1534,7 +1534,7 @@ ios_application( ":NotificationContentExtension", ":NotificationServiceExtension", ":IntentsExtension", - ":WidgetExtension", + #":WidgetExtension", ], watch_application = ":TelegramWatchApp", deps = [ diff --git a/submodules/AccountContext/Sources/PresentationCallManager.swift b/submodules/AccountContext/Sources/PresentationCallManager.swift index 73cbde9e1c..aecd38a59d 100644 --- a/submodules/AccountContext/Sources/PresentationCallManager.swift +++ b/submodules/AccountContext/Sources/PresentationCallManager.swift @@ -165,18 +165,18 @@ public struct PresentationGroupCallState: Equatable { public var networkState: NetworkState public var canManageCall: Bool public var adminIds: Set - public var isMuted: Bool + public var muteState: GroupCallParticipantsContext.Participant.MuteState? public init( networkState: NetworkState, canManageCall: Bool, adminIds: Set, - isMuted: Bool + muteState: GroupCallParticipantsContext.Participant.MuteState? ) { self.networkState = networkState self.canManageCall = canManageCall self.adminIds = adminIds - self.isMuted = isMuted + self.muteState = muteState } } diff --git a/submodules/Display/Source/UIKitUtils.swift b/submodules/Display/Source/UIKitUtils.swift index 123691766e..bc40ac4391 100644 --- a/submodules/Display/Source/UIKitUtils.swift +++ b/submodules/Display/Source/UIKitUtils.swift @@ -242,13 +242,25 @@ public extension UIColor { func interpolateTo(_ color: UIColor, fraction: CGFloat) -> UIColor? { let f = min(max(0, fraction), 1) - guard let c1 = self.cgColor.components, let c2 = color.cgColor.components else { return nil } - let r: CGFloat = CGFloat(c1[0] + (c2[0] - c1[0]) * f) - let g: CGFloat = CGFloat(c1[1] + (c2[1] - c1[1]) * f) - let b: CGFloat = CGFloat(c1[2] + (c2[2] - c1[2]) * f) - let a: CGFloat = CGFloat(c1[3] + (c2[3] - c1[3]) * f) - - return UIColor(red: r, green: g, blue: b, alpha: a) + var r1: CGFloat = 0.0 + var r2: CGFloat = 0.0 + var g1: CGFloat = 0.0 + var g2: CGFloat = 0.0 + var b1: CGFloat = 0.0 + var b2: CGFloat = 0.0 + var a1: CGFloat = 0.0 + var a2: CGFloat = 0.0 + if self.getRed(&r1, green: &g1, blue: &b1, alpha: &a1) && + color.getRed(&r2, green: &g2, blue: &b2, alpha: &a2) { + let r: CGFloat = CGFloat(r1 + (r2 - r1) * f) + let g: CGFloat = CGFloat(g1 + (g2 - g1) * f) + let b: CGFloat = CGFloat(b1 + (b2 - b1) * f) + let a: CGFloat = CGFloat(a1 + (a2 - a1) * f) + + return UIColor(red: r, green: g, blue: b, alpha: a) + } else { + return self + } } private var colorComponents: (r: Int32, g: Int32, b: Int32) { diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index 7c1978edbb..aabfad7873 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -20,7 +20,7 @@ private extension PresentationGroupCallState { networkState: .connecting, canManageCall: false, adminIds: Set(), - isMuted: true + muteState: GroupCallParticipantsContext.Participant.MuteState(canUnmute: true) ) } } @@ -406,14 +406,6 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { })) })) - self.isMutedDisposable.set((callContext.isMuted - |> deliverOnMainQueue).start(next: { [weak self] isMuted in - guard let strongSelf = self else { - return - } - strongSelf.stateValue.isMuted = isMuted - })) - self.networkStateDisposable.set((callContext.networkState |> deliverOnMainQueue).start(next: { [weak self] state in guard let strongSelf = self else { @@ -512,6 +504,16 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { ssrc: participant.ssrc, muteState: participant.muteState ) + + if participant.peer.id == strongSelf.accountContext.account.peerId { + if let muteState = participant.muteState { + strongSelf.stateValue.muteState = muteState + strongSelf.callContext?.setIsMuted(true) + } else if let currentMuteState = strongSelf.stateValue.muteState, !currentMuteState.canUnmute { + strongSelf.stateValue.muteState = GroupCallParticipantsContext.Participant.MuteState(canUnmute: true) + strongSelf.callContext?.setIsMuted(true) + } + } } strongSelf.membersValue = memberStates @@ -598,6 +600,9 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { if self.isMutedValue == action { return } + if let muteState = self.stateValue.muteState, !muteState.canUnmute { + return + } self.isMutedValue = action self.isMutedPromise.set(self.isMutedValue) let isEffectivelyMuted: Bool @@ -610,6 +615,12 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { self.updateMuteState(peerId: self.accountContext.account.peerId, isMuted: false) } self.callContext?.setIsMuted(isEffectivelyMuted) + + if isEffectivelyMuted { + self.stateValue.muteState = GroupCallParticipantsContext.Participant.MuteState(canUnmute: true) + } else { + self.stateValue.muteState = nil + } } public func setCurrentAudioOutput(_ output: AudioSessionOutput) { diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 93e57736e6..8b8c532467 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -426,7 +426,7 @@ public final class VoiceChatController: ViewController { guard let strongSelf = self else { return } - strongSelf.updateMembers(isMuted: strongSelf.callState?.isMuted ?? true, members: state.list, memberStates: strongSelf.currentMemberStates ?? [:], invitedPeers: strongSelf.currentInvitedPeers ?? Set()) + strongSelf.updateMembers(muteState: strongSelf.callState?.muteState, members: state.list, memberStates: strongSelf.currentMemberStates ?? [:], invitedPeers: strongSelf.currentInvitedPeers ?? Set()) } }) @@ -436,7 +436,7 @@ public final class VoiceChatController: ViewController { return } if let members = strongSelf.currentMembers { - strongSelf.updateMembers(isMuted: strongSelf.callState?.isMuted ?? true, members: members, memberStates: memberStates, invitedPeers: strongSelf.currentInvitedPeers ?? Set()) + strongSelf.updateMembers(muteState: strongSelf.callState?.muteState, members: members, memberStates: memberStates, invitedPeers: strongSelf.currentInvitedPeers ?? Set()) } else { strongSelf.currentMemberStates = memberStates } @@ -448,7 +448,7 @@ public final class VoiceChatController: ViewController { return } if let members = strongSelf.currentMembers { - strongSelf.updateMembers(isMuted: strongSelf.callState?.isMuted ?? true, members: members, memberStates: strongSelf.currentMemberStates ?? [:], invitedPeers: invitedPeers) + strongSelf.updateMembers(muteState: strongSelf.callState?.muteState, members: members, memberStates: strongSelf.currentMemberStates ?? [:], invitedPeers: invitedPeers) } else { strongSelf.currentInvitedPeers = invitedPeers } @@ -498,11 +498,20 @@ public final class VoiceChatController: ViewController { return } if strongSelf.callState != state { - let wasMuted = strongSelf.callState?.isMuted ?? true + let wasMuted = strongSelf.callState?.muteState != nil strongSelf.callState = state - if wasMuted != state.isMuted, let members = strongSelf.currentMembers { - strongSelf.updateMembers(isMuted: state.isMuted, members: members, memberStates: strongSelf.currentMemberStates ?? [:], invitedPeers: strongSelf.currentInvitedPeers ?? Set()) + if state.muteState != nil { + if strongSelf.pushingToTalk { + strongSelf.pushingToTalk = false + strongSelf.actionButton.pressing = false + strongSelf.actionButton.isUserInteractionEnabled = false + strongSelf.actionButton.isUserInteractionEnabled = true + } + } + + if wasMuted != (state.muteState != nil), let members = strongSelf.currentMembers { + strongSelf.updateMembers(muteState: state.muteState, members: members, memberStates: strongSelf.currentMemberStates ?? [:], invitedPeers: strongSelf.currentInvitedPeers ?? Set()) } if let (layout, navigationHeight) = strongSelf.validLayout { @@ -536,7 +545,7 @@ public final class VoiceChatController: ViewController { return } var effectiveLevel: Float = 0.0 - if let state = strongSelf.callState, !state.isMuted { + if let state = strongSelf.callState, state.muteState == nil { effectiveLevel = level } strongSelf.itemInteraction?.updateAudioLevels([(strongSelf.context.account.peerId, effectiveLevel)]) @@ -651,11 +660,16 @@ public final class VoiceChatController: ViewController { guard let callState = self.callState else { return } + if let muteState = callState.muteState { + if !muteState.canUnmute { + return + } + } switch gestureRecognizer.state { case .began: self.actionButtonPressGestureStartTime = CACurrentMediaTime() self.actionButton.pressing = true - if callState.isMuted { + if callState.muteState != nil { self.pushingToTalk = true self.call.setIsMuted(action: .muted(isPushToTalkActive: true)) } @@ -663,7 +677,7 @@ public final class VoiceChatController: ViewController { self.pushingToTalk = false self.actionButton.pressing = false let timestamp = CACurrentMediaTime() - if callState.isMuted || timestamp - self.actionButtonPressGestureStartTime < 0.1 { + if callState.muteState != nil || timestamp - self.actionButtonPressGestureStartTime < 0.1 { self.call.toggleIsMuted() } else { self.call.setIsMuted(action: .muted(isPushToTalkActive: false)) @@ -768,16 +782,12 @@ public final class VoiceChatController: ViewController { let actionButtonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - centralButtonSize.width) / 2.0), y: layout.size.height - bottomAreaHeight + floor((bottomAreaHeight - centralButtonSize.height) / 2.0)), size: centralButtonSize) - var isMicOn = false - let actionButtonState: VoiceChatActionButtonState let actionButtonTitle: String let actionButtonSubtitle: String let audioButtonAppearance: CallControllerButtonItemNode.Content.Appearance var actionButtonEnabled = true if let callState = self.callState { - isMicOn = !callState.isMuted - switch callState.networkState { case .connecting: actionButtonState = .connecting @@ -786,15 +796,26 @@ public final class VoiceChatController: ViewController { audioButtonAppearance = .color(.custom(0x1c1c1e)) actionButtonEnabled = false case .connected: - actionButtonState = .active(state: isMicOn ? .on : .muted) - if isMicOn { + if let muteState = callState.muteState { + if muteState.canUnmute { + actionButtonState = .active(state: .muted) + + actionButtonTitle = self.presentationData.strings.VoiceChat_Unmute + actionButtonSubtitle = self.presentationData.strings.VoiceChat_UnmuteHelp + audioButtonAppearance = .color(.custom(0x00274d)) + } else { + actionButtonState = .active(state: .cantSpeak) + + actionButtonTitle = self.presentationData.strings.VoiceChat_Muted + actionButtonSubtitle = self.presentationData.strings.VoiceChat_MutedHelp + audioButtonAppearance = .color(.custom(0x00274d)) + } + } else { + actionButtonState = .active(state: .on) + actionButtonTitle = self.pushingToTalk ? self.presentationData.strings.VoiceChat_Live : self.presentationData.strings.VoiceChat_Mute actionButtonSubtitle = "" audioButtonAppearance = .color(.custom(0x005720)) - } else { - actionButtonTitle = self.presentationData.strings.VoiceChat_Unmute - actionButtonSubtitle = self.presentationData.strings.VoiceChat_UnmuteHelp - audioButtonAppearance = .color(.custom(0x00274d)) } } } else { @@ -943,7 +964,7 @@ public final class VoiceChatController: ViewController { }) } - private func updateMembers(isMuted: Bool, members: [RenderedChannelParticipant], memberStates: [PeerId: PresentationGroupCallMemberState], invitedPeers: Set) { + private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, members: [RenderedChannelParticipant], memberStates: [PeerId: PresentationGroupCallMemberState], invitedPeers: Set) { var members = members members.sort(by: { lhs, rhs in if lhs.peer.id == self.context.account.peerId { @@ -980,7 +1001,7 @@ public final class VoiceChatController: ViewController { let memberState: PeerEntry.State var memberMuteState: GroupCallParticipantsContext.Participant.MuteState? if member.peer.id == self.context.account.peerId { - if !isMuted { + if muteState == nil { memberState = .speaking } else { memberState = .listening