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";
"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 {
switch status {
case let .Fetching(_, progress):
let progressString = String(format: "%d%%", Int(progress * 100.0))
badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: progressString))
mediaDownloadState = .compactFetching(progress: 0.0)
case .Local:
badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString))
case .Remote, .Paused:
badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString))
mediaDownloadState = .compactRemote
case let .Fetching(_, progress):
let progressString = String(format: "%d%%", Int(progress * 100.0))
badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: progressString), iconName: nil)
mediaDownloadState = .compactFetching(progress: 0.0)
case .Local:
badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString), iconName: nil)
case .Remote, .Paused:
badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString), iconName: nil)
mediaDownloadState = .compactRemote
}
} 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)

View File

@ -18,13 +18,13 @@ public enum ChatMessageInteractiveMediaDownloadState: 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)
public static func ==(lhs: ChatMessageInteractiveMediaBadgeContent, rhs: ChatMessageInteractiveMediaBadgeContent) -> Bool {
switch lhs {
case let .text(lhsInset, lhsBackgroundColor, lhsForegroundColor, lhsText):
if case let .text(rhsInset, rhsBackgroundColor, rhsForegroundColor, rhsText) = rhs, lhsInset.isEqual(to: rhsInset), lhsBackgroundColor.isEqual(rhsBackgroundColor), lhsForegroundColor.isEqual(rhsForegroundColor), lhsText.isEqual(to: rhsText) {
case let .text(lhsInset, lhsBackgroundColor, lhsForegroundColor, lhsText, lhsIconName):
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
} else {
return false
@ -48,6 +48,7 @@ public final class ChatMessageInteractiveMediaBadge: ASDisplayNode {
private var previousContentSize: CGSize?
private var backgroundNodeColor: UIColor?
private var foregroundColor: UIColor?
private var iconName: String?
private let backgroundNode: ASImageNode
private let durationNode: ASTextNode
@ -107,14 +108,18 @@ public final class ChatMessageInteractiveMediaBadge: ASDisplayNode {
}
switch content {
case let .text(inset, backgroundColor, foregroundColor, text):
case let .text(inset, backgroundColor, foregroundColor, text, iconName):
transition = .immediate
if self.backgroundNodeColor != backgroundColor {
self.backgroundNodeColor = 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
if let _ = attributes[ChatTextInputAttributes.bold] {
convertedText.addAttribute(.font, value: boldFont, range: range)
@ -122,12 +127,33 @@ public final class ChatMessageInteractiveMediaBadge: ASDisplayNode {
}
self.durationNode.attributedText = convertedText
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)
if let iconNode = self.iconNode {
transition.updateTransformScale(node: iconNode, scale: 0.001)
transition.updateAlpha(node: iconNode, alpha: 0.0)
if let iconName {
let iconNode: ASImageNode
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):
if self.backgroundNodeColor != backgroundColor {
@ -209,7 +235,7 @@ public final class ChatMessageInteractiveMediaBadge: ASDisplayNode {
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))
if muted {
transition.updateAlpha(node: iconNode, alpha: 1.0)
transition.updateTransformScale(node: iconNode, scale: 1.0)

View File

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

View File

@ -5,6 +5,7 @@ import AsyncDisplayKit
enum RadialStatusIcon {
case custom(UIImage)
case timeout
case play(UIColor)
case pause(UIColor)
}
@ -22,14 +23,28 @@ private final class RadialStatusIconContentNodeParameters: NSObject {
final class RadialStatusIconContentNode: RadialStatusContentNode {
private let icon: RadialStatusIcon
private var animationNode: FireIconNode?
init(icon: RadialStatusIcon, synchronous: Bool) {
self.icon = icon
super.init()
self.displaysAsynchronously = !synchronous
self.isLayerBacked = true
// self.isLayerBacked = true
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? {
@ -48,6 +63,8 @@ final class RadialStatusIconContentNode: RadialStatusContentNode {
if let parameters = parameters as? RadialStatusIconContentNodeParameters {
let diameter = min(bounds.size.width, bounds.size.height)
switch parameters.icon {
case .timeout:
break
case let .play(color):
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 check(UIColor)
case customIcon(UIImage)
case staticTimeout
case secretTimeout(color: UIColor, icon: UIImage?, beginTime: Double, timeout: Double, sparks: Bool)
public static func ==(lhs: RadialStatusNodeState, rhs: RadialStatusNodeState) -> Bool {
@ -64,6 +65,12 @@ public enum RadialStatusNodeState: Equatable {
} else {
return false
}
case .staticTimeout:
if case .staticTimeout = rhs {
return true
} else {
return false
}
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 {
return true
@ -123,6 +130,12 @@ public enum RadialStatusNodeState: Equatable {
} else {
return false
}
case .staticTimeout:
if case .staticTimeout = rhs{
return true
} else {
return false
}
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 {
return true
@ -179,6 +192,8 @@ public enum RadialStatusNodeState: Equatable {
node.progress = value
return node
}
case .staticTimeout:
return RadialStatusIconContentNode(icon: .timeout, synchronous: synchronous)
case let .secretTimeout(color, icon, beginTime, timeout, 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 var backgroundNodeColor: UIColor {
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 AsyncDisplayKit
import LegacyComponents
import ManagedAnimationNode
private struct ContentParticle {
var position: CGPoint
@ -53,6 +54,8 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
private var progress: CGFloat = 0.0
private var particles: [ContentParticle] = []
private let animationNode = FireIconNode()
private var displayLink: CADisplayLink?
init(color: UIColor, beginTime: Double, timeout: Double, icon: UIImage?, sparks: Bool) {
@ -65,7 +68,7 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
super.init()
self.isOpaque = false
self.isLayerBacked = true
// self.isLayerBacked = true
class DisplayLinkProxy: NSObject {
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?.isPaused = true
self.displayLink?.add(to: RunLoop.main, forMode: .common)
self.addSubnode(self.animationNode)
}
deinit {
@ -89,6 +94,8 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
override func 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) {
@ -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
for attribute in attributes {
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
}
} 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
}
} else if let mentionAttribute = attribute as? ConsumablePersonalMentionMessageAttribute {

View File

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

View File

@ -939,7 +939,6 @@ final class MediaEditorScreenComponent: Component {
self.appliedAudioData = audioData
var timeoutValue: String
let timeoutSelected: Bool
switch component.privacy.timeout {
case 21600:
timeoutValue = "6"
@ -952,7 +951,6 @@ final class MediaEditorScreenComponent: Component {
default:
timeoutValue = "24"
}
timeoutSelected = false
var inputPanelAvailableWidth = previewSize.width
var inputPanelAvailableHeight = 103.0
@ -1192,7 +1190,7 @@ final class MediaEditorScreenComponent: Component {
hasRecordedVideoPreview: false,
wasRecordingDismissed: false,
timeoutValue: timeoutValue,
timeoutSelected: timeoutSelected,
timeoutSelected: false,
displayGradient: false,
bottomInset: 0.0,
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 = {
self.node.mediaEditor?.play()
}
@ -3845,6 +3849,12 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
editCategory: { _, _, _ 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 = {
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))
}
}
self.cursorView.isHidden = component.audioOnly
let bounds = CGRect(origin: .zero, size: scrubberSize)

View File

@ -135,7 +135,7 @@ final class ShareWithPeersScreenComponent: Component {
self.itemHeight = itemHeight
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
topOffsetFraction = max(0.0, min(1.0, topOffsetFraction))
//let transitionFactor: CGFloat = 1.0 - topOffsetFraction
//controller.updateModalStyleOverlayTransitionFactor(transitionFactor, transition: transition.containedViewLayoutTransition)
let transitionFactor: CGFloat = 1.0 - topOffsetFraction
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
visibleBounds.origin.y -= itemLayout.topInset
@ -907,7 +915,7 @@ final class ShareWithPeersScreenComponent: Component {
let sectionTitle: String
if section.id == 0, case .stories = component.stateContext.subject {
sectionTitle = "POST STORY AS"
sectionTitle = environment.strings.Story_Privacy_PostStoryAsHeader
} else if section.id == 2 {
sectionTitle = environment.strings.Story_Privacy_WhoCanViewHeader
} else if section.id == 1 {
@ -1362,11 +1370,16 @@ final class ShareWithPeersScreenComponent: Component {
self.visibleItems[itemId] = visibleItem
}
var title = item.title
if item.id == .pin && !hasCategories {
title = environment.strings.Story_Privacy_KeepOnChannelPage
}
let _ = visibleItem.update(
transition: itemTransition,
component: AnyComponent(OptionListItemComponent(
theme: environment.theme,
title: item.title,
title: title,
hasNext: i != component.optionItems.count - 1,
selected: self.selectedOptions.contains(item.id),
selectionChanged: { [weak self] selected in
@ -1414,7 +1427,7 @@ final class ShareWithPeersScreenComponent: Component {
var footerText = environment.strings.Story_Privacy_KeepOnMyPageInfo(footerValue).string
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(
@ -1508,6 +1521,9 @@ final class ShareWithPeersScreenComponent: Component {
for id in removeSectionBackgroundIds {
self.visibleSectionBackgrounds.removeValue(forKey: id)
}
for id in removeSectionFooterIds {
self.visibleSectionFooters.removeValue(forKey: id)
}
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 {
@ -1932,11 +1948,16 @@ final class ShareWithPeersScreenComponent: Component {
)
var hasCategories = false
var hasChannels = false
if case .stories = component.stateContext.subject {
if let peerId = self.sendAsPeerId, peerId.isGroupOrChannel {
} else {
hasCategories = true
}
let sendAsPeersCount = component.stateContext.stateValue?.sendAsPeers.count ?? 1
if sendAsPeersCount > 1 {
hasChannels = true
}
}
var footersTotalHeight: CGFloat = 0.0
@ -2016,16 +2037,15 @@ final class ShareWithPeersScreenComponent: Component {
if case let .peers(peers, _) = component.stateContext.subject {
sections.append(ItemLayout.Section(
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,
itemCount: peers.count
))
} else if case let .stories(editing) = component.stateContext.subject {
let sendAsPeersCount = component.stateContext.stateValue?.sendAsPeers.count ?? 1
if !editing && sendAsPeersCount > 1 {
if !editing && hasChannels {
sections.append(ItemLayout.Section(
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,
itemCount: 1
))
@ -2040,7 +2060,7 @@ final class ShareWithPeersScreenComponent: Component {
}
sections.append(ItemLayout.Section(
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,
itemCount: component.optionItems.count
))
@ -2110,7 +2130,7 @@ final class ShareWithPeersScreenComponent: Component {
let title: String
switch component.stateContext.subject {
case .peers:
title = "Post Story As"
title = environment.strings.Story_Privacy_PostStoryAs
case let .stories(editing):
if editing {
title = environment.strings.Story_Privacy_EditStory
@ -2178,11 +2198,16 @@ final class ShareWithPeersScreenComponent: Component {
inset = 351.0
inset += 10.0 + environment.safeInsets.bottom + 50.0 + footersTotalHeight
} else {
if hasCategories {
inset = 1000.0
} else {
if !hasCategories {
inset = 314.0
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 {
@ -2201,7 +2226,7 @@ final class ShareWithPeersScreenComponent: Component {
var bottomPanelHeight: CGFloat = 0.0
var bottomPanelInset: CGFloat = 0.0
if case .peers = component.stateContext.subject {
bottomPanelInset = environment.safeInsets.bottom
} else {
let badge: Int
if case .stories = component.stateContext.subject {
@ -2367,7 +2392,7 @@ final class ShareWithPeersScreenComponent: Component {
}
return Array(filteredMentions)
}
|> deliverOnMainQueue).start(next: { mentions in
|> deliverOnMainQueue).start(next: { mentions in
if mentions.isEmpty {
proceed()
} else {
@ -2377,7 +2402,7 @@ final class ShareWithPeersScreenComponent: Component {
}
} else if case .contacts = base {
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)
let peers = contacts.peers
for peer in peers {
@ -2390,7 +2415,7 @@ final class ShareWithPeersScreenComponent: Component {
}
return Array(filteredMentions)
}
|> deliverOnMainQueue).start(next: { mentions in
|> deliverOnMainQueue).start(next: { mentions in
if mentions.isEmpty {
proceed()
} else {
@ -2399,7 +2424,7 @@ final class ShareWithPeersScreenComponent: Component {
})
} else if case .closeFriends = base {
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)
let peers = contacts.peers
for peer in peers {
@ -2409,7 +2434,7 @@ final class ShareWithPeersScreenComponent: Component {
}
return Array(filteredMentions)
}
|> deliverOnMainQueue).start(next: { mentions in
|> deliverOnMainQueue).start(next: { mentions in
if mentions.isEmpty {
proceed()
} else {
@ -2452,7 +2477,7 @@ final class ShareWithPeersScreenComponent: Component {
let previousItemLayout = self.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)

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 {
case .linear(_, .None), .linear(_, .Neighbour(true, _, _)):
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
} 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 {
skipStandardStatus = isFile
}

View File

@ -860,7 +860,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
let maxWidth: CGFloat
if isSecretMedia {
maxWidth = 180.0
maxWidth = 200.0
} else {
maxWidth = maxDimensions.width
}
@ -898,7 +898,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
switch sizeCalculation {
case .constrained:
if isSecretMedia {
boundingSize = CGSize(width: maxWidth, height: maxWidth)
boundingSize = CGSize(width: maxWidth, height: maxWidth / 5.0 * 3.0)
drawingSize = nativeSize.aspectFilled(boundingSize)
} else {
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 self.statusNode == nil {
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 backgroundColor = messageTheme.mediaOverlayControlColors.fillColor
var badgeContent: ChatMessageInteractiveMediaBadgeContent?
var mediaDownloadState: ChatMessageInteractiveMediaDownloadState?
let messageTheme = theme.chat.message
if let invoice = invoice {
if let extendedMedia = invoice.extendedMedia {
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 {
let string = NSMutableAttributedString()
@ -1808,7 +1816,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
}
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
@ -1944,7 +1952,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
}
} else {
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)
}
@ -1980,8 +1988,10 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
}
if isSecretMedia, let (maybeBeginTime, timeout) = secretBeginTimeAndTimeout, let beginTime = maybeBeginTime {
state = .secretTimeout(color: messageTheme.mediaOverlayControlColors.foregroundColor, icon: secretProgressIcon, beginTime: beginTime, timeout: timeout, sparks: true)
} else if isSecretMedia, let secretProgressIcon = secretProgressIcon {
state = .customIcon(secretProgressIcon)
backgroundColor = messageTheme.mediaDateAndStatusFillColor
} else if isSecretMedia, let _ = secretProgressIcon {
state = .staticTimeout
backgroundColor = messageTheme.mediaDateAndStatusFillColor
} else if let file = media as? TelegramMediaFile, !file.isVideoSticker {
let isInlinePlayableVideo = file.isVideo && !isSecretMedia && (self.automaticPlayback ?? false)
if (!isInlinePlayableVideo || isStory) && file.isVideo {
@ -2017,11 +2027,11 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
} else {
if isMediaStreamable(message: message, media: file) {
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
} else {
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 {
let remainingTime: Int32
if let beginTime = maybeBeginTime {
let elapsedTime = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - beginTime
remainingTime = Int32(max(0.0, timeout - elapsedTime))
if isSecretMedia {
let remainingTime: Int32?
if let (maybeBeginTime, timeout) = secretBeginTimeAndTimeout {
if let beginTime = maybeBeginTime {
let elapsedTime = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - beginTime
remainingTime = Int32(max(0.0, timeout - elapsedTime))
} else {
remainingTime = Int32(timeout)
}
} 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 {
@ -2062,6 +2088,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
statusNode?.removeFromSupernode()
}
})
statusNode.backgroundNodeColor = backgroundColor
}
if let badgeContent = badgeContent {
if self.badgeNode == nil {
@ -2100,6 +2127,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
displaySpoiler = true
} else if message.attributes.contains(where: { $0 is MediaSpoilerMessageAttribute }) {
displaySpoiler = true
} else if isSecretMedia {
displaySpoiler = true
}
if displaySpoiler {
@ -2115,11 +2144,13 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
self.extendedMediaOverlayNode?.frame = self.imageNode.frame
var tappable = false
switch state {
case .play, .pause, .download, .none:
tappable = true
default:
break
if !isSecretMedia {
switch state {
case .play, .pause, .download, .none:
tappable = true
default:
break
}
}
self.extendedMediaOverlayNode?.isUserInteractionEnabled = tappable

View File

@ -281,16 +281,16 @@ final class GridMessageItemNode: GridItemNode {
switch status {
case let .Fetching(_, progress):
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)
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:
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
}
} 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)

View File

@ -385,16 +385,16 @@ private final class VisualMediaItemNode: ASDisplayNode {
switch status {
case let .Fetching(_, progress):
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)
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:
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
}
} 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)