mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '10b679446e7c0560683ee80747e0ded7cce20976'
This commit is contained in:
commit
f173aaa5e5
@ -2746,8 +2746,22 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let text: String?
|
let text: String?
|
||||||
let rate: CGFloat?
|
let rate: CGFloat?
|
||||||
|
if case let .sliderCommit(previousValue, newValue) = changeType {
|
||||||
|
let value = String(format: "%0.1f", baseRate.doubleValue)
|
||||||
if baseRate == .x1 {
|
if baseRate == .x1 {
|
||||||
text = presentationData.strings.Conversation_AudioRateTooltipNormal
|
text = presentationData.strings.Conversation_AudioRateTooltipNormal
|
||||||
|
} else {
|
||||||
|
text = presentationData.strings.Conversation_AudioRateTooltipCustom(value).string
|
||||||
|
}
|
||||||
|
if newValue > previousValue {
|
||||||
|
rate = .infinity
|
||||||
|
} else if newValue < previousValue {
|
||||||
|
rate = -.infinity
|
||||||
|
} else {
|
||||||
|
rate = nil
|
||||||
|
}
|
||||||
|
} else if baseRate == .x1 {
|
||||||
|
text = presentationData.strings.Conversation_AudioRateTooltipNormal
|
||||||
rate = 1.0
|
rate = 1.0
|
||||||
} else if baseRate == .x1_5 {
|
} else if baseRate == .x1_5 {
|
||||||
text = presentationData.strings.Conversation_AudioRateTooltip15X
|
text = presentationData.strings.Conversation_AudioRateTooltip15X
|
||||||
@ -2756,20 +2770,9 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
text = presentationData.strings.Conversation_AudioRateTooltipSpeedUp
|
text = presentationData.strings.Conversation_AudioRateTooltipSpeedUp
|
||||||
rate = 2.0
|
rate = 2.0
|
||||||
} else {
|
} else {
|
||||||
let value = String(format: "%0.1f", baseRate.doubleValue)
|
text = nil
|
||||||
text = presentationData.strings.Conversation_AudioRateTooltipCustom(value).string
|
|
||||||
if case let .sliderCommit(previousValue, newValue) = changeType {
|
|
||||||
if newValue > previousValue {
|
|
||||||
rate = .infinity
|
|
||||||
} else if newValue < previousValue {
|
|
||||||
rate = -.infinity
|
|
||||||
} else {
|
|
||||||
rate = nil
|
rate = nil
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
rate = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var showTooltip = true
|
var showTooltip = true
|
||||||
if case .sliderChange = changeType {
|
if case .sliderChange = changeType {
|
||||||
showTooltip = false
|
showTooltip = false
|
||||||
|
@ -1086,7 +1086,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
|||||||
|
|
||||||
let avatarIconContent: EmojiStatusComponent.Content
|
let avatarIconContent: EmojiStatusComponent.Content
|
||||||
if let fileId = icon, fileId != 0 {
|
if let fileId = icon, fileId != 0 {
|
||||||
avatarIconContent = .animation(content: .customEmoji(fileId: fileId), size: CGSize(width: 48.0, height: 48.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .forever)
|
avatarIconContent = .animation(content: .customEmoji(fileId: fileId), size: CGSize(width: 48.0, height: 48.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(0))
|
||||||
} else {
|
} else {
|
||||||
avatarIconContent = .topic(title: String(title.prefix(1)), color: color, size: CGSize(width: 32.0, height: 32.0))
|
avatarIconContent = .topic(title: String(title.prefix(1)), color: color, size: CGSize(width: 32.0, height: 32.0))
|
||||||
}
|
}
|
||||||
|
@ -2625,10 +2625,11 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
c.setItems(strongSelf.contextMenuMainItems(dismiss: dismiss) |> map { ContextController.Items(content: .list($0)) }, minHeight: nil)
|
c.setItems(strongSelf.contextMenuMainItems(dismiss: dismiss) |> map { ContextController.Items(content: .list($0)) }, minHeight: nil)
|
||||||
})))
|
})))
|
||||||
|
|
||||||
items.append(.custom(SliderContextItem(minValue: 0.5, maxValue: 2.5, value: status.baseRate, valueChanged: { [weak self] newValue, finished in
|
items.append(.custom(SliderContextItem(minValue: 0.2, maxValue: 2.5, value: status.baseRate, valueChanged: { [weak self] newValue, finished in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
let newValue = normalizeValue(newValue)
|
||||||
strongSelf.updatePlaybackRate(newValue)
|
strongSelf.updatePlaybackRate(newValue)
|
||||||
if finished {
|
if finished {
|
||||||
//dismiss()
|
//dismiss()
|
||||||
@ -2852,3 +2853,7 @@ final class HeaderContextReferenceContentSource: ContextReferenceContentSource {
|
|||||||
return ContextControllerReferenceViewInfo(referenceView: self.sourceNode.view, contentAreaInScreenSpace: UIScreen.main.bounds)
|
return ContextControllerReferenceViewInfo(referenceView: self.sourceNode.view, contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func normalizeValue(_ value: CGFloat) -> CGFloat {
|
||||||
|
return round(value * 10.0) / 10.0
|
||||||
|
}
|
||||||
|
@ -18,6 +18,10 @@ import SliderContextItem
|
|||||||
private let titleFont = Font.regular(12.0)
|
private let titleFont = Font.regular(12.0)
|
||||||
private let subtitleFont = Font.regular(10.0)
|
private let subtitleFont = Font.regular(10.0)
|
||||||
|
|
||||||
|
private func normalizeValue(_ value: CGFloat) -> CGFloat {
|
||||||
|
return round(value * 10.0) / 10.0
|
||||||
|
}
|
||||||
|
|
||||||
private class MediaHeaderItemNode: ASDisplayNode {
|
private class MediaHeaderItemNode: ASDisplayNode {
|
||||||
private let titleNode: TextNode
|
private let titleNode: TextNode
|
||||||
private let subtitleNode: TextNode
|
private let subtitleNode: TextNode
|
||||||
@ -527,7 +531,8 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
|
|||||||
var presetItems: [ContextMenuItem] = []
|
var presetItems: [ContextMenuItem] = []
|
||||||
|
|
||||||
let previousValue = self.playbackBaseRate?.doubleValue ?? 1.0
|
let previousValue = self.playbackBaseRate?.doubleValue ?? 1.0
|
||||||
let sliderItem: ContextMenuItem = .custom(SliderContextItem(minValue: 0.5, maxValue: 2.5, value: previousValue, valueChanged: { [weak self] newValue, finished in
|
let sliderItem: ContextMenuItem = .custom(SliderContextItem(minValue: 0.2, maxValue: 2.5, value: previousValue, valueChanged: { [weak self] newValue, finished in
|
||||||
|
let newValue = normalizeValue(newValue)
|
||||||
self?.setRate?(AudioPlaybackRate(newValue), .sliderChange)
|
self?.setRate?(AudioPlaybackRate(newValue), .sliderChange)
|
||||||
if finished {
|
if finished {
|
||||||
scheduleTooltip(.sliderCommit(previousValue, newValue))
|
scheduleTooltip(.sliderCommit(previousValue, newValue))
|
||||||
|
@ -699,8 +699,22 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
|
|||||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let text: String?
|
let text: String?
|
||||||
let rate: CGFloat?
|
let rate: CGFloat?
|
||||||
|
if case let .sliderCommit(previousValue, newValue) = changeType {
|
||||||
|
let value = String(format: "%0.1f", baseRate.doubleValue)
|
||||||
if baseRate == .x1 {
|
if baseRate == .x1 {
|
||||||
text = presentationData.strings.Conversation_AudioRateTooltipNormal
|
text = presentationData.strings.Conversation_AudioRateTooltipNormal
|
||||||
|
} else {
|
||||||
|
text = presentationData.strings.Conversation_AudioRateTooltipCustom(value).string
|
||||||
|
}
|
||||||
|
if newValue > previousValue {
|
||||||
|
rate = .infinity
|
||||||
|
} else if newValue < previousValue {
|
||||||
|
rate = -.infinity
|
||||||
|
} else {
|
||||||
|
rate = nil
|
||||||
|
}
|
||||||
|
} else if baseRate == .x1 {
|
||||||
|
text = presentationData.strings.Conversation_AudioRateTooltipNormal
|
||||||
rate = 1.0
|
rate = 1.0
|
||||||
} else if baseRate == .x1_5 {
|
} else if baseRate == .x1_5 {
|
||||||
text = presentationData.strings.Conversation_AudioRateTooltip15X
|
text = presentationData.strings.Conversation_AudioRateTooltip15X
|
||||||
@ -709,20 +723,9 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
|
|||||||
text = presentationData.strings.Conversation_AudioRateTooltipSpeedUp
|
text = presentationData.strings.Conversation_AudioRateTooltipSpeedUp
|
||||||
rate = 2.0
|
rate = 2.0
|
||||||
} else {
|
} else {
|
||||||
let value = String(format: "%0.1f", baseRate.doubleValue)
|
text = nil
|
||||||
text = presentationData.strings.Conversation_AudioRateTooltipCustom(value).string
|
|
||||||
if case let .sliderCommit(previousValue, newValue) = changeType {
|
|
||||||
if newValue > previousValue {
|
|
||||||
rate = .infinity
|
|
||||||
} else if newValue < previousValue {
|
|
||||||
rate = -.infinity
|
|
||||||
} else {
|
|
||||||
rate = nil
|
rate = nil
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
rate = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var showTooltip = true
|
var showTooltip = true
|
||||||
if case .sliderChange = changeType {
|
if case .sliderChange = changeType {
|
||||||
showTooltip = false
|
showTooltip = false
|
||||||
|
@ -84,6 +84,15 @@ private class CallStatusBarBackgroundNode: ASDisplayNode {
|
|||||||
private let hierarchyTrackingNode: HierarchyTrackingNode
|
private let hierarchyTrackingNode: HierarchyTrackingNode
|
||||||
private var isCurrentlyInHierarchy = true
|
private var isCurrentlyInHierarchy = true
|
||||||
|
|
||||||
|
var animationsEnabled: Bool = false {
|
||||||
|
didSet {
|
||||||
|
self.updateAnimations()
|
||||||
|
if !self.animationsEnabled {
|
||||||
|
self.maskCurveView.disableCurves()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
self.foregroundView = UIView()
|
self.foregroundView = UIView()
|
||||||
self.foregroundGradientLayer = CAGradientLayer()
|
self.foregroundGradientLayer = CAGradientLayer()
|
||||||
@ -137,42 +146,11 @@ private class CallStatusBarBackgroundNode: ASDisplayNode {
|
|||||||
CATransaction.commit()
|
CATransaction.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setupGradientAnimations() {
|
|
||||||
/*if let _ = self.foregroundGradientLayer.animation(forKey: "movement") {
|
|
||||||
} else {
|
|
||||||
let previousValue = self.foregroundGradientLayer.startPoint
|
|
||||||
let newValue: CGPoint
|
|
||||||
if self.maskCurveView.presentationAudioLevel > 0.1 {
|
|
||||||
newValue = CGPoint(x: CGFloat.random(in: 1.0 ..< 1.3), y: 0.5)
|
|
||||||
} else {
|
|
||||||
newValue = CGPoint(x: CGFloat.random(in: 0.85 ..< 1.2), y: 0.5)
|
|
||||||
}
|
|
||||||
self.foregroundGradientLayer.startPoint = newValue
|
|
||||||
|
|
||||||
CATransaction.begin()
|
|
||||||
|
|
||||||
let animation = CABasicAnimation(keyPath: "endPoint")
|
|
||||||
animation.duration = Double.random(in: 0.8 ..< 1.4)
|
|
||||||
animation.fromValue = previousValue
|
|
||||||
animation.toValue = newValue
|
|
||||||
|
|
||||||
CATransaction.setCompletionBlock { [weak self] in
|
|
||||||
self?.setupGradientAnimations()
|
|
||||||
}
|
|
||||||
|
|
||||||
self.foregroundGradientLayer.add(animation, forKey: "movement")
|
|
||||||
CATransaction.commit()
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateAnimations() {
|
func updateAnimations() {
|
||||||
if !isCurrentlyInHierarchy {
|
if !self.isCurrentlyInHierarchy || !self.animationsEnabled {
|
||||||
self.foregroundGradientLayer.removeAllAnimations()
|
self.foregroundGradientLayer.removeAllAnimations()
|
||||||
self.maskCurveView.stopAnimating()
|
self.maskCurveView.stopAnimating()
|
||||||
return
|
} else {
|
||||||
}
|
|
||||||
self.setupGradientAnimations()
|
|
||||||
if isCurrentlyInHierarchy {
|
|
||||||
self.maskCurveView.startAnimating()
|
self.maskCurveView.startAnimating()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,6 +160,13 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
|
|||||||
public enum Content {
|
public enum Content {
|
||||||
case call(SharedAccountContext, Account, PresentationCall)
|
case call(SharedAccountContext, Account, PresentationCall)
|
||||||
case groupCall(SharedAccountContext, Account, PresentationGroupCall)
|
case groupCall(SharedAccountContext, Account, PresentationGroupCall)
|
||||||
|
|
||||||
|
var sharedContext: SharedAccountContext {
|
||||||
|
switch self {
|
||||||
|
case let .call(sharedContext, _, _), let .groupCall(sharedContext, _, _):
|
||||||
|
return sharedContext
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private let backgroundNode: CallStatusBarBackgroundNode
|
private let backgroundNode: CallStatusBarBackgroundNode
|
||||||
@ -252,6 +237,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
|
|||||||
|
|
||||||
public func update(content: Content) {
|
public func update(content: Content) {
|
||||||
self.currentContent = content
|
self.currentContent = content
|
||||||
|
self.backgroundNode.animationsEnabled = content.sharedContext.energyUsageSettings.fullTranslucency
|
||||||
if self.isCurrentlyInHierarchy {
|
if self.isCurrentlyInHierarchy {
|
||||||
self.update()
|
self.update()
|
||||||
}
|
}
|
||||||
@ -553,6 +539,7 @@ private final class VoiceCurveView: UIView {
|
|||||||
private let smallCurve: CurveView
|
private let smallCurve: CurveView
|
||||||
private let mediumCurve: CurveView
|
private let mediumCurve: CurveView
|
||||||
private let bigCurve: CurveView
|
private let bigCurve: CurveView
|
||||||
|
private var solidView: UIView?
|
||||||
|
|
||||||
private let maxLevel: CGFloat
|
private let maxLevel: CGFloat
|
||||||
|
|
||||||
@ -604,11 +591,11 @@ private final class VoiceCurveView: UIView {
|
|||||||
|
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
|
||||||
addSubview(bigCurve)
|
self.addSubview(self.bigCurve)
|
||||||
addSubview(mediumCurve)
|
self.addSubview(self.mediumCurve)
|
||||||
addSubview(smallCurve)
|
self.addSubview(self.smallCurve)
|
||||||
|
|
||||||
displayLinkAnimator = ConstantDisplayLinkAnimator() { [weak self] in
|
self.displayLinkAnimator = ConstantDisplayLinkAnimator() { [weak self] in
|
||||||
guard let strongSelf = self else { return }
|
guard let strongSelf = self else { return }
|
||||||
|
|
||||||
strongSelf.presentationAudioLevel = strongSelf.presentationAudioLevel * 0.9 + strongSelf.audioLevel * 0.1
|
strongSelf.presentationAudioLevel = strongSelf.presentationAudioLevel * 0.9 + strongSelf.audioLevel * 0.1
|
||||||
@ -624,28 +611,33 @@ private final class VoiceCurveView: UIView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func setColor(_ color: UIColor) {
|
public func setColor(_ color: UIColor) {
|
||||||
smallCurve.setColor(color.withAlphaComponent(1.0))
|
self.smallCurve.setColor(color.withAlphaComponent(1.0))
|
||||||
mediumCurve.setColor(color.withAlphaComponent(0.55))
|
self.mediumCurve.setColor(color.withAlphaComponent(0.55))
|
||||||
bigCurve.setColor(color.withAlphaComponent(0.35))
|
self.bigCurve.setColor(color.withAlphaComponent(0.35))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updateLevel(_ level: CGFloat) {
|
public func updateLevel(_ level: CGFloat) {
|
||||||
let normalizedLevel = min(1, max(level / maxLevel, 0))
|
let normalizedLevel = min(1, max(level / self.maxLevel, 0))
|
||||||
|
|
||||||
smallCurve.updateSpeedLevel(to: normalizedLevel)
|
self.smallCurve.updateSpeedLevel(to: normalizedLevel)
|
||||||
mediumCurve.updateSpeedLevel(to: normalizedLevel)
|
self.mediumCurve.updateSpeedLevel(to: normalizedLevel)
|
||||||
bigCurve.updateSpeedLevel(to: normalizedLevel)
|
self.bigCurve.updateSpeedLevel(to: normalizedLevel)
|
||||||
|
|
||||||
audioLevel = normalizedLevel
|
self.audioLevel = normalizedLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
public func startAnimating() {
|
public func startAnimating() {
|
||||||
guard !isAnimating else { return }
|
guard !self.isAnimating else { return }
|
||||||
isAnimating = true
|
self.isAnimating = true
|
||||||
|
|
||||||
updateCurvesState()
|
if let solidView = self.solidView {
|
||||||
|
solidView.removeFromSuperview()
|
||||||
|
self.solidView = nil
|
||||||
|
}
|
||||||
|
|
||||||
displayLinkAnimator?.isPaused = false
|
self.updateCurvesState()
|
||||||
|
|
||||||
|
self.displayLinkAnimator?.isPaused = false
|
||||||
}
|
}
|
||||||
|
|
||||||
public func stopAnimating() {
|
public func stopAnimating() {
|
||||||
@ -653,36 +645,48 @@ private final class VoiceCurveView: UIView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func stopAnimating(duration: Double) {
|
public func stopAnimating(duration: Double) {
|
||||||
guard isAnimating else { return }
|
guard self.isAnimating else { return }
|
||||||
isAnimating = false
|
self.isAnimating = false
|
||||||
|
|
||||||
updateCurvesState()
|
self.updateCurvesState()
|
||||||
|
|
||||||
displayLinkAnimator?.isPaused = true
|
self.displayLinkAnimator?.isPaused = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func disableCurves() {
|
||||||
|
self.smallCurve.isHidden = true
|
||||||
|
self.mediumCurve.isHidden = true
|
||||||
|
self.bigCurve.isHidden = true
|
||||||
|
|
||||||
|
let view = UIView(frame: .zero)
|
||||||
|
view.backgroundColor = .white
|
||||||
|
self.addSubview(view)
|
||||||
|
self.solidView = view
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateCurvesState() {
|
private func updateCurvesState() {
|
||||||
if isAnimating {
|
if self.isAnimating {
|
||||||
if smallCurve.frame.size != .zero {
|
if self.smallCurve.frame.size != .zero {
|
||||||
smallCurve.startAnimating()
|
self.smallCurve.startAnimating()
|
||||||
mediumCurve.startAnimating()
|
self.mediumCurve.startAnimating()
|
||||||
bigCurve.startAnimating()
|
self.bigCurve.startAnimating()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
smallCurve.stopAnimating()
|
self.smallCurve.stopAnimating()
|
||||||
mediumCurve.stopAnimating()
|
self.mediumCurve.stopAnimating()
|
||||||
bigCurve.stopAnimating()
|
self.bigCurve.stopAnimating()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func layoutSubviews() {
|
override public func layoutSubviews() {
|
||||||
super.layoutSubviews()
|
super.layoutSubviews()
|
||||||
|
|
||||||
smallCurve.frame = bounds
|
self.smallCurve.frame = self.bounds
|
||||||
mediumCurve.frame = bounds
|
self.mediumCurve.frame = self.bounds
|
||||||
bigCurve.frame = bounds
|
self.bigCurve.frame = self.bounds
|
||||||
|
self.solidView?.frame = CGRect(origin: .zero, size: CGSize(width: self.bounds.width, height: self.bounds.height - 18.0))
|
||||||
|
|
||||||
updateCurvesState()
|
self.updateCurvesState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -721,7 +725,6 @@ final class CurveView: UIView {
|
|||||||
return layer
|
return layer
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
||||||
override var frame: CGRect {
|
override var frame: CGRect {
|
||||||
didSet {
|
didSet {
|
||||||
if self.frame.size != oldValue.size {
|
if self.frame.size != oldValue.size {
|
||||||
@ -764,11 +767,7 @@ final class CurveView: UIView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateSpeedLevel(to newSpeedLevel: CGFloat) {
|
func updateSpeedLevel(to newSpeedLevel: CGFloat) {
|
||||||
speedLevel = max(speedLevel, newSpeedLevel)
|
self.speedLevel = max(self.speedLevel, newSpeedLevel)
|
||||||
|
|
||||||
// if abs(lastSpeedLevel - newSpeedLevel) > 0.45 {
|
|
||||||
// animateToNewShape()
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func startAnimating() {
|
func startAnimating() {
|
||||||
|
@ -130,6 +130,12 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var animationsEnabled: Bool = true {
|
||||||
|
didSet {
|
||||||
|
self.backgroundNode.animationsEnabled = self.animationsEnabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
self.bottomNode = ASDisplayNode()
|
self.bottomNode = ASDisplayNode()
|
||||||
self.bottomNode.isUserInteractionEnabled = false
|
self.bottomNode.isUserInteractionEnabled = false
|
||||||
@ -833,7 +839,9 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func playMuteAnimation() {
|
private func playMuteAnimation() {
|
||||||
|
if self.animationsEnabled {
|
||||||
self.maskBlobView.startAnimating()
|
self.maskBlobView.startAnimating()
|
||||||
|
}
|
||||||
self.maskBlobView.layer.animateScale(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak self] _ in
|
self.maskBlobView.layer.animateScale(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak self] _ in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -862,7 +870,9 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
|
|||||||
self.maskGradientLayer.removeAllAnimations()
|
self.maskGradientLayer.removeAllAnimations()
|
||||||
self.updateGlowAndGradientAnimations(type: .connecting, previousType: nil)
|
self.updateGlowAndGradientAnimations(type: .connecting, previousType: nil)
|
||||||
|
|
||||||
|
if self.animationsEnabled {
|
||||||
self.maskBlobView.startAnimating()
|
self.maskBlobView.startAnimating()
|
||||||
|
}
|
||||||
self.maskBlobView.layer.animateScale(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak self] _ in
|
self.maskBlobView.layer.animateScale(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak self] _ in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -915,7 +925,9 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
|
|||||||
self.updateGlowAndGradientAnimations(type: active ? .speaking : .active, previousType: nil)
|
self.updateGlowAndGradientAnimations(type: active ? .speaking : .active, previousType: nil)
|
||||||
|
|
||||||
self.maskBlobView.isHidden = false
|
self.maskBlobView.isHidden = false
|
||||||
|
if self.animationsEnabled {
|
||||||
self.maskBlobView.startAnimating()
|
self.maskBlobView.startAnimating()
|
||||||
|
}
|
||||||
self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.45)
|
self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.45)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -968,7 +980,9 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
|
|||||||
if case .connecting = self.state {
|
if case .connecting = self.state {
|
||||||
} else {
|
} else {
|
||||||
self.maskBlobView.isHidden = false
|
self.maskBlobView.isHidden = false
|
||||||
|
if self.animationsEnabled {
|
||||||
self.maskBlobView.startAnimating()
|
self.maskBlobView.startAnimating()
|
||||||
|
}
|
||||||
self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.45)
|
self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.45)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1038,7 +1052,9 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
|
|||||||
self.maskCircleLayer.animateSpring(from: previousPath as AnyObject, to: largerCirclePath as AnyObject, keyPath: "path", duration: 0.6, initialVelocity: 0.0, damping: 100.0)
|
self.maskCircleLayer.animateSpring(from: previousPath as AnyObject, to: largerCirclePath as AnyObject, keyPath: "path", duration: 0.6, initialVelocity: 0.0, damping: 100.0)
|
||||||
|
|
||||||
self.maskBlobView.isHidden = false
|
self.maskBlobView.isHidden = false
|
||||||
|
if self.animationsEnabled {
|
||||||
self.maskBlobView.startAnimating()
|
self.maskBlobView.startAnimating()
|
||||||
|
}
|
||||||
self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.6, damping: 100.0)
|
self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.6, damping: 100.0)
|
||||||
|
|
||||||
self.disableGlowAnimations = true
|
self.disableGlowAnimations = true
|
||||||
@ -1048,6 +1064,12 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var animationsEnabled: Bool = true {
|
||||||
|
didSet {
|
||||||
|
self.updateAnimations()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var isActive = false
|
var isActive = false
|
||||||
func updateAnimations() {
|
func updateAnimations() {
|
||||||
if !self.isCurrentlyInHierarchy {
|
if !self.isCurrentlyInHierarchy {
|
||||||
@ -1058,7 +1080,13 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
|
|||||||
self.maskBlobView.stopAnimating()
|
self.maskBlobView.stopAnimating()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !self.animationsEnabled {
|
||||||
|
self.foregroundGradientLayer.removeAllAnimations()
|
||||||
|
self.maskBlobView.stopAnimating()
|
||||||
|
} else {
|
||||||
self.setupGradientAnimations()
|
self.setupGradientAnimations()
|
||||||
|
}
|
||||||
|
|
||||||
switch self.state {
|
switch self.state {
|
||||||
case .connecting:
|
case .connecting:
|
||||||
@ -1093,8 +1121,10 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
self.transition = nil
|
self.transition = nil
|
||||||
} else {
|
} else {
|
||||||
|
if self.animationsEnabled {
|
||||||
self.maskBlobView.startAnimating()
|
self.maskBlobView.startAnimating()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
case .disabled:
|
case .disabled:
|
||||||
self.updatedActive?(true)
|
self.updatedActive?(true)
|
||||||
self.isActive = false
|
self.isActive = false
|
||||||
@ -1118,7 +1148,9 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
|
|||||||
self.maskProgressLayer.isHidden = true
|
self.maskProgressLayer.isHidden = true
|
||||||
self.maskGradientLayer.isHidden = false
|
self.maskGradientLayer.isHidden = false
|
||||||
self.maskBlobView.isHidden = false
|
self.maskBlobView.isHidden = false
|
||||||
|
if self.animationsEnabled {
|
||||||
self.maskBlobView.startAnimating()
|
self.maskBlobView.startAnimating()
|
||||||
|
}
|
||||||
self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.45)
|
self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.45)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1287,12 +1319,12 @@ private final class VoiceBlobView: UIView {
|
|||||||
|
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
|
||||||
addSubnode(hierarchyTrackingNode)
|
self.addSubnode(self.hierarchyTrackingNode)
|
||||||
|
|
||||||
addSubview(bigBlob)
|
self.addSubview(self.bigBlob)
|
||||||
addSubview(mediumBlob)
|
self.addSubview(self.mediumBlob)
|
||||||
|
|
||||||
displayLinkAnimator = ConstantDisplayLinkAnimator() { [weak self] in
|
self.displayLinkAnimator = ConstantDisplayLinkAnimator() { [weak self] in
|
||||||
guard let strongSelf = self else { return }
|
guard let strongSelf = self else { return }
|
||||||
|
|
||||||
if !strongSelf.isCurrentlyInHierarchy {
|
if !strongSelf.isCurrentlyInHierarchy {
|
||||||
@ -1317,29 +1349,29 @@ private final class VoiceBlobView: UIView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func setColor(_ color: UIColor) {
|
public func setColor(_ color: UIColor) {
|
||||||
mediumBlob.setColor(color.withAlphaComponent(0.5))
|
self.mediumBlob.setColor(color.withAlphaComponent(0.5))
|
||||||
bigBlob.setColor(color.withAlphaComponent(0.21))
|
self.bigBlob.setColor(color.withAlphaComponent(0.21))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updateLevel(_ level: CGFloat, immediately: Bool) {
|
public func updateLevel(_ level: CGFloat, immediately: Bool) {
|
||||||
let normalizedLevel = min(1, max(level / maxLevel, 0))
|
let normalizedLevel = min(1, max(level / maxLevel, 0))
|
||||||
|
|
||||||
mediumBlob.updateSpeedLevel(to: normalizedLevel)
|
self.mediumBlob.updateSpeedLevel(to: normalizedLevel)
|
||||||
bigBlob.updateSpeedLevel(to: normalizedLevel)
|
self.bigBlob.updateSpeedLevel(to: normalizedLevel)
|
||||||
|
|
||||||
audioLevel = normalizedLevel
|
self.audioLevel = normalizedLevel
|
||||||
if immediately {
|
if immediately {
|
||||||
presentationAudioLevel = normalizedLevel
|
self.presentationAudioLevel = normalizedLevel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func startAnimating() {
|
public func startAnimating() {
|
||||||
guard !isAnimating else { return }
|
guard !self.isAnimating else { return }
|
||||||
isAnimating = true
|
self.isAnimating = true
|
||||||
|
|
||||||
updateBlobsState()
|
self.updateBlobsState()
|
||||||
|
|
||||||
displayLinkAnimator?.isPaused = false
|
self.displayLinkAnimator?.isPaused = false
|
||||||
}
|
}
|
||||||
|
|
||||||
public func stopAnimating() {
|
public func stopAnimating() {
|
||||||
@ -1348,32 +1380,32 @@ private final class VoiceBlobView: UIView {
|
|||||||
|
|
||||||
public func stopAnimating(duration: Double) {
|
public func stopAnimating(duration: Double) {
|
||||||
guard isAnimating else { return }
|
guard isAnimating else { return }
|
||||||
isAnimating = false
|
self.isAnimating = false
|
||||||
|
|
||||||
updateBlobsState()
|
self.updateBlobsState()
|
||||||
|
|
||||||
displayLinkAnimator?.isPaused = true
|
self.displayLinkAnimator?.isPaused = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateBlobsState() {
|
private func updateBlobsState() {
|
||||||
if isAnimating {
|
if self.isAnimating {
|
||||||
if mediumBlob.frame.size != .zero {
|
if self.mediumBlob.frame.size != .zero {
|
||||||
mediumBlob.startAnimating()
|
self.mediumBlob.startAnimating()
|
||||||
bigBlob.startAnimating()
|
self.bigBlob.startAnimating()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mediumBlob.stopAnimating()
|
self.mediumBlob.stopAnimating()
|
||||||
bigBlob.stopAnimating()
|
self.bigBlob.stopAnimating()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func layoutSubviews() {
|
override public func layoutSubviews() {
|
||||||
super.layoutSubviews()
|
super.layoutSubviews()
|
||||||
|
|
||||||
mediumBlob.frame = bounds
|
self.mediumBlob.frame = bounds
|
||||||
bigBlob.frame = bounds
|
self.bigBlob.frame = bounds
|
||||||
|
|
||||||
updateBlobsState()
|
self.updateBlobsState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1451,10 +1483,6 @@ final class BlobView: UIView {
|
|||||||
|
|
||||||
func updateSpeedLevel(to newSpeedLevel: CGFloat) {
|
func updateSpeedLevel(to newSpeedLevel: CGFloat) {
|
||||||
self.speedLevel = max(self.speedLevel, newSpeedLevel)
|
self.speedLevel = max(self.speedLevel, newSpeedLevel)
|
||||||
|
|
||||||
// if abs(lastSpeedLevel - newSpeedLevel) > 0.45 {
|
|
||||||
// animateToNewShape()
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func startAnimating() {
|
func startAnimating() {
|
||||||
@ -1540,7 +1568,7 @@ final class BlobView: UIView {
|
|||||||
|
|
||||||
CATransaction.begin()
|
CATransaction.begin()
|
||||||
CATransaction.setDisableActions(true)
|
CATransaction.setDisableActions(true)
|
||||||
shapeLayer.position = CGPoint(x: bounds.midX, y: bounds.midY)
|
self.shapeLayer.position = CGPoint(x: bounds.midX, y: bounds.midY)
|
||||||
CATransaction.commit()
|
CATransaction.commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1064,6 +1064,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
|||||||
self.switchCameraButton.isUserInteractionEnabled = false
|
self.switchCameraButton.isUserInteractionEnabled = false
|
||||||
self.leaveButton = CallControllerButtonItemNode()
|
self.leaveButton = CallControllerButtonItemNode()
|
||||||
self.actionButton = VoiceChatActionButton()
|
self.actionButton = VoiceChatActionButton()
|
||||||
|
self.actionButton.animationsEnabled = sharedContext.energyUsageSettings.fullTranslucency
|
||||||
|
|
||||||
if self.isScheduling {
|
if self.isScheduling {
|
||||||
self.cameraButton.alpha = 0.0
|
self.cameraButton.alpha = 0.0
|
||||||
|
@ -15,7 +15,6 @@ func managedConfigurationUpdates(accountManager: AccountManager<TelegramAccountM
|
|||||||
return postbox.transaction { transaction -> Signal<Void, NoError> in
|
return postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||||
switch result {
|
switch result {
|
||||||
case let .config(flags, _, _, _, _, dcOptions, _, chatSizeMax, megagroupSizeMax, forwardedCountMax, _, _, _, _, _, _, _, _, editTimeLimit, revokeTimeLimit, revokePmTimeLimit, _, stickersRecentLimit, _, _, _, _, _, _, _, autoupdateUrlPrefix, gifSearchUsername, venueSearchUsername, imgSearchUsername, _, captionLengthMax, _, webfileDcId, suggestedLangCode, langPackVersion, baseLangPackVersion, reactionsDefault, autologinToken):
|
case let .config(flags, _, _, _, _, dcOptions, _, chatSizeMax, megagroupSizeMax, forwardedCountMax, _, _, _, _, _, _, _, _, editTimeLimit, revokeTimeLimit, revokePmTimeLimit, _, stickersRecentLimit, _, _, _, _, _, _, _, autoupdateUrlPrefix, gifSearchUsername, venueSearchUsername, imgSearchUsername, _, captionLengthMax, _, webfileDcId, suggestedLangCode, langPackVersion, baseLangPackVersion, reactionsDefault, autologinToken):
|
||||||
let _ = autologinToken
|
|
||||||
var addressList: [Int: [MTDatacenterAddress]] = [:]
|
var addressList: [Int: [MTDatacenterAddress]] = [:]
|
||||||
for option in dcOptions {
|
for option in dcOptions {
|
||||||
switch option {
|
switch option {
|
||||||
@ -66,6 +65,8 @@ func managedConfigurationUpdates(accountManager: AccountManager<TelegramAccountM
|
|||||||
|
|
||||||
updateSearchBotsConfiguration(transaction: transaction, configuration: SearchBotsConfiguration(imageBotUsername: imgSearchUsername, gifBotUsername: gifSearchUsername, venueBotUsername: venueSearchUsername))
|
updateSearchBotsConfiguration(transaction: transaction, configuration: SearchBotsConfiguration(imageBotUsername: imgSearchUsername, gifBotUsername: gifSearchUsername, venueBotUsername: venueSearchUsername))
|
||||||
|
|
||||||
|
updateLinksConfiguration(transaction: transaction, configuration: LinksConfiguration(autologinToken: autologinToken))
|
||||||
|
|
||||||
if let defaultReaction = reactionsDefault, let reaction = MessageReaction.Reaction(apiReaction: defaultReaction) {
|
if let defaultReaction = reactionsDefault, let reaction = MessageReaction.Reaction(apiReaction: defaultReaction) {
|
||||||
updateReactionSettings(transaction: transaction, { settings in
|
updateReactionSettings(transaction: transaction, { settings in
|
||||||
var settings = settings
|
var settings = settings
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
import Foundation
|
||||||
|
import Postbox
|
||||||
|
|
||||||
|
public struct LinksConfiguration: Equatable, Codable {
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case autologinToken
|
||||||
|
}
|
||||||
|
|
||||||
|
public let autologinToken: String?
|
||||||
|
|
||||||
|
public static var defaultValue: LinksConfiguration {
|
||||||
|
return LinksConfiguration(autologinToken: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(autologinToken: String?) {
|
||||||
|
self.autologinToken = autologinToken
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
self.autologinToken = try container.decodeIfPresent(String.self, forKey: .autologinToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
try container.encodeIfPresent(self.autologinToken, forKey: .autologinToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func currentLinksConfiguration(transaction: Transaction) -> LinksConfiguration {
|
||||||
|
if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.linksConfiguration)?.get(LinksConfiguration.self) {
|
||||||
|
return entry
|
||||||
|
} else {
|
||||||
|
return LinksConfiguration.defaultValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateLinksConfiguration(transaction: Transaction, configuration: LinksConfiguration) {
|
||||||
|
if currentLinksConfiguration(transaction: transaction) != configuration {
|
||||||
|
transaction.setPreferencesEntry(key: PreferencesKeys.linksConfiguration, value: PreferencesEntry(configuration))
|
||||||
|
}
|
||||||
|
}
|
@ -255,6 +255,7 @@ private enum PreferencesKeyValues: Int32 {
|
|||||||
case premiumPromo = 26
|
case premiumPromo = 26
|
||||||
case globalMessageAutoremoveTimeoutSettings = 27
|
case globalMessageAutoremoveTimeoutSettings = 27
|
||||||
case accountSpecificCacheStorageSettings = 28
|
case accountSpecificCacheStorageSettings = 28
|
||||||
|
case linksConfiguration = 29
|
||||||
}
|
}
|
||||||
|
|
||||||
public func applicationSpecificPreferencesKey(_ value: Int32) -> ValueBoxKey {
|
public func applicationSpecificPreferencesKey(_ value: Int32) -> ValueBoxKey {
|
||||||
@ -395,6 +396,12 @@ public struct PreferencesKeys {
|
|||||||
key.setInt32(0, value: PreferencesKeyValues.accountSpecificCacheStorageSettings.rawValue)
|
key.setInt32(0, value: PreferencesKeyValues.accountSpecificCacheStorageSettings.rawValue)
|
||||||
return key
|
return key
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
public static let linksConfiguration: ValueBoxKey = {
|
||||||
|
let key = ValueBoxKey(length: 4)
|
||||||
|
key.setInt32(0, value: PreferencesKeyValues.linksConfiguration.rawValue)
|
||||||
|
return key
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum SharedDataKeyValues: Int32 {
|
private enum SharedDataKeyValues: Int32 {
|
||||||
|
@ -185,6 +185,26 @@ public extension EngineConfiguration.SearchBots {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public extension EngineConfiguration {
|
||||||
|
struct Links {
|
||||||
|
public var autologinToken: String?
|
||||||
|
|
||||||
|
public init(
|
||||||
|
autologinToken: String?
|
||||||
|
) {
|
||||||
|
self.autologinToken = autologinToken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension EngineConfiguration.Links {
|
||||||
|
init(_ configuration: LinksConfiguration) {
|
||||||
|
self.init(
|
||||||
|
autologinToken: configuration.autologinToken
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public extension TelegramEngine.EngineData.Item {
|
public extension TelegramEngine.EngineData.Item {
|
||||||
enum Configuration {
|
enum Configuration {
|
||||||
public struct App: TelegramEngineDataItem, PostboxViewDataItem {
|
public struct App: TelegramEngineDataItem, PostboxViewDataItem {
|
||||||
@ -400,5 +420,26 @@ public extension TelegramEngine.EngineData.Item {
|
|||||||
return settings.messageAutoremoveTimeout
|
return settings.messageAutoremoveTimeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct Links: TelegramEngineDataItem, PostboxViewDataItem {
|
||||||
|
public typealias Result = EngineConfiguration.Links
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
var key: PostboxViewKey {
|
||||||
|
return .preferences(keys: Set([PreferencesKeys.linksConfiguration]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func extract(view: PostboxView) -> Result {
|
||||||
|
guard let view = view as? PreferencesView else {
|
||||||
|
preconditionFailure()
|
||||||
|
}
|
||||||
|
guard let value = view.values[PreferencesKeys.linksConfiguration]?.get(LinksConfiguration.self) else {
|
||||||
|
return EngineConfiguration.Links(LinksConfiguration.defaultValue)
|
||||||
|
}
|
||||||
|
return EngineConfiguration.Links(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1628,6 +1628,7 @@ public final class EntityKeyboardTopPanelComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var didReorderItems = false
|
||||||
private func beginReordering(itemView: ComponentHostView<EntityKeyboardTopPanelItemEnvironment>) {
|
private func beginReordering(itemView: ComponentHostView<EntityKeyboardTopPanelItemEnvironment>) {
|
||||||
if let currentReorderingItemView = self.currentReorderingItemView {
|
if let currentReorderingItemView = self.currentReorderingItemView {
|
||||||
if let componentView = currentReorderingItemView.componentView {
|
if let componentView = currentReorderingItemView.componentView {
|
||||||
@ -1702,7 +1703,9 @@ public final class EntityKeyboardTopPanelComponent: Component {
|
|||||||
self.currentReorderingItemId = nil
|
self.currentReorderingItemId = nil
|
||||||
self.temporaryReorderingOrderIndex = nil
|
self.temporaryReorderingOrderIndex = nil
|
||||||
|
|
||||||
|
if self.didReorderItems {
|
||||||
self.component?.reorderItems(self.items)
|
self.component?.reorderItems(self.items)
|
||||||
|
}
|
||||||
//self.state?.updated(transition: Transition(animation: .curve(duration: 0.3, curve: .spring)))
|
//self.state?.updated(transition: Transition(animation: .curve(duration: 0.3, curve: .spring)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1721,14 +1724,14 @@ public final class EntityKeyboardTopPanelComponent: Component {
|
|||||||
let containerFrame = itemLayout.containerFrame(at: i)
|
let containerFrame = itemLayout.containerFrame(at: i)
|
||||||
if containerFrame.intersects(localReorderingItemFrame) {
|
if containerFrame.intersects(localReorderingItemFrame) {
|
||||||
let temporaryReorderingOrderIndex: (id: AnyHashable, index: Int) = (currentReorderingItemId, i)
|
let temporaryReorderingOrderIndex: (id: AnyHashable, index: Int) = (currentReorderingItemId, i)
|
||||||
let hadPrevous = self.temporaryReorderingOrderIndex != nil
|
let hadPrevious = self.temporaryReorderingOrderIndex != nil
|
||||||
if self.temporaryReorderingOrderIndex?.id != temporaryReorderingOrderIndex.id || self.temporaryReorderingOrderIndex?.index != temporaryReorderingOrderIndex.index {
|
if self.temporaryReorderingOrderIndex?.id != temporaryReorderingOrderIndex.id || self.temporaryReorderingOrderIndex?.index != temporaryReorderingOrderIndex.index {
|
||||||
self.temporaryReorderingOrderIndex = temporaryReorderingOrderIndex
|
self.temporaryReorderingOrderIndex = temporaryReorderingOrderIndex
|
||||||
|
|
||||||
if hadPrevous {
|
if hadPrevious {
|
||||||
self.reorderingHapticFeedback.tap()
|
self.reorderingHapticFeedback.tap()
|
||||||
}
|
}
|
||||||
|
self.didReorderItems = true
|
||||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.3, curve: .spring)))
|
self.state?.updated(transition: Transition(animation: .curve(duration: 0.3, curve: .spring)))
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
@ -3506,10 +3506,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
if let _ = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(message.id) {
|
var messageId = message.id
|
||||||
|
if let forwardInfo = message.forwardInfo, let sourceMessageId = forwardInfo.sourceMessageId, case let .replyThread(threadMessage) = strongSelf.chatLocation, threadMessage.isChannelPost {
|
||||||
|
messageId = sourceMessageId
|
||||||
|
}
|
||||||
|
if let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId) {
|
||||||
let _ = strongSelf.controllerInteraction?.openMessage(message, .timecode(Double(timestamp)))
|
let _ = strongSelf.controllerInteraction?.openMessage(message, .timecode(Double(timestamp)))
|
||||||
} else {
|
} else {
|
||||||
strongSelf.navigateToMessage(messageLocation: .id(message.id, Double(timestamp)), animated: true, forceInCurrentChat: true)
|
strongSelf.navigateToMessage(messageLocation: .id(messageId, Double(timestamp)), animated: true, forceInCurrentChat: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,10 @@ import ContextUI
|
|||||||
import SliderContextItem
|
import SliderContextItem
|
||||||
import UndoUI
|
import UndoUI
|
||||||
|
|
||||||
|
private func normalizeValue(_ value: CGFloat) -> CGFloat {
|
||||||
|
return round(value * 10.0) / 10.0
|
||||||
|
}
|
||||||
|
|
||||||
private func generateBackground(theme: PresentationTheme) -> UIImage? {
|
private func generateBackground(theme: PresentationTheme) -> UIImage? {
|
||||||
return generateImage(CGSize(width: 20.0, height: 10.0 + 8.0), rotatedContext: { size, context in
|
return generateImage(CGSize(width: 20.0, height: 10.0 + 8.0), rotatedContext: { size, context in
|
||||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
@ -1030,7 +1034,8 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
|||||||
var presetItems: [ContextMenuItem] = []
|
var presetItems: [ContextMenuItem] = []
|
||||||
|
|
||||||
let previousValue = self.currentRate?.doubleValue ?? 1.0
|
let previousValue = self.currentRate?.doubleValue ?? 1.0
|
||||||
let sliderItem: ContextMenuItem = .custom(SliderContextItem(minValue: 0.5, maxValue: 2.5, value: previousValue, valueChanged: { [weak self] newValue, finished in
|
let sliderItem: ContextMenuItem = .custom(SliderContextItem(minValue: 0.2, maxValue: 2.5, value: previousValue, valueChanged: { [weak self] newValue, finished in
|
||||||
|
let newValue = normalizeValue(newValue)
|
||||||
self?.control?(.setBaseRate(AudioPlaybackRate(newValue)))
|
self?.control?(.setBaseRate(AudioPlaybackRate(newValue)))
|
||||||
if finished {
|
if finished {
|
||||||
scheduleTooltip(.sliderCommit(previousValue, newValue))
|
scheduleTooltip(.sliderCommit(previousValue, newValue))
|
||||||
@ -1082,8 +1087,22 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
|||||||
let presentationData = self.presentationData
|
let presentationData = self.presentationData
|
||||||
let text: String?
|
let text: String?
|
||||||
let rate: CGFloat?
|
let rate: CGFloat?
|
||||||
|
if case let .sliderCommit(previousValue, newValue) = changeType {
|
||||||
|
let value = String(format: "%0.1f", baseRate.doubleValue)
|
||||||
if baseRate == .x1 {
|
if baseRate == .x1 {
|
||||||
text = presentationData.strings.Conversation_AudioRateTooltipNormal
|
text = presentationData.strings.Conversation_AudioRateTooltipNormal
|
||||||
|
} else {
|
||||||
|
text = presentationData.strings.Conversation_AudioRateTooltipCustom(value).string
|
||||||
|
}
|
||||||
|
if newValue > previousValue {
|
||||||
|
rate = .infinity
|
||||||
|
} else if newValue < previousValue {
|
||||||
|
rate = -.infinity
|
||||||
|
} else {
|
||||||
|
rate = nil
|
||||||
|
}
|
||||||
|
} else if baseRate == .x1 {
|
||||||
|
text = presentationData.strings.Conversation_AudioRateTooltipNormal
|
||||||
rate = 1.0
|
rate = 1.0
|
||||||
} else if baseRate == .x1_5 {
|
} else if baseRate == .x1_5 {
|
||||||
text = presentationData.strings.Conversation_AudioRateTooltip15X
|
text = presentationData.strings.Conversation_AudioRateTooltip15X
|
||||||
@ -1092,20 +1111,9 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
|||||||
text = presentationData.strings.Conversation_AudioRateTooltipSpeedUp
|
text = presentationData.strings.Conversation_AudioRateTooltipSpeedUp
|
||||||
rate = 2.0
|
rate = 2.0
|
||||||
} else {
|
} else {
|
||||||
let value = String(format: "%0.1f", baseRate.doubleValue)
|
text = nil
|
||||||
text = presentationData.strings.Conversation_AudioRateTooltipCustom(value).string
|
|
||||||
if case let .sliderCommit(previousValue, newValue) = changeType {
|
|
||||||
if newValue > previousValue {
|
|
||||||
rate = .infinity
|
|
||||||
} else if newValue < previousValue {
|
|
||||||
rate = -.infinity
|
|
||||||
} else {
|
|
||||||
rate = nil
|
rate = nil
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
rate = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var showTooltip = true
|
var showTooltip = true
|
||||||
if case .sliderChange = changeType {
|
if case .sliderChange = changeType {
|
||||||
showTooltip = false
|
showTooltip = false
|
||||||
|
@ -293,8 +293,22 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
|||||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let text: String?
|
let text: String?
|
||||||
let rate: CGFloat?
|
let rate: CGFloat?
|
||||||
|
if case let .sliderCommit(previousValue, newValue) = changeType {
|
||||||
|
let value = String(format: "%0.1f", baseRate.doubleValue)
|
||||||
if baseRate == .x1 {
|
if baseRate == .x1 {
|
||||||
text = presentationData.strings.Conversation_AudioRateTooltipNormal
|
text = presentationData.strings.Conversation_AudioRateTooltipNormal
|
||||||
|
} else {
|
||||||
|
text = presentationData.strings.Conversation_AudioRateTooltipCustom(value).string
|
||||||
|
}
|
||||||
|
if newValue > previousValue {
|
||||||
|
rate = .infinity
|
||||||
|
} else if newValue < previousValue {
|
||||||
|
rate = -.infinity
|
||||||
|
} else {
|
||||||
|
rate = nil
|
||||||
|
}
|
||||||
|
} else if baseRate == .x1 {
|
||||||
|
text = presentationData.strings.Conversation_AudioRateTooltipNormal
|
||||||
rate = 1.0
|
rate = 1.0
|
||||||
} else if baseRate == .x1_5 {
|
} else if baseRate == .x1_5 {
|
||||||
text = presentationData.strings.Conversation_AudioRateTooltip15X
|
text = presentationData.strings.Conversation_AudioRateTooltip15X
|
||||||
@ -303,20 +317,9 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
|||||||
text = presentationData.strings.Conversation_AudioRateTooltipSpeedUp
|
text = presentationData.strings.Conversation_AudioRateTooltipSpeedUp
|
||||||
rate = 2.0
|
rate = 2.0
|
||||||
} else {
|
} else {
|
||||||
let value = String(format: "%0.1f", baseRate.doubleValue)
|
text = nil
|
||||||
text = presentationData.strings.Conversation_AudioRateTooltipCustom(value).string
|
|
||||||
if case let .sliderCommit(previousValue, newValue) = changeType {
|
|
||||||
if newValue > previousValue {
|
|
||||||
rate = .infinity
|
|
||||||
} else if newValue < previousValue {
|
|
||||||
rate = -.infinity
|
|
||||||
} else {
|
|
||||||
rate = nil
|
rate = nil
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
rate = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var showTooltip = true
|
var showTooltip = true
|
||||||
if case .sliderChange = changeType {
|
if case .sliderChange = changeType {
|
||||||
showTooltip = false
|
showTooltip = false
|
||||||
|
@ -11008,14 +11008,22 @@ private final class AccountPeerContextItemNode: ASDisplayNode, ContextMenuCustom
|
|||||||
let textFrame = CGRect(origin: CGPoint(x: sideInset, y: verticalOrigin), size: textSize)
|
let textFrame = CGRect(origin: CGPoint(x: sideInset, y: verticalOrigin), size: textSize)
|
||||||
transition.updateFrameAdditive(node: self.textNode, frame: textFrame)
|
transition.updateFrameAdditive(node: self.textNode, frame: textFrame)
|
||||||
|
|
||||||
if case let .user(user) = self.item.peer, let emojiStatus = user.emojiStatus {
|
var iconContent: EmojiStatusComponent.Content?
|
||||||
|
if case let .user(user) = self.item.peer {
|
||||||
|
if let emojiStatus = user.emojiStatus {
|
||||||
|
iconContent = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 28.0, height: 28.0), placeholderColor: self.presentationData.theme.list.mediaPlaceholderColor, themeColor: self.presentationData.theme.list.itemAccentColor, loopMode: .forever)
|
||||||
|
} else if user.isPremium {
|
||||||
|
iconContent = .premium(color: self.presentationData.theme.list.itemAccentColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let iconContent {
|
||||||
let emojiStatusSize = self.emojiStatusView.update(
|
let emojiStatusSize = self.emojiStatusView.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(EmojiStatusComponent(
|
component: AnyComponent(EmojiStatusComponent(
|
||||||
context: self.item.context,
|
context: self.item.context,
|
||||||
animationCache: self.item.context.animationCache,
|
animationCache: self.item.context.animationCache,
|
||||||
animationRenderer: self.item.context.animationRenderer,
|
animationRenderer: self.item.context.animationRenderer,
|
||||||
content: .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 28.0, height: 28.0), placeholderColor: self.presentationData.theme.list.mediaPlaceholderColor, themeColor: self.presentationData.theme.list.itemAccentColor, loopMode: .forever),
|
content: iconContent,
|
||||||
isVisibleForAnimations: true,
|
isVisibleForAnimations: true,
|
||||||
action: nil
|
action: nil
|
||||||
)),
|
)),
|
||||||
|
@ -925,15 +925,13 @@ public func parseWallpaperUrl(_ url: String) -> WallpaperUrlParameter? {
|
|||||||
|
|
||||||
private struct UrlHandlingConfiguration {
|
private struct UrlHandlingConfiguration {
|
||||||
static var defaultValue: UrlHandlingConfiguration {
|
static var defaultValue: UrlHandlingConfiguration {
|
||||||
return UrlHandlingConfiguration(token: nil, domains: [], urlAuthDomains: [])
|
return UrlHandlingConfiguration(domains: [], urlAuthDomains: [])
|
||||||
}
|
}
|
||||||
|
|
||||||
public let token: String?
|
|
||||||
public let domains: [String]
|
public let domains: [String]
|
||||||
public let urlAuthDomains: [String]
|
public let urlAuthDomains: [String]
|
||||||
|
|
||||||
fileprivate init(token: String?, domains: [String], urlAuthDomains: [String]) {
|
fileprivate init(domains: [String], urlAuthDomains: [String]) {
|
||||||
self.token = token
|
|
||||||
self.domains = domains
|
self.domains = domains
|
||||||
self.urlAuthDomains = urlAuthDomains
|
self.urlAuthDomains = urlAuthDomains
|
||||||
}
|
}
|
||||||
@ -941,11 +939,10 @@ private struct UrlHandlingConfiguration {
|
|||||||
static func with(appConfiguration: AppConfiguration) -> UrlHandlingConfiguration {
|
static func with(appConfiguration: AppConfiguration) -> UrlHandlingConfiguration {
|
||||||
if let data = appConfiguration.data {
|
if let data = appConfiguration.data {
|
||||||
let urlAuthDomains = data["url_auth_domains"] as? [String] ?? []
|
let urlAuthDomains = data["url_auth_domains"] as? [String] ?? []
|
||||||
if let token = data["autologin_token"] as? String, let domains = data["autologin_domains"] as? [String] {
|
if let domains = data["autologin_domains"] as? [String] {
|
||||||
return UrlHandlingConfiguration(token: token, domains: domains, urlAuthDomains: urlAuthDomains)
|
return UrlHandlingConfiguration(domains: domains, urlAuthDomains: urlAuthDomains)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO:loc move to getConfig
|
|
||||||
return .defaultValue
|
return .defaultValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -955,8 +952,8 @@ public func resolveUrlImpl(context: AccountContext, peerId: PeerId?, url: String
|
|||||||
|
|
||||||
return ApplicationSpecificNotice.getSecretChatLinkPreviews(accountManager: context.sharedContext.accountManager)
|
return ApplicationSpecificNotice.getSecretChatLinkPreviews(accountManager: context.sharedContext.accountManager)
|
||||||
|> mapToSignal { linkPreviews -> Signal<ResolvedUrl, NoError> in
|
|> mapToSignal { linkPreviews -> Signal<ResolvedUrl, NoError> in
|
||||||
return context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.App())
|
return context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.App(), TelegramEngine.EngineData.Item.Configuration.Links())
|
||||||
|> mapToSignal { appConfiguration -> Signal<ResolvedUrl, NoError> in
|
|> mapToSignal { appConfiguration, linksConfiguration -> Signal<ResolvedUrl, NoError> in
|
||||||
let urlHandlingConfiguration = UrlHandlingConfiguration.with(appConfiguration: appConfiguration)
|
let urlHandlingConfiguration = UrlHandlingConfiguration.with(appConfiguration: appConfiguration)
|
||||||
|
|
||||||
var skipUrlAuth = skipUrlAuth
|
var skipUrlAuth = skipUrlAuth
|
||||||
@ -978,7 +975,7 @@ public func resolveUrlImpl(context: AccountContext, peerId: PeerId?, url: String
|
|||||||
if urlHandlingConfiguration.domains.contains(host), var components = URLComponents(string: url) {
|
if urlHandlingConfiguration.domains.contains(host), var components = URLComponents(string: url) {
|
||||||
components.scheme = "https"
|
components.scheme = "https"
|
||||||
var queryItems = components.queryItems ?? []
|
var queryItems = components.queryItems ?? []
|
||||||
queryItems.append(URLQueryItem(name: "autologin_token", value: urlHandlingConfiguration.token))
|
queryItems.append(URLQueryItem(name: "autologin_token", value: linksConfiguration.autologinToken))
|
||||||
components.queryItems = queryItems
|
components.queryItems = queryItems
|
||||||
url = components.url?.absoluteString ?? url
|
url = components.url?.absoluteString ?? url
|
||||||
} else if !skipUrlAuth && urlHandlingConfiguration.urlAuthDomains.contains(host) {
|
} else if !skipUrlAuth && urlHandlingConfiguration.urlAuthDomains.contains(host) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user