mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 22:55:00 +00:00
Various improvements
This commit is contained in:
@@ -29,6 +29,9 @@ import AdsInfoScreen
|
||||
import AdsReportScreen
|
||||
import SaveProgressScreen
|
||||
import SectionTitleContextItem
|
||||
import RasterizedCompositionComponent
|
||||
import BadgeComponent
|
||||
import ComponentFlow
|
||||
|
||||
public enum UniversalVideoGalleryItemContentInfo {
|
||||
case message(Message, Int?)
|
||||
@@ -507,8 +510,19 @@ final class MoreHeaderButton: HighlightableButtonNode {
|
||||
final class SettingsHeaderButton: HighlightableButtonNode {
|
||||
let referenceNode: ContextReferenceContentNode
|
||||
let containerNode: ContextControllerSourceNode
|
||||
private let iconNode: ASImageNode
|
||||
private let iconDotNode: ASImageNode
|
||||
|
||||
private let iconLayer: RasterizedCompositionMonochromeLayer
|
||||
|
||||
private let gearsLayer: RasterizedCompositionImageLayer
|
||||
private let dotLayer: RasterizedCompositionImageLayer
|
||||
|
||||
private var speedBadge: ComponentView<Empty>?
|
||||
private var qualityBadge: ComponentView<Empty>?
|
||||
|
||||
private var speedBadgeText: String?
|
||||
private var qualityBadgeText: String?
|
||||
|
||||
private let badgeFont: UIFont
|
||||
|
||||
private var isMenuOpen: Bool = false
|
||||
|
||||
@@ -523,23 +537,24 @@ final class SettingsHeaderButton: HighlightableButtonNode {
|
||||
self.containerNode = ContextControllerSourceNode()
|
||||
self.containerNode.animateScale = false
|
||||
|
||||
self.iconNode = ASImageNode()
|
||||
self.iconNode.displaysAsynchronously = false
|
||||
self.iconNode.displayWithoutProcessing = true
|
||||
self.iconNode.contentMode = .scaleToFill
|
||||
self.iconLayer = RasterizedCompositionMonochromeLayer()
|
||||
//self.iconLayer.backgroundColor = UIColor.green.cgColor
|
||||
|
||||
self.iconDotNode = ASImageNode()
|
||||
self.iconDotNode.displaysAsynchronously = false
|
||||
self.iconDotNode.displayWithoutProcessing = true
|
||||
self.gearsLayer = RasterizedCompositionImageLayer()
|
||||
self.gearsLayer.image = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/NavigationSettingsNoDot"), color: .white)
|
||||
|
||||
self.dotLayer = RasterizedCompositionImageLayer()
|
||||
self.dotLayer.image = generateFilledCircleImage(diameter: 4.0, color: .white)
|
||||
|
||||
self.iconLayer.contentsLayer.addSublayer(self.gearsLayer)
|
||||
self.iconLayer.contentsLayer.addSublayer(self.dotLayer)
|
||||
|
||||
self.badgeFont = Font.with(size: 8.0, design: .round, weight: .bold)
|
||||
|
||||
super.init()
|
||||
|
||||
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/NavigationSettingsNoDot"), color: .white)
|
||||
self.iconDotNode.image = generateFilledCircleImage(diameter: 4.0, color: .white)
|
||||
|
||||
self.containerNode.addSubnode(self.referenceNode)
|
||||
self.referenceNode.addSubnode(self.iconNode)
|
||||
self.referenceNode.addSubnode(self.iconDotNode)
|
||||
self.referenceNode.layer.addSublayer(self.iconLayer)
|
||||
self.addSubnode(self.containerNode)
|
||||
|
||||
self.containerNode.shouldBegin = { [weak self] location in
|
||||
@@ -560,17 +575,32 @@ final class SettingsHeaderButton: HighlightableButtonNode {
|
||||
|
||||
self.hitTestSlop = UIEdgeInsets(top: 0.0, left: -4.0, bottom: 0.0, right: -4.0)
|
||||
|
||||
if let image = self.iconNode.image {
|
||||
let iconFrame = CGRect(origin: CGPoint(x: floor((self.containerNode.bounds.width - image.size.width) / 2.0), y: floor((self.containerNode.bounds.height - image.size.height) / 2.0)), size: image.size)
|
||||
self.iconNode.position = iconFrame.center
|
||||
self.iconNode.bounds = CGRect(origin: CGPoint(), size: iconFrame.size)
|
||||
if let image = self.gearsLayer.image {
|
||||
let iconInnerInsets = UIEdgeInsets(top: 4.0, left: 8.0, bottom: 4.0, right: 6.0)
|
||||
let iconSize = CGSize(width: image.size.width + iconInnerInsets.left + iconInnerInsets.right, height: image.size.height + iconInnerInsets.top + iconInnerInsets.bottom)
|
||||
let iconFrame = CGRect(origin: CGPoint(x: floor((self.containerNode.bounds.width - iconSize.width) / 2.0), y: floor((self.containerNode.bounds.height - iconSize.height) / 2.0)), size: iconSize)
|
||||
self.iconLayer.position = iconFrame.center
|
||||
self.iconLayer.bounds = CGRect(origin: CGPoint(), size: iconFrame.size)
|
||||
|
||||
if let dotImage = self.iconDotNode.image {
|
||||
let dotFrame = CGRect(origin: CGPoint(x: iconFrame.minX + floorToScreenPixels((iconFrame.width - dotImage.size.width) * 0.5), y: iconFrame.minY + floorToScreenPixels((iconFrame.height - dotImage.size.height) * 0.5)), size: dotImage.size)
|
||||
self.iconDotNode.position = dotFrame.center
|
||||
self.iconDotNode.bounds = CGRect(origin: CGPoint(), size: dotFrame.size)
|
||||
self.iconLayer.contentsLayer.position = CGRect(origin: CGPoint(), size: iconFrame.size).center
|
||||
self.iconLayer.contentsLayer.bounds = CGRect(origin: CGPoint(), size: iconFrame.size)
|
||||
|
||||
self.iconLayer.maskedLayer.position = CGRect(origin: CGPoint(), size: iconFrame.size).center
|
||||
self.iconLayer.maskedLayer.bounds = CGRect(origin: CGPoint(), size: iconFrame.size)
|
||||
self.iconLayer.maskedLayer.backgroundColor = UIColor.white.cgColor
|
||||
|
||||
let gearsFrame = CGRect(origin: CGPoint(x: floor((iconSize.width - image.size.width) * 0.5), y: floor((iconSize.height - image.size.height) * 0.5)), size: image.size)
|
||||
self.gearsLayer.position = gearsFrame.center
|
||||
self.gearsLayer.bounds = CGRect(origin: CGPoint(), size: gearsFrame.size)
|
||||
|
||||
if let dotImage = self.dotLayer.image {
|
||||
let dotFrame = CGRect(origin: CGPoint(x: gearsFrame.minX + floorToScreenPixels((gearsFrame.width - dotImage.size.width) * 0.5), y: gearsFrame.minY + floorToScreenPixels((gearsFrame.height - dotImage.size.height) * 0.5)), size: dotImage.size)
|
||||
self.dotLayer.position = dotFrame.center
|
||||
self.dotLayer.bounds = CGRect(origin: CGPoint(), size: dotFrame.size)
|
||||
}
|
||||
}
|
||||
|
||||
//self.setBadges(speed: "1.5x", quality: "HD", transition: .immediate)
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
@@ -592,21 +622,111 @@ final class SettingsHeaderButton: HighlightableButtonNode {
|
||||
self.isMenuOpen = isMenuOpen
|
||||
|
||||
let rotationTransition: ContainedViewLayoutTransition = .animated(duration: 0.35, curve: .spring)
|
||||
rotationTransition.updateTransform(node: self.iconNode, transform: CGAffineTransformMakeRotation(isMenuOpen ? (CGFloat.pi * 2.0 / 6.0) : 0.0))
|
||||
self.iconNode.layer.animateScale(from: 1.0, to: 1.07, duration: 0.1, removeOnCompletion: false, completion: { [weak self] finished in
|
||||
rotationTransition.updateTransform(layer: self.gearsLayer, transform: CGAffineTransformMakeRotation(isMenuOpen ? (CGFloat.pi * 2.0 / 6.0) : 0.0))
|
||||
self.gearsLayer.animateScale(from: 1.0, to: 1.07, duration: 0.1, removeOnCompletion: false, completion: { [weak self] finished in
|
||||
guard let self, finished else {
|
||||
return
|
||||
}
|
||||
self.iconNode.layer.animateScale(from: 1.07, to: 1.0, duration: 0.1, removeOnCompletion: false)
|
||||
self.gearsLayer.animateScale(from: 1.07, to: 1.0, duration: 0.1, removeOnCompletion: true)
|
||||
})
|
||||
|
||||
self.iconDotNode.layer.animateScale(from: 1.0, to: 0.8, duration: 0.1, removeOnCompletion: false, completion: { [weak self] finished in
|
||||
self.dotLayer.animateScale(from: 1.0, to: 0.8, duration: 0.1, removeOnCompletion: false, completion: { [weak self] finished in
|
||||
guard let self, finished else {
|
||||
return
|
||||
}
|
||||
self.iconDotNode.layer.animateScale(from: 0.8, to: 1.0, duration: 0.1, removeOnCompletion: false)
|
||||
self.dotLayer.animateScale(from: 0.8, to: 1.0, duration: 0.1, removeOnCompletion: true)
|
||||
})
|
||||
}
|
||||
|
||||
func setBadges(speed: String?, quality: String?, transition: ComponentTransition) {
|
||||
if self.speedBadgeText == speed && self.qualityBadgeText == quality {
|
||||
return
|
||||
}
|
||||
self.speedBadgeText = speed
|
||||
self.qualityBadgeText = quality
|
||||
|
||||
if let badgeText = speed {
|
||||
var badgeTransition = transition
|
||||
let speedBadge: ComponentView<Empty>
|
||||
if let current = self.speedBadge {
|
||||
speedBadge = current
|
||||
} else {
|
||||
speedBadge = ComponentView()
|
||||
self.speedBadge = speedBadge
|
||||
badgeTransition = badgeTransition.withAnimation(.none)
|
||||
}
|
||||
let badgeSize = speedBadge.update(
|
||||
transition: badgeTransition,
|
||||
component: AnyComponent(BadgeComponent(
|
||||
text: badgeText,
|
||||
font: self.badgeFont,
|
||||
cornerRadius: 3.0,
|
||||
insets: UIEdgeInsets(top: 1.33, left: 1.66, bottom: 1.33, right: 1.66),
|
||||
outerInsets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0)
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||
)
|
||||
if let speedBadgeView = speedBadge.view {
|
||||
if speedBadgeView.layer.superlayer == nil {
|
||||
self.iconLayer.contentsLayer.addSublayer(speedBadgeView.layer)
|
||||
|
||||
transition.animateAlpha(layer: speedBadgeView.layer, from: 0.0, to: 1.0)
|
||||
transition.animateScale(layer: speedBadgeView.layer, from: 0.001, to: 1.0)
|
||||
}
|
||||
badgeTransition.setFrame(layer: speedBadgeView.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: badgeSize))
|
||||
}
|
||||
} else if let speedBadge = self.speedBadge {
|
||||
self.speedBadge = nil
|
||||
if let speedBadgeView = speedBadge.view {
|
||||
transition.setAlpha(layer: speedBadgeView.layer, alpha: 0.0, completion: { [weak speedBadgeView] _ in
|
||||
speedBadgeView?.layer.removeFromSuperlayer()
|
||||
})
|
||||
transition.setScale(layer: speedBadgeView.layer, scale: 0.001)
|
||||
}
|
||||
}
|
||||
|
||||
if let badgeText = quality {
|
||||
var badgeTransition = transition
|
||||
let qualityBadge: ComponentView<Empty>
|
||||
if let current = self.qualityBadge {
|
||||
qualityBadge = current
|
||||
} else {
|
||||
qualityBadge = ComponentView()
|
||||
self.qualityBadge = qualityBadge
|
||||
badgeTransition = badgeTransition.withAnimation(.none)
|
||||
}
|
||||
let badgeSize = qualityBadge.update(
|
||||
transition: badgeTransition,
|
||||
component: AnyComponent(BadgeComponent(
|
||||
text: badgeText,
|
||||
font: self.badgeFont,
|
||||
cornerRadius: 3.0,
|
||||
insets: UIEdgeInsets(top: 1.0, left: 1.66, bottom: 1.0, right: 1.0),
|
||||
outerInsets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0)
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||
)
|
||||
if let qualityBadgeView = qualityBadge.view {
|
||||
if qualityBadgeView.layer.superlayer == nil {
|
||||
self.iconLayer.contentsLayer.addSublayer(qualityBadgeView.layer)
|
||||
|
||||
transition.animateAlpha(layer: qualityBadgeView.layer, from: 0.0, to: 1.0)
|
||||
transition.animateScale(layer: qualityBadgeView.layer, from: 0.001, to: 1.0)
|
||||
}
|
||||
badgeTransition.setFrame(layer: qualityBadgeView.layer, frame: CGRect(origin: CGPoint(x: self.iconLayer.bounds.width - badgeSize.width, y: self.iconLayer.bounds.height - badgeSize.height), size: badgeSize))
|
||||
}
|
||||
} else if let qualityBadge = self.qualityBadge {
|
||||
self.qualityBadge = nil
|
||||
if let qualityBadgeView = qualityBadge.view {
|
||||
transition.setAlpha(layer: qualityBadgeView.layer, alpha: 0.0, completion: { [weak qualityBadgeView] _ in
|
||||
qualityBadgeView?.layer.removeFromSuperlayer()
|
||||
})
|
||||
transition.setScale(layer: qualityBadgeView.layer, scale: 0.001)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 15.0, *)
|
||||
@@ -1201,6 +1321,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
private var playbackRate: Double?
|
||||
private var videoQuality: UniversalVideoContentVideoQuality = .auto
|
||||
private let playbackRatePromise = ValuePromise<Double>()
|
||||
private let videoQualityPromise = ValuePromise<UniversalVideoContentVideoQuality>()
|
||||
|
||||
private let statusDisposable = MetaDisposable()
|
||||
private let moreButtonStateDisposable = MetaDisposable()
|
||||
@@ -1705,46 +1826,38 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
}
|
||||
}
|
||||
|
||||
/*self.moreButtonStateDisposable.set(combineLatest(queue: .mainQueue(),
|
||||
self.moreButtonStateDisposable.set(combineLatest(queue: .mainQueue(),
|
||||
self.playbackRatePromise.get(),
|
||||
self.isShowingContextMenuPromise.get()
|
||||
).start(next: { [weak self] playbackRate, isShowingContextMenu in
|
||||
guard let strongSelf = self else {
|
||||
self.videoQualityPromise.get()
|
||||
).start(next: { [weak self] playbackRate, videoQuality in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
let effectiveBaseRate: Double
|
||||
if isShowingContextMenu {
|
||||
effectiveBaseRate = 1.0
|
||||
} else {
|
||||
effectiveBaseRate = playbackRate
|
||||
|
||||
var rateString: String?
|
||||
if abs(playbackRate - 1.0) > 0.1 {
|
||||
var stringValue = String(format: "%.1fx", playbackRate)
|
||||
if stringValue.hasSuffix(".0x") {
|
||||
stringValue = stringValue.replacingOccurrences(of: ".0x", with: "x")
|
||||
}
|
||||
rateString = stringValue
|
||||
}
|
||||
|
||||
var qualityString: String?
|
||||
if case let .quality(quality) = videoQuality {
|
||||
if quality <= 360 {
|
||||
qualityString = "LD"
|
||||
} else if quality <= 480 {
|
||||
qualityString = "SD"
|
||||
} else if quality <= 720 {
|
||||
qualityString = "HD"
|
||||
} else {
|
||||
qualityString = "UHD"
|
||||
}
|
||||
}
|
||||
|
||||
if abs(effectiveBaseRate - strongSelf.moreBarButtonRate) > 0.01 {
|
||||
strongSelf.moreBarButtonRate = effectiveBaseRate
|
||||
let animated: Bool
|
||||
if let moreBarButtonRateTimestamp = strongSelf.moreBarButtonRateTimestamp {
|
||||
animated = CFAbsoluteTimeGetCurrent() > (moreBarButtonRateTimestamp + 0.2)
|
||||
} else {
|
||||
animated = false
|
||||
}
|
||||
strongSelf.moreBarButtonRateTimestamp = CFAbsoluteTimeGetCurrent()
|
||||
|
||||
if abs(effectiveBaseRate - 1.0) > 0.01 {
|
||||
var stringValue = String(format: "%.1fx", effectiveBaseRate)
|
||||
if stringValue.hasSuffix(".0x") {
|
||||
stringValue = stringValue.replacingOccurrences(of: ".0x", with: "x")
|
||||
}
|
||||
strongSelf.moreBarButton.setContent(.image(optionsRateImage(rate: stringValue, isLarge: true)), animated: animated)
|
||||
} else {
|
||||
strongSelf.moreBarButton.setContent(.more(optionsCircleImage(dark: false)), animated: animated)
|
||||
}
|
||||
} else {
|
||||
if strongSelf.moreBarButtonRateTimestamp == nil {
|
||||
strongSelf.moreBarButtonRateTimestamp = CFAbsoluteTimeGetCurrent()
|
||||
}
|
||||
}
|
||||
}))*/
|
||||
self.settingsBarButton.setBadges(speed: rateString, quality: qualityString, transition: .spring(duration: 0.35))
|
||||
}))
|
||||
|
||||
self.settingsButtonStateDisposable.set((self.isShowingSettingsMenuPromise.get()
|
||||
|> deliverOnMainQueue).start(next: { [weak self] isShowingSettingsMenu in
|
||||
@@ -1996,6 +2109,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
}
|
||||
|
||||
self.playbackRatePromise.set(self.playbackRate ?? 1.0)
|
||||
self.videoQualityPromise.set(self.videoQuality)
|
||||
|
||||
var isAd = false
|
||||
if let contentInfo = item.contentInfo {
|
||||
@@ -3333,8 +3447,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
return
|
||||
}
|
||||
videoNode.setVideoQuality(.auto)
|
||||
//TODO:release
|
||||
//self.settingsBarButton.setContent(.image(generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/NavigationSettingsQAuto"), color: .white)))
|
||||
self.videoQualityPromise.set(.auto)
|
||||
|
||||
/*if let controller = strongSelf.galleryController() as? GalleryController {
|
||||
controller.updateSharedPlaybackRate(rate)
|
||||
@@ -3367,12 +3480,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
return
|
||||
}
|
||||
videoNode.setVideoQuality(.quality(quality))
|
||||
//TODO:release
|
||||
/*if quality >= 700 {
|
||||
self.settingsBarButton.setContent(.image(generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/NavigationSettingsQHD"), color: .white)))
|
||||
} else {
|
||||
self.settingsBarButton.setContent(.image(generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/NavigationSettingsQSD"), color: .white)))
|
||||
}*/
|
||||
self.videoQualityPromise.set(.quality(quality))
|
||||
|
||||
/*if let controller = strongSelf.galleryController() as? GalleryController {
|
||||
controller.updateSharedPlaybackRate(rate)
|
||||
@@ -3407,15 +3515,18 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
c?.popItems()
|
||||
})))
|
||||
|
||||
for quality in qualityState.available {
|
||||
guard let qualityFile = qualitySet.qualityFiles[quality] else {
|
||||
continue
|
||||
}
|
||||
let addItem: (Int?, FileMediaReference) -> Void = { quality, qualityFile in
|
||||
guard let qualityFileSize = qualityFile.media.size else {
|
||||
continue
|
||||
return
|
||||
}
|
||||
let fileSizeString = dataSizeString(qualityFileSize, formatting: DataSizeStringFormatting(presentationData: self.presentationData))
|
||||
items.append(.action(ContextMenuActionItem(text: "Save in \(quality)p", textLayout: .secondLineWithValue(fileSizeString), icon: { _ in
|
||||
let title: String
|
||||
if let quality {
|
||||
title = "Save in \(quality)p"
|
||||
} else {
|
||||
title = "Save Original"
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: title, textLayout: .secondLineWithValue(fileSizeString), icon: { _ in
|
||||
return nil
|
||||
}, action: { [weak self] c, _ in
|
||||
c?.dismiss(result: .default, completion: nil)
|
||||
@@ -3458,6 +3569,21 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
})))
|
||||
}
|
||||
|
||||
if self.context.isPremium {
|
||||
addItem(nil, content.fileReference)
|
||||
} else {
|
||||
#if DEBUG
|
||||
addItem(nil, content.fileReference)
|
||||
#endif
|
||||
}
|
||||
|
||||
for quality in qualityState.available {
|
||||
guard let qualityFile = qualitySet.qualityFiles[quality] else {
|
||||
continue
|
||||
}
|
||||
addItem(quality, qualityFile)
|
||||
}
|
||||
|
||||
c?.pushItems(items: .single(ContextController.Items(content: .list(items))))
|
||||
} else {
|
||||
c?.dismiss(result: .default, completion: nil)
|
||||
@@ -3683,6 +3809,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
|
||||
func updateVideoQuality(_ videoQuality: UniversalVideoContentVideoQuality) {
|
||||
self.videoQuality = videoQuality
|
||||
self.videoQualityPromise.set(videoQuality)
|
||||
|
||||
self.videoNode?.setVideoQuality(videoQuality)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user