Various improvements

This commit is contained in:
Ilya Laktyushin 2023-11-28 16:03:13 +04:00
parent 4fcdfebb02
commit 18f41cd24f
6 changed files with 108 additions and 29 deletions

View File

@ -379,7 +379,7 @@ class StatsOverviewItemNode: ListViewItemNode {
middle1RightItemLayoutAndApply = makeMiddle1RightItemLayout(
params.width,
item.presentationData,
compactNumericCountString(views.forwardCount),
compactNumericCountString(views.forwardCount - Int(item.publicShares ?? 0)),
item.presentationData.strings.Stats_Message_PrivateShares,
nil
)

View File

@ -107,8 +107,14 @@ public final class MediaEditor {
private let clock = CMClockGetHostTimeClock()
private var player: AVPlayer?
private var playerAudioMix: AVMutableAudioMix?
private var additionalPlayer: AVPlayer?
private var additionalPlayerAudioMix: AVMutableAudioMix?
private var audioPlayer: AVPlayer?
private var audioPlayerAudioMix: AVMutableAudioMix?
private var volumeFadeIn: SwiftSignalKit.Timer?
private var timeObserver: Any?
@ -901,7 +907,12 @@ public final class MediaEditor {
return values.withUpdatedVideoVolume(volume)
}
self.player?.volume = Float(volume ?? 1.0)
if let audioMix = self.playerAudioMix, let asset = self.player?.currentItem?.asset {
let audioMixInputParameters = AVMutableAudioMixInputParameters(track: asset.tracks(withMediaType: .audio).first)
audioMixInputParameters.setVolume(Float(volume ?? 1.0), at: .zero)
audioMix.inputParameters = [audioMixInputParameters]
self.player?.currentItem?.audioMix = audioMix
}
}
public func setVideoIsMirrored(_ videoIsMirrored: Bool) {
@ -1334,6 +1345,7 @@ public final class MediaEditor {
self.additionalPlayer = nil
self.additionalPlayerPromise.set(.single(nil))
self.additionalPlayerAudioMix = nil
if let textureSource = self.renderer.textureSource as? UniversalTextureSource {
textureSource.forceUpdates = true
@ -1376,12 +1388,18 @@ public final class MediaEditor {
player.masterClock = clock
}
player.automaticallyWaitsToMinimizeStalling = false
let audioMix = AVMutableAudioMix()
let audioMixInputParameters = AVMutableAudioMixInputParameters(track: asset.tracks(withMediaType: .audio).first)
if let volume = self.values.additionalVideoVolume {
audioMixInputParameters.setVolume(Float(volume), at: .zero)
}
audioMix.inputParameters = [audioMixInputParameters]
player.currentItem?.audioMix = audioMix
self.additionalPlayer = player
self.additionalPlayerPromise.set(.single(player))
if let volume = self.values.additionalVideoVolume {
self.additionalPlayer?.volume = Float(volume)
}
self.additionalPlayerAudioMix = audioMix
(self.renderer.textureSource as? UniversalTextureSource)?.setAdditionalInput(.video(playerItem))
}
@ -1417,7 +1435,12 @@ public final class MediaEditor {
return values.withUpdatedAdditionalVideoVolume(volume)
}
self.additionalPlayer?.volume = Float(volume ?? 1.0)
if let audioMix = self.additionalPlayerAudioMix, let asset = self.additionalPlayer?.currentItem?.asset {
let audioMixInputParameters = AVMutableAudioMixInputParameters(track: asset.tracks(withMediaType: .audio).first)
audioMixInputParameters.setVolume(Float(volume ?? 1.0), at: .zero)
audioMix.inputParameters = [audioMixInputParameters]
self.additionalPlayer?.currentItem?.audioMix = audioMix
}
}
private func updateAdditionalVideoPlaybackRange() {
@ -1444,6 +1467,7 @@ public final class MediaEditor {
self.audioPlayer = nil
self.audioPlayerPromise.set(.single(nil))
self.audioPlayerAudioMix = nil
self.audioDelayTimer?.invalidate()
self.audioDelayTimer = nil
@ -1465,14 +1489,20 @@ public final class MediaEditor {
let audioAsset = AVURLAsset(url: URL(fileURLWithPath: audioPath))
let audioPlayer = AVPlayer(playerItem: AVPlayerItem(asset: audioAsset))
audioPlayer.automaticallyWaitsToMinimizeStalling = false
let audioMix = AVMutableAudioMix()
let audioMixInputParameters = AVMutableAudioMixInputParameters(track: audioAsset.tracks(withMediaType: .audio).first)
if let volume = self.values.audioTrackVolume {
audioMixInputParameters.setVolume(Float(volume), at: .zero)
}
audioMix.inputParameters = [audioMixInputParameters]
audioPlayer.currentItem?.audioMix = audioMix
self.audioPlayer = audioPlayer
self.audioPlayerPromise.set(.single(audioPlayer))
self.audioPlayerAudioMix = audioMix
self.maybeGenerateAudioSamples(asset: audioAsset)
if let volume = self.values.audioTrackVolume {
self.audioPlayer?.volume = Float(volume)
}
self.setupTimeObservers()
}
@ -1510,7 +1540,12 @@ public final class MediaEditor {
return values.withUpdatedAudioTrackVolume(volume)
}
self.audioPlayer?.volume = Float(volume ?? 1.0)
if let audioMix = self.audioPlayerAudioMix, let asset = self.audioPlayer?.currentItem?.asset {
let audioMixInputParameters = AVMutableAudioMixInputParameters(track: asset.tracks(withMediaType: .audio).first)
audioMixInputParameters.setVolume(Float(volume ?? 1.0), at: .zero)
audioMix.inputParameters = [audioMixInputParameters]
self.audioPlayer?.currentItem?.audioMix = audioMix
}
}
public func setDrawingAndEntities(data: Data?, image: UIImage?, entities: [CodableDrawingEntity]) {

View File

@ -520,7 +520,7 @@ public final class MediaEditorVideoExport {
if let compositionTrack = composition?.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) {
try? compositionTrack.insertTimeRange(CMTimeRange(start: .zero, duration: asset.duration), of: audioAssetTrack, at: .zero)
if let volume = self.configuration.values.videoVolume, volume < 1.0 {
if let volume = self.configuration.values.videoVolume, volume != 1.0 {
let trackParameters = AVMutableAudioMixInputParameters(track: compositionTrack)
trackParameters.trackID = compositionTrack.trackID
trackParameters.setVolume(Float(volume), at: .zero)
@ -558,7 +558,7 @@ public final class MediaEditorVideoExport {
if let compositionTrack = composition?.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) {
try? compositionTrack.insertTimeRange(timeRange, of: audioAssetTrack, at: startTime)
if let volume = self.configuration.values.additionalVideoVolume, volume < 1.0 {
if let volume = self.configuration.values.additionalVideoVolume, volume != 1.0 {
let trackParameters = AVMutableAudioMixInputParameters(track: compositionTrack)
trackParameters.trackID = compositionTrack.trackID
trackParameters.setVolume(Float(volume), at: .zero)
@ -582,7 +582,7 @@ public final class MediaEditorVideoExport {
if let compositionTrack = composition?.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) {
try? compositionTrack.insertTimeRange(timeRange, of: audioAssetTrack, at: startTime)
if let volume = self.configuration.values.audioTrackVolume, volume < 1.0 {
if let volume = self.configuration.values.audioTrackVolume, volume != 1.0 {
let trackParameters = AVMutableAudioMixInputParameters(track: compositionTrack)
trackParameters.trackID = compositionTrack.trackID
trackParameters.setVolume(Float(volume), at: .zero)

View File

@ -3450,7 +3450,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
var items: [ContextMenuItem] = []
items.append(
.custom(VolumeSliderContextItem(minValue: 0.0, value: value, valueChanged: { [weak self] value, _ in
.custom(VolumeSliderContextItem(minValue: 0.0, maxValue: 1.5, value: value, valueChanged: { [weak self] value, _ in
if let self, let mediaEditor = self.mediaEditor {
if trackId == 0 {
if mediaEditor.values.videoIsMuted {

View File

@ -126,7 +126,8 @@ public final class StoryFooterPanelComponent: Component {
private var likeStatsText: AnimatedCountLabelView?
private var forwardButton: ComponentView<Empty>?
private var repostButton: ComponentView<Empty>?
private var forwardStatsText: AnimatedCountLabelView?
private var reactionStatsIcon: UIImageView?
private var reactionStatsText: AnimatedCountLabelView?
@ -368,11 +369,11 @@ public final class StoryFooterPanelComponent: Component {
var viewCount = 0
var reactionCount = 0
var repostCount = 0
var forwardCount = 0
if let views = component.externalViews ?? component.storyItem.views, views.seenCount != 0 {
viewCount = views.seenCount
reactionCount = views.reactedCount
repostCount = 0
forwardCount = views.forwardCount
}
if component.isChannel {
@ -388,9 +389,11 @@ public final class StoryFooterPanelComponent: Component {
if component.isChannel {
var likeStatsTransition = transition
var forwardStatsTransition = transition
if transition.animation.isImmediate, !isFirstTime, let previousComponent, previousComponent.storyItem.id == component.storyItem.id, previousComponent.expandFraction == component.expandFraction {
likeStatsTransition = .easeInOut(duration: 0.2)
forwardStatsTransition = .easeInOut(duration: 0.2)
}
let likeStatsText: AnimatedCountLabelView
@ -491,6 +494,40 @@ public final class StoryFooterPanelComponent: Component {
}
if component.canShare {
let forwardStatsText: AnimatedCountLabelView
if let current = self.forwardStatsText {
forwardStatsText = current
} else {
forwardStatsTransition = forwardStatsTransition.withAnimation(.none)
forwardStatsText = AnimatedCountLabelView(frame: CGRect())
forwardStatsText.isUserInteractionEnabled = false
self.forwardStatsText = forwardStatsText
self.externalContainerView.addSubview(forwardStatsText)
}
let forwardStatsLayout = forwardStatsText.update(
size: CGSize(width: availableSize.width, height: size.height),
segments: [
.number(forwardCount, NSAttributedString(string: "\(forwardCount)", font: Font.with(size: 15.0, traits: .monospacedNumbers), textColor: .white))
],
transition: (isFirstTime || likeStatsTransition.animation.isImmediate) ? .immediate : ContainedViewLayoutTransition.animated(duration: 0.25, curve: .easeInOut)
)
var forwardStatsFrame = CGRect(origin: CGPoint(x: rightContentOffset - forwardStatsLayout.size.width, y: floor((size.height - forwardStatsLayout.size.height) * 0.5)), size: forwardStatsLayout.size)
forwardStatsFrame.origin.y += component.expandFraction * 45.0
forwardStatsTransition.setPosition(view: forwardStatsText, position: forwardStatsFrame.center)
forwardStatsTransition.setBounds(view: forwardStatsText, bounds: CGRect(origin: CGPoint(), size: forwardStatsFrame.size))
var forwardStatsAlpha: CGFloat = (1.0 - component.expandFraction)
if forwardCount == 0 {
forwardStatsAlpha = 0.0
}
forwardStatsTransition.setAlpha(view: forwardStatsText, alpha: forwardStatsAlpha)
forwardStatsTransition.setScale(view: forwardStatsText, scale: forwardCount == 0 ? 0.001 : 1.0)
if forwardCount != 0 {
rightContentOffset -= forwardStatsLayout.size.width + 1.0
}
let repostButton: ComponentView<Empty>
if let current = self.repostButton {
repostButton = current
@ -720,7 +757,7 @@ public final class StoryFooterPanelComponent: Component {
}
}
if repostCount != 0 && !component.isChannel {
if forwardCount != 0 && !component.isChannel {
var repostTransition = transition
let repostStatsIcon: UIImageView
if let current = self.repostStatsIcon {
@ -749,7 +786,7 @@ public final class StoryFooterPanelComponent: Component {
let repostStatsLayout = repostStatsText.update(
size: CGSize(width: availableSize.width, height: size.height),
segments: [
.number(repostCount, NSAttributedString(string: "\(repostCount)", font: Font.with(size: 15.0, traits: .monospacedNumbers), textColor: .white))
.number(forwardCount, NSAttributedString(string: "\(forwardCount)", font: Font.with(size: 15.0, traits: .monospacedNumbers), textColor: .white))
],
reducedLetterSpacing: true,
transition: (isFirstTime || repostTransition.animation.isImmediate) ? .immediate : ContainedViewLayoutTransition.animated(duration: 0.25, curve: .easeInOut)

View File

@ -10,17 +10,19 @@ import AnimatedCountLabelNode
public final class VolumeSliderContextItem: ContextMenuCustomItem {
private let minValue: CGFloat
private let maxValue: CGFloat
private let value: CGFloat
private let valueChanged: (CGFloat, Bool) -> Void
public init(minValue: CGFloat, value: CGFloat, valueChanged: @escaping (CGFloat, Bool) -> Void) {
public init(minValue: CGFloat, maxValue: CGFloat = 1.0, value: CGFloat, valueChanged: @escaping (CGFloat, Bool) -> Void) {
self.minValue = minValue
self.maxValue = maxValue
self.value = value
self.valueChanged = valueChanged
}
public func node(presentationData: PresentationData, getController: @escaping () -> ContextControllerProtocol?, actionSelected: @escaping (ContextMenuActionResult) -> Void) -> ContextMenuCustomNode {
return VolumeSliderContextItemNode(presentationData: presentationData, getController: getController, minValue: self.minValue, value: self.value, valueChanged: self.valueChanged)
return VolumeSliderContextItemNode(presentationData: presentationData, getController: getController, minValue: self.minValue, maxValue: self.maxValue, value: self.value, valueChanged: self.valueChanged)
}
}
@ -40,6 +42,7 @@ private final class VolumeSliderContextItemNode: ASDisplayNode, ContextMenuCusto
private let foregroundTextNode: ImmediateAnimatedCountLabelNode
let minValue: CGFloat
let maxValue: CGFloat
var value: CGFloat = 1.0 {
didSet {
self.updateValue(transition: .animated(duration: 0.2, curve: .spring))
@ -50,9 +53,10 @@ private final class VolumeSliderContextItemNode: ASDisplayNode, ContextMenuCusto
private let hapticFeedback = HapticFeedback()
init(presentationData: PresentationData, getController: @escaping () -> ContextControllerProtocol?, minValue: CGFloat, value: CGFloat, valueChanged: @escaping (CGFloat, Bool) -> Void) {
init(presentationData: PresentationData, getController: @escaping () -> ContextControllerProtocol?, minValue: CGFloat, maxValue: CGFloat, value: CGFloat, valueChanged: @escaping (CGFloat, Bool) -> Void) {
self.presentationData = presentationData
self.minValue = minValue
self.maxValue = maxValue
self.value = value
self.valueChanged = valueChanged
@ -153,8 +157,9 @@ private final class VolumeSliderContextItemNode: ASDisplayNode, ContextMenuCusto
private func updateValue(transition: ContainedViewLayoutTransition = .immediate) {
let width = self.frame.width
let range = self.maxValue - self.minValue
let value = self.value
transition.updateFrameAdditive(node: self.foregroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: value * width, height: self.frame.height)))
transition.updateFrameAdditive(node: self.foregroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: value / range * width, height: self.frame.height)))
let stringValue = "\(Int(self.value * 100.0))%"
@ -236,10 +241,10 @@ private final class VolumeSliderContextItemNode: ASDisplayNode, ContextMenuCusto
let translation: CGFloat = gestureRecognizer.translation(in: gestureRecognizer.view).x
let delta = translation / self.bounds.width
self.value = max(self.minValue, min(1.0, self.value + delta))
self.value = max(self.minValue, min(self.maxValue, self.value + delta))
gestureRecognizer.setTranslation(CGPoint(), in: gestureRecognizer.view)
if self.value == 1.0 && previousValue != 1.0 {
if self.value == self.maxValue && previousValue != self.maxValue {
self.backgroundIconNode.layer.animateScale(from: 1.0, to: 1.1, duration: 0.16, removeOnCompletion: false, completion: { [weak self] _ in
if let strongSelf = self {
strongSelf.backgroundIconNode.layer.animateScale(from: 1.1, to: 1.0, duration: 0.16)
@ -251,6 +256,8 @@ private final class VolumeSliderContextItemNode: ASDisplayNode, ContextMenuCusto
}
})
self.hapticFeedback.impact(.soft)
} else if self.maxValue != 1.0 && self.value == 1.0 && previousValue != 1.0 {
self.hapticFeedback.impact(.soft)
} else if self.value == 0.0 && previousValue != 0.0 {
self.hapticFeedback.impact(.soft)
}
@ -260,7 +267,7 @@ private final class VolumeSliderContextItemNode: ASDisplayNode, ContextMenuCusto
case .ended:
let translation: CGFloat = gestureRecognizer.translation(in: gestureRecognizer.view).x
let delta = translation / self.bounds.width
self.value = max(self.minValue, min(1.0, self.value + delta))
self.value = max(self.minValue, min(self.maxValue, self.value + delta))
self.valueChanged(self.value, true)
default:
break
@ -269,7 +276,7 @@ private final class VolumeSliderContextItemNode: ASDisplayNode, ContextMenuCusto
@objc private func tapGesture(_ gestureRecognizer: UITapGestureRecognizer) {
let location = gestureRecognizer.location(in: gestureRecognizer.view)
self.value = max(self.minValue, min(1.0, location.x / self.bounds.width))
self.value = max(self.minValue, min(self.maxValue, location.x / self.bounds.width))
self.valueChanged(self.value, true)
}