mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 17:30:12 +00:00
Voice Chat Fixes
This commit is contained in:
parent
0ec1dd0484
commit
34f4daf07d
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -6261,3 +6261,5 @@ Sorry for the inconvenience.";
|
|||||||
"Invitation.JoinVoiceChat" = "Join Voice Chat";
|
"Invitation.JoinVoiceChat" = "Join Voice Chat";
|
||||||
|
|
||||||
"VoiceChat.CancelSpeakRequest" = "Cancel Request to Speak";
|
"VoiceChat.CancelSpeakRequest" = "Cancel Request to Speak";
|
||||||
|
|
||||||
|
"VoiceChat.RemovePeerConfirmationChannel" = "Are you sure you want to remove %@ from the channel?";
|
||||||
|
|||||||
@ -16,6 +16,7 @@ public enum DeleteChatPeerAction {
|
|||||||
case clearCache
|
case clearCache
|
||||||
case clearCacheSuggestion
|
case clearCacheSuggestion
|
||||||
case removeFromGroup
|
case removeFromGroup
|
||||||
|
case removeFromChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
private let avatarFont = avatarPlaceholderFont(size: 26.0)
|
private let avatarFont = avatarPlaceholderFont(size: 26.0)
|
||||||
@ -142,6 +143,8 @@ private final class DeleteChatPeerActionSheetItemNode: ActionSheetItemNode {
|
|||||||
}
|
}
|
||||||
case .removeFromGroup:
|
case .removeFromGroup:
|
||||||
text = strings.VoiceChat_RemovePeerConfirmation(peer.displayTitle(strings: strings, displayOrder: nameOrder))
|
text = strings.VoiceChat_RemovePeerConfirmation(peer.displayTitle(strings: strings, displayOrder: nameOrder))
|
||||||
|
case .removeFromChannel:
|
||||||
|
text = strings.VoiceChat_RemovePeerConfirmationChannel(peer.displayTitle(strings: strings, displayOrder: nameOrder))
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@ -137,6 +137,8 @@ open class ManagedAnimationNode: ASDisplayNode {
|
|||||||
public var trackStack: [ManagedAnimationItem] = []
|
public var trackStack: [ManagedAnimationItem] = []
|
||||||
public var didTryAdvancingState = false
|
public var didTryAdvancingState = false
|
||||||
|
|
||||||
|
public var isPlaying = false
|
||||||
|
|
||||||
public init(size: CGSize) {
|
public init(size: CGSize) {
|
||||||
self.intrinsicSize = size
|
self.intrinsicSize = size
|
||||||
|
|
||||||
|
|||||||
@ -549,6 +549,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
let peer = peerEntry.peer
|
let peer = peerEntry.peer
|
||||||
|
|
||||||
var text: VoiceChatParticipantItem.ParticipantText
|
var text: VoiceChatParticipantItem.ParticipantText
|
||||||
|
var expandedText: VoiceChatParticipantItem.ParticipantText?
|
||||||
let icon: VoiceChatParticipantItem.Icon
|
let icon: VoiceChatParticipantItem.Icon
|
||||||
switch peerEntry.state {
|
switch peerEntry.state {
|
||||||
case .listening:
|
case .listening:
|
||||||
@ -587,9 +588,13 @@ public final class VoiceChatController: ViewController {
|
|||||||
icon = .wantsToSpeak
|
icon = .wantsToSpeak
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let about = peerEntry.about, !about.isEmpty {
|
||||||
|
expandedText = .text(about, .generic)
|
||||||
|
}
|
||||||
|
|
||||||
let revealOptions: [VoiceChatParticipantItem.RevealOption] = []
|
let revealOptions: [VoiceChatParticipantItem.RevealOption] = []
|
||||||
|
|
||||||
return VoiceChatParticipantItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: context, peer: peer, ssrc: peerEntry.ssrc, presence: peerEntry.presence, text: text, icon: icon, enabled: true, selectable: !peerEntry.isMyPeer || peerEntry.canManageCall || peerEntry.raisedHand, getAudioLevel: { return interaction.getAudioLevel(peer.id) }, getVideo: {
|
return VoiceChatParticipantItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: context, peer: peer, ssrc: peerEntry.ssrc, presence: peerEntry.presence, text: text, expandedText: expandedText, icon: icon, enabled: true, selectable: !peerEntry.isMyPeer || peerEntry.canManageCall || peerEntry.raisedHand, getAudioLevel: { return interaction.getAudioLevel(peer.id) }, getVideo: {
|
||||||
if let ssrc = peerEntry.ssrc {
|
if let ssrc = peerEntry.ssrc {
|
||||||
return interaction.getPeerVideo(ssrc)
|
return interaction.getPeerVideo(ssrc)
|
||||||
} else {
|
} else {
|
||||||
@ -2054,7 +2059,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
return formatSendTitle(self.presentationData.strings.VoiceChat_InviteLink_InviteListeners(Int32(count)))
|
return formatSendTitle(self.presentationData.strings.VoiceChat_InviteLink_InviteListeners(Int32(count)))
|
||||||
})]
|
})]
|
||||||
}
|
}
|
||||||
let shareController = ShareController(context: self.context, subject: .url(inviteLinks.listenerLink), segmentedValues: segmentedValues, forcedTheme: self.darkTheme, forcedActionTitle: self.presentationData.strings.VoiceChat_InviteLink_CopyListenerLink)
|
let shareController = ShareController(context: self.context, subject: .url(inviteLinks.listenerLink), segmentedValues: segmentedValues, forcedTheme: self.darkTheme, forcedActionTitle: self.presentationData.strings.VoiceChat_CopyInviteLink)
|
||||||
shareController.actionCompleted = { [weak self] in
|
shareController.actionCompleted = { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|||||||
@ -108,6 +108,7 @@ public final class VoiceChatJoinScreen: ViewController {
|
|||||||
|
|
||||||
let activeCall = CachedChannelData.ActiveCall(id: call.info.id, accessHash: call.info.accessHash, title: call.info.title)
|
let activeCall = CachedChannelData.ActiveCall(id: call.info.id, accessHash: call.info.accessHash, title: call.info.title)
|
||||||
if availablePeers.count > 0 && defaultJoinAsPeerId == nil {
|
if availablePeers.count > 0 && defaultJoinAsPeerId == nil {
|
||||||
|
strongSelf.dismiss()
|
||||||
strongSelf.join(activeCall)
|
strongSelf.join(activeCall)
|
||||||
} else {
|
} else {
|
||||||
strongSelf.controllerNode.setPeer(call: activeCall, peer: peer, title: call.info.title, memberCount: call.info.participantCount)
|
strongSelf.controllerNode.setPeer(call: activeCall, peer: peer, title: call.info.title, memberCount: call.info.participantCount)
|
||||||
|
|||||||
@ -66,6 +66,7 @@ final class VoiceChatParticipantItem: ListViewItem {
|
|||||||
let ssrc: UInt32?
|
let ssrc: UInt32?
|
||||||
let presence: PeerPresence?
|
let presence: PeerPresence?
|
||||||
let text: ParticipantText
|
let text: ParticipantText
|
||||||
|
let expandedText: ParticipantText?
|
||||||
let icon: Icon
|
let icon: Icon
|
||||||
let enabled: Bool
|
let enabled: Bool
|
||||||
public let selectable: Bool
|
public let selectable: Bool
|
||||||
@ -77,7 +78,7 @@ final class VoiceChatParticipantItem: ListViewItem {
|
|||||||
let action: ((ASDisplayNode) -> Void)?
|
let action: ((ASDisplayNode) -> Void)?
|
||||||
let contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
|
let contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
|
||||||
|
|
||||||
public init(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, context: AccountContext, peer: Peer, ssrc: UInt32?, presence: PeerPresence?, text: ParticipantText, icon: Icon, enabled: Bool, selectable: Bool, getAudioLevel: (() -> Signal<Float, NoError>)?, getVideo: @escaping () -> GroupVideoNode?, revealOptions: [RevealOption], revealed: Bool?, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, action: ((ASDisplayNode) -> Void)?, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? = nil) {
|
public init(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, context: AccountContext, peer: Peer, ssrc: UInt32?, presence: PeerPresence?, text: ParticipantText, expandedText: ParticipantText?, icon: Icon, enabled: Bool, selectable: Bool, getAudioLevel: (() -> Signal<Float, NoError>)?, getVideo: @escaping () -> GroupVideoNode?, revealOptions: [RevealOption], revealed: Bool?, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, action: ((ASDisplayNode) -> Void)?, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? = nil) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.dateTimeFormat = dateTimeFormat
|
self.dateTimeFormat = dateTimeFormat
|
||||||
self.nameDisplayOrder = nameDisplayOrder
|
self.nameDisplayOrder = nameDisplayOrder
|
||||||
@ -86,6 +87,7 @@ final class VoiceChatParticipantItem: ListViewItem {
|
|||||||
self.ssrc = ssrc
|
self.ssrc = ssrc
|
||||||
self.presence = presence
|
self.presence = presence
|
||||||
self.text = text
|
self.text = text
|
||||||
|
self.expandedText = expandedText
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
self.enabled = enabled
|
self.enabled = enabled
|
||||||
self.selectable = selectable
|
self.selectable = selectable
|
||||||
@ -160,6 +162,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
|||||||
fileprivate let avatarNode: AvatarNode
|
fileprivate let avatarNode: AvatarNode
|
||||||
private let titleNode: TextNode
|
private let titleNode: TextNode
|
||||||
private let statusNode: TextNode
|
private let statusNode: TextNode
|
||||||
|
private let expandedStatusNode: TextNode
|
||||||
private var credibilityIconNode: ASImageNode?
|
private var credibilityIconNode: ASImageNode?
|
||||||
|
|
||||||
private let actionContainerNode: ASDisplayNode
|
private let actionContainerNode: ASDisplayNode
|
||||||
@ -215,6 +218,12 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
|||||||
self.statusNode.contentMode = .left
|
self.statusNode.contentMode = .left
|
||||||
self.statusNode.contentsScale = UIScreen.main.scale
|
self.statusNode.contentsScale = UIScreen.main.scale
|
||||||
|
|
||||||
|
self.expandedStatusNode = TextNode()
|
||||||
|
self.expandedStatusNode.isUserInteractionEnabled = false
|
||||||
|
self.expandedStatusNode.contentMode = .left
|
||||||
|
self.expandedStatusNode.contentsScale = UIScreen.main.scale
|
||||||
|
self.expandedStatusNode.alpha = 0.0
|
||||||
|
|
||||||
self.actionContainerNode = ASDisplayNode()
|
self.actionContainerNode = ASDisplayNode()
|
||||||
self.actionButtonNode = HighlightableButtonNode()
|
self.actionButtonNode = HighlightableButtonNode()
|
||||||
|
|
||||||
@ -234,6 +243,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
|||||||
self.offsetContainerNode.addSubnode(self.avatarNode)
|
self.offsetContainerNode.addSubnode(self.avatarNode)
|
||||||
self.offsetContainerNode.addSubnode(self.titleNode)
|
self.offsetContainerNode.addSubnode(self.titleNode)
|
||||||
self.offsetContainerNode.addSubnode(self.statusNode)
|
self.offsetContainerNode.addSubnode(self.statusNode)
|
||||||
|
self.offsetContainerNode.addSubnode(self.expandedStatusNode)
|
||||||
self.offsetContainerNode.addSubnode(self.actionContainerNode)
|
self.offsetContainerNode.addSubnode(self.actionContainerNode)
|
||||||
self.actionContainerNode.addSubnode(self.actionButtonNode)
|
self.actionContainerNode.addSubnode(self.actionButtonNode)
|
||||||
self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode
|
self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode
|
||||||
@ -278,6 +288,9 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
|||||||
transition.updateFrame(node: strongSelf.extractedBackgroundImageNode, frame: rect)
|
transition.updateFrame(node: strongSelf.extractedBackgroundImageNode, frame: rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transition.updateAlpha(node: strongSelf.statusNode, alpha: isExtracted ? 0.0 : 1.0)
|
||||||
|
transition.updateAlpha(node: strongSelf.expandedStatusNode, alpha: isExtracted ? 1.0 : 0.0)
|
||||||
|
|
||||||
transition.updateAlpha(node: strongSelf.actionContainerNode, alpha: isExtracted ? 0.0 : 1.0)
|
transition.updateAlpha(node: strongSelf.actionContainerNode, alpha: isExtracted ? 0.0 : 1.0)
|
||||||
|
|
||||||
transition.updateSublayerTransformOffset(layer: strongSelf.offsetContainerNode.layer, offset: CGPoint(x: isExtracted ? 12.0 : 0.0, y: 0.0))
|
transition.updateSublayerTransformOffset(layer: strongSelf.offsetContainerNode.layer, offset: CGPoint(x: isExtracted ? 12.0 : 0.0, y: 0.0))
|
||||||
@ -305,6 +318,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
|||||||
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 makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||||
let makeStatusLayout = TextNode.asyncLayout(self.statusNode)
|
let makeStatusLayout = TextNode.asyncLayout(self.statusNode)
|
||||||
|
let makeExpandedStatusLayout = TextNode.asyncLayout(self.expandedStatusNode)
|
||||||
var currentDisabledOverlayNode = self.disabledOverlayNode
|
var currentDisabledOverlayNode = self.disabledOverlayNode
|
||||||
|
|
||||||
let currentItem = self.layoutParams?.0
|
let currentItem = self.layoutParams?.0
|
||||||
@ -415,6 +429,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
|||||||
|
|
||||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 12.0 - rightInset - 30.0 - titleIconsWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 12.0 - rightInset - 30.0 - titleIconsWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
let (statusLayout, statusApply) = makeStatusLayout(TextNodeLayoutArguments(attributedString: statusAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 8.0 - rightInset - 30.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
let (statusLayout, statusApply) = makeStatusLayout(TextNodeLayoutArguments(attributedString: statusAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 8.0 - rightInset - 30.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
let (expandedStatusLayout, expandedStatusApply) = makeExpandedStatusLayout(TextNodeLayoutArguments(attributedString: statusAttributedString, backgroundColor: nil, maximumNumberOfLines: 4, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 8.0 - rightInset - 30.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
let insets = UIEdgeInsets()
|
let insets = UIEdgeInsets()
|
||||||
|
|
||||||
@ -480,7 +495,11 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
|||||||
strongSelf.wavesColor = wavesColor
|
strongSelf.wavesColor = wavesColor
|
||||||
|
|
||||||
let nonExtractedRect = CGRect(origin: CGPoint(), size: CGSize(width: layout.contentSize.width - 16.0, height: layout.contentSize.height))
|
let nonExtractedRect = CGRect(origin: CGPoint(), size: CGSize(width: layout.contentSize.width - 16.0, height: layout.contentSize.height))
|
||||||
let extractedRect = CGRect(origin: CGPoint(), size: layout.contentSize).insetBy(dx: 16.0 + params.leftInset, dy: 0.0)
|
|
||||||
|
var extractedRect = CGRect(origin: CGPoint(), size: layout.contentSize).insetBy(dx: 16.0 + params.leftInset, dy: 0.0)
|
||||||
|
let extractedHeight = extractedRect.height + expandedStatusLayout.size.height - statusLayout.size.height
|
||||||
|
extractedRect.size.height = extractedHeight
|
||||||
|
|
||||||
strongSelf.extractedRect = extractedRect
|
strongSelf.extractedRect = extractedRect
|
||||||
strongSelf.nonExtractedRect = nonExtractedRect
|
strongSelf.nonExtractedRect = nonExtractedRect
|
||||||
|
|
||||||
@ -554,6 +573,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
|||||||
|
|
||||||
let _ = titleApply()
|
let _ = titleApply()
|
||||||
let _ = statusApply()
|
let _ = statusApply()
|
||||||
|
let _ = expandedStatusApply()
|
||||||
|
|
||||||
if strongSelf.topStripeNode.supernode == nil {
|
if strongSelf.topStripeNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.topStripeNode, at: 0)
|
strongSelf.insertSubnode(strongSelf.topStripeNode, at: 0)
|
||||||
@ -570,6 +590,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
|||||||
|
|
||||||
transition.updateFrame(node: strongSelf.titleNode, frame: CGRect(origin: CGPoint(x: leftInset, y: verticalInset + verticalOffset), size: titleLayout.size))
|
transition.updateFrame(node: strongSelf.titleNode, frame: CGRect(origin: CGPoint(x: leftInset, y: verticalInset + verticalOffset), size: titleLayout.size))
|
||||||
transition.updateFrame(node: strongSelf.statusNode, frame: CGRect(origin: CGPoint(x: leftInset, y: strongSelf.titleNode.frame.maxY + titleSpacing), size: statusLayout.size))
|
transition.updateFrame(node: strongSelf.statusNode, frame: CGRect(origin: CGPoint(x: leftInset, y: strongSelf.titleNode.frame.maxY + titleSpacing), size: statusLayout.size))
|
||||||
|
transition.updateFrame(node: strongSelf.expandedStatusNode, frame: CGRect(origin: CGPoint(x: leftInset, y: strongSelf.titleNode.frame.maxY + titleSpacing), size: expandedStatusLayout.size))
|
||||||
|
|
||||||
if let currentCredibilityIconImage = currentCredibilityIconImage {
|
if let currentCredibilityIconImage = currentCredibilityIconImage {
|
||||||
let iconNode: ASImageNode
|
let iconNode: ASImageNode
|
||||||
|
|||||||
@ -74,9 +74,9 @@ class VoiceChatRecordingIconNode: ASDisplayNode {
|
|||||||
|
|
||||||
private func setupAnimation() {
|
private func setupAnimation() {
|
||||||
let animation = CAKeyframeAnimation(keyPath: "opacity")
|
let animation = CAKeyframeAnimation(keyPath: "opacity")
|
||||||
animation.values = [1.0 as NSNumber, 1.0 as NSNumber, 0.0 as NSNumber]
|
animation.values = [1.0 as NSNumber, 1.0 as NSNumber, 0.55 as NSNumber]
|
||||||
animation.keyTimes = [0.0 as NSNumber, 0.4546 as NSNumber, 0.9091 as NSNumber, 1 as NSNumber]
|
animation.keyTimes = [0.0 as NSNumber, 0.4546 as NSNumber, 0.9091 as NSNumber, 1 as NSNumber]
|
||||||
animation.duration = 0.5
|
animation.duration = 0.7
|
||||||
animation.autoreverses = true
|
animation.autoreverses = true
|
||||||
animation.repeatCount = Float.infinity
|
animation.repeatCount = Float.infinity
|
||||||
self.dotNode.layer.add(animation, forKey: "recording")
|
self.dotNode.layer.add(animation, forKey: "recording")
|
||||||
|
|||||||
@ -431,7 +431,7 @@ func voiceChatTitleEditController(sharedContext: SharedAccountContext, account:
|
|||||||
|
|
||||||
let previousValue = value ?? ""
|
let previousValue = value ?? ""
|
||||||
let newValue = contentNode.value
|
let newValue = contentNode.value
|
||||||
apply(previousValue != newValue ? newValue : nil)
|
apply(previousValue != newValue || value == nil ? newValue : nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode)
|
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -413,7 +413,18 @@ public final class MediaManagerImpl: NSObject, MediaManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.mediaPlaybackStateDisposable.set(throttledSignal.start(next: { accountStateAndType in
|
self.mediaPlaybackStateDisposable.set(throttledSignal.start(next: { accountStateAndType in
|
||||||
if let (account, stateOrLoading, type) = accountStateAndType, type == .music, case let .state(state) = stateOrLoading, state.status.duration >= 60.0 * 20.0, case .playing = state.status.status {
|
let minimumStoreDuration: Double?
|
||||||
|
if let (account, stateOrLoading, type) = accountStateAndType {
|
||||||
|
switch type {
|
||||||
|
case .music:
|
||||||
|
minimumStoreDuration = 15.0 * 60.0
|
||||||
|
case .voice:
|
||||||
|
minimumStoreDuration = 5.0 * 60.0
|
||||||
|
case .file:
|
||||||
|
minimumStoreDuration = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if let minimumStoreDuration = minimumStoreDuration, case let .state(state) = stateOrLoading, state.status.duration >= minimumStoreDuration, case .playing = state.status.status {
|
||||||
if let item = state.item as? MessageMediaPlaylistItem {
|
if let item = state.item as? MessageMediaPlaylistItem {
|
||||||
var storedState: MediaPlaybackStoredState?
|
var storedState: MediaPlaybackStoredState?
|
||||||
if state.status.timestamp > 5.0 && state.status.timestamp < state.status.duration - 5.0 {
|
if state.status.timestamp > 5.0 && state.status.timestamp < state.status.duration - 5.0 {
|
||||||
@ -422,6 +433,7 @@ public final class MediaManagerImpl: NSObject, MediaManager {
|
|||||||
let _ = updateMediaPlaybackStoredStateInteractively(postbox: account.postbox, messageId: item.message.id, state: storedState).start()
|
let _ = updateMediaPlaybackStoredStateInteractively(postbox: account.postbox, messageId: item.message.id, state: storedState).start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
self.globalAudioSessionForegroundDisposable.set((shouldKeepAudioSession |> deliverOnMainQueue).start(next: { [weak self] value in
|
self.globalAudioSessionForegroundDisposable.set((shouldKeepAudioSession |> deliverOnMainQueue).start(next: { [weak self] value in
|
||||||
@ -492,7 +504,7 @@ public final class MediaManagerImpl: NSObject, MediaManager {
|
|||||||
case .voice:
|
case .voice:
|
||||||
strongSelf.musicMediaPlayer?.control(.playback(.pause))
|
strongSelf.musicMediaPlayer?.control(.playback(.pause))
|
||||||
strongSelf.voiceMediaPlayer?.stop()
|
strongSelf.voiceMediaPlayer?.stop()
|
||||||
if let (account, playlist, settings, _) = inputData {
|
if let (account, playlist, settings, storedState) = inputData {
|
||||||
let voiceMediaPlayer = SharedMediaPlayer(mediaManager: strongSelf, inForeground: strongSelf.inForeground, account: account, audioSession: strongSelf.audioSession, overlayMediaManager: strongSelf.overlayMediaManager, playlist: playlist, initialOrder: .reversed, initialLooping: .none, initialPlaybackRate: settings.voicePlaybackRate, playerIndex: nextPlayerIndex, controlPlaybackWithProximity: true, type: type)
|
let voiceMediaPlayer = SharedMediaPlayer(mediaManager: strongSelf, inForeground: strongSelf.inForeground, account: account, audioSession: strongSelf.audioSession, overlayMediaManager: strongSelf.overlayMediaManager, playlist: playlist, initialOrder: .reversed, initialLooping: .none, initialPlaybackRate: settings.voicePlaybackRate, playerIndex: nextPlayerIndex, controlPlaybackWithProximity: true, type: type)
|
||||||
strongSelf.voiceMediaPlayer = voiceMediaPlayer
|
strongSelf.voiceMediaPlayer = voiceMediaPlayer
|
||||||
voiceMediaPlayer.playedToEnd = { [weak voiceMediaPlayer] in
|
voiceMediaPlayer.playedToEnd = { [weak voiceMediaPlayer] in
|
||||||
@ -507,6 +519,11 @@ public final class MediaManagerImpl: NSObject, MediaManager {
|
|||||||
strongSelf.voiceMediaPlayer = nil
|
strongSelf.voiceMediaPlayer = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var control = control
|
||||||
|
if let timestamp = storedState?.timestamp {
|
||||||
|
control = .seek(timestamp)
|
||||||
|
}
|
||||||
voiceMediaPlayer.control(control)
|
voiceMediaPlayer.control(control)
|
||||||
} else {
|
} else {
|
||||||
strongSelf.voiceMediaPlayer = nil
|
strongSelf.voiceMediaPlayer = nil
|
||||||
|
|||||||
@ -111,7 +111,30 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode {
|
|||||||
if self.theme != presentationData.theme || self.icon != icon || self.isActive != isActive {
|
if self.theme != presentationData.theme || self.icon != icon || self.isActive != isActive {
|
||||||
self.theme = presentationData.theme
|
self.theme = presentationData.theme
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
|
|
||||||
|
let isActiveUpdated = self.isActive != isActive
|
||||||
self.isActive = isActive
|
self.isActive = isActive
|
||||||
|
|
||||||
|
|
||||||
|
if isActiveUpdated {
|
||||||
|
if let snapshotView = self.backgroundNode.view.snapshotContentTree() {
|
||||||
|
snapshotView.frame = self.backgroundNode.view.frame
|
||||||
|
self.view.addSubview(snapshotView)
|
||||||
|
|
||||||
|
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||||
|
snapshotView?.removeFromSuperview()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if let snapshotView = self.textNode.view.snapshotContentTree() {
|
||||||
|
snapshotView.frame = self.textNode.view.frame
|
||||||
|
self.view.addSubview(snapshotView)
|
||||||
|
|
||||||
|
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||||
|
snapshotView?.removeFromSuperview()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.backgroundNode.image = generateImage(CGSize(width: 40.0, height: 40.0), contextGenerator: { size, context in
|
self.backgroundNode.image = generateImage(CGSize(width: 40.0, height: 40.0), contextGenerator: { size, context in
|
||||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
context.setFillColor(isActive ? presentationData.theme.list.itemAccentColor.cgColor : presentationData.theme.list.itemDisabledTextColor.cgColor)
|
context.setFillColor(isActive ? presentationData.theme.list.itemAccentColor.cgColor : presentationData.theme.list.itemDisabledTextColor.cgColor)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user