From e31d3bbad6f027edbcbed2006159de9292f8c64d Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 3 May 2023 23:38:06 +0400 Subject: [PATCH] Various fixes --- .../ConfettiEffect/Sources/ConfettiView.swift | 9 +- .../Source/VolumeControlStatusBar.swift | 269 ------------------ .../Sources/ManagedAnimationNode.swift | 17 +- .../Sources/MediaPlayerAudioRenderer.swift | 2 +- .../Sources/ChatMessageBubbleItemNode.swift | 13 +- .../Sources/PeerSelectionController.swift | 13 +- 6 files changed, 21 insertions(+), 302 deletions(-) delete mode 100644 submodules/Display/Source/VolumeControlStatusBar.swift diff --git a/submodules/ConfettiEffect/Sources/ConfettiView.swift b/submodules/ConfettiEffect/Sources/ConfettiView.swift index 7d6d0a7815..cb38579a81 100644 --- a/submodules/ConfettiEffect/Sources/ConfettiView.swift +++ b/submodules/ConfettiEffect/Sources/ConfettiView.swift @@ -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)] = [] diff --git a/submodules/Display/Source/VolumeControlStatusBar.swift b/submodules/Display/Source/VolumeControlStatusBar.swift deleted file mode 100644 index e498d4bda0..0000000000 --- a/submodules/Display/Source/VolumeControlStatusBar.swift +++ /dev/null @@ -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) { - 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 - } - } - } -} diff --git a/submodules/ManagedAnimationNode/Sources/ManagedAnimationNode.swift b/submodules/ManagedAnimationNode/Sources/ManagedAnimationNode.swift index 6720f7df92..914f8c2279 100644 --- a/submodules/ManagedAnimationNode/Sources/ManagedAnimationNode.swift +++ b/submodules/ManagedAnimationNode/Sources/ManagedAnimationNode.swift @@ -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 } } } diff --git a/submodules/MediaPlayer/Sources/MediaPlayerAudioRenderer.swift b/submodules/MediaPlayer/Sources/MediaPlayerAudioRenderer.swift index cc3ef112a9..7d1c46f697 100644 --- a/submodules/MediaPlayer/Sources/MediaPlayerAudioRenderer.swift +++ b/submodules/MediaPlayer/Sources/MediaPlayerAudioRenderer.swift @@ -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) } } } diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index c771cca291..86195c01d6 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -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,10 +1996,10 @@ 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 } - + var hasReply = replyMessage != nil if !isInstantVideo, case let .peer(peerId) = item.chatLocation, (peerId == replyMessage?.id.peerId || item.message.threadId == 1), let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum), item.message.associatedThreadInfo != nil { if let threadId = item.message.threadId, let replyMessage = replyMessage, Int64(replyMessage.id.id) == threadId { @@ -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 } diff --git a/submodules/TelegramUI/Sources/PeerSelectionController.swift b/submodules/TelegramUI/Sources/PeerSelectionController.swift index 5d796e49ea..653c2ecda1 100644 --- a/submodules/TelegramUI/Sources/PeerSelectionController.swift +++ b/submodules/TelegramUI/Sources/PeerSelectionController.swift @@ -451,17 +451,8 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon } else { 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