Improve audio playback rate controls

This commit is contained in:
Ilya Laktyushin 2023-02-10 07:48:41 +04:00
parent c53d7a1401
commit 88dd028371
14 changed files with 146 additions and 71 deletions

View File

@ -8910,3 +8910,11 @@ Sorry for the inconvenience.";
"Appearance.VoiceOver.Theme" = "%@ Theme"; "Appearance.VoiceOver.Theme" = "%@ Theme";
"ChatList.EmptyChatListWithArchive" = "All of your chats are archived."; "ChatList.EmptyChatListWithArchive" = "All of your chats are archived.";
"VoiceOver.Media.PlaybackRate05X" = "0.5X";
"VoiceOver.Media.PlaybackRate125X" = "1.25X";
"VoiceOver.Media.PlaybackRate15X" = "1.5X";
"VoiceOver.Media.PlaybackRate175X" = "1.75X";
"VoiceOver.Media.PlaybackRate2X" = "2X";
"Conversation.AudioRateTooltip15X" = "Audio will play at 1.5X speed.";

View File

@ -2713,7 +2713,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
strongSelf.context.sharedContext.mediaManager.setPlaylist(nil, type: type, control: SharedMediaPlayerControlAction.playback(.pause)) strongSelf.context.sharedContext.mediaManager.setPlaylist(nil, type: type, control: SharedMediaPlayerControlAction.playback(.pause))
} }
} }
mediaAccessoryPanel.setRate = { [weak self] rate in mediaAccessoryPanel.setRate = { [weak self] rate, fromMenu in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
@ -2742,21 +2742,28 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
}) })
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let slowdown: Bool? let text: String?
let rate: CGFloat?
if baseRate == .x1 { if baseRate == .x1 {
slowdown = true text = presentationData.strings.Conversation_AudioRateTooltipNormal
rate = 1.0
} else if baseRate == .x1_5 {
text = presentationData.strings.Conversation_AudioRateTooltip15X
rate = 1.5
} else if baseRate == .x2 { } else if baseRate == .x2 {
slowdown = false text = presentationData.strings.Conversation_AudioRateTooltipSpeedUp
rate = 2.0
} else { } else {
slowdown = nil text = nil
rate = nil
} }
if let slowdown = slowdown { if let rate, let text, !fromMenu {
controller.present( controller.present(
UndoOverlayController( UndoOverlayController(
presentationData: presentationData, presentationData: presentationData,
content: .audioRate( content: .audioRate(
slowdown: slowdown, rate: rate,
text: slowdown ? presentationData.strings.Conversation_AudioRateTooltipNormal : presentationData.strings.Conversation_AudioRateTooltipSpeedUp text: text
), ),
elevatedLayout: false, elevatedLayout: false,
animateInAsReplacement: hasTooltip, animateInAsReplacement: hasTooltip,

View File

@ -171,7 +171,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
public var tapAction: (() -> Void)? public var tapAction: (() -> Void)?
public var close: (() -> Void)? public var close: (() -> Void)?
public var setRate: ((AudioPlaybackRate) -> Void)? public var setRate: ((AudioPlaybackRate, Bool) -> Void)?
public var togglePlayPause: (() -> Void)? public var togglePlayPause: (() -> Void)?
public var playPrevious: (() -> Void)? public var playPrevious: (() -> Void)?
public var playNext: (() -> Void)? public var playNext: (() -> Void)?
@ -184,21 +184,27 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
guard self.playbackBaseRate != oldValue, let playbackBaseRate = self.playbackBaseRate else { guard self.playbackBaseRate != oldValue, let playbackBaseRate = self.playbackBaseRate else {
return return
} }
self.rateButton.accessibilityLabel = self.strings.VoiceOver_Media_PlaybackRate
self.rateButton.accessibilityHint = self.strings.VoiceOver_Media_PlaybackRateChange
switch playbackBaseRate { switch playbackBaseRate {
case .x0_5: case .x0_5:
self.rateButton.setContent(.image(optionsRateImage(rate: "0.5X", color: self.theme.rootController.navigationBar.accentTextColor))) self.rateButton.setContent(.image(optionsRateImage(rate: "0.5X", color: self.theme.rootController.navigationBar.accentTextColor)))
self.rateButton.accessibilityValue = self.strings.VoiceOver_Media_PlaybackRate05X
case .x1: case .x1:
self.rateButton.setContent(.image(optionsRateImage(rate: "1X", color: self.theme.rootController.navigationBar.controlColor))) self.rateButton.setContent(.image(optionsRateImage(rate: "1X", color: self.theme.rootController.navigationBar.controlColor)))
self.rateButton.accessibilityLabel = self.strings.VoiceOver_Media_PlaybackRate
self.rateButton.accessibilityValue = self.strings.VoiceOver_Media_PlaybackRateNormal self.rateButton.accessibilityValue = self.strings.VoiceOver_Media_PlaybackRateNormal
self.rateButton.accessibilityHint = self.strings.VoiceOver_Media_PlaybackRateChange case .x1_25:
self.rateButton.setContent(.image(optionsRateImage(rate: "1.25X", color: self.theme.rootController.navigationBar.accentTextColor)))
self.rateButton.accessibilityValue = self.strings.VoiceOver_Media_PlaybackRate125X
case .x1_5: case .x1_5:
self.rateButton.setContent(.image(optionsRateImage(rate: "1.5X", color: self.theme.rootController.navigationBar.accentTextColor))) self.rateButton.setContent(.image(optionsRateImage(rate: "1.5X", color: self.theme.rootController.navigationBar.accentTextColor)))
self.rateButton.accessibilityValue = self.strings.VoiceOver_Media_PlaybackRate15X
case .x1_75:
self.rateButton.setContent(.image(optionsRateImage(rate: "1.75X", color: self.theme.rootController.navigationBar.accentTextColor)))
self.rateButton.accessibilityValue = self.strings.VoiceOver_Media_PlaybackRate175X
case .x2: case .x2:
self.rateButton.setContent(.image(optionsRateImage(rate: "2X", color: self.theme.rootController.navigationBar.accentTextColor))) self.rateButton.setContent(.image(optionsRateImage(rate: "2X", color: self.theme.rootController.navigationBar.accentTextColor)))
self.rateButton.accessibilityLabel = self.strings.VoiceOver_Media_PlaybackRate self.rateButton.accessibilityValue = self.strings.VoiceOver_Media_PlaybackRate2X
self.rateButton.accessibilityValue = self.strings.VoiceOver_Media_PlaybackRateFast
self.rateButton.accessibilityHint = self.strings.VoiceOver_Media_PlaybackRateChange
default: default:
break break
} }
@ -379,8 +385,12 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
self.rateButton.setContent(.image(optionsRateImage(rate: "0.5X", color: self.theme.rootController.navigationBar.accentTextColor))) self.rateButton.setContent(.image(optionsRateImage(rate: "0.5X", color: self.theme.rootController.navigationBar.accentTextColor)))
case .x1: case .x1:
self.rateButton.setContent(.image(optionsRateImage(rate: "1X", color: self.theme.rootController.navigationBar.controlColor))) self.rateButton.setContent(.image(optionsRateImage(rate: "1X", color: self.theme.rootController.navigationBar.controlColor)))
case .x1_25:
self.rateButton.setContent(.image(optionsRateImage(rate: "1.25X", color: self.theme.rootController.navigationBar.controlColor)))
case .x1_5: case .x1_5:
self.rateButton.setContent(.image(optionsRateImage(rate: "1.5X", color: self.theme.rootController.navigationBar.accentTextColor))) self.rateButton.setContent(.image(optionsRateImage(rate: "1.5X", color: self.theme.rootController.navigationBar.accentTextColor)))
case .x1_75:
self.rateButton.setContent(.image(optionsRateImage(rate: "1.75X", color: self.theme.rootController.navigationBar.controlColor)))
case .x2: case .x2:
self.rateButton.setContent(.image(optionsRateImage(rate: "2X", color: self.theme.rootController.navigationBar.accentTextColor))) self.rateButton.setContent(.image(optionsRateImage(rate: "2X", color: self.theme.rootController.navigationBar.accentTextColor)))
default: default:
@ -493,6 +503,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
transition.updateFrame(node: self.closeButton, frame: CGRect(origin: CGPoint(x: bounds.size.width - 44.0 - rightInset, y: 0.0), size: CGSize(width: 44.0, height: minHeight))) transition.updateFrame(node: self.closeButton, frame: CGRect(origin: CGPoint(x: bounds.size.width - 44.0 - rightInset, y: 0.0), size: CGSize(width: 44.0, height: minHeight)))
let rateButtonSize = CGSize(width: 30.0, height: minHeight) let rateButtonSize = CGSize(width: 30.0, height: minHeight)
transition.updateFrame(node: self.rateButton, frame: CGRect(origin: CGPoint(x: bounds.size.width - 33.0 - closeButtonSize.width - rateButtonSize.width - rightInset, y: -4.0), size: rateButtonSize)) transition.updateFrame(node: self.rateButton, frame: CGRect(origin: CGPoint(x: bounds.size.width - 33.0 - closeButtonSize.width - rateButtonSize.width - rightInset, y: -4.0), size: rateButtonSize))
transition.updateFrame(node: self.playPauseIconNode, frame: CGRect(origin: CGPoint(x: 6.0, y: 4.0 + UIScreenPixel), size: CGSize(width: 28.0, height: 28.0))) transition.updateFrame(node: self.playPauseIconNode, frame: CGRect(origin: CGPoint(x: 6.0, y: 4.0 + UIScreenPixel), size: CGSize(width: 28.0, height: 28.0)))
transition.updateFrame(node: self.actionButton, frame: CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: 40.0, height: 37.0))) transition.updateFrame(node: self.actionButton, frame: CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: 40.0, height: 37.0)))
transition.updateFrame(node: self.scrubbingNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 37.0 - 2.0), size: CGSize(width: size.width, height: 2.0))) transition.updateFrame(node: self.scrubbingNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 37.0 - 2.0), size: CGSize(width: size.width, height: 2.0)))
@ -520,14 +531,16 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
} else { } else {
nextRate = .x2 nextRate = .x2
} }
self.setRate?(nextRate) self.setRate?(nextRate, false)
} }
private func speedList(strings: PresentationStrings) -> [(String, String, AudioPlaybackRate)] { private func speedList(strings: PresentationStrings) -> [(String, String, AudioPlaybackRate)] {
let speedList: [(String, String, AudioPlaybackRate)] = [ let speedList: [(String, String, AudioPlaybackRate)] = [
("0.5x", "0.5x", .x0_5), ("0.5x", "0.5x", .x0_5),
(strings.PlaybackSpeed_Normal, "1x", .x1), (strings.PlaybackSpeed_Normal, "1x", .x1),
("1.25x", "1.25x", .x1_25),
("1.5x", "1.5x", .x1_5), ("1.5x", "1.5x", .x1_5),
("1.75x", "1.75x", .x1_75),
("2x", "2x", .x2) ("2x", "2x", .x2)
] ]
return speedList return speedList
@ -547,7 +560,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
}, action: { [weak self] _, f in }, action: { [weak self] _, f in
f(.default) f(.default)
self?.setRate?(rate) self?.setRate?(rate, true)
}))) })))
} }
@ -626,7 +639,7 @@ private final class PlayPauseIconNode: ManagedAnimationNode {
} }
private func optionsRateImage(rate: String, color: UIColor = .white) -> UIImage? { private func optionsRateImage(rate: String, color: UIColor = .white) -> UIImage? {
return generateImage(CGSize(width: 30.0, height: 16.0), rotatedContext: { size, context in return generateImage(CGSize(width: 36.0, height: 16.0), rotatedContext: { size, context in
UIGraphicsPushContext(context) UIGraphicsPushContext(context)
context.clear(CGRect(origin: CGPoint(), size: size)) context.clear(CGRect(origin: CGPoint(), size: size))
@ -640,7 +653,11 @@ private func optionsRateImage(rate: String, color: UIColor = .white) -> UIImage?
var offset = CGPoint(x: 1.0, y: 0.0) var offset = CGPoint(x: 1.0, y: 0.0)
var width: CGFloat var width: CGFloat
if rate.count >= 3 { if rate.count >= 5 {
string.addAttribute(.kern, value: -0.8 as NSNumber, range: NSRange(string.string.startIndex ..< string.string.endIndex, in: string.string))
offset.x += -0.5
width = 34.0
} else if rate.count >= 3 {
if rate == "0.5X" { if rate == "0.5X" {
string.addAttribute(.kern, value: -0.8 as NSNumber, range: NSRange(string.string.startIndex ..< string.string.endIndex, in: string.string)) string.addAttribute(.kern, value: -0.8 as NSNumber, range: NSRange(string.string.startIndex ..< string.string.endIndex, in: string.string))
offset.x += -0.5 offset.x += -0.5

View File

@ -11,7 +11,7 @@ public final class MediaNavigationAccessoryPanel: ASDisplayNode {
public let containerNode: MediaNavigationAccessoryContainerNode public let containerNode: MediaNavigationAccessoryContainerNode
public var close: (() -> Void)? public var close: (() -> Void)?
public var setRate: ((AudioPlaybackRate) -> Void)? public var setRate: ((AudioPlaybackRate, Bool) -> Void)?
public var togglePlayPause: (() -> Void)? public var togglePlayPause: (() -> Void)?
public var tapAction: (() -> Void)? public var tapAction: (() -> Void)?
public var playPrevious: (() -> Void)? public var playPrevious: (() -> Void)?
@ -32,8 +32,8 @@ public final class MediaNavigationAccessoryPanel: ASDisplayNode {
close() close()
} }
} }
self.containerNode.headerNode.setRate = { [weak self] rate in self.containerNode.headerNode.setRate = { [weak self] rate, fromMenu in
self?.setRate?(rate) self?.setRate?(rate, fromMenu)
} }
self.containerNode.headerNode.togglePlayPause = { [weak self] in self.containerNode.headerNode.togglePlayPause = { [weak self] in
if let strongSelf = self, let togglePlayPause = strongSelf.togglePlayPause { if let strongSelf = self, let togglePlayPause = strongSelf.togglePlayPause {

View File

@ -669,7 +669,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
strongSelf.context.sharedContext.mediaManager.setPlaylist(nil, type: type, control: SharedMediaPlayerControlAction.playback(.pause)) strongSelf.context.sharedContext.mediaManager.setPlaylist(nil, type: type, control: SharedMediaPlayerControlAction.playback(.pause))
} }
} }
mediaAccessoryPanel.setRate = { [weak self] rate in mediaAccessoryPanel.setRate = { [weak self] rate, fromMenu in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
@ -687,41 +687,48 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
} }
strongSelf.context.sharedContext.mediaManager.playlistControl(.setBaseRate(baseRate), type: type) strongSelf.context.sharedContext.mediaManager.playlistControl(.setBaseRate(baseRate), type: type)
// var hasTooltip = false var hasTooltip = false
// strongSelf.forEachController({ controller in strongSelf.forEachController({ controller in
// if let controller = controller as? UndoOverlayController { if let controller = controller as? UndoOverlayController {
// hasTooltip = true hasTooltip = true
// controller.dismissWithCommitAction() controller.dismissWithCommitAction()
// } }
// return true return true
// }) })
//
// let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
// let slowdown: Bool? let text: String?
// if baseRate == .x1 { let rate: CGFloat?
// slowdown = true if baseRate == .x1 {
// } else if baseRate == .x2 { text = presentationData.strings.Conversation_AudioRateTooltipNormal
// slowdown = false rate = 1.0
// } else { } else if baseRate == .x1_5 {
// slowdown = nil text = presentationData.strings.Conversation_AudioRateTooltip15X
// } rate = 1.5
// if let slowdown = slowdown { } else if baseRate == .x2 {
// strongSelf.present( text = presentationData.strings.Conversation_AudioRateTooltipSpeedUp
// UndoOverlayController( rate = 2.0
// presentationData: presentationData, } else {
// content: .audioRate( text = nil
// slowdown: slowdown, rate = nil
// text: slowdown ? presentationData.strings.Conversation_AudioRateTooltipNormal : presentationData.strings.Conversation_AudioRateTooltipSpeedUp }
// ), if let rate, let text, !fromMenu {
// elevatedLayout: false, strongSelf.present(
// animateInAsReplacement: hasTooltip, UndoOverlayController(
// action: { action in presentationData: presentationData,
// return true content: .audioRate(
// } rate: rate,
// ), text: text
// in: .current ),
// ) elevatedLayout: false,
// } animateInAsReplacement: hasTooltip,
action: { action in
return true
}
),
in: .current
)
}
}) })
} }
mediaAccessoryPanel.togglePlayPause = { [weak self] in mediaAccessoryPanel.togglePlayPause = { [weak self] in

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -36,7 +36,7 @@ private func generateCollapseIcon(theme: PresentationTheme) -> UIImage? {
} }
private func optionsRateImage(rate: String, color: UIColor = .white) -> UIImage? { private func optionsRateImage(rate: String, color: UIColor = .white) -> UIImage? {
return generateImage(CGSize(width: 30.0, height: 16.0), rotatedContext: { size, context in return generateImage(CGSize(width: 36.0, height: 16.0), rotatedContext: { size, context in
UIGraphicsPushContext(context) UIGraphicsPushContext(context)
context.clear(CGRect(origin: CGPoint(), size: size)) context.clear(CGRect(origin: CGPoint(), size: size))
@ -50,7 +50,11 @@ private func optionsRateImage(rate: String, color: UIColor = .white) -> UIImage?
var offset = CGPoint(x: 1.0, y: 0.0) var offset = CGPoint(x: 1.0, y: 0.0)
var width: CGFloat var width: CGFloat
if rate.count >= 3 { if rate.count >= 5 {
string.addAttribute(.kern, value: -0.8 as NSNumber, range: NSRange(string.string.startIndex ..< string.string.endIndex, in: string.string))
offset.x += -0.5
width = 33.0
} else if rate.count >= 3 {
if rate == "0.5X" { if rate == "0.5X" {
string.addAttribute(.kern, value: -0.8 as NSNumber, range: NSRange(string.string.startIndex ..< string.string.endIndex, in: string.string)) string.addAttribute(.kern, value: -0.8 as NSNumber, range: NSRange(string.string.startIndex ..< string.string.endIndex, in: string.string))
offset.x += -0.5 offset.x += -0.5
@ -418,8 +422,14 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
let baseRate: AudioPlaybackRate let baseRate: AudioPlaybackRate
if value.status.baseRate.isEqual(to: 2.0) { if value.status.baseRate.isEqual(to: 2.0) {
baseRate = .x2 baseRate = .x2
} else if value.status.baseRate.isEqual(to: 1.75) {
baseRate = .x1_75
} else if value.status.baseRate.isEqual(to: 1.5) { } else if value.status.baseRate.isEqual(to: 1.5) {
baseRate = .x1_25
} else if value.status.baseRate.isEqual(to: 1.25) {
baseRate = .x1_5 baseRate = .x1_5
} else if value.status.baseRate.isEqual(to: 0.5) {
baseRate = .x0_5
} else { } else {
baseRate = .x1 baseRate = .x1
} }
@ -784,8 +794,14 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
switch baseRate { switch baseRate {
case .x2: case .x2:
self.rateButton.setImage(optionsRateImage(rate: "2X", color: self.presentationData.theme.list.itemAccentColor), for: []) self.rateButton.setImage(optionsRateImage(rate: "2X", color: self.presentationData.theme.list.itemAccentColor), for: [])
case .x1_75:
self.rateButton.setImage(optionsRateImage(rate: "1.75X", color: self.presentationData.theme.list.itemAccentColor), for: [])
case .x1_5: case .x1_5:
self.rateButton.setImage(optionsRateImage(rate: "1.5X", color: self.presentationData.theme.list.itemAccentColor), for: []) self.rateButton.setImage(optionsRateImage(rate: "1.5X", color: self.presentationData.theme.list.itemAccentColor), for: [])
case .x1_25:
self.rateButton.setImage(optionsRateImage(rate: "1.25X", color: self.presentationData.theme.list.itemAccentColor), for: [])
case .x0_5:
self.rateButton.setImage(optionsRateImage(rate: "0.5X", color: self.presentationData.theme.list.itemAccentColor), for: [])
default: default:
self.rateButton.setImage(optionsRateImage(rate: "1X", color: self.presentationData.theme.list.itemSecondaryTextColor), for: []) self.rateButton.setImage(optionsRateImage(rate: "1X", color: self.presentationData.theme.list.itemSecondaryTextColor), for: [])
} }

View File

@ -262,7 +262,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
strongSelf.context.sharedContext.mediaManager.setPlaylist(nil, type: type, control: SharedMediaPlayerControlAction.playback(.pause)) strongSelf.context.sharedContext.mediaManager.setPlaylist(nil, type: type, control: SharedMediaPlayerControlAction.playback(.pause))
} }
} }
mediaAccessoryPanel.setRate = { [weak self] rate in mediaAccessoryPanel.setRate = { [weak self] rate, fromMenu in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
@ -291,21 +291,28 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
}) })
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let slowdown: Bool? let text: String?
let rate: CGFloat?
if baseRate == .x1 { if baseRate == .x1 {
slowdown = true text = presentationData.strings.Conversation_AudioRateTooltipNormal
rate = 1.0
} else if baseRate == .x1_5 {
text = presentationData.strings.Conversation_AudioRateTooltip15X
rate = 1.5
} else if baseRate == .x2 { } else if baseRate == .x2 {
slowdown = false text = presentationData.strings.Conversation_AudioRateTooltipSpeedUp
rate = 2.0
} else { } else {
slowdown = nil text = nil
rate = nil
} }
if let slowdown = slowdown { if let rate, let text, !fromMenu {
controller.present( controller.present(
UndoOverlayController( UndoOverlayController(
presentationData: presentationData, presentationData: presentationData,
content: .audioRate( content: .audioRate(
slowdown: slowdown, rate: rate,
text: slowdown ? presentationData.strings.Conversation_AudioRateTooltipNormal : presentationData.strings.Conversation_AudioRateTooltipSpeedUp text: text
), ),
elevatedLayout: false, elevatedLayout: false,
animateInAsReplacement: hasTooltip, animateInAsReplacement: hasTooltip,

View File

@ -18,7 +18,9 @@ public enum MusicPlaybackSettingsLooping: Int32 {
public enum AudioPlaybackRate: Int32 { public enum AudioPlaybackRate: Int32 {
case x0_5 = 500 case x0_5 = 500
case x1 = 1000 case x1 = 1000
case x1_25 = 1250
case x1_5 = 1500 case x1_5 = 1500
case x1_75 = 1750
case x2 = 2000 case x2 = 2000
case x4 = 4000 case x4 = 4000
case x8 = 8000 case x8 = 8000

View File

@ -26,7 +26,7 @@ public enum UndoOverlayContent {
case linkCopied(text: String) case linkCopied(text: String)
case banned(text: String) case banned(text: String)
case importedMessage(text: String) case importedMessage(text: String)
case audioRate(slowdown: Bool, text: String) case audioRate(rate: CGFloat, text: String)
case forward(savedMessages: Bool, text: String) case forward(savedMessages: Bool, text: String)
case autoDelete(isOn: Bool, title: String?, text: String) case autoDelete(isOn: Bool, title: String?, text: String)
case gigagroupConversion(text: String) case gigagroupConversion(text: String)

View File

@ -540,11 +540,21 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
displayUndo = false displayUndo = false
} }
self.originalRemainingSeconds = duration self.originalRemainingSeconds = duration
case let .audioRate(slowdown, text): case let .audioRate(rate, text):
self.avatarNode = nil self.avatarNode = nil
self.iconNode = nil self.iconNode = nil
self.iconCheckNode = nil self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: slowdown ? "anim_voicespeedstop" : "anim_voicespeed", colors: [:], scale: 0.066)
let animationName: String
if rate == 1.5 {
animationName = "anim_voice1_5x"
} else if rate == 2.0 {
animationName = "anim_voice2x"
} else {
animationName = "anim_voice1x"
}
self.animationNode = AnimationNode(animation: animationName, colors: [:], scale: 0.066)
self.animatedStickerNode = nil self.animatedStickerNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white) let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)