mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-03 21:16:35 +00:00
[WIP] Privacy
This commit is contained in:
parent
f001ee483e
commit
b299cbb452
@ -844,6 +844,40 @@ public extension TelegramEngine.EngineData.Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct MessageReadStatsAreHidden: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||||
|
public typealias Result = Bool?
|
||||||
|
|
||||||
|
fileprivate var id: EnginePeer.Id
|
||||||
|
public var mapKey: EnginePeer.Id {
|
||||||
|
return self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(id: EnginePeer.Id) {
|
||||||
|
self.id = id
|
||||||
|
}
|
||||||
|
|
||||||
|
var key: PostboxViewKey {
|
||||||
|
return .cachedPeerData(peerId: self.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func extract(view: PostboxView) -> Result {
|
||||||
|
guard let view = view as? CachedPeerDataView else {
|
||||||
|
preconditionFailure()
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.id.namespace == Namespaces.Peer.CloudUser {
|
||||||
|
if let cachedData = view.cachedPeerData as? CachedUserData, cachedData.flags.contains(.readDatesPrivate) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public struct CanDeleteHistory: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
public struct CanDeleteHistory: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||||
public typealias Result = Bool
|
public typealias Result = Bool
|
||||||
|
|
||||||
|
|||||||
@ -1282,6 +1282,13 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
transition.updateFrame(node: self.avatarListNode.listContainerNode.bottomShadowNode, frame: bottomShadowFrame, beginWithCurrentState: true)
|
transition.updateFrame(node: self.avatarListNode.listContainerNode.bottomShadowNode, frame: bottomShadowFrame, beginWithCurrentState: true)
|
||||||
self.avatarListNode.listContainerNode.bottomShadowNode.update(size: bottomShadowFrame.size, transition: transition)
|
self.avatarListNode.listContainerNode.bottomShadowNode.update(size: bottomShadowFrame.size, transition: transition)
|
||||||
|
|
||||||
|
let singleTitleLockOffset: CGFloat = (peer?.id == self.context.account.peerId || subtitleSize.height.isZero) ? 8.0 : 0.0
|
||||||
|
|
||||||
|
let titleLockOffset: CGFloat = 7.0 + singleTitleLockOffset
|
||||||
|
let titleMaxLockOffset: CGFloat = 7.0
|
||||||
|
let titleOffset: CGFloat
|
||||||
|
let titleCollapseFraction: CGFloat
|
||||||
|
|
||||||
if self.isAvatarExpanded {
|
if self.isAvatarExpanded {
|
||||||
let minTitleSize = CGSize(width: titleSize.width * expandedTitleScale, height: titleSize.height * expandedTitleScale)
|
let minTitleSize = CGSize(width: titleSize.width * expandedTitleScale, height: titleSize.height * expandedTitleScale)
|
||||||
var minTitleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - 58.0 - UIScreenPixel + (subtitleSize.height.isZero ? 10.0 : 0.0)), size: minTitleSize)
|
var minTitleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - 58.0 - UIScreenPixel + (subtitleSize.height.isZero ? 10.0 : 0.0)), size: minTitleSize)
|
||||||
@ -1290,14 +1297,29 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
titleFrame = CGRect(origin: CGPoint(x: minTitleFrame.midX - titleSize.width / 2.0, y: minTitleFrame.midY - titleSize.height / 2.0), size: titleSize)
|
titleFrame = CGRect(origin: CGPoint(x: minTitleFrame.midX - titleSize.width / 2.0, y: minTitleFrame.midY - titleSize.height / 2.0), size: titleSize)
|
||||||
|
|
||||||
|
var titleCollapseOffset = titleFrame.midY - statusBarHeight - titleLockOffset
|
||||||
|
if case .regular = metrics.widthClass, !isSettings {
|
||||||
|
titleCollapseOffset -= 7.0
|
||||||
|
}
|
||||||
|
titleOffset = -min(titleCollapseOffset, contentOffset)
|
||||||
|
titleCollapseFraction = max(0.0, min(1.0, contentOffset / titleCollapseOffset))
|
||||||
|
|
||||||
subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: minTitleFrame.maxY + 2.0), size: subtitleSize)
|
subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: minTitleFrame.maxY + 2.0), size: subtitleSize)
|
||||||
usernameFrame = CGRect(origin: CGPoint(x: width - usernameSize.width - 16.0, y: minTitleFrame.midY - usernameSize.height / 2.0), size: usernameSize)
|
usernameFrame = CGRect(origin: CGPoint(x: width - usernameSize.width - 16.0, y: minTitleFrame.midY - usernameSize.height / 2.0), size: usernameSize)
|
||||||
} else {
|
} else {
|
||||||
titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 9.0 + (subtitleSize.height.isZero ? 11.0 : 0.0)), size: titleSize)
|
titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 9.0 + (subtitleSize.height.isZero ? 11.0 : 0.0)), size: titleSize)
|
||||||
|
|
||||||
|
var titleCollapseOffset = titleFrame.midY - statusBarHeight - titleLockOffset
|
||||||
|
if case .regular = metrics.widthClass, !isSettings {
|
||||||
|
titleCollapseOffset -= 7.0
|
||||||
|
}
|
||||||
|
titleOffset = -min(titleCollapseOffset, contentOffset)
|
||||||
|
titleCollapseFraction = max(0.0, min(1.0, contentOffset / titleCollapseOffset))
|
||||||
|
|
||||||
var effectiveSubtitleWidth = subtitleSize.width
|
var effectiveSubtitleWidth = subtitleSize.width
|
||||||
if let subtitleBadgeSize {
|
if let subtitleBadgeSize {
|
||||||
effectiveSubtitleWidth += subtitleBadgeSize.width + 7.0
|
effectiveSubtitleWidth += (subtitleBadgeSize.width + 7.0) * (1.0 - titleCollapseFraction)
|
||||||
}
|
}
|
||||||
|
|
||||||
let totalSubtitleWidth = effectiveSubtitleWidth + usernameSpacing + usernameSize.width
|
let totalSubtitleWidth = effectiveSubtitleWidth + usernameSpacing + usernameSize.width
|
||||||
@ -1310,17 +1332,6 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let singleTitleLockOffset: CGFloat = (peer?.id == self.context.account.peerId || subtitleSize.height.isZero) ? 8.0 : 0.0
|
|
||||||
|
|
||||||
let titleLockOffset: CGFloat = 7.0 + singleTitleLockOffset
|
|
||||||
let titleMaxLockOffset: CGFloat = 7.0
|
|
||||||
var titleCollapseOffset = titleFrame.midY - statusBarHeight - titleLockOffset
|
|
||||||
if case .regular = metrics.widthClass, !isSettings {
|
|
||||||
titleCollapseOffset -= 7.0
|
|
||||||
}
|
|
||||||
let titleOffset = -min(titleCollapseOffset, contentOffset)
|
|
||||||
let titleCollapseFraction = max(0.0, min(1.0, contentOffset / titleCollapseOffset))
|
|
||||||
|
|
||||||
let titleMinScale: CGFloat = 0.6
|
let titleMinScale: CGFloat = 0.6
|
||||||
let subtitleMinScale: CGFloat = 0.8
|
let subtitleMinScale: CGFloat = 0.8
|
||||||
let avatarMinScale: CGFloat = 0.55
|
let avatarMinScale: CGFloat = 0.55
|
||||||
@ -1686,17 +1697,26 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
transition.updateSublayerTransformScale(node: self.titleNodeContainer, scale: titleScale)
|
transition.updateSublayerTransformScale(node: self.titleNodeContainer, scale: titleScale)
|
||||||
transition.updateSublayerTransformScale(node: self.subtitleNodeContainer, scale: subtitleScale)
|
transition.updateSublayerTransformScale(node: self.subtitleNodeContainer, scale: subtitleScale)
|
||||||
transition.updateSublayerTransformScale(node: self.usernameNodeContainer, scale: subtitleScale)
|
transition.updateSublayerTransformScale(node: self.usernameNodeContainer, scale: subtitleScale)
|
||||||
|
|
||||||
|
if let subtitleBadgeView = self.subtitleBadgeView, let subtitleBadgeSize {
|
||||||
|
let subtitleBadgeFrame = CGRect(origin: CGPoint(x: (subtitleSize.width + 8.0) * 0.5, y: floor((-subtitleBadgeSize.height) * 0.5)), size: subtitleBadgeSize)
|
||||||
|
transition.updateFrameAdditive(view: subtitleBadgeView, frame: subtitleBadgeFrame)
|
||||||
|
transition.updateAlpha(layer: subtitleBadgeView.layer, alpha: (1.0 - transitionFraction))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let titleScale: CGFloat
|
let titleScale: CGFloat
|
||||||
let subtitleScale: CGFloat
|
let subtitleScale: CGFloat
|
||||||
var subtitleOffset: CGFloat = 0.0
|
var subtitleOffset: CGFloat = 0.0
|
||||||
|
let subtitleBadgeFraction: CGFloat
|
||||||
if self.isAvatarExpanded {
|
if self.isAvatarExpanded {
|
||||||
titleScale = expandedTitleScale
|
titleScale = expandedTitleScale
|
||||||
subtitleScale = 1.0
|
subtitleScale = 1.0
|
||||||
|
subtitleBadgeFraction = 1.0
|
||||||
} else {
|
} else {
|
||||||
titleScale = (1.0 - titleCollapseFraction) * 1.0 + titleCollapseFraction * titleMinScale
|
titleScale = (1.0 - titleCollapseFraction) * 1.0 + titleCollapseFraction * titleMinScale
|
||||||
subtitleScale = (1.0 - titleCollapseFraction) * 1.0 + titleCollapseFraction * subtitleMinScale
|
subtitleScale = (1.0 - titleCollapseFraction) * 1.0 + titleCollapseFraction * subtitleMinScale
|
||||||
subtitleOffset = titleCollapseFraction * -1.0
|
subtitleOffset = titleCollapseFraction * -1.0
|
||||||
|
subtitleBadgeFraction = (1.0 - titleCollapseFraction)
|
||||||
}
|
}
|
||||||
|
|
||||||
let rawTitleFrame = titleFrame.offsetBy(dx: self.isAvatarExpanded ? 0.0 : titleHorizontalOffset * titleScale, dy: 0.0)
|
let rawTitleFrame = titleFrame.offsetBy(dx: self.isAvatarExpanded ? 0.0 : titleHorizontalOffset * titleScale, dy: 0.0)
|
||||||
@ -1728,13 +1748,13 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
transition.updateSublayerTransformScaleAdditive(node: self.titleNodeContainer, scale: titleScale)
|
transition.updateSublayerTransformScaleAdditive(node: self.titleNodeContainer, scale: titleScale)
|
||||||
transition.updateSublayerTransformScaleAdditive(node: self.subtitleNodeContainer, scale: subtitleScale)
|
transition.updateSublayerTransformScaleAdditive(node: self.subtitleNodeContainer, scale: subtitleScale)
|
||||||
transition.updateSublayerTransformScaleAdditive(node: self.usernameNodeContainer, scale: subtitleScale)
|
transition.updateSublayerTransformScaleAdditive(node: self.usernameNodeContainer, scale: subtitleScale)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let subtitleBadgeView = self.subtitleBadgeView, let subtitleBadgeSize {
|
if let subtitleBadgeView = self.subtitleBadgeView, let subtitleBadgeSize {
|
||||||
let subtitleBadgeFrame = CGRect(origin: CGPoint(x: (subtitleSize.width + 7.0) * 0.5, y: floor((-subtitleBadgeSize.height) * 0.5)), size: subtitleBadgeSize)
|
let subtitleBadgeFrame = CGRect(origin: CGPoint(x: (subtitleSize.width + 8.0) * 0.5, y: floor((-subtitleBadgeSize.height) * 0.5)), size: subtitleBadgeSize)
|
||||||
transition.updateFrameAdditive(view: subtitleBadgeView, frame: subtitleBadgeFrame)
|
transition.updateFrameAdditive(view: subtitleBadgeView, frame: subtitleBadgeFrame)
|
||||||
transition.updateAlpha(layer: subtitleBadgeView.layer, alpha: 1.0 - transitionFraction)
|
transition.updateAlpha(layer: subtitleBadgeView.layer, alpha: (1.0 - transitionFraction) * subtitleBadgeFraction)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let buttonsTransitionDistance: CGFloat = -min(0.0, apparentBackgroundHeight - backgroundHeight)
|
let buttonsTransitionDistance: CGFloat = -min(0.0, apparentBackgroundHeight - backgroundHeight)
|
||||||
|
|||||||
@ -244,8 +244,13 @@ private func canViewReadStats(message: Message, participantCount: Int?, isMessag
|
|||||||
if group.participantCount > maxParticipantCount {
|
if group.participantCount > maxParticipantCount {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case _ as TelegramUser:
|
case let user as TelegramUser:
|
||||||
break
|
if user.botInfo != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if user.flags.contains(.isSupport) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -719,18 +724,28 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
|||||||
var linkedDiscusionPeerId: EnginePeerCachedInfoItem<EnginePeer.Id?>
|
var linkedDiscusionPeerId: EnginePeerCachedInfoItem<EnginePeer.Id?>
|
||||||
var canViewStats: Bool
|
var canViewStats: Bool
|
||||||
var participantCount: Int?
|
var participantCount: Int?
|
||||||
|
var messageReadStatsAreHidden: Bool?
|
||||||
|
|
||||||
|
init(linkedDiscusionPeerId: EnginePeerCachedInfoItem<EnginePeer.Id?>, canViewStats: Bool, participantCount: Int?, messageReadStatsAreHidden: Bool?) {
|
||||||
|
self.linkedDiscusionPeerId = linkedDiscusionPeerId
|
||||||
|
self.canViewStats = canViewStats
|
||||||
|
self.participantCount = participantCount
|
||||||
|
self.messageReadStatsAreHidden = messageReadStatsAreHidden
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let infoSummaryData = context.engine.data.get(
|
let infoSummaryData = context.engine.data.get(
|
||||||
TelegramEngine.EngineData.Item.Peer.LinkedDiscussionPeerId(id: messages[0].id.peerId),
|
TelegramEngine.EngineData.Item.Peer.LinkedDiscussionPeerId(id: messages[0].id.peerId),
|
||||||
TelegramEngine.EngineData.Item.Peer.CanViewStats(id: messages[0].id.peerId),
|
TelegramEngine.EngineData.Item.Peer.CanViewStats(id: messages[0].id.peerId),
|
||||||
TelegramEngine.EngineData.Item.Peer.ParticipantCount(id: messages[0].id.peerId)
|
TelegramEngine.EngineData.Item.Peer.ParticipantCount(id: messages[0].id.peerId),
|
||||||
|
TelegramEngine.EngineData.Item.Peer.MessageReadStatsAreHidden(id: messages[0].id.peerId)
|
||||||
)
|
)
|
||||||
|> map { linkedDiscusionPeerId, canViewStats, participantCount -> InfoSummaryData in
|
|> map { linkedDiscusionPeerId, canViewStats, participantCount, messageReadStatsAreHidden -> InfoSummaryData in
|
||||||
return InfoSummaryData(
|
return InfoSummaryData(
|
||||||
linkedDiscusionPeerId: linkedDiscusionPeerId,
|
linkedDiscusionPeerId: linkedDiscusionPeerId,
|
||||||
canViewStats: canViewStats,
|
canViewStats: canViewStats,
|
||||||
participantCount: participantCount
|
participantCount: participantCount,
|
||||||
|
messageReadStatsAreHidden: messageReadStatsAreHidden
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1696,7 +1711,13 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let canViewStats = canViewReadStats(message: message, participantCount: infoSummaryData.participantCount, isMessageRead: isMessageRead, appConfig: appConfig)
|
let canViewStats: Bool
|
||||||
|
if let messageReadStatsAreHidden = infoSummaryData.messageReadStatsAreHidden, !messageReadStatsAreHidden {
|
||||||
|
canViewStats = canViewReadStats(message: message, participantCount: infoSummaryData.participantCount, isMessageRead: isMessageRead, appConfig: appConfig)
|
||||||
|
} else {
|
||||||
|
canViewStats = false
|
||||||
|
}
|
||||||
|
|
||||||
var reactionCount = 0
|
var reactionCount = 0
|
||||||
for reaction in mergedMessageReactionsAndPeers(accountPeerId: context.account.peerId, accountPeer: nil, message: message).reactions {
|
for reaction in mergedMessageReactionsAndPeers(accountPeerId: context.account.peerId, accountPeer: nil, message: message).reactions {
|
||||||
reactionCount += Int(reaction.count)
|
reactionCount += Int(reaction.count)
|
||||||
@ -2392,6 +2413,8 @@ private final class ChatReadReportContextItemNode: ASDisplayNode, ContextMenuCus
|
|||||||
private let highlightedBackgroundNode: ASDisplayNode
|
private let highlightedBackgroundNode: ASDisplayNode
|
||||||
private let placeholderCalculationTextNode: ImmediateTextNode
|
private let placeholderCalculationTextNode: ImmediateTextNode
|
||||||
private let textNode: ImmediateTextNode
|
private let textNode: ImmediateTextNode
|
||||||
|
private var badgeBackground: UIImageView?
|
||||||
|
private var badgeText: ImmediateTextNode?
|
||||||
private let shimmerNode: ShimmerEffectNode
|
private let shimmerNode: ShimmerEffectNode
|
||||||
private let iconNode: ASImageNode
|
private let iconNode: ASImageNode
|
||||||
|
|
||||||
@ -2449,7 +2472,9 @@ private final class ChatReadReportContextItemNode: ASDisplayNode, ContextMenuCus
|
|||||||
self.buttonNode.accessibilityLabel = presentationData.strings.VoiceChat_StopRecording
|
self.buttonNode.accessibilityLabel = presentationData.strings.VoiceChat_StopRecording
|
||||||
|
|
||||||
self.iconNode = ASImageNode()
|
self.iconNode = ASImageNode()
|
||||||
if let reactionsAttribute = item.message.reactionsAttribute, !reactionsAttribute.reactions.isEmpty {
|
if self.item.message.id.peerId.namespace == Namespaces.Peer.CloudUser {
|
||||||
|
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/MenuReadIcon"), color: presentationData.theme.actionSheet.primaryTextColor)
|
||||||
|
} else if let reactionsAttribute = item.message.reactionsAttribute, !reactionsAttribute.reactions.isEmpty {
|
||||||
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Reactions"), color: presentationData.theme.actionSheet.primaryTextColor)
|
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Reactions"), color: presentationData.theme.actionSheet.primaryTextColor)
|
||||||
} else {
|
} else {
|
||||||
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Read"), color: presentationData.theme.actionSheet.primaryTextColor)
|
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Read"), color: presentationData.theme.actionSheet.primaryTextColor)
|
||||||
@ -2607,12 +2632,19 @@ private final class ChatReadReportContextItemNode: ASDisplayNode, ContextMenuCus
|
|||||||
|
|
||||||
func updateLayout(constrainedWidth: CGFloat, constrainedHeight: CGFloat) -> (CGSize, (CGSize, ContainedViewLayoutTransition) -> Void) {
|
func updateLayout(constrainedWidth: CGFloat, constrainedHeight: CGFloat) -> (CGSize, (CGSize, ContainedViewLayoutTransition) -> Void) {
|
||||||
let sideInset: CGFloat = 14.0
|
let sideInset: CGFloat = 14.0
|
||||||
let verticalInset: CGFloat = 12.0
|
let verticalInset: CGFloat
|
||||||
|
let rightTextInset: CGFloat
|
||||||
|
|
||||||
|
if self.item.message.id.peerId.namespace == Namespaces.Peer.CloudUser {
|
||||||
|
verticalInset = 7.0
|
||||||
|
rightTextInset = 8.0
|
||||||
|
} else {
|
||||||
|
verticalInset = 12.0
|
||||||
|
rightTextInset = sideInset + 36.0
|
||||||
|
}
|
||||||
|
|
||||||
let iconSize: CGSize = self.iconNode.image?.size ?? CGSize(width: 10.0, height: 10.0)
|
let iconSize: CGSize = self.iconNode.image?.size ?? CGSize(width: 10.0, height: 10.0)
|
||||||
|
|
||||||
let rightTextInset: CGFloat = sideInset + 36.0
|
|
||||||
|
|
||||||
let calculatedWidth = min(constrainedWidth, 250.0)
|
let calculatedWidth = min(constrainedWidth, 250.0)
|
||||||
|
|
||||||
let textFont = Font.regular(self.presentationData.listsFontSize.baseDisplaySize)
|
let textFont = Font.regular(self.presentationData.listsFontSize.baseDisplaySize)
|
||||||
@ -2622,13 +2654,21 @@ private final class ChatReadReportContextItemNode: ASDisplayNode, ContextMenuCus
|
|||||||
reactionCount += Int(reaction.count)
|
reactionCount += Int(reaction.count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var showReadBadge = false
|
||||||
|
var animatePositions = true
|
||||||
|
|
||||||
if let currentStats = self.currentStats {
|
if let currentStats = self.currentStats {
|
||||||
reactionCount = currentStats.reactionCount
|
reactionCount = currentStats.reactionCount
|
||||||
|
|
||||||
if currentStats.peers.isEmpty {
|
if currentStats.peers.isEmpty {
|
||||||
if self.item.message.id.peerId.namespace == Namespaces.Peer.CloudUser {
|
if self.item.message.id.peerId.namespace == Namespaces.Peer.CloudUser {
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
self.textNode.attributedText = NSAttributedString(string: "Show Read Time", font: textFont, textColor: self.presentationData.theme.contextMenu.primaryColor)
|
let text = NSAttributedString(string: "read", font: Font.regular(floor(self.presentationData.listsFontSize.baseDisplaySize * 0.8)), textColor: self.presentationData.theme.contextMenu.primaryColor)
|
||||||
|
if self.textNode.attributedText != text {
|
||||||
|
animatePositions = false
|
||||||
|
}
|
||||||
|
self.textNode.attributedText = text
|
||||||
|
showReadBadge = true
|
||||||
} else {
|
} else {
|
||||||
if reactionCount != 0 {
|
if reactionCount != 0 {
|
||||||
let text: String = self.presentationData.strings.Chat_ContextReactionCount(Int32(reactionCount))
|
let text: String = self.presentationData.strings.Chat_ContextReactionCount(Int32(reactionCount))
|
||||||
@ -2698,14 +2738,72 @@ private final class ChatReadReportContextItemNode: ASDisplayNode, ContextMenuCus
|
|||||||
|
|
||||||
let placeholderTextSize = self.placeholderCalculationTextNode.updateLayout(CGSize(width: calculatedWidth - sideInset - rightTextInset - iconSize.width - 4.0, height: .greatestFiniteMagnitude))
|
let placeholderTextSize = self.placeholderCalculationTextNode.updateLayout(CGSize(width: calculatedWidth - sideInset - rightTextInset - iconSize.width - 4.0, height: .greatestFiniteMagnitude))
|
||||||
|
|
||||||
|
var badgeTextSize: CGSize?
|
||||||
|
if showReadBadge {
|
||||||
|
let badgeBackground: UIImageView
|
||||||
|
if let current = self.badgeBackground {
|
||||||
|
badgeBackground = current
|
||||||
|
} else {
|
||||||
|
badgeBackground = UIImageView()
|
||||||
|
badgeBackground.alpha = 0.0
|
||||||
|
self.badgeBackground = badgeBackground
|
||||||
|
self.view.addSubview(badgeBackground)
|
||||||
|
}
|
||||||
|
|
||||||
|
let badgeText: ImmediateTextNode
|
||||||
|
if let current = self.badgeText {
|
||||||
|
badgeText = current
|
||||||
|
} else {
|
||||||
|
badgeText = ImmediateTextNode()
|
||||||
|
badgeText.alpha = 0.0
|
||||||
|
self.badgeText = badgeText
|
||||||
|
self.addSubnode(badgeText)
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
|
badgeText.attributedText = NSAttributedString(string: "show when", font: Font.regular(self.presentationData.listsFontSize.baseDisplaySize * 11.0 / 17.0), textColor: self.presentationData.theme.contextMenu.primaryColor)
|
||||||
|
|
||||||
|
badgeTextSize = badgeText.updateLayout(CGSize(width: calculatedWidth - sideInset - rightTextInset - iconSize.width - 4.0 - textSize.width - 12.0, height: 100.0))
|
||||||
|
} else {
|
||||||
|
if let badgeBackground = self.badgeBackground {
|
||||||
|
badgeBackground.removeFromSuperview()
|
||||||
|
self.badgeBackground = nil
|
||||||
|
}
|
||||||
|
if let badgeText = self.badgeText {
|
||||||
|
badgeText.removeFromSupernode()
|
||||||
|
self.badgeText = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let combinedTextHeight = textSize.height
|
let combinedTextHeight = textSize.height
|
||||||
return (CGSize(width: calculatedWidth, height: verticalInset * 2.0 + combinedTextHeight), { size, transition in
|
return (CGSize(width: calculatedWidth, height: verticalInset * 2.0 + combinedTextHeight), { size, transition in
|
||||||
self.validLayout = (calculatedWidth: calculatedWidth, size: size)
|
self.validLayout = (calculatedWidth: calculatedWidth, size: size)
|
||||||
|
|
||||||
|
let positionTransition: ContainedViewLayoutTransition = animatePositions ? transition : .immediate
|
||||||
|
|
||||||
let verticalOrigin = floor((size.height - combinedTextHeight) / 2.0)
|
let verticalOrigin = floor((size.height - combinedTextHeight) / 2.0)
|
||||||
let textFrame = CGRect(origin: CGPoint(x: sideInset + iconSize.width + 4.0, y: verticalOrigin), size: textSize)
|
let textFrame = CGRect(origin: CGPoint(x: sideInset + iconSize.width + 4.0, y: verticalOrigin), size: textSize)
|
||||||
transition.updateFrameAdditive(node: self.textNode, frame: textFrame)
|
positionTransition.updateFrameAdditive(node: self.textNode, frame: textFrame)
|
||||||
transition.updateAlpha(node: self.textNode, alpha: self.currentStats == nil ? 0.0 : 1.0)
|
transition.updateAlpha(node: self.textNode, alpha: self.currentStats == nil ? 0.0 : 1.0)
|
||||||
|
|
||||||
|
if let badgeTextSize, let badgeText = self.badgeText, let badgeBackground = self.badgeBackground {
|
||||||
|
let backgroundSideInset: CGFloat = 5.0
|
||||||
|
let backgroundVerticalInset: CGFloat = 3.0
|
||||||
|
let badgeTextFrame = CGRect(origin: CGPoint(x: textFrame.maxX + 5.0 + backgroundSideInset, y: textFrame.minY + floor((textFrame.height - badgeTextSize.height) * 0.5)), size: badgeTextSize)
|
||||||
|
positionTransition.updateFrameAdditive(node: badgeText, frame: badgeTextFrame)
|
||||||
|
transition.updateAlpha(node: badgeText, alpha: self.currentStats == nil ? 0.0 : 1.0)
|
||||||
|
|
||||||
|
let badgeBackgroundFrame = badgeTextFrame.insetBy(dx: -backgroundSideInset, dy: -backgroundVerticalInset).offsetBy(dx: 0.0, dy: 1.0)
|
||||||
|
|
||||||
|
if badgeBackground.image?.size.height != ceil(badgeBackgroundFrame.height) {
|
||||||
|
badgeBackground.image = generateStretchableFilledCircleImage(diameter: ceil(badgeBackgroundFrame.height), color: .white, strokeColor: nil, strokeWidth: nil, backgroundColor: nil)?.withRenderingMode(.alwaysTemplate)
|
||||||
|
}
|
||||||
|
badgeBackground.tintColor = self.presentationData.theme.contextMenu.primaryColor.withMultipliedAlpha(0.05)
|
||||||
|
|
||||||
|
positionTransition.updateFrame(view: badgeBackground, frame: badgeBackgroundFrame)
|
||||||
|
transition.updateAlpha(layer: badgeBackground.layer, alpha: self.currentStats == nil ? 0.0 : 1.0)
|
||||||
|
}
|
||||||
|
|
||||||
let shimmerHeight: CGFloat = 8.0
|
let shimmerHeight: CGFloat = 8.0
|
||||||
|
|
||||||
self.shimmerNode.frame = CGRect(origin: CGPoint(x: textFrame.minX, y: floor((size.height - shimmerHeight) / 2.0)), size: CGSize(width: placeholderTextSize.width, height: shimmerHeight))
|
self.shimmerNode.frame = CGRect(origin: CGPoint(x: textFrame.minX, y: floor((size.height - shimmerHeight) / 2.0)), size: CGSize(width: placeholderTextSize.width, height: shimmerHeight))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user