Various fixes

This commit is contained in:
Ilya Laktyushin 2023-05-03 23:38:06 +04:00
parent cd4940865d
commit e31d3bbad6
6 changed files with 21 additions and 302 deletions

View File

@ -124,8 +124,11 @@ public final class ConfettiView: UIView {
}
}
var previousTimestamp = CACurrentMediaTime()
self.displayLink = ConstantDisplayLinkAnimator(update: { [weak self] in
self?.step()
let currentTimestamp = CACurrentMediaTime()
self?.step(dt: currentTimestamp - previousTimestamp)
previousTimestamp = currentTimestamp
})
self.displayLink?.isPaused = false
@ -137,12 +140,12 @@ public final class ConfettiView: UIView {
private var slowdownStartTimestamps: [Float?] = [nil, nil, nil]
private func step() {
private func step(dt: Double) {
let dt = Float(dt)
self.slowdownStartTimestamps[0] = 0.33
var haveParticlesAboveGround = false
let maxPositionY = self.bounds.height + 30.0
let dt: Float = 1.0 * 1.0 / 60.0
let typeDelays: [Float] = [0.0, 0.01, 0.08]
var dtAndDamping: [(Float, Float)] = []

View File

@ -1,269 +0,0 @@
import Foundation
import UIKit
import AsyncDisplayKit
import MediaPlayer
import SwiftSignalKit
private let volumeNotificationKey = "AVSystemController_SystemVolumeDidChangeNotification"
private let volumeParameterKey = "AVSystemController_AudioVolumeNotificationParameter"
private let changeReasonParameterKey = "AVSystemController_AudioVolumeChangeReasonNotificationParameter"
private let explicitChangeReasonValue = "ExplicitVolumeChange"
private final class VolumeView: MPVolumeView {
@objc func _updateWirelessRouteStatus() {
}
}
final class VolumeControlStatusBar: UIView {
private let control: VolumeView
private var observer: Any?
private var currentValue: Float
var valueChanged: ((Float, Float) -> Void)?
private var disposable: Disposable?
private var ignoreAdjustmentOnce = false
init(frame: CGRect, shouldBeVisible: Signal<Bool, NoError>) {
self.control = VolumeView(frame: CGRect(origin: CGPoint(x: -100.0, y: -100.0), size: CGSize(width: 100.0, height: 20.0)))
self.control.alpha = 0.0001
self.currentValue = AVAudioSession.sharedInstance().outputVolume
super.init(frame: frame)
self.addSubview(self.control)
self.observer = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: volumeNotificationKey), object: nil, queue: OperationQueue.main, using: { [weak self] notification in
if let strongSelf = self, let userInfo = notification.userInfo {
if let volume = userInfo[volumeParameterKey] as? Float {
let previous = strongSelf.currentValue
if !previous.isEqual(to: volume) {
strongSelf.currentValue = volume
if strongSelf.ignoreAdjustmentOnce {
strongSelf.ignoreAdjustmentOnce = false
} else {
if strongSelf.control.superview != nil {
if let reason = userInfo[changeReasonParameterKey], reason as? String != explicitChangeReasonValue {
return
}
strongSelf.valueChanged?(previous, volume)
}
}
}
}
}
})
self.disposable = (shouldBeVisible
|> deliverOnMainQueue).start(next: { [weak self] value in
guard let strongSelf = self else {
return
}
if value {
if strongSelf.control.superview == nil {
strongSelf.ignoreAdjustmentOnce = true
strongSelf.addSubview(strongSelf.control)
}
} else {
strongSelf.control.removeFromSuperview()
strongSelf.ignoreAdjustmentOnce = false
}
})
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
if let observer = self.observer {
NotificationCenter.default.removeObserver(observer)
}
self.disposable?.dispose()
}
}
final class VolumeControlStatusBarNode: ASDisplayNode {
var innerGraphics: (UIImage, UIImage, UIImage, Bool)?
var graphics: (UIImage, UIImage, UIImage)? = nil {
didSet {
if self.isDark {
self.innerGraphics = generateDarkGraphics(self.graphics)
} else {
if let graphics = self.graphics {
self.innerGraphics = (graphics.0, graphics.1, graphics.2, false)
} else {
self.innerGraphics = nil
}
}
}
}
private let outlineNode: ASImageNode
private let backgroundNode: ASImageNode
private let iconNode: ASImageNode
private let foregroundNode: ASImageNode
private let foregroundClippingNode: ASDisplayNode
private var validLayout: ContainerViewLayout?
var isDark: Bool = false {
didSet {
if self.isDark != oldValue {
if self.isDark {
self.outlineNode.image = generateStretchableFilledCircleImage(diameter: 12.0, color: UIColor(white: 0.0, alpha: 0.7))
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: UIColor(white: 0.6, alpha: 1.0))
self.foregroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: .white)
self.innerGraphics = generateDarkGraphics(self.graphics)
} else {
self.outlineNode.image = nil
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: UIColor(rgb: 0xc5c5c5))
self.foregroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: .black)
if let graphics = self.graphics {
self.innerGraphics = (graphics.0, graphics.1, graphics.2, false)
}
}
self.updateIcon()
}
}
}
private var value: CGFloat = 1.0
override init() {
self.outlineNode = ASImageNode()
self.outlineNode.isLayerBacked = true
self.outlineNode.displaysAsynchronously = false
self.backgroundNode = ASImageNode()
self.backgroundNode.isLayerBacked = true
self.backgroundNode.displaysAsynchronously = false
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: UIColor(rgb: 0xc5c5c5))
self.foregroundNode = ASImageNode()
self.foregroundNode.isLayerBacked = true
self.foregroundNode.displaysAsynchronously = false
self.foregroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: .black)
self.foregroundClippingNode = ASDisplayNode()
self.foregroundClippingNode.clipsToBounds = true
self.foregroundClippingNode.addSubnode(self.foregroundNode)
self.iconNode = ASImageNode()
self.iconNode.isLayerBacked = true
self.iconNode.displaysAsynchronously = false
super.init()
self.isUserInteractionEnabled = false
self.addSubnode(self.outlineNode)
self.addSubnode(self.backgroundNode)
self.addSubnode(self.foregroundClippingNode)
self.addSubnode(self.iconNode)
}
func generateDarkGraphics(_ graphics: (UIImage, UIImage, UIImage)?) -> (UIImage, UIImage, UIImage, Bool)? {
if var (offImage, halfImage, onImage) = graphics {
offImage = generateTintedImage(image: offImage, color: UIColor.white)!
halfImage = generateTintedImage(image: halfImage, color: UIColor.white)!
onImage = generateTintedImage(image: onImage, color: UIColor.white)!
return (offImage, halfImage, onImage, true)
} else {
return nil
}
}
func updateGraphics() {
if self.isDark {
self.outlineNode.image = generateStretchableFilledCircleImage(diameter: 12.0, color: UIColor(white: 0.0, alpha: 0.7))
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: UIColor(white: 0.6, alpha: 1.0))
self.foregroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: .white)
} else {
self.outlineNode.image = nil
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: UIColor(white: 0.6, alpha: 1.0))
self.foregroundNode.image = generateStretchableFilledCircleImage(diameter: 4.0, color: .black)
}
}
func updateLayout(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
self.validLayout = layout
let barHeight: CGFloat = 4.0
var barWidth: CGFloat
let statusBarHeight: CGFloat
var sideInset: CGFloat
if let actual = layout.statusBarHeight {
statusBarHeight = actual
} else {
statusBarHeight = 24.0
}
if layout.safeInsets.left.isZero && layout.safeInsets.top.isZero && layout.intrinsicInsets.left.isZero && layout.intrinsicInsets.top.isZero {
sideInset = 4.0
} else {
sideInset = 12.0
}
let iconRect = CGRect(x: sideInset + 4.0, y: 14.0, width: 21.0, height: 16.0)
if !layout.intrinsicInsets.bottom.isZero {
if layout.size.width > 375.0 {
barWidth = 88.0 - sideInset * 2.0
} else {
barWidth = 80.0 - sideInset * 2.0
}
if layout.size.width < layout.size.height {
self.outlineNode.isHidden = true
} else {
self.outlineNode.isHidden = false
}
if self.graphics != nil {
if layout.size.width < layout.size.height {
self.iconNode.isHidden = false
barWidth -= iconRect.width - 8.0
sideInset += iconRect.width + 8.0
} else {
sideInset += layout.safeInsets.left
self.iconNode.isHidden = true
}
}
} else {
self.iconNode.isHidden = true
barWidth = layout.size.width - sideInset * 2.0
}
let boundingRect = CGRect(origin: CGPoint(x: sideInset, y: floor((statusBarHeight - barHeight) / 2.0)), size: CGSize(width: barWidth, height: barHeight))
transition.updateFrame(node: self.iconNode, frame: iconRect)
transition.updateFrame(node: self.outlineNode, frame: boundingRect.insetBy(dx: -4.0, dy: -4.0))
transition.updateFrame(node: self.backgroundNode, frame: boundingRect)
transition.updateFrame(node: self.foregroundNode, frame: CGRect(origin: CGPoint(), size: boundingRect.size))
transition.updateFrame(node: self.foregroundClippingNode, frame: CGRect(origin: boundingRect.origin, size: CGSize(width: self.value * boundingRect.width, height: boundingRect.height)))
}
func updateValue(from fromValue: CGFloat, to toValue: CGFloat) {
if let layout = self.validLayout {
if self.foregroundClippingNode.layer.animation(forKey: "bounds") == nil {
self.value = fromValue
self.updateLayout(layout: layout, transition: .immediate)
}
self.value = toValue
self.updateLayout(layout: layout, transition: .animated(duration: 0.25, curve: .spring))
self.updateIcon()
} else {
self.value = toValue
}
}
private func updateIcon() {
if let graphics = self.innerGraphics {
if self.value > 0.5 {
self.iconNode.image = graphics.2
} else if self.value > 0.001 {
self.iconNode.image = graphics.1
} else {
self.iconNode.image = graphics.0
}
}
}
}

View File

@ -190,22 +190,13 @@ open class ManagedAnimationNode: ASDisplayNode {
self.addSubnode(self.imageNode)
var previousTimestamp = CACurrentMediaTime()
displayLinkUpdate = { [weak self] in
if let strongSelf = self {
// let timestamp = CACurrentMediaTime()
// var delta: Double
// if let previousTimestamp = strongSelf.previousTimestamp {
// delta = min(timestamp - previousTimestamp, 1.0 / 60.0)
// if let currentDelta = strongSelf.delta, currentDelta < delta {
// delta = currentDelta
// }
// } else {
let delta = 1.0 / 60.0
// }
// strongSelf.previousTimestamp = timestamp
strongSelf.delta = delta
let currentTimestamp = CACurrentMediaTime()
strongSelf.delta = currentTimestamp - previousTimestamp
strongSelf.updateAnimation()
previousTimestamp = currentTimestamp
}
}
}

View File

@ -245,7 +245,7 @@ private final class AudioPlayerRendererContext {
audioSessionControl.setOutputMode(self.forceAudioToSpeaker ? .speakerIfNoHeadphones : .system)
}
if let equalizerAudioUnit = self.equalizerAudioUnit, self.forAudioVideoMessage && !self.ambient {
AudioUnitSetParameter(equalizerAudioUnit, kAUNBandEQParam_GlobalGain, kAudioUnitScope_Global, 0, self.forceAudioToSpeaker ? 0.0 : 12.0, 0)
AudioUnitSetParameter(equalizerAudioUnit, kAUNBandEQParam_GlobalGain, kAudioUnitScope_Global, 0, self.forceAudioToSpeaker ? 0.0 : 5.0, 0)
}
}
}

View File

@ -1733,6 +1733,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
currentCredibilityIcon = .text(color: incoming ? item.presentationData.theme.theme.chat.message.incoming.scamColor : item.presentationData.theme.theme.chat.message.outgoing.scamColor, string: item.presentationData.strings.Message_FakeAccount.uppercased())
} else if let user = effectiveAuthor as? TelegramUser, let emojiStatus = user.emojiStatus {
currentCredibilityIcon = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 20.0, height: 20.0), placeholderColor: incoming ? item.presentationData.theme.theme.chat.message.incoming.mediaPlaceholderColor : item.presentationData.theme.theme.chat.message.outgoing.mediaPlaceholderColor, themeColor: nameColor.withMultipliedAlpha(0.4), loopMode: .count(2))
} else if effectiveAuthor.isVerified {
currentCredibilityIcon = .verified(fillColor: item.presentationData.theme.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.theme.list.itemCheckColors.foregroundColor, sizeType: .compact)
} else if effectiveAuthor.isPremium {
currentCredibilityIcon = .premium(color: nameColor.withMultipliedAlpha(0.4))
}
@ -1897,6 +1899,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
var forwardAuthorSignature: String?
if displayHeader {
let bubbleWidthInsets: CGFloat = mosaicRange == nil ? layoutConstants.text.bubbleInsets.left + layoutConstants.text.bubbleInsets.right : 0.0
if authorNameString != nil || inlineBotNameString != nil {
if headerSize.height.isZero {
headerSize.height += 5.0
@ -1960,7 +1963,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
})
nameNodeOriginY = headerSize.height
headerSize.width = max(headerSize.width, nameNodeSizeApply.0.width + adminBadgeSizeAndApply.0.size.width + layoutConstants.text.bubbleInsets.left + layoutConstants.text.bubbleInsets.right + credibilityIconWidth)
headerSize.width = max(headerSize.width, nameNodeSizeApply.0.width + adminBadgeSizeAndApply.0.size.width + credibilityIconWidth + bubbleWidthInsets)
headerSize.height += nameNodeSizeApply.0.height
}
@ -1993,7 +1996,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
forwardInfoSizeApply = (sizeAndApply.0, { width in sizeAndApply.1(width) })
forwardInfoOriginY = headerSize.height
headerSize.width = max(headerSize.width, forwardInfoSizeApply.0.width + layoutConstants.text.bubbleInsets.left + layoutConstants.text.bubbleInsets.right)
headerSize.width = max(headerSize.width, forwardInfoSizeApply.0.width + bubbleWidthInsets)
headerSize.height += forwardInfoSizeApply.0.height
}
@ -2024,7 +2027,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
threadInfoSizeApply = (sizeAndApply.0, { synchronousLoads in sizeAndApply.1(synchronousLoads) })
threadInfoOriginY = headerSize.height
headerSize.width = max(headerSize.width, threadInfoSizeApply.0.width + layoutConstants.text.bubbleInsets.left + layoutConstants.text.bubbleInsets.right)
headerSize.width = max(headerSize.width, threadInfoSizeApply.0.width + bubbleWidthInsets)
headerSize.height += threadInfoSizeApply.0.height + 5.0
}
}
@ -2050,7 +2053,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
replyInfoSizeApply = (sizeAndApply.0, { synchronousLoads in sizeAndApply.1(synchronousLoads) })
replyInfoOriginY = headerSize.height
headerSize.width = max(headerSize.width, replyInfoSizeApply.0.width + layoutConstants.text.bubbleInsets.left + layoutConstants.text.bubbleInsets.right)
headerSize.width = max(headerSize.width, replyInfoSizeApply.0.width + bubbleWidthInsets)
headerSize.height += replyInfoSizeApply.0.height + 2.0
}

View File

@ -452,16 +452,7 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
wasEmpty = true
}
let firstItem = countAndFilterItems.1.first?.0 ?? .allChats
let firstItemEntryId: ChatListFilterTabEntryId
switch firstItem {
case .allChats:
firstItemEntryId = .all
case let .filter(id, _, _, _):
firstItemEntryId = .filter(id)
}
var selectedEntryId = !strongSelf.initializedFilters ? firstItemEntryId : (strongSelf.peerSelectionNode.mainContainerNode?.currentItemFilter ?? .all)
var selectedEntryId = !strongSelf.initializedFilters ? .all : (strongSelf.peerSelectionNode.mainContainerNode?.currentItemFilter ?? .all)
var resetCurrentEntry = false
if !resolvedItems.contains(where: { $0.id == selectedEntryId }) {
resetCurrentEntry = true