mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Autoremove improvements
This commit is contained in:
parent
1656ecff49
commit
fea0e8b23e
@ -6249,6 +6249,10 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"Conversation.AutoremoveTimerSetUserYou" = "You set messages to automatically delete after %1$@";
|
"Conversation.AutoremoveTimerSetUserYou" = "You set messages to automatically delete after %1$@";
|
||||||
"Conversation.AutoremoveTimerSetUser" = "%1$@ set messages to automatically delete after %2$@";
|
"Conversation.AutoremoveTimerSetUser" = "%1$@ set messages to automatically delete after %2$@";
|
||||||
|
|
||||||
|
"Conversation.AutoremoveTimerSetUserGlobalYou" = "You set a self-destruct timer for all chats.\nAll new messages in this chat will be automatically deleted after %1$@ they're sent.";
|
||||||
|
"Conversation.AutoremoveTimerSetUserGlobal" = "%1$@ set a self-destruct timer for all chats.\nAll new messages in this chat will be automatically deleted after %2$@ they're sent.";
|
||||||
|
|
||||||
"Conversation.AutoremoveTimerRemovedUserYou" = "You disabled the auto-delete timer";
|
"Conversation.AutoremoveTimerRemovedUserYou" = "You disabled the auto-delete timer";
|
||||||
"Conversation.AutoremoveTimerRemovedUser" = "%1$@ disabled the auto-delete timer";
|
"Conversation.AutoremoveTimerRemovedUser" = "%1$@ disabled the auto-delete timer";
|
||||||
"Conversation.AutoremoveTimerSetGroup" = "A group admin set messages to automatically delete after %1$@";
|
"Conversation.AutoremoveTimerSetGroup" = "A group admin set messages to automatically delete after %1$@";
|
||||||
|
@ -9,6 +9,7 @@ import AnimationUI
|
|||||||
import AppBundle
|
import AppBundle
|
||||||
import AccountContext
|
import AccountContext
|
||||||
import Emoji
|
import Emoji
|
||||||
|
import Accelerate
|
||||||
|
|
||||||
private let deletedIcon = UIImage(bundleImageName: "Avatar/DeletedIcon")?.precomposed()
|
private let deletedIcon = UIImage(bundleImageName: "Avatar/DeletedIcon")?.precomposed()
|
||||||
private let phoneIcon = generateTintedImage(image: UIImage(bundleImageName: "Avatar/PhoneIcon"), color: .white)
|
private let phoneIcon = generateTintedImage(image: UIImage(bundleImageName: "Avatar/PhoneIcon"), color: .white)
|
||||||
@ -30,6 +31,7 @@ private class AvatarNodeParameters: NSObject {
|
|||||||
let theme: PresentationTheme?
|
let theme: PresentationTheme?
|
||||||
let accountPeerId: EnginePeer.Id?
|
let accountPeerId: EnginePeer.Id?
|
||||||
let peerId: EnginePeer.Id?
|
let peerId: EnginePeer.Id?
|
||||||
|
let colors: [UIColor]
|
||||||
let letters: [String]
|
let letters: [String]
|
||||||
let font: UIFont
|
let font: UIFont
|
||||||
let icon: AvatarNodeIcon
|
let icon: AvatarNodeIcon
|
||||||
@ -37,10 +39,11 @@ private class AvatarNodeParameters: NSObject {
|
|||||||
let hasImage: Bool
|
let hasImage: Bool
|
||||||
let clipStyle: AvatarNodeClipStyle
|
let clipStyle: AvatarNodeClipStyle
|
||||||
|
|
||||||
init(theme: PresentationTheme?, accountPeerId: EnginePeer.Id?, peerId: EnginePeer.Id?, letters: [String], font: UIFont, icon: AvatarNodeIcon, explicitColorIndex: Int?, hasImage: Bool, clipStyle: AvatarNodeClipStyle) {
|
init(theme: PresentationTheme?, accountPeerId: EnginePeer.Id?, peerId: EnginePeer.Id?, colors: [UIColor], letters: [String], font: UIFont, icon: AvatarNodeIcon, explicitColorIndex: Int?, hasImage: Bool, clipStyle: AvatarNodeClipStyle) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.accountPeerId = accountPeerId
|
self.accountPeerId = accountPeerId
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
|
self.colors = colors
|
||||||
self.letters = letters
|
self.letters = letters
|
||||||
self.font = font
|
self.font = font
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
@ -52,18 +55,71 @@ private class AvatarNodeParameters: NSObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedHasImage(_ hasImage: Bool) -> AvatarNodeParameters {
|
func withUpdatedHasImage(_ hasImage: Bool) -> AvatarNodeParameters {
|
||||||
return AvatarNodeParameters(theme: self.theme, accountPeerId: self.accountPeerId, peerId: self.peerId, letters: self.letters, font: self.font, icon: self.icon, explicitColorIndex: self.explicitColorIndex, hasImage: hasImage, clipStyle: self.clipStyle)
|
return AvatarNodeParameters(theme: self.theme, accountPeerId: self.accountPeerId, peerId: self.peerId, colors: self.colors, letters: self.letters, font: self.font, icon: self.icon, explicitColorIndex: self.explicitColorIndex, hasImage: hasImage, clipStyle: self.clipStyle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private let grayscaleColors: NSArray = [
|
private let grayscaleColors: [UIColor] = [
|
||||||
UIColor(rgb: 0xb1b1b1).cgColor, UIColor(rgb: 0xcdcdcd).cgColor
|
UIColor(rgb: 0xb1b1b1), UIColor(rgb: 0xcdcdcd)
|
||||||
]
|
]
|
||||||
|
|
||||||
private let savedMessagesColors: NSArray = [
|
private let savedMessagesColors: [UIColor] = [
|
||||||
UIColor(rgb: 0x2a9ef1).cgColor, UIColor(rgb: 0x72d5fd).cgColor
|
UIColor(rgb: 0x2a9ef1), UIColor(rgb: 0x72d5fd)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
private func calculateColors(explicitColorIndex: Int?, peerId: EnginePeer.Id?, icon: AvatarNodeIcon, theme: PresentationTheme?) -> [UIColor] {
|
||||||
|
let colorIndex: Int
|
||||||
|
if let explicitColorIndex = explicitColorIndex {
|
||||||
|
colorIndex = explicitColorIndex
|
||||||
|
} else {
|
||||||
|
if let peerId {
|
||||||
|
if peerId.namespace == .max {
|
||||||
|
colorIndex = -1
|
||||||
|
} else {
|
||||||
|
colorIndex = abs(Int(clamping: peerId.id._internalGetInt64Value()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
colorIndex = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let colors: [UIColor]
|
||||||
|
if icon != .none {
|
||||||
|
if case .deletedIcon = icon {
|
||||||
|
colors = grayscaleColors
|
||||||
|
} else if case .phoneIcon = icon {
|
||||||
|
colors = grayscaleColors
|
||||||
|
} else if case .savedMessagesIcon = icon {
|
||||||
|
colors = savedMessagesColors
|
||||||
|
} else if case .repliesIcon = icon {
|
||||||
|
colors = savedMessagesColors
|
||||||
|
} else if case .editAvatarIcon = icon, let theme {
|
||||||
|
colors = [theme.list.itemAccentColor.withAlphaComponent(0.1), theme.list.itemAccentColor.withAlphaComponent(0.1)]
|
||||||
|
} else if case let .archivedChatsIcon(hiddenByDefault) = icon, let theme = theme {
|
||||||
|
let backgroundColors: (UIColor, UIColor)
|
||||||
|
if hiddenByDefault {
|
||||||
|
backgroundColors = theme.chatList.unpinnedArchiveAvatarColor.backgroundColors.colors
|
||||||
|
} else {
|
||||||
|
backgroundColors = theme.chatList.pinnedArchiveAvatarColor.backgroundColors.colors
|
||||||
|
}
|
||||||
|
colors = [backgroundColors.1, backgroundColors.0]
|
||||||
|
} else {
|
||||||
|
colors = grayscaleColors
|
||||||
|
}
|
||||||
|
} else if colorIndex == -1 {
|
||||||
|
if let theme {
|
||||||
|
let backgroundColors = theme.chatList.unpinnedArchiveAvatarColor.backgroundColors.colors
|
||||||
|
colors = [backgroundColors.1, backgroundColors.0]
|
||||||
|
} else {
|
||||||
|
colors = grayscaleColors
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
colors = AvatarNode.gradientColors[colorIndex % AvatarNode.gradientColors.count]
|
||||||
|
}
|
||||||
|
|
||||||
|
return colors
|
||||||
|
}
|
||||||
|
|
||||||
public enum AvatarNodeExplicitIcon {
|
public enum AvatarNodeExplicitIcon {
|
||||||
case phone
|
case phone
|
||||||
}
|
}
|
||||||
@ -158,21 +214,21 @@ public final class AvatarEditOverlayNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class AvatarNode: ASDisplayNode {
|
public final class AvatarNode: ASDisplayNode {
|
||||||
public static let gradientColors: [NSArray] = [
|
public static let gradientColors: [[UIColor]] = [
|
||||||
[UIColor(rgb: 0xff516a).cgColor, UIColor(rgb: 0xff885e).cgColor],
|
[UIColor(rgb: 0xff516a), UIColor(rgb: 0xff885e)],
|
||||||
[UIColor(rgb: 0xffa85c).cgColor, UIColor(rgb: 0xffcd6a).cgColor],
|
[UIColor(rgb: 0xffa85c), UIColor(rgb: 0xffcd6a)],
|
||||||
[UIColor(rgb: 0x665fff).cgColor, UIColor(rgb: 0x82b1ff).cgColor],
|
[UIColor(rgb: 0x665fff), UIColor(rgb: 0x82b1ff)],
|
||||||
[UIColor(rgb: 0x54cb68).cgColor, UIColor(rgb: 0xa0de7e).cgColor],
|
[UIColor(rgb: 0x54cb68), UIColor(rgb: 0xa0de7e)],
|
||||||
[UIColor(rgb: 0x4acccd).cgColor, UIColor(rgb: 0x00fcfd).cgColor],
|
[UIColor(rgb: 0x4acccd), UIColor(rgb: 0x00fcfd)],
|
||||||
[UIColor(rgb: 0x2a9ef1).cgColor, UIColor(rgb: 0x72d5fd).cgColor],
|
[UIColor(rgb: 0x2a9ef1), UIColor(rgb: 0x72d5fd)],
|
||||||
[UIColor(rgb: 0xd669ed).cgColor, UIColor(rgb: 0xe0a2f3).cgColor],
|
[UIColor(rgb: 0xd669ed), UIColor(rgb: 0xe0a2f3)],
|
||||||
]
|
]
|
||||||
|
|
||||||
public var font: UIFont {
|
public var font: UIFont {
|
||||||
didSet {
|
didSet {
|
||||||
if oldValue.pointSize != font.pointSize {
|
if oldValue.pointSize != font.pointSize {
|
||||||
if let parameters = self.parameters {
|
if let parameters = self.parameters {
|
||||||
self.parameters = AvatarNodeParameters(theme: parameters.theme, accountPeerId: parameters.accountPeerId, peerId: parameters.peerId, letters: parameters.letters, font: self.font, icon: parameters.icon, explicitColorIndex: parameters.explicitColorIndex, hasImage: parameters.hasImage, clipStyle: parameters.clipStyle)
|
self.parameters = AvatarNodeParameters(theme: parameters.theme, accountPeerId: parameters.accountPeerId, peerId: parameters.peerId, colors: parameters.colors, letters: parameters.letters, font: self.font, icon: parameters.icon, explicitColorIndex: parameters.explicitColorIndex, hasImage: parameters.hasImage, clipStyle: parameters.clipStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.displaySuspended {
|
if !self.displaySuspended {
|
||||||
@ -193,6 +249,29 @@ public final class AvatarNode: ASDisplayNode {
|
|||||||
private var state: AvatarNodeState = .empty
|
private var state: AvatarNodeState = .empty
|
||||||
|
|
||||||
public var unroundedImage: UIImage?
|
public var unroundedImage: UIImage?
|
||||||
|
private var currentImage: UIImage?
|
||||||
|
|
||||||
|
public var badgeView: AvatarBadgeView? {
|
||||||
|
didSet {
|
||||||
|
if self.badgeView !== oldValue {
|
||||||
|
if let badgeView = self.badgeView, let parameters = self.parameters {
|
||||||
|
if parameters.hasImage {
|
||||||
|
if let currentImage = self.currentImage {
|
||||||
|
badgeView.update(content: .image(currentImage))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let badgeColor: UIColor
|
||||||
|
if parameters.colors.isEmpty {
|
||||||
|
badgeColor = .white
|
||||||
|
} else {
|
||||||
|
badgeColor = parameters.colors[parameters.colors.count - 1]
|
||||||
|
}
|
||||||
|
badgeView.update(content: .color(badgeColor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private let imageReady = Promise<Bool>(false)
|
private let imageReady = Promise<Bool>(false)
|
||||||
public var ready: Signal<Void, NoError> {
|
public var ready: Signal<Void, NoError> {
|
||||||
@ -217,6 +296,22 @@ public final class AvatarNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.imageNode.isLayerBacked = true
|
self.imageNode.isLayerBacked = true
|
||||||
self.addSubnode(self.imageNode)
|
self.addSubnode(self.imageNode)
|
||||||
|
|
||||||
|
self.imageNode.contentUpdated = { [weak self] image in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.currentImage = image
|
||||||
|
|
||||||
|
guard let badgeView = self.badgeView, let parameters = self.parameters else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if parameters.hasImage, let image {
|
||||||
|
badgeView.update(content: .image(image))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func didLoad() {
|
override public func didLoad() {
|
||||||
@ -365,7 +460,7 @@ public final class AvatarNode: ASDisplayNode {
|
|||||||
self.editOverlayNode?.isHidden = true
|
self.editOverlayNode?.isHidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
parameters = AvatarNodeParameters(theme: theme, accountPeerId: account.peerId, peerId: peer.id, letters: peer.displayLetters, font: self.font, icon: icon, explicitColorIndex: nil, hasImage: true, clipStyle: clipStyle)
|
parameters = AvatarNodeParameters(theme: theme, accountPeerId: account.peerId, peerId: peer.id, colors: calculateColors(explicitColorIndex: nil, peerId: peer.id, icon: icon, theme: theme), letters: peer.displayLetters, font: self.font, icon: icon, explicitColorIndex: nil, hasImage: true, clipStyle: clipStyle)
|
||||||
} else {
|
} else {
|
||||||
self.imageReady.set(.single(true))
|
self.imageReady.set(.single(true))
|
||||||
self.displaySuspended = false
|
self.displaySuspended = false
|
||||||
@ -374,7 +469,18 @@ public final class AvatarNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.editOverlayNode?.isHidden = true
|
self.editOverlayNode?.isHidden = true
|
||||||
parameters = AvatarNodeParameters(theme: theme, accountPeerId: account.peerId, peerId: peer?.id ?? EnginePeer.Id(0), letters: peer?.displayLetters ?? [], font: self.font, icon: icon, explicitColorIndex: nil, hasImage: false, clipStyle: clipStyle)
|
let colors = calculateColors(explicitColorIndex: nil, peerId: peer?.id ?? EnginePeer.Id(0), icon: icon, theme: theme)
|
||||||
|
parameters = AvatarNodeParameters(theme: theme, accountPeerId: account.peerId, peerId: peer?.id ?? EnginePeer.Id(0), colors: colors, letters: peer?.displayLetters ?? [], font: self.font, icon: icon, explicitColorIndex: nil, hasImage: false, clipStyle: clipStyle)
|
||||||
|
|
||||||
|
if let badgeView = self.badgeView {
|
||||||
|
let badgeColor: UIColor
|
||||||
|
if colors.isEmpty {
|
||||||
|
badgeColor = .white
|
||||||
|
} else {
|
||||||
|
badgeColor = colors[colors.count - 1]
|
||||||
|
}
|
||||||
|
badgeView.update(content: .color(badgeColor))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if self.parameters == nil || self.parameters != parameters {
|
if self.parameters == nil || self.parameters != parameters {
|
||||||
self.parameters = parameters
|
self.parameters = parameters
|
||||||
@ -400,9 +506,9 @@ public final class AvatarNode: ASDisplayNode {
|
|||||||
|
|
||||||
let parameters: AvatarNodeParameters
|
let parameters: AvatarNodeParameters
|
||||||
if let icon = icon, case .phone = icon {
|
if let icon = icon, case .phone = icon {
|
||||||
parameters = AvatarNodeParameters(theme: nil, accountPeerId: nil, peerId: nil, letters: [], font: self.font, icon: .phoneIcon, explicitColorIndex: explicitIndex, hasImage: false, clipStyle: .round)
|
parameters = AvatarNodeParameters(theme: nil, accountPeerId: nil, peerId: nil, colors: calculateColors(explicitColorIndex: explicitIndex, peerId: nil, icon: .phoneIcon, theme: nil), letters: [], font: self.font, icon: .phoneIcon, explicitColorIndex: explicitIndex, hasImage: false, clipStyle: .round)
|
||||||
} else {
|
} else {
|
||||||
parameters = AvatarNodeParameters(theme: nil, accountPeerId: nil, peerId: nil, letters: letters, font: self.font, icon: .none, explicitColorIndex: explicitIndex, hasImage: false, clipStyle: .round)
|
parameters = AvatarNodeParameters(theme: nil, accountPeerId: nil, peerId: nil, colors: calculateColors(explicitColorIndex: explicitIndex, peerId: nil, icon: .none, theme: nil), letters: letters, font: self.font, icon: .none, explicitColorIndex: explicitIndex, hasImage: false, clipStyle: .round)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.displaySuspended = true
|
self.displaySuspended = true
|
||||||
@ -433,8 +539,10 @@ public final class AvatarNode: ASDisplayNode {
|
|||||||
context.fill(bounds)
|
context.fill(bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
let colorIndex: Int
|
let colors: [UIColor]
|
||||||
if let parameters = parameters as? AvatarNodeParameters {
|
if let parameters = parameters as? AvatarNodeParameters {
|
||||||
|
colors = parameters.colors
|
||||||
|
|
||||||
if case .round = parameters.clipStyle {
|
if case .round = parameters.clipStyle {
|
||||||
context.beginPath()
|
context.beginPath()
|
||||||
context.addEllipse(in: CGRect(x: 0.0, y: 0.0, width: bounds.size.width, height:
|
context.addEllipse(in: CGRect(x: 0.0, y: 0.0, width: bounds.size.width, height:
|
||||||
@ -445,59 +553,21 @@ public final class AvatarNode: ASDisplayNode {
|
|||||||
context.addPath(UIBezierPath(roundedRect: CGRect(x: 0.0, y: 0.0, width: bounds.size.width, height: bounds.size.height), cornerRadius: floor(bounds.size.width * 0.25)).cgPath)
|
context.addPath(UIBezierPath(roundedRect: CGRect(x: 0.0, y: 0.0, width: bounds.size.width, height: bounds.size.height), cornerRadius: floor(bounds.size.width * 0.25)).cgPath)
|
||||||
context.clip()
|
context.clip()
|
||||||
}
|
}
|
||||||
|
|
||||||
if let explicitColorIndex = parameters.explicitColorIndex {
|
|
||||||
colorIndex = explicitColorIndex
|
|
||||||
} else {
|
|
||||||
if let peerId = parameters.peerId {
|
|
||||||
if peerId.namespace == .max {
|
|
||||||
colorIndex = -1
|
|
||||||
} else {
|
|
||||||
colorIndex = abs(Int(clamping: peerId.id._internalGetInt64Value()))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
colorIndex = -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
colorIndex = -1
|
colors = grayscaleColors
|
||||||
}
|
}
|
||||||
|
|
||||||
let colorsArray: NSArray
|
let colorsArray: NSArray = colors.map(\.cgColor) as NSArray
|
||||||
|
|
||||||
var iconColor = UIColor.white
|
var iconColor = UIColor.white
|
||||||
if let parameters = parameters as? AvatarNodeParameters, parameters.icon != .none {
|
if let parameters = parameters as? AvatarNodeParameters, parameters.icon != .none {
|
||||||
if case .deletedIcon = parameters.icon {
|
if case let .archivedChatsIcon(hiddenByDefault) = parameters.icon, let theme = parameters.theme {
|
||||||
colorsArray = grayscaleColors
|
|
||||||
} else if case .phoneIcon = parameters.icon {
|
|
||||||
colorsArray = grayscaleColors
|
|
||||||
} else if case .savedMessagesIcon = parameters.icon {
|
|
||||||
colorsArray = savedMessagesColors
|
|
||||||
} else if case .repliesIcon = parameters.icon {
|
|
||||||
colorsArray = savedMessagesColors
|
|
||||||
} else if case .editAvatarIcon = parameters.icon, let theme = parameters.theme {
|
|
||||||
colorsArray = [theme.list.itemAccentColor.withAlphaComponent(0.1).cgColor, theme.list.itemAccentColor.withAlphaComponent(0.1).cgColor]
|
|
||||||
} else if case let .archivedChatsIcon(hiddenByDefault) = parameters.icon, let theme = parameters.theme {
|
|
||||||
let backgroundColors: (UIColor, UIColor)
|
|
||||||
if hiddenByDefault {
|
if hiddenByDefault {
|
||||||
iconColor = theme.chatList.unpinnedArchiveAvatarColor.foregroundColor
|
iconColor = theme.chatList.unpinnedArchiveAvatarColor.foregroundColor
|
||||||
backgroundColors = theme.chatList.unpinnedArchiveAvatarColor.backgroundColors.colors
|
|
||||||
} else {
|
} else {
|
||||||
iconColor = theme.chatList.pinnedArchiveAvatarColor.foregroundColor
|
iconColor = theme.chatList.pinnedArchiveAvatarColor.foregroundColor
|
||||||
backgroundColors = theme.chatList.pinnedArchiveAvatarColor.backgroundColors.colors
|
|
||||||
}
|
}
|
||||||
colorsArray = [backgroundColors.1.cgColor, backgroundColors.0.cgColor]
|
|
||||||
} else {
|
|
||||||
colorsArray = grayscaleColors
|
|
||||||
}
|
}
|
||||||
} else if colorIndex == -1 {
|
|
||||||
if let parameters = parameters as? AvatarNodeParameters, let theme = parameters.theme {
|
|
||||||
let colors = theme.chatList.unpinnedArchiveAvatarColor.backgroundColors.colors
|
|
||||||
colorsArray = [colors.1.cgColor, colors.0.cgColor]
|
|
||||||
} else {
|
|
||||||
colorsArray = grayscaleColors
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
colorsArray = AvatarNode.gradientColors[colorIndex % AvatarNode.gradientColors.count]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var locations: [CGFloat] = [1.0, 0.0]
|
var locations: [CGFloat] = [1.0, 0.0]
|
||||||
@ -636,9 +706,9 @@ public func drawPeerAvatarLetters(context: CGContext, size: CGSize, round: Bool
|
|||||||
|
|
||||||
let colorsArray: NSArray
|
let colorsArray: NSArray
|
||||||
if colorIndex == -1 {
|
if colorIndex == -1 {
|
||||||
colorsArray = grayscaleColors
|
colorsArray = grayscaleColors.map(\.cgColor) as NSArray
|
||||||
} else {
|
} else {
|
||||||
colorsArray = AvatarNode.gradientColors[colorIndex % AvatarNode.gradientColors.count]
|
colorsArray = AvatarNode.gradientColors[colorIndex % AvatarNode.gradientColors.count].map(\.cgColor) as NSArray
|
||||||
}
|
}
|
||||||
|
|
||||||
var locations: [CGFloat] = [1.0, 0.0]
|
var locations: [CGFloat] = [1.0, 0.0]
|
||||||
@ -707,9 +777,9 @@ public func generateAvatarImage(size: CGSize, icon: UIImage?, iconScale: CGFloat
|
|||||||
|
|
||||||
let colorsArray: NSArray
|
let colorsArray: NSArray
|
||||||
if colorIndex == -1 {
|
if colorIndex == -1 {
|
||||||
colorsArray = grayscaleColors
|
colorsArray = grayscaleColors.map(\.cgColor) as NSArray
|
||||||
} else {
|
} else {
|
||||||
colorsArray = AvatarNode.gradientColors[colorIndex % AvatarNode.gradientColors.count]
|
colorsArray = AvatarNode.gradientColors[colorIndex % AvatarNode.gradientColors.count].map(\.cgColor) as NSArray
|
||||||
}
|
}
|
||||||
|
|
||||||
var locations: [CGFloat] = [1.0, 0.0]
|
var locations: [CGFloat] = [1.0, 0.0]
|
||||||
@ -734,3 +804,190 @@ public func generateAvatarImage(size: CGSize, icon: UIImage?, iconScale: CGFloat
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class AvatarBadgeView: UIImageView {
|
||||||
|
enum OriginalContent: Equatable {
|
||||||
|
case color(UIColor)
|
||||||
|
case image(UIImage)
|
||||||
|
|
||||||
|
static func ==(lhs: OriginalContent, rhs: OriginalContent) -> Bool {
|
||||||
|
switch lhs {
|
||||||
|
case let .color(color):
|
||||||
|
if case .color(color) = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .image(lhsImage):
|
||||||
|
if case let .image(rhsImage) = rhs {
|
||||||
|
return lhsImage === rhsImage
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct Parameters: Equatable {
|
||||||
|
var size: CGSize
|
||||||
|
var text: String
|
||||||
|
}
|
||||||
|
|
||||||
|
private var originalContent: OriginalContent?
|
||||||
|
private var parameters: Parameters?
|
||||||
|
|
||||||
|
override public init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(content: OriginalContent) {
|
||||||
|
if self.originalContent != content {
|
||||||
|
self.originalContent = content
|
||||||
|
self.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func update(size: CGSize, text: String) {
|
||||||
|
let parameters = Parameters(size: size, text: text)
|
||||||
|
if self.parameters != parameters {
|
||||||
|
self.parameters = parameters
|
||||||
|
self.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func update() {
|
||||||
|
guard let originalContent = self.originalContent, let parameters = self.parameters else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let blurredWidth = 16
|
||||||
|
let blurredHeight = 16
|
||||||
|
guard let blurredContext = DrawingContext(size: CGSize(width: CGFloat(blurredWidth), height: CGFloat(blurredHeight)), scale: 1.0, opaque: true) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let blurredSize = CGSize(width: CGFloat(blurredWidth), height: CGFloat(blurredHeight))
|
||||||
|
blurredContext.withContext { c in
|
||||||
|
switch originalContent {
|
||||||
|
case let .color(color):
|
||||||
|
c.setFillColor(color.cgColor)
|
||||||
|
c.fill(CGRect(origin: CGPoint(), size: blurredSize))
|
||||||
|
case let .image(image):
|
||||||
|
c.scaleBy(x: blurredSize.width / parameters.size.width, y: blurredSize.height / parameters.size.height)
|
||||||
|
let offsetFactor: CGFloat = 1.0 - 0.7071
|
||||||
|
let imageFrame = CGRect(origin: CGPoint(x: parameters.size.width - image.size.width + offsetFactor * parameters.size.width, y: parameters.size.height - image.size.height + offsetFactor * parameters.size.height), size: image.size)
|
||||||
|
|
||||||
|
UIGraphicsPushContext(c)
|
||||||
|
image.draw(in: imageFrame)
|
||||||
|
UIGraphicsPopContext()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var destinationBuffer = vImage_Buffer()
|
||||||
|
destinationBuffer.width = UInt(blurredWidth)
|
||||||
|
destinationBuffer.height = UInt(blurredHeight)
|
||||||
|
destinationBuffer.data = blurredContext.bytes
|
||||||
|
destinationBuffer.rowBytes = blurredContext.bytesPerRow
|
||||||
|
|
||||||
|
vImageBoxConvolve_ARGB8888(
|
||||||
|
&destinationBuffer,
|
||||||
|
&destinationBuffer,
|
||||||
|
nil,
|
||||||
|
0, 0,
|
||||||
|
UInt32(15),
|
||||||
|
UInt32(15),
|
||||||
|
nil,
|
||||||
|
vImage_Flags(kvImageEdgeExtend)
|
||||||
|
)
|
||||||
|
|
||||||
|
let divisor: Int32 = 0x1000
|
||||||
|
|
||||||
|
let rwgt: CGFloat = 0.3086
|
||||||
|
let gwgt: CGFloat = 0.6094
|
||||||
|
let bwgt: CGFloat = 0.0820
|
||||||
|
|
||||||
|
let adjustSaturation: CGFloat = 1.9
|
||||||
|
|
||||||
|
let a = (1.0 - adjustSaturation) * rwgt + adjustSaturation
|
||||||
|
let b = (1.0 - adjustSaturation) * rwgt
|
||||||
|
let c = (1.0 - adjustSaturation) * rwgt
|
||||||
|
let d = (1.0 - adjustSaturation) * gwgt
|
||||||
|
let e = (1.0 - adjustSaturation) * gwgt + adjustSaturation
|
||||||
|
let f = (1.0 - adjustSaturation) * gwgt
|
||||||
|
let g = (1.0 - adjustSaturation) * bwgt
|
||||||
|
let h = (1.0 - adjustSaturation) * bwgt
|
||||||
|
let i = (1.0 - adjustSaturation) * bwgt + adjustSaturation
|
||||||
|
|
||||||
|
let satMatrix: [CGFloat] = [
|
||||||
|
a, b, c, 0,
|
||||||
|
d, e, f, 0,
|
||||||
|
g, h, i, 0,
|
||||||
|
0, 0, 0, 1
|
||||||
|
]
|
||||||
|
|
||||||
|
var matrix: [Int16] = satMatrix.map { value in
|
||||||
|
return Int16(value * CGFloat(divisor))
|
||||||
|
}
|
||||||
|
|
||||||
|
vImageMatrixMultiply_ARGB8888(&destinationBuffer, &destinationBuffer, &matrix, divisor, nil, nil, vImage_Flags(kvImageDoNotTile))
|
||||||
|
|
||||||
|
guard let blurredImage = blurredContext.generateImage() else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.image = generateImage(parameters.size, rotatedContext: { size, context in
|
||||||
|
UIGraphicsPushContext(context)
|
||||||
|
|
||||||
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
context.setBlendMode(.copy)
|
||||||
|
context.setFillColor(UIColor.black.cgColor)
|
||||||
|
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
context.setBlendMode(.sourceIn)
|
||||||
|
|
||||||
|
blurredImage.draw(in: CGRect(origin: CGPoint(), size: size), blendMode: .sourceIn, alpha: 1.0)
|
||||||
|
|
||||||
|
context.setBlendMode(.normal)
|
||||||
|
|
||||||
|
context.setFillColor(UIColor(white: 0.0, alpha: 0.05).cgColor)
|
||||||
|
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
let string = NSAttributedString(string: parameters.text, font: Font.bold(floor(parameters.size.height * 0.48)), textColor: .white)
|
||||||
|
let stringBounds = string.boundingRect(with: CGSize(width: 100.0, height: 100.0), options: .usesLineFragmentOrigin, context: nil)
|
||||||
|
string.draw(at: CGPoint(x: stringBounds.minX + floorToScreenPixels((size.width - stringBounds.width) / 2.0), y: stringBounds.minY + floorToScreenPixels((size.height - stringBounds.height) / 2.0)))
|
||||||
|
|
||||||
|
let lineWidth: CGFloat = 1.5
|
||||||
|
let lineInset: CGFloat = 2.0
|
||||||
|
let lineRadius: CGFloat = size.width * 0.5 - lineInset - lineWidth * 0.5
|
||||||
|
context.setLineWidth(lineWidth)
|
||||||
|
context.setStrokeColor(UIColor.white.cgColor)
|
||||||
|
context.setLineCap(.round)
|
||||||
|
|
||||||
|
context.addArc(center: CGPoint(x: size.width * 0.5, y: size.height * 0.5), radius: lineRadius, startAngle: CGFloat.pi * 0.5, endAngle: -CGFloat.pi * 0.5, clockwise: false)
|
||||||
|
context.strokePath()
|
||||||
|
|
||||||
|
|
||||||
|
let sectionAngle: CGFloat = CGFloat.pi / 11.0
|
||||||
|
|
||||||
|
for i in 0 ..< 10 {
|
||||||
|
if i % 2 == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let startAngle = CGFloat.pi * 0.5 - CGFloat(i) * sectionAngle - sectionAngle * 0.1
|
||||||
|
let endAngle = startAngle - sectionAngle * 0.8
|
||||||
|
|
||||||
|
context.addArc(center: CGPoint(x: size.width * 0.5, y: size.height * 0.5), radius: lineRadius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
|
||||||
|
context.strokePath()
|
||||||
|
}
|
||||||
|
|
||||||
|
//context.strokeEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: 2.0 + lineWidth * 0.5, dy: 2.0 + lineWidth * 0.5))
|
||||||
|
|
||||||
|
UIGraphicsPopContext()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1228,7 +1228,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
var joined = false
|
var joined = false
|
||||||
if case let .peer(messages, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = item.content, let message = messages.first {
|
if case let .peer(peerData) = item.content, let message = peerData.messages.first {
|
||||||
for media in message.media {
|
for media in message.media {
|
||||||
if let action = media as? TelegramMediaAction, action.action == .peerJoined {
|
if let action = media as? TelegramMediaAction, action.action == .peerJoined {
|
||||||
joined = true
|
joined = true
|
||||||
@ -1242,7 +1242,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
chatListController.navigationPresentation = .master
|
chatListController.navigationPresentation = .master
|
||||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: archiveContextMenuItems(context: strongSelf.context, groupId: groupId._asGroup(), chatListController: strongSelf) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
|
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: archiveContextMenuItems(context: strongSelf.context, groupId: groupId._asGroup(), chatListController: strongSelf) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
|
||||||
strongSelf.presentInGlobalOverlay(contextController)
|
strongSelf.presentInGlobalOverlay(contextController)
|
||||||
case let .peer(_, peer, threadInfo, _, _, _, _, _, _, _, promoInfo, _, _, _, _, _):
|
case let .peer(peerData):
|
||||||
|
let peer = peerData.peer
|
||||||
|
let threadInfo = peerData.threadInfo
|
||||||
|
let promoInfo = peerData.promoInfo
|
||||||
|
|
||||||
switch item.index {
|
switch item.index {
|
||||||
case .chatList:
|
case .chatList:
|
||||||
if case let .channel(channel) = peer.peer, channel.flags.contains(.isForum) {
|
if case let .channel(channel) = peer.peer, channel.flags.contains(.isForum) {
|
||||||
|
@ -215,7 +215,25 @@ private final class ChatListShimmerNode: ASDisplayNode {
|
|||||||
)
|
)
|
||||||
let readState = EnginePeerReadCounters()
|
let readState = EnginePeerReadCounters()
|
||||||
|
|
||||||
return ChatListItem(presentationData: chatListPresentationData, context: context, chatListLocation: .chatList(groupId: .root), filterData: nil, index: .chatList(EngineChatList.Item.Index.ChatList(pinningIndex: 0, messageIndex: EngineMessage.Index(id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1))), content: .peer(messages: [message], peer: EngineRenderedPeer(peer: peer1), threadInfo: nil, combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, hasUnseenMentions: false, hasUnseenReactions: false, draftState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false, forumTopicData: nil, topForumTopicItems: []), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
return ChatListItem(presentationData: chatListPresentationData, context: context, chatListLocation: .chatList(groupId: .root), filterData: nil, index: .chatList(EngineChatList.Item.Index.ChatList(pinningIndex: 0, messageIndex: EngineMessage.Index(id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1))), content: .peer(ChatListItemContent.PeerData(
|
||||||
|
messages: [message],
|
||||||
|
peer: EngineRenderedPeer(peer: peer1),
|
||||||
|
threadInfo: nil,
|
||||||
|
combinedReadState: readState,
|
||||||
|
isRemovedFromTotalUnreadCount: false,
|
||||||
|
presence: nil,
|
||||||
|
hasUnseenMentions: false,
|
||||||
|
hasUnseenReactions: false,
|
||||||
|
draftState: nil,
|
||||||
|
inputActivities: nil,
|
||||||
|
promoInfo: nil,
|
||||||
|
ignoreUnreadBadge: false,
|
||||||
|
displayAsMessage: false,
|
||||||
|
hasFailedMessages: false,
|
||||||
|
forumTopicData: nil,
|
||||||
|
topForumTopicItems: [],
|
||||||
|
autoremoveTimeout: nil
|
||||||
|
)), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemNodes: [ChatListItemNode] = []
|
var itemNodes: [ChatListItemNode] = []
|
||||||
|
@ -749,7 +749,25 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
index = .chatList( EngineChatList.Item.Index.ChatList(pinningIndex: nil, messageIndex: message.index))
|
index = .chatList( EngineChatList.Item.Index.ChatList(pinningIndex: nil, messageIndex: message.index))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ChatListItem(presentationData: presentationData, context: context, chatListLocation: location, filterData: nil, index: index, content: .peer(messages: [message], peer: peer, threadInfo: chatThreadInfo, combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, hasUnseenMentions: false, hasUnseenReactions: false, draftState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: true, displayAsMessage: false, hasFailedMessages: false, forumTopicData: nil, topForumTopicItems: []), editing: false, hasActiveRevealControls: false, selected: false, header: tagMask == nil ? header : nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
return ChatListItem(presentationData: presentationData, context: context, chatListLocation: location, filterData: nil, index: index, content: .peer(ChatListItemContent.PeerData(
|
||||||
|
messages: [message],
|
||||||
|
peer: peer,
|
||||||
|
threadInfo: chatThreadInfo,
|
||||||
|
combinedReadState: readState,
|
||||||
|
isRemovedFromTotalUnreadCount: false,
|
||||||
|
presence: nil,
|
||||||
|
hasUnseenMentions: false,
|
||||||
|
hasUnseenReactions: false,
|
||||||
|
draftState: nil,
|
||||||
|
inputActivities: nil,
|
||||||
|
promoInfo: nil,
|
||||||
|
ignoreUnreadBadge: true,
|
||||||
|
displayAsMessage: false,
|
||||||
|
hasFailedMessages: false,
|
||||||
|
forumTopicData: nil,
|
||||||
|
topForumTopicItems: [],
|
||||||
|
autoremoveTimeout: nil
|
||||||
|
)), editing: false, hasActiveRevealControls: false, selected: false, header: tagMask == nil ? header : nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
||||||
}
|
}
|
||||||
case let .addContact(phoneNumber, theme, strings):
|
case let .addContact(phoneNumber, theme, strings):
|
||||||
return ContactsAddItem(theme: theme, strings: strings, phoneNumber: phoneNumber, header: ChatListSearchItemHeader(type: .phoneNumber, theme: theme, strings: strings, actionTitle: nil, action: nil), action: {
|
return ContactsAddItem(theme: theme, strings: strings, phoneNumber: phoneNumber, header: ChatListSearchItemHeader(type: .phoneNumber, theme: theme, strings: strings, actionTitle: nil, action: nil), action: {
|
||||||
@ -1878,8 +1896,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(messages, peer, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(peerData):
|
||||||
if let peer = peer.peer, let message = messages.first {
|
if let peer = peerData.peer.peer, let message = peerData.messages.first {
|
||||||
peerContextAction(peer, .search(message.id), node, gesture, location)
|
peerContextAction(peer, .search(message.id), node, gesture, location)
|
||||||
}
|
}
|
||||||
case .groupReference:
|
case .groupReference:
|
||||||
@ -2935,8 +2953,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
bounds = selectedItemNode.bounds
|
bounds = selectedItemNode.bounds
|
||||||
}
|
}
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(messages, peer, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(peerData):
|
||||||
return (selectedItemNode.view, bounds, messages.last?.id ?? peer.peerId)
|
return (selectedItemNode.view, bounds, peerData.messages.last?.id ?? peerData.peer.peerId)
|
||||||
case let .groupReference(groupId, _, _, _, _):
|
case let .groupReference(groupId, _, _, _, _):
|
||||||
return (selectedItemNode.view, bounds, groupId)
|
return (selectedItemNode.view, bounds, groupId)
|
||||||
}
|
}
|
||||||
@ -3129,7 +3147,25 @@ private final class ChatListSearchShimmerNode: ASDisplayNode {
|
|||||||
associatedThreadInfo: nil
|
associatedThreadInfo: nil
|
||||||
)
|
)
|
||||||
let readState = EnginePeerReadCounters()
|
let readState = EnginePeerReadCounters()
|
||||||
return ChatListItem(presentationData: chatListPresentationData, context: context, chatListLocation: .chatList(groupId: .root), filterData: nil, index: .chatList(EngineChatList.Item.Index.ChatList(pinningIndex: 0, messageIndex: EngineMessage.Index(id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1))), content: .peer(messages: [message], peer: EngineRenderedPeer(peer: peer1), threadInfo: nil, combinedReadState: readState, isRemovedFromTotalUnreadCount: false, presence: nil, hasUnseenMentions: false, hasUnseenReactions: false, draftState: nil, inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false, forumTopicData: nil, topForumTopicItems: []), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
return ChatListItem(presentationData: chatListPresentationData, context: context, chatListLocation: .chatList(groupId: .root), filterData: nil, index: .chatList(EngineChatList.Item.Index.ChatList(pinningIndex: 0, messageIndex: EngineMessage.Index(id: EngineMessage.Id(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1))), content: .peer(ChatListItemContent.PeerData(
|
||||||
|
messages: [message],
|
||||||
|
peer: EngineRenderedPeer(peer: peer1),
|
||||||
|
threadInfo: nil,
|
||||||
|
combinedReadState: readState,
|
||||||
|
isRemovedFromTotalUnreadCount: false,
|
||||||
|
presence: nil,
|
||||||
|
hasUnseenMentions: false,
|
||||||
|
hasUnseenReactions: false,
|
||||||
|
draftState: nil,
|
||||||
|
inputActivities: nil,
|
||||||
|
promoInfo: nil,
|
||||||
|
ignoreUnreadBadge: false,
|
||||||
|
displayAsMessage: false,
|
||||||
|
hasFailedMessages: false,
|
||||||
|
forumTopicData: nil,
|
||||||
|
topForumTopicItems: [],
|
||||||
|
autoremoveTimeout: nil
|
||||||
|
)), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
||||||
case .media:
|
case .media:
|
||||||
return nil
|
return nil
|
||||||
case .links:
|
case .links:
|
||||||
|
@ -64,16 +64,74 @@ public enum ChatListItemContent {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct PeerData {
|
||||||
|
public var messages: [EngineMessage]
|
||||||
|
public var peer: EngineRenderedPeer
|
||||||
|
public var threadInfo: ThreadInfo?
|
||||||
|
public var combinedReadState: EnginePeerReadCounters?
|
||||||
|
public var isRemovedFromTotalUnreadCount: Bool
|
||||||
|
public var presence: EnginePeer.Presence?
|
||||||
|
public var hasUnseenMentions: Bool
|
||||||
|
public var hasUnseenReactions: Bool
|
||||||
|
public var draftState: DraftState?
|
||||||
|
public var inputActivities: [(EnginePeer, PeerInputActivity)]?
|
||||||
|
public var promoInfo: ChatListNodeEntryPromoInfo?
|
||||||
|
public var ignoreUnreadBadge: Bool
|
||||||
|
public var displayAsMessage: Bool
|
||||||
|
public var hasFailedMessages: Bool
|
||||||
|
public var forumTopicData: EngineChatList.ForumTopicData?
|
||||||
|
public var topForumTopicItems: [EngineChatList.ForumTopicData]
|
||||||
|
public var autoremoveTimeout: Int32?
|
||||||
|
|
||||||
|
public init(
|
||||||
|
messages: [EngineMessage],
|
||||||
|
peer: EngineRenderedPeer,
|
||||||
|
threadInfo: ThreadInfo?,
|
||||||
|
combinedReadState: EnginePeerReadCounters?,
|
||||||
|
isRemovedFromTotalUnreadCount: Bool,
|
||||||
|
presence: EnginePeer.Presence?,
|
||||||
|
hasUnseenMentions: Bool,
|
||||||
|
hasUnseenReactions: Bool,
|
||||||
|
draftState: DraftState?,
|
||||||
|
inputActivities: [(EnginePeer, PeerInputActivity)]?,
|
||||||
|
promoInfo: ChatListNodeEntryPromoInfo?,
|
||||||
|
ignoreUnreadBadge: Bool,
|
||||||
|
displayAsMessage: Bool,
|
||||||
|
hasFailedMessages: Bool,
|
||||||
|
forumTopicData: EngineChatList.ForumTopicData?,
|
||||||
|
topForumTopicItems: [EngineChatList.ForumTopicData],
|
||||||
|
autoremoveTimeout: Int32?
|
||||||
|
) {
|
||||||
|
self.messages = messages
|
||||||
|
self.peer = peer
|
||||||
|
self.threadInfo = threadInfo
|
||||||
|
self.combinedReadState = combinedReadState
|
||||||
|
self.isRemovedFromTotalUnreadCount = isRemovedFromTotalUnreadCount
|
||||||
|
self.presence = presence
|
||||||
|
self.hasUnseenMentions = hasUnseenMentions
|
||||||
|
self.hasUnseenReactions = hasUnseenReactions
|
||||||
|
self.draftState = draftState
|
||||||
|
self.inputActivities = inputActivities
|
||||||
|
self.promoInfo = promoInfo
|
||||||
|
self.ignoreUnreadBadge = ignoreUnreadBadge
|
||||||
|
self.displayAsMessage = displayAsMessage
|
||||||
|
self.hasFailedMessages = hasFailedMessages
|
||||||
|
self.forumTopicData = forumTopicData
|
||||||
|
self.topForumTopicItems = topForumTopicItems
|
||||||
|
self.autoremoveTimeout = autoremoveTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case peer(messages: [EngineMessage], peer: EngineRenderedPeer, threadInfo: ThreadInfo?, combinedReadState: EnginePeerReadCounters?, isRemovedFromTotalUnreadCount: Bool, presence: EnginePeer.Presence?, hasUnseenMentions: Bool, hasUnseenReactions: Bool, draftState: DraftState?, inputActivities: [(EnginePeer, PeerInputActivity)]?, promoInfo: ChatListNodeEntryPromoInfo?, ignoreUnreadBadge: Bool, displayAsMessage: Bool, hasFailedMessages: Bool, forumTopicData: EngineChatList.ForumTopicData?, topForumTopicItems: [EngineChatList.ForumTopicData])
|
case peer(PeerData)
|
||||||
case groupReference(groupId: EngineChatList.Group, peers: [EngineChatList.GroupItem.Item], message: EngineMessage?, unreadCount: Int, hiddenByDefault: Bool)
|
case groupReference(groupId: EngineChatList.Group, peers: [EngineChatList.GroupItem.Item], message: EngineMessage?, unreadCount: Int, hiddenByDefault: Bool)
|
||||||
|
|
||||||
public var chatLocation: ChatLocation? {
|
public var chatLocation: ChatLocation? {
|
||||||
switch self {
|
switch self {
|
||||||
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(peerData):
|
||||||
return .peer(id: peer.peerId)
|
return .peer(id: peerData.peer.peerId)
|
||||||
case .groupReference:
|
case .groupReference:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,23 +236,23 @@ public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
|
|||||||
|
|
||||||
public func selected(listView: ListView) {
|
public func selected(listView: ListView) {
|
||||||
switch self.content {
|
switch self.content {
|
||||||
case let .peer(messages, peer, _, _, _, _, _, _, _, _, promoInfo, _, _, _, _, _):
|
case let .peer(peerData):
|
||||||
if let message = messages.last, let peer = peer.peer {
|
if let message = peerData.messages.last, let peer = peerData.peer.peer {
|
||||||
var threadId: Int64?
|
var threadId: Int64?
|
||||||
if case let .forum(_, _, threadIdValue, _, _) = self.index {
|
if case let .forum(_, _, threadIdValue, _, _) = self.index {
|
||||||
threadId = threadIdValue
|
threadId = threadIdValue
|
||||||
}
|
|
||||||
if threadId == nil, self.interaction.searchTextHighightState != nil, case let .channel(channel) = peer, channel.flags.contains(.isForum) {
|
|
||||||
threadId = message.threadId
|
|
||||||
}
|
|
||||||
self.interaction.messageSelected(peer, threadId, message, promoInfo)
|
|
||||||
} else if let peer = peer.peer {
|
|
||||||
self.interaction.peerSelected(peer, nil, nil, promoInfo)
|
|
||||||
} else if let peer = peer.peers[peer.peerId] {
|
|
||||||
self.interaction.peerSelected(peer, nil, nil, promoInfo)
|
|
||||||
}
|
}
|
||||||
case let .groupReference(groupId, _, _, _, _):
|
if threadId == nil, self.interaction.searchTextHighightState != nil, case let .channel(channel) = peerData.peer.peer, channel.flags.contains(.isForum) {
|
||||||
self.interaction.groupSelected(groupId)
|
threadId = message.threadId
|
||||||
|
}
|
||||||
|
self.interaction.messageSelected(peer, threadId, message, peerData.promoInfo)
|
||||||
|
} else if let peer = peerData.peer.peer {
|
||||||
|
self.interaction.peerSelected(peer, nil, nil, peerData.promoInfo)
|
||||||
|
} else if let peer = peerData.peer.peers[peerData.peer.peerId] {
|
||||||
|
self.interaction.peerSelected(peer, nil, nil, peerData.promoInfo)
|
||||||
|
}
|
||||||
|
case let .groupReference(groupId, _, _, _, _):
|
||||||
|
self.interaction.groupSelected(groupId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -837,6 +895,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
var avatarBadgeNode: ChatListBadgeNode?
|
var avatarBadgeNode: ChatListBadgeNode?
|
||||||
var avatarBadgeBackground: ASImageNode?
|
var avatarBadgeBackground: ASImageNode?
|
||||||
let onlineNode: PeerOnlineMarkerNode
|
let onlineNode: PeerOnlineMarkerNode
|
||||||
|
var avatarTimerBadge: AvatarBadgeView?
|
||||||
let pinnedIconNode: ASImageNode
|
let pinnedIconNode: ASImageNode
|
||||||
var secretIconNode: ASImageNode?
|
var secretIconNode: ASImageNode?
|
||||||
var credibilityIconView: ComponentHostView<Empty>?
|
var credibilityIconView: ComponentHostView<Empty>?
|
||||||
@ -905,8 +964,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
result += "\n\(item.presentationData.strings.VoiceOver_Chat_UnreadMessages(Int32(allCount)))"
|
result += "\n\(item.presentationData.strings.VoiceOver_Chat_UnreadMessages(Int32(allCount)))"
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
case let .peer(_, peer, _, combinedReadState, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(peerData):
|
||||||
guard let chatMainPeer = peer.chatMainPeer else {
|
guard let chatMainPeer = peerData.peer.chatMainPeer else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var result = ""
|
var result = ""
|
||||||
@ -915,7 +974,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
} else {
|
} else {
|
||||||
result += chatMainPeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
|
result += chatMainPeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
|
||||||
}
|
}
|
||||||
if let combinedReadState = combinedReadState, combinedReadState.count > 0 {
|
if let combinedReadState = peerData.combinedReadState, combinedReadState.count > 0 {
|
||||||
result += "\n\(item.presentationData.strings.VoiceOver_Chat_UnreadMessages(combinedReadState.count))"
|
result += "\n\(item.presentationData.strings.VoiceOver_Chat_UnreadMessages(combinedReadState.count))"
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
@ -965,19 +1024,19 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
} else {
|
} else {
|
||||||
return item.presentationData.strings.VoiceOver_ChatList_MessageEmpty
|
return item.presentationData.strings.VoiceOver_ChatList_MessageEmpty
|
||||||
}
|
}
|
||||||
case let .peer(messages, peer, _, combinedReadState, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(peerData):
|
||||||
if let message = messages.last {
|
if let message = peerData.messages.last {
|
||||||
var result = ""
|
var result = ""
|
||||||
if message.flags.contains(.Incoming) {
|
if message.flags.contains(.Incoming) {
|
||||||
result += item.presentationData.strings.VoiceOver_ChatList_Message
|
result += item.presentationData.strings.VoiceOver_ChatList_Message
|
||||||
} else {
|
} else {
|
||||||
result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage
|
result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage
|
||||||
}
|
}
|
||||||
let (_, initialHideAuthor, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, contentSettings: item.context.currentContentSettings.with { $0 }, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
|
let (_, initialHideAuthor, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, contentSettings: item.context.currentContentSettings.with { $0 }, messages: peerData.messages, chatPeer: peerData.peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
|
||||||
if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, case .user = author {
|
if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, case .user = author {
|
||||||
result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)"
|
result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)"
|
||||||
}
|
}
|
||||||
if !message.flags.contains(.Incoming), let combinedReadState = combinedReadState, combinedReadState.isOutgoingMessageIndexRead(message.index) {
|
if !message.flags.contains(.Incoming), let combinedReadState = peerData.combinedReadState, combinedReadState.isOutgoingMessageIndexRead(message.index) {
|
||||||
result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageRead)"
|
result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageRead)"
|
||||||
}
|
}
|
||||||
result += "\n\(messageText)"
|
result += "\n\(messageText)"
|
||||||
@ -1165,7 +1224,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
}
|
}
|
||||||
var threadId: Int64?
|
var threadId: Int64?
|
||||||
if let value = strongSelf.hitTest(location, with: nil), value === strongSelf.compoundTextButtonNode?.view {
|
if let value = strongSelf.hitTest(location, with: nil), value === strongSelf.compoundTextButtonNode?.view {
|
||||||
if case let .peer(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, topForumTopicItems) = item.content, let topicItem = topForumTopicItems.first {
|
if case let .peer(peerData) = item.content, let topicItem = peerData.topForumTopicItems.first {
|
||||||
threadId = topicItem.id
|
threadId = topicItem.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1193,14 +1252,14 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
var displayAsMessage = false
|
var displayAsMessage = false
|
||||||
var enablePreview = true
|
var enablePreview = true
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(messages, peerValue, _, _, _, _, _, _, _, _, _, _, displayAsMessageValue, _, _, _):
|
case let .peer(peerData):
|
||||||
displayAsMessage = displayAsMessageValue
|
displayAsMessage = peerData.displayAsMessage
|
||||||
if displayAsMessage, case let .user(author) = messages.last?.author {
|
if displayAsMessage, case let .user(author) = peerData.messages.last?.author {
|
||||||
peer = .user(author)
|
peer = .user(author)
|
||||||
} else {
|
} else {
|
||||||
peer = peerValue.chatMainPeer
|
peer = peerData.peer.chatMainPeer
|
||||||
}
|
}
|
||||||
if peerValue.peerId.namespace == Namespaces.Peer.SecretChat {
|
if peerData.peer.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
enablePreview = false
|
enablePreview = false
|
||||||
}
|
}
|
||||||
case let .groupReference(_, _, _, _, hiddenByDefault):
|
case let .groupReference(_, _, _, _, hiddenByDefault):
|
||||||
@ -1371,8 +1430,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
guard let item = self.item, item.editing else {
|
guard let item = self.item, item.editing else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if case let .peer(_, peer, _, _, _, _, _, _, _, _, promoInfo, _, _, _, _, _) = item.content {
|
if case let .peer(peerData) = item.content {
|
||||||
if promoInfo == nil, let mainPeer = peer.peer {
|
if peerData.promoInfo == nil, let mainPeer = peerData.peer.peer {
|
||||||
switch item.index {
|
switch item.index {
|
||||||
case let .forum(_, _, threadIdValue, _, _):
|
case let .forum(_, _, threadIdValue, _, _):
|
||||||
item.interaction.toggleThreadsSelection([threadIdValue], !item.selected)
|
item.interaction.toggleThreadsSelection([threadIdValue], !item.selected)
|
||||||
@ -1429,12 +1488,30 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
var threadInfo: ChatListItemContent.ThreadInfo?
|
var threadInfo: ChatListItemContent.ThreadInfo?
|
||||||
var forumTopicData: EngineChatList.ForumTopicData?
|
var forumTopicData: EngineChatList.ForumTopicData?
|
||||||
var topForumTopicItems: [EngineChatList.ForumTopicData] = []
|
var topForumTopicItems: [EngineChatList.ForumTopicData] = []
|
||||||
topForumTopicItems.removeAll()
|
var autoremoveTimeout: Int32?
|
||||||
|
|
||||||
var groupHiddenByDefault = false
|
var groupHiddenByDefault = false
|
||||||
|
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(messagesValue, peerValue, threadInfoValue, combinedReadStateValue, isRemovedFromTotalUnreadCountValue, peerPresenceValue, hasUnseenMentionsValue, hasUnseenReactionsValue, draftStateValue, inputActivitiesValue, promoInfoValue, ignoreUnreadBadge, displayAsMessageValue, _, forumTopicDataValue, topForumTopicItemsValue):
|
case let .peer(peerData):
|
||||||
|
let messagesValue = peerData.messages
|
||||||
|
let peerValue = peerData.peer
|
||||||
|
let threadInfoValue = peerData.threadInfo
|
||||||
|
let combinedReadStateValue = peerData.combinedReadState
|
||||||
|
let isRemovedFromTotalUnreadCountValue = peerData.isRemovedFromTotalUnreadCount
|
||||||
|
let peerPresenceValue = peerData.presence
|
||||||
|
let hasUnseenMentionsValue = peerData.hasUnseenMentions
|
||||||
|
let hasUnseenReactionsValue = peerData.hasUnseenReactions
|
||||||
|
let draftStateValue = peerData.draftState
|
||||||
|
let inputActivitiesValue = peerData.inputActivities
|
||||||
|
let promoInfoValue = peerData.promoInfo
|
||||||
|
let ignoreUnreadBadge = peerData.ignoreUnreadBadge
|
||||||
|
let displayAsMessageValue = peerData.displayAsMessage
|
||||||
|
let forumTopicDataValue = peerData.forumTopicData
|
||||||
|
let topForumTopicItemsValue = peerData.topForumTopicItems
|
||||||
|
|
||||||
|
autoremoveTimeout = peerData.autoremoveTimeout
|
||||||
|
|
||||||
messages = messagesValue
|
messages = messagesValue
|
||||||
contentPeer = .chat(peerValue)
|
contentPeer = .chat(peerValue)
|
||||||
combinedReadState = combinedReadStateValue
|
combinedReadState = combinedReadStateValue
|
||||||
@ -1582,6 +1659,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
|
|
||||||
let badgeDiameter = floor(item.presentationData.fontSize.baseDisplaySize * 20.0 / 17.0)
|
let badgeDiameter = floor(item.presentationData.fontSize.baseDisplaySize * 20.0 / 17.0)
|
||||||
let avatarBadgeDiameter: CGFloat = floor(floor(item.presentationData.fontSize.itemListBaseFontSize * 22.0 / 17.0))
|
let avatarBadgeDiameter: CGFloat = floor(floor(item.presentationData.fontSize.itemListBaseFontSize * 22.0 / 17.0))
|
||||||
|
let avatarTimerBadgeDiameter: CGFloat = floor(floor(item.presentationData.fontSize.itemListBaseFontSize * 24.0 / 17.0))
|
||||||
|
|
||||||
let currentAvatarBadgeCleanBackgroundImage: UIImage? = PresentationResourcesChatList.badgeBackgroundBorder(item.presentationData.theme, diameter: avatarBadgeDiameter + 4.0)
|
let currentAvatarBadgeCleanBackgroundImage: UIImage? = PresentationResourcesChatList.badgeBackgroundBorder(item.presentationData.theme, diameter: avatarBadgeDiameter + 4.0)
|
||||||
|
|
||||||
@ -1905,8 +1983,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
switch item.content {
|
switch item.content {
|
||||||
case let .groupReference(_, _, message, _, _):
|
case let .groupReference(_, _, message, _, _):
|
||||||
topIndex = message?.index
|
topIndex = message?.index
|
||||||
case let .peer(messages, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(peerData):
|
||||||
topIndex = messages.first?.index
|
topIndex = peerData.messages.first?.index
|
||||||
}
|
}
|
||||||
if let topIndex {
|
if let topIndex {
|
||||||
var t = Int(topIndex.timestamp)
|
var t = Int(topIndex.timestamp)
|
||||||
@ -2073,8 +2151,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
if !isPeerGroup && !isAccountPeer && threadInfo == nil {
|
if !isPeerGroup && !isAccountPeer && threadInfo == nil {
|
||||||
if displayAsMessage {
|
if displayAsMessage {
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(messages, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(peerData):
|
||||||
if let peer = messages.last?.author {
|
if let peer = peerData.messages.last?.author {
|
||||||
if case let .user(user) = peer, let emojiStatus = user.emojiStatus, !premiumConfiguration.isPremiumDisabled {
|
if case let .user(user) = peer, let emojiStatus = user.emojiStatus, !premiumConfiguration.isPremiumDisabled {
|
||||||
currentCredibilityIconContent = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 32.0, height: 32.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(2))
|
currentCredibilityIconContent = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 32.0, height: 32.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(2))
|
||||||
} else if peer.isScam {
|
} else if peer.isScam {
|
||||||
@ -2258,7 +2336,11 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
var peerRevealOptions: [ItemListRevealOption]
|
var peerRevealOptions: [ItemListRevealOption]
|
||||||
var peerLeftRevealOptions: [ItemListRevealOption]
|
var peerLeftRevealOptions: [ItemListRevealOption]
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(_, renderedPeer, _, _, _, presence, _, _, _, _, _, _, displayAsMessage, _, _, _):
|
case let .peer(peerData):
|
||||||
|
let renderedPeer = peerData.peer
|
||||||
|
let presence = peerData.presence
|
||||||
|
let displayAsMessage = peerData.displayAsMessage
|
||||||
|
|
||||||
if !displayAsMessage {
|
if !displayAsMessage {
|
||||||
if case let .user(peer) = renderedPeer.chatMainPeer, let presence = presence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != item.context.account.peerId {
|
if case let .user(peer) = renderedPeer.chatMainPeer, let presence = presence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != item.context.account.peerId {
|
||||||
let updatedPresence = EnginePeer.Presence(status: presence.status, lastActivity: 0)
|
let updatedPresence = EnginePeer.Presence(status: presence.status, lastActivity: 0)
|
||||||
@ -2676,6 +2758,37 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .regular, voiceChat: onlineIsVoiceChat)
|
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .regular, voiceChat: onlineIsVoiceChat)
|
||||||
}
|
}
|
||||||
strongSelf.onlineNode.setImage(onlineIcon, color: item.presentationData.theme.list.itemCheckColors.foregroundColor, transition: .immediate)
|
strongSelf.onlineNode.setImage(onlineIcon, color: item.presentationData.theme.list.itemCheckColors.foregroundColor, transition: .immediate)
|
||||||
|
|
||||||
|
let autoremoveTimeoutFraction: CGFloat
|
||||||
|
if online {
|
||||||
|
autoremoveTimeoutFraction = 0.0
|
||||||
|
} else {
|
||||||
|
autoremoveTimeoutFraction = 1.0 - onlineInlineNavigationFraction
|
||||||
|
}
|
||||||
|
|
||||||
|
if let autoremoveTimeout = autoremoveTimeout {
|
||||||
|
let avatarTimerBadge: AvatarBadgeView
|
||||||
|
var avatarTimerTransition = transition
|
||||||
|
if let current = strongSelf.avatarTimerBadge {
|
||||||
|
avatarTimerBadge = current
|
||||||
|
} else {
|
||||||
|
avatarTimerTransition = .immediate
|
||||||
|
avatarTimerBadge = AvatarBadgeView(frame: CGRect())
|
||||||
|
strongSelf.avatarTimerBadge = avatarTimerBadge
|
||||||
|
strongSelf.avatarNode.badgeView = avatarTimerBadge
|
||||||
|
strongSelf.contextContainer.view.addSubview(avatarTimerBadge)
|
||||||
|
}
|
||||||
|
let avatarBadgeSize = CGSize(width: avatarTimerBadgeDiameter, height: avatarTimerBadgeDiameter)
|
||||||
|
avatarTimerBadge.update(size: avatarBadgeSize, text: shortTimeIntervalString(strings: item.presentationData.strings, value: autoremoveTimeout))
|
||||||
|
let avatarBadgeFrame = CGRect(origin: CGPoint(x: avatarFrame.maxX - avatarBadgeSize.width, y: avatarFrame.maxY - avatarBadgeSize.height), size: avatarBadgeSize)
|
||||||
|
avatarTimerTransition.updatePosition(layer: avatarTimerBadge.layer, position: avatarBadgeFrame.center)
|
||||||
|
avatarTimerTransition.updateBounds(layer: avatarTimerBadge.layer, bounds: CGRect(origin: CGPoint(), size: avatarBadgeFrame.size))
|
||||||
|
avatarTimerTransition.updateTransformScale(layer: avatarTimerBadge.layer, scale: autoremoveTimeoutFraction * 1.0 + (1.0 - autoremoveTimeoutFraction) * 0.001)
|
||||||
|
} else if let avatarTimerBadge = strongSelf.avatarTimerBadge {
|
||||||
|
strongSelf.avatarTimerBadge = nil
|
||||||
|
strongSelf.avatarNode.badgeView = nil
|
||||||
|
avatarTimerBadge.removeFromSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
let _ = measureApply()
|
let _ = measureApply()
|
||||||
let _ = dateApply()
|
let _ = dateApply()
|
||||||
@ -3194,10 +3307,10 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
guard let item else {
|
guard let item else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard case let .peer(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, topForumTopicItems) = item.content else {
|
guard case let .peer(peerData) = item.content else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard let topicItem = topForumTopicItems.first else {
|
guard let topicItem = peerData.topForumTopicItems.first else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard case let .chatList(index) = item.index else {
|
guard case let .chatList(index) = item.index else {
|
||||||
@ -3522,7 +3635,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
close = false
|
close = false
|
||||||
case RevealOptionKey.delete.rawValue:
|
case RevealOptionKey.delete.rawValue:
|
||||||
var joined = false
|
var joined = false
|
||||||
if case let .peer(messages, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = item.content, let message = messages.first {
|
if case let .peer(peerData) = item.content, let message = peerData.messages.first {
|
||||||
for media in message.media {
|
for media in message.media {
|
||||||
if let action = media as? TelegramMediaAction, action.action == .peerJoined {
|
if let action = media as? TelegramMediaAction, action.action == .peerJoined {
|
||||||
joined = true
|
joined = true
|
||||||
@ -3558,8 +3671,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
item.interaction.toggleArchivedFolderHiddenByDefault()
|
item.interaction.toggleArchivedFolderHiddenByDefault()
|
||||||
close = false
|
close = false
|
||||||
case RevealOptionKey.hidePsa.rawValue:
|
case RevealOptionKey.hidePsa.rawValue:
|
||||||
if let item = self.item, case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = item.content {
|
if let item = self.item, case let .peer(peerData) = item.content {
|
||||||
item.interaction.hidePsa(peer.peerId)
|
item.interaction.hidePsa(peerData.peer.peerId)
|
||||||
}
|
}
|
||||||
close = false
|
close = false
|
||||||
self.skipFadeout = true
|
self.skipFadeout = true
|
||||||
|
@ -345,7 +345,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
chatListLocation: location,
|
chatListLocation: location,
|
||||||
filterData: filterData,
|
filterData: filterData,
|
||||||
index: index,
|
index: index,
|
||||||
content: .peer(
|
content: .peer(ChatListItemContent.PeerData(
|
||||||
messages: peerEntry.messages,
|
messages: peerEntry.messages,
|
||||||
peer: peer,
|
peer: peer,
|
||||||
threadInfo: threadInfo,
|
threadInfo: threadInfo,
|
||||||
@ -361,8 +361,9 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
displayAsMessage: false,
|
displayAsMessage: false,
|
||||||
hasFailedMessages: hasFailedMessages,
|
hasFailedMessages: hasFailedMessages,
|
||||||
forumTopicData: forumTopicData,
|
forumTopicData: forumTopicData,
|
||||||
topForumTopicItems: topForumTopicItems
|
topForumTopicItems: topForumTopicItems,
|
||||||
),
|
autoremoveTimeout: peerEntry.autoremoveTimeout
|
||||||
|
)),
|
||||||
editing: editing,
|
editing: editing,
|
||||||
hasActiveRevealControls: hasActiveRevealControls,
|
hasActiveRevealControls: hasActiveRevealControls,
|
||||||
selected: selected,
|
selected: selected,
|
||||||
@ -601,7 +602,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
chatListLocation: location,
|
chatListLocation: location,
|
||||||
filterData: filterData,
|
filterData: filterData,
|
||||||
index: index,
|
index: index,
|
||||||
content: .peer(
|
content: .peer(ChatListItemContent.PeerData(
|
||||||
messages: peerEntry.messages,
|
messages: peerEntry.messages,
|
||||||
peer: peer,
|
peer: peer,
|
||||||
threadInfo: threadInfo,
|
threadInfo: threadInfo,
|
||||||
@ -617,8 +618,9 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||||||
displayAsMessage: false,
|
displayAsMessage: false,
|
||||||
hasFailedMessages: hasFailedMessages,
|
hasFailedMessages: hasFailedMessages,
|
||||||
forumTopicData: forumTopicData,
|
forumTopicData: forumTopicData,
|
||||||
topForumTopicItems: topForumTopicItems
|
topForumTopicItems: topForumTopicItems,
|
||||||
),
|
autoremoveTimeout: peerEntry.autoremoveTimeout
|
||||||
|
)),
|
||||||
editing: editing,
|
editing: editing,
|
||||||
hasActiveRevealControls: hasActiveRevealControls,
|
hasActiveRevealControls: hasActiveRevealControls,
|
||||||
selected: selected,
|
selected: selected,
|
||||||
@ -2084,7 +2086,7 @@ public final class ChatListNode: ListView {
|
|||||||
var isHiddenItemVisible = false
|
var isHiddenItemVisible = false
|
||||||
strongSelf.forEachItemNode({ itemNode in
|
strongSelf.forEachItemNode({ itemNode in
|
||||||
if let itemNode = itemNode as? ChatListItemNode, let item = itemNode.item {
|
if let itemNode = itemNode as? ChatListItemNode, let item = itemNode.item {
|
||||||
if case let .peer(_, _, threadInfo, _, _, _, _, _, _, _, _, _, _, _, _, _) = item.content, let threadInfo {
|
if case let .peer(peerData) = item.content, let threadInfo = peerData.threadInfo {
|
||||||
if threadInfo.isHidden {
|
if threadInfo.isHidden {
|
||||||
isHiddenItemVisible = true
|
isHiddenItemVisible = true
|
||||||
}
|
}
|
||||||
@ -2368,8 +2370,8 @@ public final class ChatListNode: ListView {
|
|||||||
for item in transition.insertItems {
|
for item in transition.insertItems {
|
||||||
if let item = item.item as? ChatListItem {
|
if let item = item.item as? ChatListItem {
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(peerData):
|
||||||
insertedPeerIds.append(peer.peerId)
|
insertedPeerIds.append(peerData.peer.peerId)
|
||||||
case .groupReference:
|
case .groupReference:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -2754,8 +2756,8 @@ public final class ChatListNode: ListView {
|
|||||||
if resultPeer == nil, let itemNode = itemNode as? ListViewItemNode, itemNode.frame.contains(point) {
|
if resultPeer == nil, let itemNode = itemNode as? ListViewItemNode, itemNode.frame.contains(point) {
|
||||||
if let itemNode = itemNode as? ChatListItemNode, let item = itemNode.item {
|
if let itemNode = itemNode as? ChatListItemNode, let item = itemNode.item {
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(peerData):
|
||||||
resultPeer = peer.peer
|
resultPeer = peerData.peer.peer
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -2771,8 +2773,8 @@ public final class ChatListNode: ListView {
|
|||||||
if resultThreadId == nil, let itemNode = itemNode as? ListViewItemNode, itemNode.frame.contains(point) {
|
if resultThreadId == nil, let itemNode = itemNode as? ListViewItemNode, itemNode.frame.contains(point) {
|
||||||
if let itemNode = itemNode as? ChatListItemNode, let item = itemNode.item {
|
if let itemNode = itemNode as? ChatListItemNode, let item = itemNode.item {
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(_, _, threadInfo, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(peerData):
|
||||||
resultThreadId = threadInfo?.id
|
resultThreadId = peerData.threadInfo?.id
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -143,6 +143,8 @@ public class ImageNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var contentUpdated: ((UIImage?) -> Void)?
|
||||||
|
|
||||||
public init(enableHasImage: Bool = false, enableEmpty: Bool = false, enableAnimatedTransition: Bool = false) {
|
public init(enableHasImage: Bool = false, enableEmpty: Bool = false, enableAnimatedTransition: Bool = false) {
|
||||||
if enableHasImage {
|
if enableHasImage {
|
||||||
self.hasImage = ValuePromise(false, ignoreRepeated: true)
|
self.hasImage = ValuePromise(false, ignoreRepeated: true)
|
||||||
@ -187,8 +189,10 @@ public class ImageNode: ASDisplayNode {
|
|||||||
} else {
|
} else {
|
||||||
strongSelf.contents = image
|
strongSelf.contents = image
|
||||||
}
|
}
|
||||||
|
strongSelf.contentUpdated?(next)
|
||||||
} else if strongSelf.enableEmpty {
|
} else if strongSelf.enableEmpty {
|
||||||
strongSelf.contents = nil
|
strongSelf.contents = nil
|
||||||
|
strongSelf.contentUpdated?(nil)
|
||||||
}
|
}
|
||||||
if !reportedHasImage {
|
if !reportedHasImage {
|
||||||
if let hasImage = strongSelf.hasImage {
|
if let hasImage = strongSelf.hasImage {
|
||||||
@ -210,6 +214,7 @@ public class ImageNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.contents = nil
|
self.contents = nil
|
||||||
self.disposable.set(nil)
|
self.disposable.set(nil)
|
||||||
|
self.contentUpdated?(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var image: UIImage? {
|
public var image: UIImage? {
|
||||||
|
@ -76,7 +76,7 @@ class GlobalAutoremoveHeaderItemNode: ListViewItemNode {
|
|||||||
func asyncLayout() -> (_ item: GlobalAutoremoveHeaderItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
func asyncLayout() -> (_ item: GlobalAutoremoveHeaderItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||||
return { item, params, neighbors in
|
return { item, params, neighbors in
|
||||||
//let leftInset: CGFloat = 32.0 + params.leftInset
|
//let leftInset: CGFloat = 32.0 + params.leftInset
|
||||||
let topInset: CGFloat = 92.0
|
let topInset: CGFloat = 110.0
|
||||||
|
|
||||||
let contentSize = CGSize(width: params.width, height: topInset)
|
let contentSize = CGSize(width: params.width, height: topInset)
|
||||||
let insets = itemListNeighborsGroupedInsets(neighbors, params)
|
let insets = itemListNeighborsGroupedInsets(neighbors, params)
|
||||||
@ -86,12 +86,12 @@ class GlobalAutoremoveHeaderItemNode: ListViewItemNode {
|
|||||||
return (layout, { [weak self] in
|
return (layout, { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if strongSelf.item == nil {
|
if strongSelf.item == nil {
|
||||||
strongSelf.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "GlobalAutoRemove"), width: 192, height: 192, playbackMode: .once, mode: .direct(cachePathPrefix: nil))
|
strongSelf.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "GlobalAutoRemove"), width: 220, height: 220, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
|
||||||
strongSelf.animationNode.visibility = true
|
strongSelf.animationNode.visibility = true
|
||||||
}
|
}
|
||||||
strongSelf.item = item
|
strongSelf.item = item
|
||||||
|
|
||||||
let iconSize = CGSize(width: 96.0, height: 96.0)
|
let iconSize = CGSize(width: 110.0, height: 110.0)
|
||||||
strongSelf.animationNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: -10.0), size: iconSize)
|
strongSelf.animationNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: -10.0), size: iconSize)
|
||||||
strongSelf.animationNode.updateLayout(size: iconSize)
|
strongSelf.animationNode.updateLayout(size: iconSize)
|
||||||
}
|
}
|
||||||
|
@ -267,7 +267,7 @@ public func globalAutoremoveScreen(context: AccountContext, initialValue: Int32,
|
|||||||
presentControllerImpl?(standardTextAlertController(
|
presentControllerImpl?(standardTextAlertController(
|
||||||
theme: AlertControllerTheme(presentationData: presentationData),
|
theme: AlertControllerTheme(presentationData: presentationData),
|
||||||
title: "Self-Destruct Timer",
|
title: "Self-Destruct Timer",
|
||||||
text: "Are you sure you want all messages in new chats started by you to be automatically deleted for everyone \(valueText) after they have been sent?",
|
text: "Are you sure you want all messages in your new private chats and in new groups you create to be automatically deleted for everyone \(valueText) after they have been sent?",
|
||||||
actions: [
|
actions: [
|
||||||
TextAlertAction(type: .defaultAction, title: "Enable Auto-Deletion", action: {
|
TextAlertAction(type: .defaultAction, title: "Enable Auto-Deletion", action: {
|
||||||
apply(timeout)
|
apply(timeout)
|
||||||
|
@ -242,7 +242,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
|||||||
chatListLocation: .chatList(groupId: .root),
|
chatListLocation: .chatList(groupId: .root),
|
||||||
filterData: nil,
|
filterData: nil,
|
||||||
index: .chatList(ChatListIndex(pinningIndex: isPinned ? 0 : nil, messageIndex: MessageIndex(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), timestamp: timestamp))),
|
index: .chatList(ChatListIndex(pinningIndex: isPinned ? 0 : nil, messageIndex: MessageIndex(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), timestamp: timestamp))),
|
||||||
content: .peer(
|
content: .peer(ChatListItemContent.PeerData(
|
||||||
messages: [
|
messages: [
|
||||||
EngineMessage(
|
EngineMessage(
|
||||||
stableId: 0,
|
stableId: 0,
|
||||||
@ -285,8 +285,9 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
|||||||
displayAsMessage: false,
|
displayAsMessage: false,
|
||||||
hasFailedMessages: false,
|
hasFailedMessages: false,
|
||||||
forumTopicData: nil,
|
forumTopicData: nil,
|
||||||
topForumTopicItems: []
|
topForumTopicItems: [],
|
||||||
),
|
autoremoveTimeout: nil
|
||||||
|
)),
|
||||||
editing: false,
|
editing: false,
|
||||||
hasActiveRevealControls: false,
|
hasActiveRevealControls: false,
|
||||||
selected: false,
|
selected: false,
|
||||||
|
@ -862,7 +862,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
|||||||
chatListLocation: .chatList(groupId: .root),
|
chatListLocation: .chatList(groupId: .root),
|
||||||
filterData: nil,
|
filterData: nil,
|
||||||
index: .chatList(ChatListIndex(pinningIndex: isPinned ? 0 : nil, messageIndex: MessageIndex(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), timestamp: timestamp))),
|
index: .chatList(ChatListIndex(pinningIndex: isPinned ? 0 : nil, messageIndex: MessageIndex(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), timestamp: timestamp))),
|
||||||
content: .peer(
|
content: .peer(ChatListItemContent.PeerData(
|
||||||
messages: [
|
messages: [
|
||||||
EngineMessage(
|
EngineMessage(
|
||||||
stableId: 0,
|
stableId: 0,
|
||||||
@ -905,8 +905,9 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
|||||||
displayAsMessage: false,
|
displayAsMessage: false,
|
||||||
hasFailedMessages: false,
|
hasFailedMessages: false,
|
||||||
forumTopicData: nil,
|
forumTopicData: nil,
|
||||||
topForumTopicItems: []
|
topForumTopicItems: [],
|
||||||
),
|
autoremoveTimeout: nil
|
||||||
|
)),
|
||||||
editing: false,
|
editing: false,
|
||||||
hasActiveRevealControls: false,
|
hasActiveRevealControls: false,
|
||||||
selected: false,
|
selected: false,
|
||||||
|
@ -385,7 +385,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
chatListLocation: .chatList(groupId: .root),
|
chatListLocation: .chatList(groupId: .root),
|
||||||
filterData: nil,
|
filterData: nil,
|
||||||
index: .chatList(ChatListIndex(pinningIndex: isPinned ? 0 : nil, messageIndex: MessageIndex(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), timestamp: timestamp))),
|
index: .chatList(ChatListIndex(pinningIndex: isPinned ? 0 : nil, messageIndex: MessageIndex(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), timestamp: timestamp))),
|
||||||
content: .peer(
|
content: .peer(ChatListItemContent.PeerData(
|
||||||
messages: [
|
messages: [
|
||||||
EngineMessage(
|
EngineMessage(
|
||||||
stableId: 0,
|
stableId: 0,
|
||||||
@ -428,8 +428,9 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
displayAsMessage: false,
|
displayAsMessage: false,
|
||||||
hasFailedMessages: false,
|
hasFailedMessages: false,
|
||||||
forumTopicData: nil,
|
forumTopicData: nil,
|
||||||
topForumTopicItems: []
|
topForumTopicItems: [],
|
||||||
),
|
autoremoveTimeout: nil
|
||||||
|
)),
|
||||||
editing: false,
|
editing: false,
|
||||||
hasActiveRevealControls: false,
|
hasActiveRevealControls: false,
|
||||||
selected: false,
|
selected: false,
|
||||||
|
@ -336,7 +336,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
}
|
}
|
||||||
case .channelMigratedFromGroup, .groupMigratedToChannel:
|
case .channelMigratedFromGroup, .groupMigratedToChannel:
|
||||||
attributedString = NSAttributedString(string: "", font: titleFont, textColor: primaryTextColor)
|
attributedString = NSAttributedString(string: "", font: titleFont, textColor: primaryTextColor)
|
||||||
case let .messageAutoremoveTimeoutUpdated(timeout, _):
|
case let .messageAutoremoveTimeoutUpdated(timeout, autoSourcePeerId):
|
||||||
let authorString: String
|
let authorString: String
|
||||||
if let author = messageMainPeer(message) {
|
if let author = messageMainPeer(message) {
|
||||||
authorString = author.compactDisplayTitle
|
authorString = author.compactDisplayTitle
|
||||||
@ -349,37 +349,41 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
if timeout > 0 {
|
if timeout > 0 {
|
||||||
let timeValue = timeIntervalString(strings: strings, value: timeout, preferLowerValue: false)
|
let timeValue = timeIntervalString(strings: strings, value: timeout, preferLowerValue: false)
|
||||||
|
|
||||||
let string: String
|
if let user = messagePeer as? TelegramUser {
|
||||||
if let _ = messagePeer as? TelegramUser {
|
if let autoSourcePeerId = autoSourcePeerId {
|
||||||
if message.author?.id == accountPeerId {
|
if autoSourcePeerId == accountPeerId {
|
||||||
string = strings.Conversation_AutoremoveTimerSetUserYou(timeValue).string
|
attributedString = NSAttributedString(string: strings.Conversation_AutoremoveTimerSetUserGlobalYou(timeValue).string, font: titleFont, textColor: primaryTextColor)
|
||||||
|
} else {
|
||||||
|
attributedString = addAttributesToStringWithRanges(strings.Conversation_AutoremoveTimerSetUserGlobal(authorString, timeValue)._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, user.id)]))
|
||||||
|
}
|
||||||
|
} else if message.author?.id == accountPeerId {
|
||||||
|
attributedString = NSAttributedString(string: strings.Conversation_AutoremoveTimerSetUserYou(timeValue).string, font: titleFont, textColor: primaryTextColor)
|
||||||
} else {
|
} else {
|
||||||
string = strings.Conversation_AutoremoveTimerSetUser(authorString, timeValue).string
|
attributedString = NSAttributedString(string: strings.Conversation_AutoremoveTimerSetUser(authorString, timeValue).string, font: titleFont, textColor: primaryTextColor)
|
||||||
}
|
}
|
||||||
} else if let _ = messagePeer as? TelegramGroup {
|
} else if let _ = messagePeer as? TelegramGroup {
|
||||||
if message.author?.id == accountPeerId {
|
if message.author?.id == accountPeerId {
|
||||||
string = strings.Conversation_AutoremoveTimerSetUserYou(timeValue).string
|
attributedString = NSAttributedString(string: strings.Conversation_AutoremoveTimerSetUserYou(timeValue).string, font: titleFont, textColor: primaryTextColor)
|
||||||
} else {
|
} else {
|
||||||
string = strings.Conversation_AutoremoveTimerSetGroup(timeValue).string
|
attributedString = NSAttributedString(string: strings.Conversation_AutoremoveTimerSetGroup(timeValue).string, font: titleFont, textColor: primaryTextColor)
|
||||||
}
|
}
|
||||||
} else if let channel = messagePeer as? TelegramChannel {
|
} else if let channel = messagePeer as? TelegramChannel {
|
||||||
if message.author?.id == accountPeerId {
|
if message.author?.id == accountPeerId {
|
||||||
string = strings.Conversation_AutoremoveTimerSetUserYou(timeValue).string
|
attributedString = NSAttributedString(string: strings.Conversation_AutoremoveTimerSetUserYou(timeValue).string, font: titleFont, textColor: primaryTextColor)
|
||||||
} else {
|
} else {
|
||||||
if case .group = channel.info {
|
if case .group = channel.info {
|
||||||
string = strings.Conversation_AutoremoveTimerSetGroup(timeValue).string
|
attributedString = NSAttributedString(string: strings.Conversation_AutoremoveTimerSetGroup(timeValue).string, font: titleFont, textColor: primaryTextColor)
|
||||||
} else {
|
} else {
|
||||||
string = strings.Conversation_AutoremoveTimerSetChannel(timeValue).string
|
attributedString = NSAttributedString(string: strings.Conversation_AutoremoveTimerSetChannel(timeValue).string, font: titleFont, textColor: primaryTextColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if message.author?.id == accountPeerId {
|
if message.author?.id == accountPeerId {
|
||||||
string = strings.Notification_MessageLifetimeChangedOutgoing(timeValue).string
|
attributedString = NSAttributedString(string: strings.Notification_MessageLifetimeChangedOutgoing(timeValue).string, font: titleFont, textColor: primaryTextColor)
|
||||||
} else {
|
} else {
|
||||||
string = strings.Notification_MessageLifetimeChanged(authorString, timeValue).string
|
attributedString = NSAttributedString(string: strings.Notification_MessageLifetimeChanged(authorString, timeValue).string, font: titleFont, textColor: primaryTextColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
attributedString = NSAttributedString(string: string, font: titleFont, textColor: primaryTextColor)
|
|
||||||
} else {
|
} else {
|
||||||
let string: String
|
let string: String
|
||||||
if let _ = messagePeer as? TelegramUser {
|
if let _ = messagePeer as? TelegramUser {
|
||||||
|
@ -85,7 +85,7 @@ private enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
chatListLocation: .chatList(groupId: .root),
|
chatListLocation: .chatList(groupId: .root),
|
||||||
filterData: nil,
|
filterData: nil,
|
||||||
index: .chatList(EngineChatList.Item.Index.ChatList(pinningIndex: nil, messageIndex: message.index)),
|
index: .chatList(EngineChatList.Item.Index.ChatList(pinningIndex: nil, messageIndex: message.index)),
|
||||||
content: .peer(
|
content: .peer(ChatListItemContent.PeerData(
|
||||||
messages: [EngineMessage(message)],
|
messages: [EngineMessage(message)],
|
||||||
peer: EngineRenderedPeer(peer),
|
peer: EngineRenderedPeer(peer),
|
||||||
threadInfo: nil,
|
threadInfo: nil,
|
||||||
@ -101,8 +101,9 @@ private enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
displayAsMessage: true,
|
displayAsMessage: true,
|
||||||
hasFailedMessages: false,
|
hasFailedMessages: false,
|
||||||
forumTopicData: nil,
|
forumTopicData: nil,
|
||||||
topForumTopicItems: []
|
topForumTopicItems: [],
|
||||||
),
|
autoremoveTimeout: nil
|
||||||
|
)),
|
||||||
editing: false,
|
editing: false,
|
||||||
hasActiveRevealControls: false,
|
hasActiveRevealControls: false,
|
||||||
selected: false,
|
selected: false,
|
||||||
@ -247,9 +248,9 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .peer(messages, peer, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
case let .peer(peerData):
|
||||||
if let message = messages.first {
|
if let message = peerData.messages.first {
|
||||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: peer.peerId), subject: .message(id: .id(message.id), highlight: true, timecode: nil), botStart: nil, mode: .standard(previewing: true))
|
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: peerData.peer.peerId), subject: .message(id: .id(message.id), highlight: true, timecode: nil), botStart: nil, mode: .standard(previewing: true))
|
||||||
chatController.canReadHistory.set(false)
|
chatController.canReadHistory.set(false)
|
||||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single(ContextController.Items(content: .list([]))), gesture: gesture)
|
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single(ContextController.Items(content: .list([]))), gesture: gesture)
|
||||||
presentInGlobalOverlay(contextController)
|
presentInGlobalOverlay(contextController)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user