Various improvements

This commit is contained in:
Ilya Laktyushin 2023-08-30 04:35:07 +04:00
parent d0e9953d28
commit 167b9b3eac
20 changed files with 437 additions and 84 deletions

View File

@ -9863,3 +9863,8 @@ Sorry for the inconvenience.";
"Story.ViewList.ViewerCount_any" = "%d Viewers"; "Story.ViewList.ViewerCount_any" = "%d Viewers";
"AuthSessions.MessageApp" = "You allowed this bot to message you when you opened %@."; "AuthSessions.MessageApp" = "You allowed this bot to message you when you opened %@.";
"Story.Privacy.PostStoryAs" = "Post Story As";
"Story.Privacy.PostStoryAsHeader" = "POST STORY AS";
"Story.Privacy.KeepOnChannelPage" = "Post to Channel Profile";
"Story.Privacy.KeepOnChannelPageInfo" = "Keep this story on channel profile even after it expires in %@.";

View File

@ -264,18 +264,18 @@ private final class VisualMediaItemNode: ASDisplayNode {
if isStreamable { if isStreamable {
switch status { switch status {
case let .Fetching(_, progress): case let .Fetching(_, progress):
let progressString = String(format: "%d%%", Int(progress * 100.0)) let progressString = String(format: "%d%%", Int(progress * 100.0))
badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: progressString)) badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: progressString), iconName: nil)
mediaDownloadState = .compactFetching(progress: 0.0) mediaDownloadState = .compactFetching(progress: 0.0)
case .Local: case .Local:
badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString)) badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString), iconName: nil)
case .Remote, .Paused: case .Remote, .Paused:
badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString)) badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString), iconName: nil)
mediaDownloadState = .compactRemote mediaDownloadState = .compactRemote
} }
} else { } else {
badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString)) badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString), iconName: nil)
} }
strongSelf.mediaBadgeNode.update(theme: nil, content: badgeContent, mediaDownloadState: mediaDownloadState, alignment: .right, animated: false, badgeAnimated: false) strongSelf.mediaBadgeNode.update(theme: nil, content: badgeContent, mediaDownloadState: mediaDownloadState, alignment: .right, animated: false, badgeAnimated: false)

View File

@ -18,13 +18,13 @@ public enum ChatMessageInteractiveMediaDownloadState: Equatable {
} }
public enum ChatMessageInteractiveMediaBadgeContent: Equatable { public enum ChatMessageInteractiveMediaBadgeContent: Equatable {
case text(inset: CGFloat, backgroundColor: UIColor, foregroundColor: UIColor, text: NSAttributedString) case text(inset: CGFloat, backgroundColor: UIColor, foregroundColor: UIColor, text: NSAttributedString, iconName: String?)
case mediaDownload(backgroundColor: UIColor, foregroundColor: UIColor, duration: String, size: String?, muted: Bool, active: Bool) case mediaDownload(backgroundColor: UIColor, foregroundColor: UIColor, duration: String, size: String?, muted: Bool, active: Bool)
public static func ==(lhs: ChatMessageInteractiveMediaBadgeContent, rhs: ChatMessageInteractiveMediaBadgeContent) -> Bool { public static func ==(lhs: ChatMessageInteractiveMediaBadgeContent, rhs: ChatMessageInteractiveMediaBadgeContent) -> Bool {
switch lhs { switch lhs {
case let .text(lhsInset, lhsBackgroundColor, lhsForegroundColor, lhsText): case let .text(lhsInset, lhsBackgroundColor, lhsForegroundColor, lhsText, lhsIconName):
if case let .text(rhsInset, rhsBackgroundColor, rhsForegroundColor, rhsText) = rhs, lhsInset.isEqual(to: rhsInset), lhsBackgroundColor.isEqual(rhsBackgroundColor), lhsForegroundColor.isEqual(rhsForegroundColor), lhsText.isEqual(to: rhsText) { if case let .text(rhsInset, rhsBackgroundColor, rhsForegroundColor, rhsText, rhsIconName) = rhs, lhsInset.isEqual(to: rhsInset), lhsBackgroundColor.isEqual(rhsBackgroundColor), lhsForegroundColor.isEqual(rhsForegroundColor), lhsText.isEqual(to: rhsText), lhsIconName == rhsIconName {
return true return true
} else { } else {
return false return false
@ -48,6 +48,7 @@ public final class ChatMessageInteractiveMediaBadge: ASDisplayNode {
private var previousContentSize: CGSize? private var previousContentSize: CGSize?
private var backgroundNodeColor: UIColor? private var backgroundNodeColor: UIColor?
private var foregroundColor: UIColor? private var foregroundColor: UIColor?
private var iconName: String?
private let backgroundNode: ASImageNode private let backgroundNode: ASImageNode
private let durationNode: ASTextNode private let durationNode: ASTextNode
@ -107,14 +108,18 @@ public final class ChatMessageInteractiveMediaBadge: ASDisplayNode {
} }
switch content { switch content {
case let .text(inset, backgroundColor, foregroundColor, text): case let .text(inset, backgroundColor, foregroundColor, text, iconName):
transition = .immediate transition = .immediate
if self.backgroundNodeColor != backgroundColor { if self.backgroundNodeColor != backgroundColor {
self.backgroundNodeColor = backgroundColor self.backgroundNodeColor = backgroundColor
self.backgroundNode.image = generateStretchableFilledCircleImage(radius: 9.0, color: backgroundColor) self.backgroundNode.image = generateStretchableFilledCircleImage(radius: 9.0, color: backgroundColor)
} }
let convertedText = NSMutableAttributedString(string: text.string, attributes: [.font: font, .foregroundColor: foregroundColor]) var textFont = font
if iconName != nil {
textFont = boldFont
}
let convertedText = NSMutableAttributedString(string: text.string, attributes: [.font: textFont, .foregroundColor: foregroundColor])
text.enumerateAttributes(in: NSRange(location: 0, length: text.length), options: []) { attributes, range, _ in text.enumerateAttributes(in: NSRange(location: 0, length: text.length), options: []) { attributes, range, _ in
if let _ = attributes[ChatTextInputAttributes.bold] { if let _ = attributes[ChatTextInputAttributes.bold] {
convertedText.addAttribute(.font, value: boldFont, range: range) convertedText.addAttribute(.font, value: boldFont, range: range)
@ -122,12 +127,33 @@ public final class ChatMessageInteractiveMediaBadge: ASDisplayNode {
} }
self.durationNode.attributedText = convertedText self.durationNode.attributedText = convertedText
let durationSize = self.durationNode.measure(CGSize(width: 160.0, height: 160.0)) let durationSize = self.durationNode.measure(CGSize(width: 160.0, height: 160.0))
self.durationNode.frame = CGRect(x: 7.0 + inset, y: 3.0, width: durationSize.width, height: durationSize.height) self.durationNode.frame = CGRect(x: 7.0 + inset, y: 2.0 + UIScreenPixel, width: durationSize.width, height: durationSize.height)
currentContentSize = CGSize(width: widthForString(text.string) + 14.0 + inset, height: 18.0) currentContentSize = CGSize(width: widthForString(text.string) + 14.0 + inset, height: 18.0)
if let iconNode = self.iconNode { if let iconName {
transition.updateTransformScale(node: iconNode, scale: 0.001) let iconNode: ASImageNode
transition.updateAlpha(node: iconNode, alpha: 0.0) if let current = self.iconNode {
iconNode = current
} else {
iconNode = ASImageNode()
self.iconNode = iconNode
self.backgroundNode.addSubnode(iconNode)
}
if self.foregroundColor != foregroundColor || self.iconName != iconName {
self.foregroundColor = foregroundColor
self.iconName = iconName
iconNode.image = generateTintedImage(image: UIImage(bundleImageName: iconName), color: foregroundColor)
}
transition.updateAlpha(node: iconNode, alpha: 1.0)
transition.updateTransformScale(node: iconNode, scale: 1.0)
iconNode.frame = CGRect(x: 3.0, y: 2.0, width: 12.0, height: 14.0)
} else {
if let iconNode = self.iconNode {
transition.updateTransformScale(node: iconNode, scale: 0.001)
transition.updateAlpha(node: iconNode, alpha: 0.0)
}
} }
case let .mediaDownload(backgroundColor, foregroundColor, duration, size, muted, active): case let .mediaDownload(backgroundColor, foregroundColor, duration, size, muted, active):
if self.backgroundNodeColor != backgroundColor { if self.backgroundNodeColor != backgroundColor {
@ -209,7 +235,7 @@ public final class ChatMessageInteractiveMediaBadge: ASDisplayNode {
let durationWidth = widthForString(duration) let durationWidth = widthForString(duration)
transition.updatePosition(node: iconNode, position: CGPoint(x: (active ? 42.0 : 7.0) + durationWidth + 4.0 + 7.0, y: (active ? 8.0 : 4.0) + 5.0)) transition.updatePosition(node: iconNode, position: CGPoint(x: (active ? 42.0 : 7.0) + durationWidth + 4.0 + 7.0, y: (active ? 8.0 : 4.0) + 5.0))
if muted { if muted {
transition.updateAlpha(node: iconNode, alpha: 1.0) transition.updateAlpha(node: iconNode, alpha: 1.0)
transition.updateTransformScale(node: iconNode, scale: 1.0) transition.updateTransformScale(node: iconNode, scale: 1.0)

View File

@ -14,6 +14,7 @@ swift_library(
"//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/LegacyComponents:LegacyComponents", "//submodules/LegacyComponents:LegacyComponents",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/ManagedAnimationNode:ManagedAnimationNode"
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -5,6 +5,7 @@ import AsyncDisplayKit
enum RadialStatusIcon { enum RadialStatusIcon {
case custom(UIImage) case custom(UIImage)
case timeout
case play(UIColor) case play(UIColor)
case pause(UIColor) case pause(UIColor)
} }
@ -22,14 +23,28 @@ private final class RadialStatusIconContentNodeParameters: NSObject {
final class RadialStatusIconContentNode: RadialStatusContentNode { final class RadialStatusIconContentNode: RadialStatusContentNode {
private let icon: RadialStatusIcon private let icon: RadialStatusIcon
private var animationNode: FireIconNode?
init(icon: RadialStatusIcon, synchronous: Bool) { init(icon: RadialStatusIcon, synchronous: Bool) {
self.icon = icon self.icon = icon
super.init() super.init()
self.displaysAsynchronously = !synchronous self.displaysAsynchronously = !synchronous
self.isLayerBacked = true // self.isLayerBacked = true
self.isOpaque = false self.isOpaque = false
if case .timeout = icon {
let animationNode = FireIconNode()
self.animationNode = animationNode
self.addSubnode(animationNode)
}
}
override func layout() {
super.layout()
self.animationNode?.frame = CGRect(x: 6.0, y: 2.0, width: 36.0, height: 36.0)
} }
override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? { override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
@ -48,6 +63,8 @@ final class RadialStatusIconContentNode: RadialStatusContentNode {
if let parameters = parameters as? RadialStatusIconContentNodeParameters { if let parameters = parameters as? RadialStatusIconContentNodeParameters {
let diameter = min(bounds.size.width, bounds.size.height) let diameter = min(bounds.size.width, bounds.size.height)
switch parameters.icon { switch parameters.icon {
case .timeout:
break
case let .play(color): case let .play(color):
context.setFillColor(color.cgColor) context.setFillColor(color.cgColor)

View File

@ -12,6 +12,7 @@ public enum RadialStatusNodeState: Equatable {
case cloudProgress(color: UIColor, strokeBackgroundColor: UIColor, lineWidth: CGFloat, value: CGFloat?) case cloudProgress(color: UIColor, strokeBackgroundColor: UIColor, lineWidth: CGFloat, value: CGFloat?)
case check(UIColor) case check(UIColor)
case customIcon(UIImage) case customIcon(UIImage)
case staticTimeout
case secretTimeout(color: UIColor, icon: UIImage?, beginTime: Double, timeout: Double, sparks: Bool) case secretTimeout(color: UIColor, icon: UIImage?, beginTime: Double, timeout: Double, sparks: Bool)
public static func ==(lhs: RadialStatusNodeState, rhs: RadialStatusNodeState) -> Bool { public static func ==(lhs: RadialStatusNodeState, rhs: RadialStatusNodeState) -> Bool {
@ -64,6 +65,12 @@ public enum RadialStatusNodeState: Equatable {
} else { } else {
return false return false
} }
case .staticTimeout:
if case .staticTimeout = rhs {
return true
} else {
return false
}
case let .secretTimeout(lhsColor, lhsIcon, lhsBeginTime, lhsTimeout, lhsSparks): case let .secretTimeout(lhsColor, lhsIcon, lhsBeginTime, lhsTimeout, lhsSparks):
if case let .secretTimeout(rhsColor, rhsIcon, rhsBeginTime, rhsTimeout, rhsSparks) = rhs, lhsColor.isEqual(rhsColor), lhsIcon === rhsIcon, lhsBeginTime.isEqual(to: rhsBeginTime), lhsTimeout.isEqual(to: rhsTimeout), lhsSparks == rhsSparks { if case let .secretTimeout(rhsColor, rhsIcon, rhsBeginTime, rhsTimeout, rhsSparks) = rhs, lhsColor.isEqual(rhsColor), lhsIcon === rhsIcon, lhsBeginTime.isEqual(to: rhsBeginTime), lhsTimeout.isEqual(to: rhsTimeout), lhsSparks == rhsSparks {
return true return true
@ -123,6 +130,12 @@ public enum RadialStatusNodeState: Equatable {
} else { } else {
return false return false
} }
case .staticTimeout:
if case .staticTimeout = rhs{
return true
} else {
return false
}
case let .secretTimeout(lhsColor, lhsIcon, lhsBeginTime, lhsTimeout, lhsSparks): case let .secretTimeout(lhsColor, lhsIcon, lhsBeginTime, lhsTimeout, lhsSparks):
if case let .secretTimeout(rhsColor, rhsIcon, rhsBeginTime, rhsTimeout, rhsSparks) = rhs, lhsColor.isEqual(rhsColor), lhsIcon === rhsIcon, lhsBeginTime.isEqual(to: rhsBeginTime), lhsTimeout.isEqual(to: rhsTimeout), lhsSparks == rhsSparks { if case let .secretTimeout(rhsColor, rhsIcon, rhsBeginTime, rhsTimeout, rhsSparks) = rhs, lhsColor.isEqual(rhsColor), lhsIcon === rhsIcon, lhsBeginTime.isEqual(to: rhsBeginTime), lhsTimeout.isEqual(to: rhsTimeout), lhsSparks == rhsSparks {
return true return true
@ -179,6 +192,8 @@ public enum RadialStatusNodeState: Equatable {
node.progress = value node.progress = value
return node return node
} }
case .staticTimeout:
return RadialStatusIconContentNode(icon: .timeout, synchronous: synchronous)
case let .secretTimeout(color, icon, beginTime, timeout, sparks): case let .secretTimeout(color, icon, beginTime, timeout, sparks):
return RadialStatusSecretTimeoutContentNode(color: color, beginTime: beginTime, timeout: timeout, icon: icon, sparks: sparks) return RadialStatusSecretTimeoutContentNode(color: color, beginTime: beginTime, timeout: timeout, icon: icon, sparks: sparks)
} }
@ -188,7 +203,9 @@ public enum RadialStatusNodeState: Equatable {
public final class RadialStatusNode: ASControlNode { public final class RadialStatusNode: ASControlNode {
public var backgroundNodeColor: UIColor { public var backgroundNodeColor: UIColor {
didSet { didSet {
self.transitionToBackgroundColor(self.state.backgroundColor(color: self.backgroundNodeColor), previousContentNode: nil, animated: false, synchronous: false, completion: {}) if self.backgroundNodeColor != oldValue {
self.transitionToBackgroundColor(self.state.backgroundColor(color: self.backgroundNodeColor), previousContentNode: nil, animated: false, synchronous: false, completion: {})
}
} }
} }

View File

@ -3,6 +3,7 @@ import UIKit
import Display import Display
import AsyncDisplayKit import AsyncDisplayKit
import LegacyComponents import LegacyComponents
import ManagedAnimationNode
private struct ContentParticle { private struct ContentParticle {
var position: CGPoint var position: CGPoint
@ -53,6 +54,8 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
private var progress: CGFloat = 0.0 private var progress: CGFloat = 0.0
private var particles: [ContentParticle] = [] private var particles: [ContentParticle] = []
private let animationNode = FireIconNode()
private var displayLink: CADisplayLink? private var displayLink: CADisplayLink?
init(color: UIColor, beginTime: Double, timeout: Double, icon: UIImage?, sparks: Bool) { init(color: UIColor, beginTime: Double, timeout: Double, icon: UIImage?, sparks: Bool) {
@ -65,7 +68,7 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
super.init() super.init()
self.isOpaque = false self.isOpaque = false
self.isLayerBacked = true // self.isLayerBacked = true
class DisplayLinkProxy: NSObject { class DisplayLinkProxy: NSObject {
weak var target: RadialStatusSecretTimeoutContentNode? weak var target: RadialStatusSecretTimeoutContentNode?
@ -81,6 +84,8 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
self.displayLink = CADisplayLink(target: DisplayLinkProxy(target: self), selector: #selector(DisplayLinkProxy.displayLinkEvent)) self.displayLink = CADisplayLink(target: DisplayLinkProxy(target: self), selector: #selector(DisplayLinkProxy.displayLinkEvent))
self.displayLink?.isPaused = true self.displayLink?.isPaused = true
self.displayLink?.add(to: RunLoop.main, forMode: .common) self.displayLink?.add(to: RunLoop.main, forMode: .common)
self.addSubnode(self.animationNode)
} }
deinit { deinit {
@ -89,6 +94,8 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
override func layout() { override func layout() {
super.layout() super.layout()
self.animationNode.frame = CGRect(x: 6.0, y: 2.0, width: 36.0, height: 36.0)
} }
override func animateOut(to: RadialStatusNodeState, completion: @escaping () -> Void) { override func animateOut(to: RadialStatusNodeState, completion: @escaping () -> Void) {
@ -231,3 +238,10 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
} }
} }
final class FireIconNode: ManagedAnimationNode {
init() {
super.init(size: CGSize(width: 100.0, height: 100.0))
self.trackTo(item: ManagedAnimationItem(source: .local("anim_autoremove_on"), frames: .range(startFrame: 0, endFrame: 120), duration: 2.0))
}
}

View File

@ -9,11 +9,11 @@ public func tagsForStoreMessage(incoming: Bool, attributes: [MessageAttribute],
var hasUnseenReactions = false var hasUnseenReactions = false
for attribute in attributes { for attribute in attributes {
if let timerAttribute = attribute as? AutoclearTimeoutMessageAttribute { if let timerAttribute = attribute as? AutoclearTimeoutMessageAttribute {
if timerAttribute.timeout > 0 && timerAttribute.timeout <= 60 { if timerAttribute.timeout > 0 && (timerAttribute.timeout <= 60 || timerAttribute.timeout == viewOnceTimeout) {
isSecret = true isSecret = true
} }
} else if let timerAttribute = attribute as? AutoremoveTimeoutMessageAttribute { } else if let timerAttribute = attribute as? AutoremoveTimeoutMessageAttribute {
if timerAttribute.timeout > 0 && timerAttribute.timeout <= 60 { if timerAttribute.timeout > 0 && (timerAttribute.timeout <= 60 || timerAttribute.timeout == viewOnceTimeout) {
isSecret = true isSecret = true
} }
} else if let mentionAttribute = attribute as? ConsumablePersonalMentionMessageAttribute { } else if let mentionAttribute = attribute as? ConsumablePersonalMentionMessageAttribute {

View File

@ -1,6 +1,8 @@
import Foundation import Foundation
import Postbox import Postbox
public let viewOnceTimeout: Int32 = 0x7fffffff
public class AutoremoveTimeoutMessageAttribute: MessageAttribute { public class AutoremoveTimeoutMessageAttribute: MessageAttribute {
public let timeout: Int32 public let timeout: Int32
public let countdownBeginTime: Int32? public let countdownBeginTime: Int32?
@ -124,7 +126,7 @@ public extension Message {
guard let timeout = self.minAutoremoveOrClearTimeout else { guard let timeout = self.minAutoremoveOrClearTimeout else {
return false return false
} }
if timeout > 1 * 60 { if timeout > 1 * 60 && timeout != viewOnceTimeout {
return false return false
} }

View File

@ -939,7 +939,6 @@ final class MediaEditorScreenComponent: Component {
self.appliedAudioData = audioData self.appliedAudioData = audioData
var timeoutValue: String var timeoutValue: String
let timeoutSelected: Bool
switch component.privacy.timeout { switch component.privacy.timeout {
case 21600: case 21600:
timeoutValue = "6" timeoutValue = "6"
@ -952,7 +951,6 @@ final class MediaEditorScreenComponent: Component {
default: default:
timeoutValue = "24" timeoutValue = "24"
} }
timeoutSelected = false
var inputPanelAvailableWidth = previewSize.width var inputPanelAvailableWidth = previewSize.width
var inputPanelAvailableHeight = 103.0 var inputPanelAvailableHeight = 103.0
@ -1192,7 +1190,7 @@ final class MediaEditorScreenComponent: Component {
hasRecordedVideoPreview: false, hasRecordedVideoPreview: false,
wasRecordingDismissed: false, wasRecordingDismissed: false,
timeoutValue: timeoutValue, timeoutValue: timeoutValue,
timeoutSelected: timeoutSelected, timeoutSelected: false,
displayGradient: false, displayGradient: false,
bottomInset: 0.0, bottomInset: 0.0,
isFormattingLocked: !state.isPremium, isFormattingLocked: !state.isPremium,
@ -3794,6 +3792,12 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
}) })
} }
) )
controller.customModalStyleOverlayTransitionFactorUpdated = { [weak self, weak controller] transition in
if let self, let controller {
let transitionFactor = controller.modalStyleOverlayTransitionFactor
self.node.updateModalTransitionFactor(transitionFactor, transition: transition)
}
}
controller.dismissed = { controller.dismissed = {
self.node.mediaEditor?.play() self.node.mediaEditor?.play()
} }
@ -3845,6 +3849,12 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
editCategory: { _, _, _ in }, editCategory: { _, _, _ in },
editBlockedPeers: { _, _, _ in } editBlockedPeers: { _, _, _ in }
) )
controller.customModalStyleOverlayTransitionFactorUpdated = { [weak self, weak controller] transition in
if let self, let controller {
let transitionFactor = controller.modalStyleOverlayTransitionFactor
self.node.updateModalTransitionFactor(transitionFactor, transition: transition)
}
}
controller.dismissed = { controller.dismissed = {
self.node.mediaEditor?.play() self.node.mediaEditor?.play()
} }

View File

@ -581,6 +581,7 @@ final class VideoScrubberComponent: Component {
audioTransition.setFrame(view: view, frame: CGRect(origin: CGPoint(x: 0.0, y: self.isAudioSelected || component.audioOnly ? 0.0 : 6.0), size: audioWaveformSize)) audioTransition.setFrame(view: view, frame: CGRect(origin: CGPoint(x: 0.0, y: self.isAudioSelected || component.audioOnly ? 0.0 : 6.0), size: audioWaveformSize))
} }
} }
self.cursorView.isHidden = component.audioOnly
let bounds = CGRect(origin: .zero, size: scrubberSize) let bounds = CGRect(origin: .zero, size: scrubberSize)

View File

@ -135,7 +135,7 @@ final class ShareWithPeersScreenComponent: Component {
self.itemHeight = itemHeight self.itemHeight = itemHeight
self.itemCount = itemCount self.itemCount = itemCount
self.totalHeight = insets.top + itemHeight * CGFloat(itemCount) self.totalHeight = insets.top + itemHeight * CGFloat(itemCount) + insets.bottom
} }
} }
@ -818,8 +818,16 @@ final class ShareWithPeersScreenComponent: Component {
var topOffsetFraction = topOffset / topOffsetDistance var topOffsetFraction = topOffset / topOffsetDistance
topOffsetFraction = max(0.0, min(1.0, topOffsetFraction)) topOffsetFraction = max(0.0, min(1.0, topOffsetFraction))
//let transitionFactor: CGFloat = 1.0 - topOffsetFraction let transitionFactor: CGFloat = 1.0 - topOffsetFraction
//controller.updateModalStyleOverlayTransitionFactor(transitionFactor, transition: transition.containedViewLayoutTransition) if let controller = environment.controller() {
Queue.mainQueue().justDispatch {
var transition = transition
if controller.modalStyleOverlayTransitionFactor.isZero && transitionFactor > 0.0, transition.animation.isImmediate {
transition = .spring(duration: 0.4)
}
controller.updateModalStyleOverlayTransitionFactor(transitionFactor, transition: transition.containedViewLayoutTransition)
}
}
var visibleBounds = self.scrollView.bounds var visibleBounds = self.scrollView.bounds
visibleBounds.origin.y -= itemLayout.topInset visibleBounds.origin.y -= itemLayout.topInset
@ -907,7 +915,7 @@ final class ShareWithPeersScreenComponent: Component {
let sectionTitle: String let sectionTitle: String
if section.id == 0, case .stories = component.stateContext.subject { if section.id == 0, case .stories = component.stateContext.subject {
sectionTitle = "POST STORY AS" sectionTitle = environment.strings.Story_Privacy_PostStoryAsHeader
} else if section.id == 2 { } else if section.id == 2 {
sectionTitle = environment.strings.Story_Privacy_WhoCanViewHeader sectionTitle = environment.strings.Story_Privacy_WhoCanViewHeader
} else if section.id == 1 { } else if section.id == 1 {
@ -1362,11 +1370,16 @@ final class ShareWithPeersScreenComponent: Component {
self.visibleItems[itemId] = visibleItem self.visibleItems[itemId] = visibleItem
} }
var title = item.title
if item.id == .pin && !hasCategories {
title = environment.strings.Story_Privacy_KeepOnChannelPage
}
let _ = visibleItem.update( let _ = visibleItem.update(
transition: itemTransition, transition: itemTransition,
component: AnyComponent(OptionListItemComponent( component: AnyComponent(OptionListItemComponent(
theme: environment.theme, theme: environment.theme,
title: item.title, title: title,
hasNext: i != component.optionItems.count - 1, hasNext: i != component.optionItems.count - 1,
selected: self.selectedOptions.contains(item.id), selected: self.selectedOptions.contains(item.id),
selectionChanged: { [weak self] selected in selectionChanged: { [weak self] selected in
@ -1414,7 +1427,7 @@ final class ShareWithPeersScreenComponent: Component {
var footerText = environment.strings.Story_Privacy_KeepOnMyPageInfo(footerValue).string var footerText = environment.strings.Story_Privacy_KeepOnMyPageInfo(footerValue).string
if self.sendAsPeerId?.isGroupOrChannel == true { if self.sendAsPeerId?.isGroupOrChannel == true {
footerText = "Keep this story on channel profile even after it expires in 24 hours." footerText = environment.strings.Story_Privacy_KeepOnChannelPageInfo(footerValue).string
} }
let footerSize = sectionFooter.update( let footerSize = sectionFooter.update(
@ -1508,6 +1521,9 @@ final class ShareWithPeersScreenComponent: Component {
for id in removeSectionBackgroundIds { for id in removeSectionBackgroundIds {
self.visibleSectionBackgrounds.removeValue(forKey: id) self.visibleSectionBackgrounds.removeValue(forKey: id)
} }
for id in removeSectionFooterIds {
self.visibleSectionFooters.removeValue(forKey: id)
}
let fadeTransition = Transition.easeInOut(duration: 0.25) let fadeTransition = Transition.easeInOut(duration: 0.25)
if let searchStateContext = self.searchStateContext, case let .search(query, _) = searchStateContext.subject, let value = searchStateContext.stateValue, value.peers.isEmpty { if let searchStateContext = self.searchStateContext, case let .search(query, _) = searchStateContext.subject, let value = searchStateContext.stateValue, value.peers.isEmpty {
@ -1932,11 +1948,16 @@ final class ShareWithPeersScreenComponent: Component {
) )
var hasCategories = false var hasCategories = false
var hasChannels = false
if case .stories = component.stateContext.subject { if case .stories = component.stateContext.subject {
if let peerId = self.sendAsPeerId, peerId.isGroupOrChannel { if let peerId = self.sendAsPeerId, peerId.isGroupOrChannel {
} else { } else {
hasCategories = true hasCategories = true
} }
let sendAsPeersCount = component.stateContext.stateValue?.sendAsPeers.count ?? 1
if sendAsPeersCount > 1 {
hasChannels = true
}
} }
var footersTotalHeight: CGFloat = 0.0 var footersTotalHeight: CGFloat = 0.0
@ -2016,16 +2037,15 @@ final class ShareWithPeersScreenComponent: Component {
if case let .peers(peers, _) = component.stateContext.subject { if case let .peers(peers, _) = component.stateContext.subject {
sections.append(ItemLayout.Section( sections.append(ItemLayout.Section(
id: 0, id: 0,
insets: UIEdgeInsets(top: 12.0, left: 0.0, bottom: 24.0, right: 0.0), insets: UIEdgeInsets(top: 12.0, left: 0.0, bottom: 0.0, right: 0.0),
itemHeight: peerItemSize.height, itemHeight: peerItemSize.height,
itemCount: peers.count itemCount: peers.count
)) ))
} else if case let .stories(editing) = component.stateContext.subject { } else if case let .stories(editing) = component.stateContext.subject {
let sendAsPeersCount = component.stateContext.stateValue?.sendAsPeers.count ?? 1 if !editing && hasChannels {
if !editing && sendAsPeersCount > 1 {
sections.append(ItemLayout.Section( sections.append(ItemLayout.Section(
id: 0, id: 0,
insets: UIEdgeInsets(top: 28.0, left: 0.0, bottom: 24.0, right: 0.0), insets: UIEdgeInsets(top: 28.0, left: 0.0, bottom: 0.0, right: 0.0),
itemHeight: peerItemSize.height, itemHeight: peerItemSize.height,
itemCount: 1 itemCount: 1
)) ))
@ -2040,7 +2060,7 @@ final class ShareWithPeersScreenComponent: Component {
} }
sections.append(ItemLayout.Section( sections.append(ItemLayout.Section(
id: 3, id: 3,
insets: UIEdgeInsets(top: 28.0, left: 0.0, bottom: 24.0, right: 0.0), insets: UIEdgeInsets(top: 28.0, left: 0.0, bottom: 0.0, right: 0.0),
itemHeight: optionItemSize.height, itemHeight: optionItemSize.height,
itemCount: component.optionItems.count itemCount: component.optionItems.count
)) ))
@ -2110,7 +2130,7 @@ final class ShareWithPeersScreenComponent: Component {
let title: String let title: String
switch component.stateContext.subject { switch component.stateContext.subject {
case .peers: case .peers:
title = "Post Story As" title = environment.strings.Story_Privacy_PostStoryAs
case let .stories(editing): case let .stories(editing):
if editing { if editing {
title = environment.strings.Story_Privacy_EditStory title = environment.strings.Story_Privacy_EditStory
@ -2178,11 +2198,16 @@ final class ShareWithPeersScreenComponent: Component {
inset = 351.0 inset = 351.0
inset += 10.0 + environment.safeInsets.bottom + 50.0 + footersTotalHeight inset += 10.0 + environment.safeInsets.bottom + 50.0 + footersTotalHeight
} else { } else {
if hasCategories { if !hasCategories {
inset = 1000.0
} else {
inset = 314.0 inset = 314.0
inset += 10.0 + environment.safeInsets.bottom + 50.0 + footersTotalHeight inset += 10.0 + environment.safeInsets.bottom + 50.0 + footersTotalHeight
} else {
if hasChannels {
inset = 1000.0
} else {
inset = 464.0
inset += 10.0 + environment.safeInsets.bottom + 50.0 + footersTotalHeight
}
} }
} }
} else if case .peers = component.stateContext.subject { } else if case .peers = component.stateContext.subject {
@ -2201,7 +2226,7 @@ final class ShareWithPeersScreenComponent: Component {
var bottomPanelHeight: CGFloat = 0.0 var bottomPanelHeight: CGFloat = 0.0
var bottomPanelInset: CGFloat = 0.0 var bottomPanelInset: CGFloat = 0.0
if case .peers = component.stateContext.subject { if case .peers = component.stateContext.subject {
bottomPanelInset = environment.safeInsets.bottom
} else { } else {
let badge: Int let badge: Int
if case .stories = component.stateContext.subject { if case .stories = component.stateContext.subject {
@ -2367,7 +2392,7 @@ final class ShareWithPeersScreenComponent: Component {
} }
return Array(filteredMentions) return Array(filteredMentions)
} }
|> deliverOnMainQueue).start(next: { mentions in |> deliverOnMainQueue).start(next: { mentions in
if mentions.isEmpty { if mentions.isEmpty {
proceed() proceed()
} else { } else {
@ -2377,7 +2402,7 @@ final class ShareWithPeersScreenComponent: Component {
} }
} else if case .contacts = base { } else if case .contacts = base {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Contacts.List(includePresences: false)) let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Contacts.List(includePresences: false))
|> map { contacts -> [String] in |> map { contacts -> [String] in
var filteredMentions = Set(component.mentions) var filteredMentions = Set(component.mentions)
let peers = contacts.peers let peers = contacts.peers
for peer in peers { for peer in peers {
@ -2390,7 +2415,7 @@ final class ShareWithPeersScreenComponent: Component {
} }
return Array(filteredMentions) return Array(filteredMentions)
} }
|> deliverOnMainQueue).start(next: { mentions in |> deliverOnMainQueue).start(next: { mentions in
if mentions.isEmpty { if mentions.isEmpty {
proceed() proceed()
} else { } else {
@ -2399,7 +2424,7 @@ final class ShareWithPeersScreenComponent: Component {
}) })
} else if case .closeFriends = base { } else if case .closeFriends = base {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Contacts.List(includePresences: false)) let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Contacts.List(includePresences: false))
|> map { contacts -> [String] in |> map { contacts -> [String] in
var filteredMentions = Set(component.mentions) var filteredMentions = Set(component.mentions)
let peers = contacts.peers let peers = contacts.peers
for peer in peers { for peer in peers {
@ -2409,7 +2434,7 @@ final class ShareWithPeersScreenComponent: Component {
} }
return Array(filteredMentions) return Array(filteredMentions)
} }
|> deliverOnMainQueue).start(next: { mentions in |> deliverOnMainQueue).start(next: { mentions in
if mentions.isEmpty { if mentions.isEmpty {
proceed() proceed()
} else { } else {
@ -2452,7 +2477,7 @@ final class ShareWithPeersScreenComponent: Component {
let previousItemLayout = self.itemLayout let previousItemLayout = self.itemLayout
self.itemLayout = itemLayout self.itemLayout = itemLayout
contentTransition.setFrame(view: self.itemContainerView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: containerWidth, height: itemLayout.contentHeight))) contentTransition.setFrame(view: self.itemContainerView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: containerWidth, height: itemLayout.contentHeight + footersTotalHeight)))
let scrollContentHeight = max(topInset + itemLayout.contentHeight + containerInset, availableSize.height - containerInset) let scrollContentHeight = max(topInset + itemLayout.contentHeight + containerInset, availableSize.height - containerInset)

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "miniplayonce.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,107 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 2.000000 1.669922 cm
0.000000 0.000000 0.000000 scn
4.000000 8.665078 m
4.367270 8.665078 4.665000 8.962809 4.665000 9.330078 c
4.665000 9.697348 4.367270 9.995078 4.000000 9.995078 c
4.000000 8.665078 l
h
8.665000 5.330078 m
8.665000 5.697348 8.367270 5.995078 8.000000 5.995078 c
7.632730 5.995078 7.335000 5.697348 7.335000 5.330078 c
8.665000 5.330078 l
h
4.000000 9.995078 m
1.423591 9.995078 -0.665000 7.906487 -0.665000 5.330078 c
0.665000 5.330078 l
0.665000 7.171948 2.158130 8.665078 4.000000 8.665078 c
4.000000 9.995078 l
h
-0.665000 5.330078 m
-0.665000 2.753670 1.423591 0.665078 4.000000 0.665078 c
4.000000 1.995078 l
2.158130 1.995078 0.665000 3.488208 0.665000 5.330078 c
-0.665000 5.330078 l
h
4.000000 0.665078 m
6.576408 0.665078 8.665000 2.753670 8.665000 5.330078 c
7.335000 5.330078 l
7.335000 3.488208 5.841870 1.995078 4.000000 1.995078 c
4.000000 0.665078 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 6.000000 8.705566 cm
0.000000 0.000000 0.000000 scn
0.800000 4.694434 m
0.470382 4.941647 0.000000 4.706456 0.000000 4.294434 c
0.000000 0.294434 l
0.000000 -0.117589 0.470382 -0.352780 0.800000 -0.105567 c
3.466667 1.894433 l
3.733333 2.094434 3.733333 2.494434 3.466667 2.694434 c
0.800000 4.694434 l
h
f*
n
Q
endstream
endobj
3 0 obj
1311
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 12.000000 14.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000001401 00000 n
0000001424 00000 n
0000001597 00000 n
0000001671 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
1730
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "miniplay.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,73 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 3.000000 2.780273 cm
0.000000 0.000000 0.000000 scn
2.332051 -0.225573 m
7.127887 2.971651 l
8.018486 3.565384 8.018486 4.874069 7.127886 5.467803 c
2.332050 8.665027 l
1.335218 9.329581 0.000000 8.614994 0.000000 7.416951 c
0.000000 1.022502 l
0.000000 -0.175541 1.335219 -0.890127 2.332051 -0.225573 c
h
f
n
Q
endstream
endobj
3 0 obj
379
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 12.000000 14.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000000469 00000 n
0000000491 00000 n
0000000664 00000 n
0000000738 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
797
%%EOF

View File

@ -542,10 +542,10 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
switch preparePosition { switch preparePosition {
case .linear(_, .None), .linear(_, .Neighbour(true, _, _)): case .linear(_, .None), .linear(_, .Neighbour(true, _, _)):
if let count = webpageGalleryMediaCount { if let count = webpageGalleryMediaCount {
additionalImageBadgeContent = .text(inset: 0.0, backgroundColor: presentationData.theme.theme.chat.message.mediaDateAndStatusFillColor, foregroundColor: presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor, text: NSAttributedString(string: presentationData.strings.Items_NOfM("1", "\(count)").string)) additionalImageBadgeContent = .text(inset: 0.0, backgroundColor: presentationData.theme.theme.chat.message.mediaDateAndStatusFillColor, foregroundColor: presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor, text: NSAttributedString(string: presentationData.strings.Items_NOfM("1", "\(count)").string), iconName: nil)
skipStandardStatus = isImage skipStandardStatus = isImage
} else if let mediaBadge = mediaBadge { } else if let mediaBadge = mediaBadge {
additionalImageBadgeContent = .text(inset: 0.0, backgroundColor: presentationData.theme.theme.chat.message.mediaDateAndStatusFillColor, foregroundColor: presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor, text: NSAttributedString(string: mediaBadge)) additionalImageBadgeContent = .text(inset: 0.0, backgroundColor: presentationData.theme.theme.chat.message.mediaDateAndStatusFillColor, foregroundColor: presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor, text: NSAttributedString(string: mediaBadge), iconName: nil)
} else { } else {
skipStandardStatus = isFile skipStandardStatus = isFile
} }

View File

@ -860,7 +860,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
let maxWidth: CGFloat let maxWidth: CGFloat
if isSecretMedia { if isSecretMedia {
maxWidth = 180.0 maxWidth = 200.0
} else { } else {
maxWidth = maxDimensions.width maxWidth = maxDimensions.width
} }
@ -898,7 +898,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
switch sizeCalculation { switch sizeCalculation {
case .constrained: case .constrained:
if isSecretMedia { if isSecretMedia {
boundingSize = CGSize(width: maxWidth, height: maxWidth) boundingSize = CGSize(width: maxWidth, height: maxWidth / 5.0 * 3.0)
drawingSize = nativeSize.aspectFilled(boundingSize) drawingSize = nativeSize.aspectFilled(boundingSize)
} else { } else {
let fittedSize = nativeSize.fittedToWidthOrSmaller(boundingWidth) let fittedSize = nativeSize.fittedToWidthOrSmaller(boundingWidth)
@ -1764,7 +1764,12 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
} }
} }
let radialStatusSize: CGFloat = wideLayout ? 50.0 : 32.0 var radialStatusSize: CGFloat
if isSecretMedia {
radialStatusSize = 48.0
} else {
radialStatusSize = wideLayout ? 50.0 : 32.0
}
if progressRequired { if progressRequired {
if self.statusNode == nil { if self.statusNode == nil {
let statusNode = RadialStatusNode(backgroundNodeColor: theme.chat.message.mediaOverlayControlColors.fillColor) let statusNode = RadialStatusNode(backgroundNodeColor: theme.chat.message.mediaOverlayControlColors.fillColor)
@ -1782,14 +1787,17 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
} }
} }
let messageTheme = theme.chat.message
var state: RadialStatusNodeState = .none var state: RadialStatusNodeState = .none
var backgroundColor = messageTheme.mediaOverlayControlColors.fillColor
var badgeContent: ChatMessageInteractiveMediaBadgeContent? var badgeContent: ChatMessageInteractiveMediaBadgeContent?
var mediaDownloadState: ChatMessageInteractiveMediaDownloadState? var mediaDownloadState: ChatMessageInteractiveMediaDownloadState?
let messageTheme = theme.chat.message
if let invoice = invoice { if let invoice = invoice {
if let extendedMedia = invoice.extendedMedia { if let extendedMedia = invoice.extendedMedia {
if case let .preview(_, _, maybeVideoDuration) = extendedMedia, let videoDuration = maybeVideoDuration { if case let .preview(_, _, maybeVideoDuration) = extendedMedia, let videoDuration = maybeVideoDuration {
badgeContent = .text(inset: 0.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: NSAttributedString(string: stringForDuration(videoDuration, position: nil))) badgeContent = .text(inset: 0.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: NSAttributedString(string: stringForDuration(videoDuration, position: nil)), iconName: nil)
} }
} else { } else {
let string = NSMutableAttributedString() let string = NSMutableAttributedString()
@ -1808,7 +1816,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
} }
string.append(NSAttributedString(string: title)) string.append(NSAttributedString(string: title))
} }
badgeContent = .text(inset: 0.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: string) badgeContent = .text(inset: 0.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: string, iconName: nil)
} }
} }
var animated = animated var animated = animated
@ -1944,7 +1952,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
} }
} else { } else {
let progressString = String(format: "%d%%", Int(progress * 100.0)) let progressString = String(format: "%d%%", Int(progress * 100.0))
badgeContent = .text(inset: message.flags.contains(.Unsent) ? 0.0 : 12.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: NSAttributedString(string: progressString)) badgeContent = .text(inset: message.flags.contains(.Unsent) ? 0.0 : 12.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: NSAttributedString(string: progressString), iconName: nil)
mediaDownloadState = automaticPlayback ? .none : .compactFetching(progress: 0.0) mediaDownloadState = automaticPlayback ? .none : .compactFetching(progress: 0.0)
} }
@ -1980,8 +1988,10 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
} }
if isSecretMedia, let (maybeBeginTime, timeout) = secretBeginTimeAndTimeout, let beginTime = maybeBeginTime { if isSecretMedia, let (maybeBeginTime, timeout) = secretBeginTimeAndTimeout, let beginTime = maybeBeginTime {
state = .secretTimeout(color: messageTheme.mediaOverlayControlColors.foregroundColor, icon: secretProgressIcon, beginTime: beginTime, timeout: timeout, sparks: true) state = .secretTimeout(color: messageTheme.mediaOverlayControlColors.foregroundColor, icon: secretProgressIcon, beginTime: beginTime, timeout: timeout, sparks: true)
} else if isSecretMedia, let secretProgressIcon = secretProgressIcon { backgroundColor = messageTheme.mediaDateAndStatusFillColor
state = .customIcon(secretProgressIcon) } else if isSecretMedia, let _ = secretProgressIcon {
state = .staticTimeout
backgroundColor = messageTheme.mediaDateAndStatusFillColor
} else if let file = media as? TelegramMediaFile, !file.isVideoSticker { } else if let file = media as? TelegramMediaFile, !file.isVideoSticker {
let isInlinePlayableVideo = file.isVideo && !isSecretMedia && (self.automaticPlayback ?? false) let isInlinePlayableVideo = file.isVideo && !isSecretMedia && (self.automaticPlayback ?? false)
if (!isInlinePlayableVideo || isStory) && file.isVideo { if (!isInlinePlayableVideo || isStory) && file.isVideo {
@ -2017,11 +2027,11 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
} else { } else {
if isMediaStreamable(message: message, media: file) { if isMediaStreamable(message: message, media: file) {
state = automaticPlayback ? .none : .play(messageTheme.mediaOverlayControlColors.foregroundColor) state = automaticPlayback ? .none : .play(messageTheme.mediaOverlayControlColors.foregroundColor)
badgeContent = .text(inset: 12.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: NSAttributedString(string: durationString)) badgeContent = .text(inset: 12.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: NSAttributedString(string: durationString), iconName: nil)
mediaDownloadState = .compactRemote mediaDownloadState = .compactRemote
} else { } else {
state = automaticPlayback ? .none : state state = automaticPlayback ? .none : state
badgeContent = .text(inset: 0.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: NSAttributedString(string: durationString)) badgeContent = .text(inset: 0.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: NSAttributedString(string: durationString), iconName: nil)
} }
} }
} }
@ -2031,16 +2041,32 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
} }
} }
if isSecretMedia, let (maybeBeginTime, timeout) = secretBeginTimeAndTimeout { if isSecretMedia {
let remainingTime: Int32 let remainingTime: Int32?
if let beginTime = maybeBeginTime { if let (maybeBeginTime, timeout) = secretBeginTimeAndTimeout {
let elapsedTime = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - beginTime if let beginTime = maybeBeginTime {
remainingTime = Int32(max(0.0, timeout - elapsedTime)) let elapsedTime = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - beginTime
remainingTime = Int32(max(0.0, timeout - elapsedTime))
} else {
remainingTime = Int32(timeout)
}
} else { } else {
remainingTime = Int32(timeout) if let attribute = message.autoclearAttribute {
remainingTime = attribute.timeout
} else if let attribute = message.autoremoveAttribute {
remainingTime = attribute.timeout
} else {
remainingTime = nil
}
} }
badgeContent = .text(inset: 0.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: NSAttributedString(string: strings.MessageTimer_ShortSeconds(Int32(remainingTime)))) if let remainingTime {
if remainingTime == viewOnceTimeout {
badgeContent = .text(inset: 10.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: NSAttributedString(string: "1"), iconName: "Chat/Message/SecretMediaOnce")
} else {
badgeContent = .text(inset: 10.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: NSAttributedString(string: strings.MessageTimer_ShortSeconds(Int32(remainingTime))), iconName: "Chat/Message/SecretMediaPlay")
}
}
} }
if let statusNode = self.statusNode { if let statusNode = self.statusNode {
@ -2062,6 +2088,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
statusNode?.removeFromSupernode() statusNode?.removeFromSupernode()
} }
}) })
statusNode.backgroundNodeColor = backgroundColor
} }
if let badgeContent = badgeContent { if let badgeContent = badgeContent {
if self.badgeNode == nil { if self.badgeNode == nil {
@ -2100,6 +2127,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
displaySpoiler = true displaySpoiler = true
} else if message.attributes.contains(where: { $0 is MediaSpoilerMessageAttribute }) { } else if message.attributes.contains(where: { $0 is MediaSpoilerMessageAttribute }) {
displaySpoiler = true displaySpoiler = true
} else if isSecretMedia {
displaySpoiler = true
} }
if displaySpoiler { if displaySpoiler {
@ -2115,11 +2144,13 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
self.extendedMediaOverlayNode?.frame = self.imageNode.frame self.extendedMediaOverlayNode?.frame = self.imageNode.frame
var tappable = false var tappable = false
switch state { if !isSecretMedia {
case .play, .pause, .download, .none: switch state {
tappable = true case .play, .pause, .download, .none:
default: tappable = true
break default:
break
}
} }
self.extendedMediaOverlayNode?.isUserInteractionEnabled = tappable self.extendedMediaOverlayNode?.isUserInteractionEnabled = tappable

View File

@ -281,16 +281,16 @@ final class GridMessageItemNode: GridItemNode {
switch status { switch status {
case let .Fetching(_, progress): case let .Fetching(_, progress):
let progressString = String(format: "%d%%", Int(progress * 100.0)) let progressString = String(format: "%d%%", Int(progress * 100.0))
badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: progressString)) badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: progressString), iconName: nil)
mediaDownloadState = .compactFetching(progress: 0.0) mediaDownloadState = .compactFetching(progress: 0.0)
case .Local: case .Local:
badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString)) badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString), iconName: nil)
case .Remote, .Paused: case .Remote, .Paused:
badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString)) badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString), iconName: nil)
mediaDownloadState = .compactRemote mediaDownloadState = .compactRemote
} }
} else { } else {
badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString)) badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString), iconName: nil)
} }
strongSelf.mediaBadgeNode.update(theme: item.theme, content: badgeContent, mediaDownloadState: mediaDownloadState, alignment: .right, animated: false, badgeAnimated: false) strongSelf.mediaBadgeNode.update(theme: item.theme, content: badgeContent, mediaDownloadState: mediaDownloadState, alignment: .right, animated: false, badgeAnimated: false)

View File

@ -385,16 +385,16 @@ private final class VisualMediaItemNode: ASDisplayNode {
switch status { switch status {
case let .Fetching(_, progress): case let .Fetching(_, progress):
let progressString = String(format: "%d%%", Int(progress * 100.0)) let progressString = String(format: "%d%%", Int(progress * 100.0))
badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: progressString)) badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: progressString), iconName: nil)
mediaDownloadState = .compactFetching(progress: 0.0) mediaDownloadState = .compactFetching(progress: 0.0)
case .Local: case .Local:
badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString)) badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString), iconName: nil)
case .Remote, .Paused: case .Remote, .Paused:
badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString)) badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString), iconName: nil)
mediaDownloadState = .compactRemote mediaDownloadState = .compactRemote
} }
} else { } else {
badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString)) badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString), iconName: nil)
} }
strongSelf.mediaBadgeNode.update(theme: nil, content: badgeContent, mediaDownloadState: mediaDownloadState, alignment: .right, animated: false, badgeAnimated: false) strongSelf.mediaBadgeNode.update(theme: nil, content: badgeContent, mediaDownloadState: mediaDownloadState, alignment: .right, animated: false, badgeAnimated: false)