mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
WIP
This commit is contained in:
parent
c4b41cbe66
commit
e80c198605
@ -5989,3 +5989,10 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Conversation.ForwardTooltip.SavedMessages.One" = "Message forwarded to **Saved Messages**";
|
||||
"Conversation.ForwardTooltip.SavedMessages.Many" = "Messages forwarded to **Saved Messages**";
|
||||
|
||||
"Conversation.AutoremoveRemainingTime" = "auto-delete in %@";
|
||||
"Conversation.AutoremoveRemainingDays_1" = "auto-delete in %@ day";
|
||||
"Conversation.AutoremoveRemainingDays_any" = "auto-delete in %@ days";
|
||||
|
||||
"PeerInfo.AutoremoveMessages" = "Auto-Delete Messages";
|
||||
"PeerInfo.AutoremoveMessagesDisabled" = "Never";
|
||||
|
@ -84,17 +84,27 @@ private final class InnerActionsContainerNode: ASDisplayNode {
|
||||
switch items[i] {
|
||||
case let .action(action):
|
||||
itemNodes.append(.action(ContextActionNode(presentationData: presentationData, action: action, getController: getController, actionSelected: actionSelected)))
|
||||
if i != items.count - 1, case .action = items[i + 1] {
|
||||
let separatorNode = ASDisplayNode()
|
||||
separatorNode.backgroundColor = presentationData.theme.contextMenu.itemSeparatorColor
|
||||
itemNodes.append(.itemSeparator(separatorNode))
|
||||
if i != items.count - 1 {
|
||||
switch items[i + 1] {
|
||||
case .action, .custom:
|
||||
let separatorNode = ASDisplayNode()
|
||||
separatorNode.backgroundColor = presentationData.theme.contextMenu.itemSeparatorColor
|
||||
itemNodes.append(.itemSeparator(separatorNode))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
case let .custom(item, _):
|
||||
itemNodes.append(.custom(item.node(presentationData: presentationData, getController: getController, actionSelected: actionSelected)))
|
||||
if i != items.count - 1, case .action = items[i + 1] {
|
||||
let separatorNode = ASDisplayNode()
|
||||
separatorNode.backgroundColor = presentationData.theme.contextMenu.itemSeparatorColor
|
||||
itemNodes.append(.itemSeparator(separatorNode))
|
||||
if i != items.count - 1 {
|
||||
switch items[i + 1] {
|
||||
case .action, .custom:
|
||||
let separatorNode = ASDisplayNode()
|
||||
separatorNode.backgroundColor = presentationData.theme.contextMenu.itemSeparatorColor
|
||||
itemNodes.append(.itemSeparator(separatorNode))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
case .separator:
|
||||
let separatorNode = ASDisplayNode()
|
||||
|
@ -84,4 +84,13 @@ public extension Message {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var isSelfExpiring: Bool {
|
||||
for attribute in self.attributes {
|
||||
if let _ = attribute as? AutoremoveTimeoutMessageAttribute {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -590,9 +590,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[2027216577] = { return Api.Updates.parse_updateShort($0) }
|
||||
dict[1918567619] = { return Api.Updates.parse_updatesCombined($0) }
|
||||
dict[1957577280] = { return Api.Updates.parse_updates($0) }
|
||||
dict[301019932] = { return Api.Updates.parse_updateShortSentMessage($0) }
|
||||
dict[580309704] = { return Api.Updates.parse_updateShortMessage($0) }
|
||||
dict[1076714939] = { return Api.Updates.parse_updateShortChatMessage($0) }
|
||||
dict[-84936653] = { return Api.Updates.parse_updateShortMessage($0) }
|
||||
dict[290961496] = { return Api.Updates.parse_updateShortChatMessage($0) }
|
||||
dict[-1877614335] = { return Api.Updates.parse_updateShortSentMessage($0) }
|
||||
dict[-276825834] = { return Api.stats.MegagroupStats.parse_megagroupStats($0) }
|
||||
dict[-884757282] = { return Api.StatsAbsValueAndPrev.parse_statsAbsValueAndPrev($0) }
|
||||
dict[1038967584] = { return Api.MessageMedia.parse_messageMediaEmpty($0) }
|
||||
|
@ -17094,9 +17094,9 @@ public extension Api {
|
||||
case updateShort(update: Api.Update, date: Int32)
|
||||
case updatesCombined(updates: [Api.Update], users: [Api.User], chats: [Api.Chat], date: Int32, seqStart: Int32, seq: Int32)
|
||||
case updates(updates: [Api.Update], users: [Api.User], chats: [Api.Chat], date: Int32, seq: Int32)
|
||||
case updateShortSentMessage(flags: Int32, id: Int32, pts: Int32, ptsCount: Int32, date: Int32, media: Api.MessageMedia?, entities: [Api.MessageEntity]?)
|
||||
case updateShortMessage(flags: Int32, id: Int32, userId: Int32, message: String, pts: Int32, ptsCount: Int32, date: Int32, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int32?, replyTo: Api.MessageReplyHeader?, entities: [Api.MessageEntity]?)
|
||||
case updateShortChatMessage(flags: Int32, id: Int32, fromId: Int32, chatId: Int32, message: String, pts: Int32, ptsCount: Int32, date: Int32, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int32?, replyTo: Api.MessageReplyHeader?, entities: [Api.MessageEntity]?)
|
||||
case updateShortMessage(flags: Int32, id: Int32, userId: Int32, message: String, pts: Int32, ptsCount: Int32, date: Int32, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int32?, replyTo: Api.MessageReplyHeader?, entities: [Api.MessageEntity]?, ttlPeriod: Int32?)
|
||||
case updateShortChatMessage(flags: Int32, id: Int32, fromId: Int32, chatId: Int32, message: String, pts: Int32, ptsCount: Int32, date: Int32, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int32?, replyTo: Api.MessageReplyHeader?, entities: [Api.MessageEntity]?, ttlPeriod: Int32?)
|
||||
case updateShortSentMessage(flags: Int32, id: Int32, pts: Int32, ptsCount: Int32, date: Int32, media: Api.MessageMedia?, entities: [Api.MessageEntity]?, ttlPeriod: Int32?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
@ -17158,25 +17158,9 @@ public extension Api {
|
||||
serializeInt32(date, buffer: buffer, boxed: false)
|
||||
serializeInt32(seq, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .updateShortSentMessage(let flags, let id, let pts, let ptsCount, let date, let media, let entities):
|
||||
case .updateShortMessage(let flags, let id, let userId, let message, let pts, let ptsCount, let date, let fwdFrom, let viaBotId, let replyTo, let entities, let ttlPeriod):
|
||||
if boxed {
|
||||
buffer.appendInt32(301019932)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(id, buffer: buffer, boxed: false)
|
||||
serializeInt32(pts, buffer: buffer, boxed: false)
|
||||
serializeInt32(ptsCount, buffer: buffer, boxed: false)
|
||||
serializeInt32(date, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 9) != 0 {media!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 7) != 0 {buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(entities!.count))
|
||||
for item in entities! {
|
||||
item.serialize(buffer, true)
|
||||
}}
|
||||
break
|
||||
case .updateShortMessage(let flags, let id, let userId, let message, let pts, let ptsCount, let date, let fwdFrom, let viaBotId, let replyTo, let entities):
|
||||
if boxed {
|
||||
buffer.appendInt32(580309704)
|
||||
buffer.appendInt32(-84936653)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(id, buffer: buffer, boxed: false)
|
||||
@ -17193,10 +17177,11 @@ public extension Api {
|
||||
for item in entities! {
|
||||
item.serialize(buffer, true)
|
||||
}}
|
||||
if Int(flags) & Int(1 << 25) != 0 {serializeInt32(ttlPeriod!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
case .updateShortChatMessage(let flags, let id, let fromId, let chatId, let message, let pts, let ptsCount, let date, let fwdFrom, let viaBotId, let replyTo, let entities):
|
||||
case .updateShortChatMessage(let flags, let id, let fromId, let chatId, let message, let pts, let ptsCount, let date, let fwdFrom, let viaBotId, let replyTo, let entities, let ttlPeriod):
|
||||
if boxed {
|
||||
buffer.appendInt32(1076714939)
|
||||
buffer.appendInt32(290961496)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(id, buffer: buffer, boxed: false)
|
||||
@ -17214,6 +17199,24 @@ public extension Api {
|
||||
for item in entities! {
|
||||
item.serialize(buffer, true)
|
||||
}}
|
||||
if Int(flags) & Int(1 << 25) != 0 {serializeInt32(ttlPeriod!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
case .updateShortSentMessage(let flags, let id, let pts, let ptsCount, let date, let media, let entities, let ttlPeriod):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1877614335)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(id, buffer: buffer, boxed: false)
|
||||
serializeInt32(pts, buffer: buffer, boxed: false)
|
||||
serializeInt32(ptsCount, buffer: buffer, boxed: false)
|
||||
serializeInt32(date, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 9) != 0 {media!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 7) != 0 {buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(entities!.count))
|
||||
for item in entities! {
|
||||
item.serialize(buffer, true)
|
||||
}}
|
||||
if Int(flags) & Int(1 << 25) != 0 {serializeInt32(ttlPeriod!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -17228,12 +17231,12 @@ public extension Api {
|
||||
return ("updatesCombined", [("updates", updates), ("users", users), ("chats", chats), ("date", date), ("seqStart", seqStart), ("seq", seq)])
|
||||
case .updates(let updates, let users, let chats, let date, let seq):
|
||||
return ("updates", [("updates", updates), ("users", users), ("chats", chats), ("date", date), ("seq", seq)])
|
||||
case .updateShortSentMessage(let flags, let id, let pts, let ptsCount, let date, let media, let entities):
|
||||
return ("updateShortSentMessage", [("flags", flags), ("id", id), ("pts", pts), ("ptsCount", ptsCount), ("date", date), ("media", media), ("entities", entities)])
|
||||
case .updateShortMessage(let flags, let id, let userId, let message, let pts, let ptsCount, let date, let fwdFrom, let viaBotId, let replyTo, let entities):
|
||||
return ("updateShortMessage", [("flags", flags), ("id", id), ("userId", userId), ("message", message), ("pts", pts), ("ptsCount", ptsCount), ("date", date), ("fwdFrom", fwdFrom), ("viaBotId", viaBotId), ("replyTo", replyTo), ("entities", entities)])
|
||||
case .updateShortChatMessage(let flags, let id, let fromId, let chatId, let message, let pts, let ptsCount, let date, let fwdFrom, let viaBotId, let replyTo, let entities):
|
||||
return ("updateShortChatMessage", [("flags", flags), ("id", id), ("fromId", fromId), ("chatId", chatId), ("message", message), ("pts", pts), ("ptsCount", ptsCount), ("date", date), ("fwdFrom", fwdFrom), ("viaBotId", viaBotId), ("replyTo", replyTo), ("entities", entities)])
|
||||
case .updateShortMessage(let flags, let id, let userId, let message, let pts, let ptsCount, let date, let fwdFrom, let viaBotId, let replyTo, let entities, let ttlPeriod):
|
||||
return ("updateShortMessage", [("flags", flags), ("id", id), ("userId", userId), ("message", message), ("pts", pts), ("ptsCount", ptsCount), ("date", date), ("fwdFrom", fwdFrom), ("viaBotId", viaBotId), ("replyTo", replyTo), ("entities", entities), ("ttlPeriod", ttlPeriod)])
|
||||
case .updateShortChatMessage(let flags, let id, let fromId, let chatId, let message, let pts, let ptsCount, let date, let fwdFrom, let viaBotId, let replyTo, let entities, let ttlPeriod):
|
||||
return ("updateShortChatMessage", [("flags", flags), ("id", id), ("fromId", fromId), ("chatId", chatId), ("message", message), ("pts", pts), ("ptsCount", ptsCount), ("date", date), ("fwdFrom", fwdFrom), ("viaBotId", viaBotId), ("replyTo", replyTo), ("entities", entities), ("ttlPeriod", ttlPeriod)])
|
||||
case .updateShortSentMessage(let flags, let id, let pts, let ptsCount, let date, let media, let entities, let ttlPeriod):
|
||||
return ("updateShortSentMessage", [("flags", flags), ("id", id), ("pts", pts), ("ptsCount", ptsCount), ("date", date), ("media", media), ("entities", entities), ("ttlPeriod", ttlPeriod)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -17317,39 +17320,6 @@ public extension Api {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_updateShortSentMessage(_ reader: BufferReader) -> Updates? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int32?
|
||||
_2 = reader.readInt32()
|
||||
var _3: Int32?
|
||||
_3 = reader.readInt32()
|
||||
var _4: Int32?
|
||||
_4 = reader.readInt32()
|
||||
var _5: Int32?
|
||||
_5 = reader.readInt32()
|
||||
var _6: Api.MessageMedia?
|
||||
if Int(_1!) & Int(1 << 9) != 0 {if let signature = reader.readInt32() {
|
||||
_6 = Api.parse(reader, signature: signature) as? Api.MessageMedia
|
||||
} }
|
||||
var _7: [Api.MessageEntity]?
|
||||
if Int(_1!) & Int(1 << 7) != 0 {if let _ = reader.readInt32() {
|
||||
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
|
||||
} }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = (Int(_1!) & Int(1 << 9) == 0) || _6 != nil
|
||||
let _c7 = (Int(_1!) & Int(1 << 7) == 0) || _7 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
|
||||
return Api.Updates.updateShortSentMessage(flags: _1!, id: _2!, pts: _3!, ptsCount: _4!, date: _5!, media: _6, entities: _7)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_updateShortMessage(_ reader: BufferReader) -> Updates? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
@ -17379,6 +17349,8 @@ public extension Api {
|
||||
if Int(_1!) & Int(1 << 7) != 0 {if let _ = reader.readInt32() {
|
||||
_11 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
|
||||
} }
|
||||
var _12: Int32?
|
||||
if Int(_1!) & Int(1 << 25) != 0 {_12 = reader.readInt32() }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
@ -17390,8 +17362,9 @@ public extension Api {
|
||||
let _c9 = (Int(_1!) & Int(1 << 11) == 0) || _9 != nil
|
||||
let _c10 = (Int(_1!) & Int(1 << 3) == 0) || _10 != nil
|
||||
let _c11 = (Int(_1!) & Int(1 << 7) == 0) || _11 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 {
|
||||
return Api.Updates.updateShortMessage(flags: _1!, id: _2!, userId: _3!, message: _4!, pts: _5!, ptsCount: _6!, date: _7!, fwdFrom: _8, viaBotId: _9, replyTo: _10, entities: _11)
|
||||
let _c12 = (Int(_1!) & Int(1 << 25) == 0) || _12 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 {
|
||||
return Api.Updates.updateShortMessage(flags: _1!, id: _2!, userId: _3!, message: _4!, pts: _5!, ptsCount: _6!, date: _7!, fwdFrom: _8, viaBotId: _9, replyTo: _10, entities: _11, ttlPeriod: _12)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
@ -17428,6 +17401,8 @@ public extension Api {
|
||||
if Int(_1!) & Int(1 << 7) != 0 {if let _ = reader.readInt32() {
|
||||
_12 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
|
||||
} }
|
||||
var _13: Int32?
|
||||
if Int(_1!) & Int(1 << 25) != 0 {_13 = reader.readInt32() }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
@ -17440,8 +17415,45 @@ public extension Api {
|
||||
let _c10 = (Int(_1!) & Int(1 << 11) == 0) || _10 != nil
|
||||
let _c11 = (Int(_1!) & Int(1 << 3) == 0) || _11 != nil
|
||||
let _c12 = (Int(_1!) & Int(1 << 7) == 0) || _12 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 {
|
||||
return Api.Updates.updateShortChatMessage(flags: _1!, id: _2!, fromId: _3!, chatId: _4!, message: _5!, pts: _6!, ptsCount: _7!, date: _8!, fwdFrom: _9, viaBotId: _10, replyTo: _11, entities: _12)
|
||||
let _c13 = (Int(_1!) & Int(1 << 25) == 0) || _13 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 {
|
||||
return Api.Updates.updateShortChatMessage(flags: _1!, id: _2!, fromId: _3!, chatId: _4!, message: _5!, pts: _6!, ptsCount: _7!, date: _8!, fwdFrom: _9, viaBotId: _10, replyTo: _11, entities: _12, ttlPeriod: _13)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_updateShortSentMessage(_ reader: BufferReader) -> Updates? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int32?
|
||||
_2 = reader.readInt32()
|
||||
var _3: Int32?
|
||||
_3 = reader.readInt32()
|
||||
var _4: Int32?
|
||||
_4 = reader.readInt32()
|
||||
var _5: Int32?
|
||||
_5 = reader.readInt32()
|
||||
var _6: Api.MessageMedia?
|
||||
if Int(_1!) & Int(1 << 9) != 0 {if let signature = reader.readInt32() {
|
||||
_6 = Api.parse(reader, signature: signature) as? Api.MessageMedia
|
||||
} }
|
||||
var _7: [Api.MessageEntity]?
|
||||
if Int(_1!) & Int(1 << 7) != 0 {if let _ = reader.readInt32() {
|
||||
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
|
||||
} }
|
||||
var _8: Int32?
|
||||
if Int(_1!) & Int(1 << 25) != 0 {_8 = reader.readInt32() }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = (Int(_1!) & Int(1 << 9) == 0) || _6 != nil
|
||||
let _c7 = (Int(_1!) & Int(1 << 7) == 0) || _7 != nil
|
||||
let _c8 = (Int(_1!) & Int(1 << 25) == 0) || _8 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
|
||||
return Api.Updates.updateShortSentMessage(flags: _1!, id: _2!, pts: _3!, ptsCount: _4!, date: _5!, media: _6, entities: _7, ttlPeriod: _8)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -74,7 +74,7 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
||||
}
|
||||
} else {
|
||||
switch result {
|
||||
case let .updateShortSentMessage(_, _, _, _, date, _, _):
|
||||
case let .updateShortSentMessage(_, _, _, _, date, _, _, _):
|
||||
updatedTimestamp = date
|
||||
default:
|
||||
break
|
||||
@ -117,7 +117,7 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
||||
attributes = updatedMessage.attributes
|
||||
text = updatedMessage.text
|
||||
forwardInfo = updatedMessage.forwardInfo
|
||||
} else if case let .updateShortSentMessage(_, _, _, _, _, apiMedia, entities) = result {
|
||||
} else if case let .updateShortSentMessage(_, _, _, _, _, apiMedia, entities, ttlPeriod) = result {
|
||||
let (mediaValue, _) = textMediaAndExpirationTimerFromApiMedia(apiMedia, currentMessage.id.peerId)
|
||||
if let mediaValue = mediaValue {
|
||||
media = [mediaValue]
|
||||
@ -136,6 +136,11 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
||||
updatedAttributes.append(TextEntitiesMessageAttribute(entities: messageTextEntitiesFromApiEntities(entities)))
|
||||
}
|
||||
|
||||
updatedAttributes = updatedAttributes.filter({ !($0 is AutoremoveTimeoutMessageAttribute) })
|
||||
if let ttlPeriod = ttlPeriod {
|
||||
updatedAttributes.append(AutoremoveTimeoutMessageAttribute(timeout: ttlPeriod, countdownBeginTime: updatedTimestamp))
|
||||
}
|
||||
|
||||
if Namespaces.Message.allScheduled.contains(message.id.namespace) && updatedId.namespace == Namespaces.Message.Cloud {
|
||||
for i in 0 ..< updatedAttributes.count {
|
||||
if updatedAttributes[i] is OutgoingScheduleInfoMessageAttribute {
|
||||
|
@ -57,14 +57,14 @@ class UpdateMessageService: NSObject, MTMessageService {
|
||||
if groups.count != 0 {
|
||||
self.putNext(groups)
|
||||
}
|
||||
case let .updateShortChatMessage(flags, id, fromId, chatId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyHeader, entities):
|
||||
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: .peerUser(userId: fromId), peerId: Api.Peer.peerChat(chatId: chatId), fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, restrictionReason: nil, ttlPeriod: nil)
|
||||
case let .updateShortChatMessage(flags, id, fromId, chatId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyHeader, entities, ttlPeriod):
|
||||
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: .peerUser(userId: fromId), peerId: Api.Peer.peerChat(chatId: chatId), fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, restrictionReason: nil, ttlPeriod: ttlPeriod)
|
||||
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
|
||||
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
|
||||
if groups.count != 0 {
|
||||
self.putNext(groups)
|
||||
}
|
||||
case let .updateShortMessage(flags, id, userId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyHeader, entities):
|
||||
case let .updateShortMessage(flags, id, userId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyHeader, entities, ttlPeriod):
|
||||
let generatedFromId: Api.Peer
|
||||
if (Int(flags) & 1 << 1) != 0 {
|
||||
generatedFromId = Api.Peer.peerUser(userId: self.peerId.id)
|
||||
@ -74,7 +74,7 @@ class UpdateMessageService: NSObject, MTMessageService {
|
||||
|
||||
let generatedPeerId = Api.Peer.peerUser(userId: userId)
|
||||
|
||||
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: generatedFromId, peerId: generatedPeerId, fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, restrictionReason: nil, ttlPeriod: nil)
|
||||
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: generatedFromId, peerId: generatedPeerId, fwdFrom: fwdFrom, viaBotId: viaBotId, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, restrictionReason: nil, ttlPeriod: ttlPeriod)
|
||||
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
|
||||
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
|
||||
if groups.count != 0 {
|
||||
@ -82,7 +82,7 @@ class UpdateMessageService: NSObject, MTMessageService {
|
||||
}
|
||||
case .updatesTooLong:
|
||||
self.pipe.putNext([.reset])
|
||||
case let .updateShortSentMessage(_, _, pts, ptsCount, _, _, _):
|
||||
case let .updateShortSentMessage(_, _, pts, ptsCount, _, _, _, _):
|
||||
self.pipe.putNext([.updatePts(pts: pts, ptsCount: ptsCount)])
|
||||
}
|
||||
}
|
||||
|
@ -384,13 +384,13 @@ extension Api.Updates {
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
case let .updateShortSentMessage(_, id, _, _, _, _, _):
|
||||
case let .updateShortSentMessage(_, id, _, _, _, _, _, _):
|
||||
return [id]
|
||||
case .updatesTooLong:
|
||||
return []
|
||||
case let .updateShortMessage(_, id, _, _, _, _, _, _, _, _, _):
|
||||
case let .updateShortMessage(_, id, _, _, _, _, _, _, _, _, _, _):
|
||||
return [id]
|
||||
case let .updateShortChatMessage(_, id, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .updateShortChatMessage(_, id, _, _, _, _, _, _, _, _, _, _, _):
|
||||
return [id]
|
||||
}
|
||||
}
|
||||
@ -423,9 +423,9 @@ extension Api.Updates {
|
||||
return []
|
||||
case .updatesTooLong:
|
||||
return []
|
||||
case let .updateShortMessage(_, id, userId, _, _, _, _, _, _, _, _):
|
||||
case let .updateShortMessage(_, id, userId, _, _, _, _, _, _, _, _, _):
|
||||
return [MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), namespace: Namespaces.Message.Cloud, id: id)]
|
||||
case let .updateShortChatMessage(_, id, _, chatId, _, _, _, _, _, _, _, _):
|
||||
case let .updateShortChatMessage(_, id, _, chatId, _, _, _, _, _, _, _, _, _):
|
||||
return [MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId), namespace: Namespaces.Message.Cloud, id: id)]
|
||||
}
|
||||
}
|
||||
@ -458,9 +458,9 @@ extension Api.Updates {
|
||||
return [:]
|
||||
case .updatesTooLong:
|
||||
return [:]
|
||||
case let .updateShortMessage(_, id, userId, _, _, _, _, _, _, _, _):
|
||||
case let .updateShortMessage(_, id, userId, _, _, _, _, _, _, _, _, _):
|
||||
return [:]
|
||||
case let .updateShortChatMessage(_, id, _, chatId, _, _, _, _, _, _, _, _):
|
||||
case let .updateShortChatMessage(_, id, _, chatId, _, _, _, _, _, _, _, _, _):
|
||||
return [:]
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -176,6 +176,10 @@ public final class PrincipalThemeEssentialGraphics {
|
||||
public let outgoingDateAndStatusPinnedIcon: UIImage
|
||||
public let mediaPinnedIcon: UIImage
|
||||
public let freePinnedIcon: UIImage
|
||||
public let incomingDateAndStatusSelfExpiringIcon: UIImage
|
||||
public let outgoingDateAndStatusSelfExpiringIcon: UIImage
|
||||
public let mediaSelfExpiringIcon: UIImage
|
||||
public let freeSelfExpiringIcon: UIImage
|
||||
|
||||
public let dateStaticBackground: UIImage
|
||||
public let dateFloatingBackground: UIImage
|
||||
@ -350,6 +354,12 @@ public final class PrincipalThemeEssentialGraphics {
|
||||
self.mediaPinnedIcon = generateTintedImage(image: pinnedImage, color: .white)!
|
||||
self.freePinnedIcon = generateTintedImage(image: pinnedImage, color: serviceColor.primaryText)!
|
||||
|
||||
let selfExpiringImage = UIImage(bundleImageName: "Chat/Message/SelfExpiring")!
|
||||
self.incomingDateAndStatusSelfExpiringIcon = generateTintedImage(image: selfExpiringImage, color: theme.message.incoming.secondaryTextColor)!
|
||||
self.outgoingDateAndStatusSelfExpiringIcon = generateTintedImage(image: selfExpiringImage, color: theme.message.outgoing.secondaryTextColor)!
|
||||
self.mediaSelfExpiringIcon = generateTintedImage(image: selfExpiringImage, color: .white)!
|
||||
self.freeSelfExpiringIcon = generateTintedImage(image: selfExpiringImage, color: serviceColor.primaryText)!
|
||||
|
||||
self.radialIndicatorFileIconIncoming = emptyImage
|
||||
self.radialIndicatorFileIconOutgoing = emptyImage
|
||||
} else {
|
||||
@ -463,6 +473,12 @@ public final class PrincipalThemeEssentialGraphics {
|
||||
self.mediaPinnedIcon = generateTintedImage(image: pinnedImage, color: .white)!
|
||||
self.freePinnedIcon = generateTintedImage(image: pinnedImage, color: serviceColor.primaryText)!
|
||||
|
||||
let selfExpiringImage = UIImage(bundleImageName: "Chat/Message/SelfExpiring")!
|
||||
self.incomingDateAndStatusSelfExpiringIcon = generateTintedImage(image: selfExpiringImage, color: theme.message.incoming.secondaryTextColor)!
|
||||
self.outgoingDateAndStatusSelfExpiringIcon = generateTintedImage(image: selfExpiringImage, color: theme.message.outgoing.secondaryTextColor)!
|
||||
self.mediaSelfExpiringIcon = generateTintedImage(image: selfExpiringImage, color: .white)!
|
||||
self.freeSelfExpiringIcon = generateTintedImage(image: selfExpiringImage, color: serviceColor.primaryText)!
|
||||
|
||||
self.radialIndicatorFileIconIncoming = generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/RadialProgressIconDocument"), color: .black)!
|
||||
self.radialIndicatorFileIconOutgoing = generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/RadialProgressIconDocument"), color: .black)!
|
||||
}
|
||||
|
@ -16,6 +16,3 @@ public func stringForDuration(_ duration: Int32, position: Int32? = nil) -> Stri
|
||||
}
|
||||
return durationString
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
12
submodules/TelegramUI/Images.xcassets/Chat/Message/SelfExpiring.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Message/SelfExpiring.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ic_autodeleteindicator.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Chat/Message/SelfExpiring.imageset/ic_autodeleteindicator.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Chat/Message/SelfExpiring.imageset/ic_autodeleteindicator.pdf
vendored
Normal file
Binary file not shown.
Binary file not shown.
@ -3,6 +3,7 @@ import UIKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
@ -15,6 +16,8 @@ import LegacyUI
|
||||
import AppBundle
|
||||
import SaveToCameraRoll
|
||||
import PresentationDataUtils
|
||||
import TelegramPresentationData
|
||||
import TelegramStringFormatting
|
||||
|
||||
private struct MessageContextMenuData {
|
||||
let starStatus: Bool?
|
||||
@ -881,6 +884,16 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
}
|
||||
|
||||
if !isReplyThreadHead, (!data.messageActions.options.intersection([.deleteLocally, .deleteGlobally]).isEmpty || clearCacheAsDelete) && !isAction {
|
||||
var autoremoveDeadline: Int32?
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? AutoremoveTimeoutMessageAttribute {
|
||||
if let countdownBeginTime = attribute.countdownBeginTime {
|
||||
autoremoveDeadline = countdownBeginTime + attribute.timeout
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let title: String
|
||||
var isSending = false
|
||||
var isEditing = false
|
||||
@ -894,16 +907,27 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
} else {
|
||||
title = chatPresentationInterfaceState.strings.Conversation_ContextMenuDelete
|
||||
}
|
||||
actions.append(.action(ContextMenuActionItem(text: title, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: isSending ? "Chat/Context Menu/Clear" : "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor)
|
||||
}, action: { controller, f in
|
||||
if isEditing {
|
||||
context.account.pendingUpdateMessageManager.cancel(messageId: message.id)
|
||||
f(.default)
|
||||
} else {
|
||||
interfaceInteraction.deleteMessages(selectAll ? messages : [message], controller, f)
|
||||
}
|
||||
})))
|
||||
if let autoremoveDeadline = autoremoveDeadline, !isEditing, !isSending {
|
||||
actions.append(.custom(ChatDeleteMessageContextItem(timestamp: Double(autoremoveDeadline), action: { controller, f in
|
||||
if isEditing {
|
||||
context.account.pendingUpdateMessageManager.cancel(messageId: message.id)
|
||||
f(.default)
|
||||
} else {
|
||||
interfaceInteraction.deleteMessages(selectAll ? messages : [message], controller, f)
|
||||
}
|
||||
}), false))
|
||||
} else {
|
||||
actions.append(.action(ContextMenuActionItem(text: title, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: isSending ? "Chat/Context Menu/Clear" : "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor)
|
||||
}, action: { controller, f in
|
||||
if isEditing {
|
||||
context.account.pendingUpdateMessageManager.cancel(messageId: message.id)
|
||||
f(.default)
|
||||
} else {
|
||||
interfaceInteraction.deleteMessages(selectAll ? messages : [message], controller, f)
|
||||
}
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
if !isPinnedMessages, !isReplyThreadHead, data.canSelect {
|
||||
@ -1195,3 +1219,228 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class ChatDeleteMessageContextItem: ContextMenuCustomItem {
|
||||
fileprivate let timestamp: Double
|
||||
fileprivate let action: (ContextController, @escaping (ContextMenuActionResult) -> Void) -> Void
|
||||
|
||||
init(timestamp: Double, action: @escaping (ContextController, @escaping (ContextMenuActionResult) -> Void) -> Void) {
|
||||
self.timestamp = timestamp
|
||||
self.action = action
|
||||
}
|
||||
|
||||
func node(presentationData: PresentationData, getController: @escaping () -> ContextController?, actionSelected: @escaping (ContextMenuActionResult) -> Void) -> ContextMenuCustomNode {
|
||||
return ChatDeleteMessageContextItemNode(presentationData: presentationData, item: self, getController: getController, actionSelected: actionSelected)
|
||||
}
|
||||
}
|
||||
|
||||
private let textFont = Font.regular(17.0)
|
||||
|
||||
private final class ChatDeleteMessageContextItemNode: ASDisplayNode, ContextMenuCustomNode {
|
||||
private let item: ChatDeleteMessageContextItem
|
||||
private let presentationData: PresentationData
|
||||
private let getController: () -> ContextController?
|
||||
private let actionSelected: (ContextMenuActionResult) -> Void
|
||||
|
||||
private let backgroundNode: ASDisplayNode
|
||||
private let highlightedBackgroundNode: ASDisplayNode
|
||||
private let textNode: ImmediateTextNode
|
||||
private let statusNode: ImmediateTextNode
|
||||
private let iconNode: ASImageNode
|
||||
private let textIconNode: ASImageNode
|
||||
private let buttonNode: HighlightTrackingButtonNode
|
||||
|
||||
private var timer: SwiftSignalKit.Timer?
|
||||
|
||||
private var pointerInteraction: PointerInteraction?
|
||||
|
||||
init(presentationData: PresentationData, item: ChatDeleteMessageContextItem, getController: @escaping () -> ContextController?, actionSelected: @escaping (ContextMenuActionResult) -> Void) {
|
||||
self.item = item
|
||||
self.presentationData = presentationData
|
||||
self.getController = getController
|
||||
self.actionSelected = actionSelected
|
||||
|
||||
let textFont = Font.regular(presentationData.listsFontSize.baseDisplaySize)
|
||||
let subtextFont = Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0)
|
||||
|
||||
self.backgroundNode = ASDisplayNode()
|
||||
self.backgroundNode.isAccessibilityElement = false
|
||||
self.backgroundNode.backgroundColor = presentationData.theme.contextMenu.itemBackgroundColor
|
||||
self.highlightedBackgroundNode = ASDisplayNode()
|
||||
self.highlightedBackgroundNode.isAccessibilityElement = false
|
||||
self.highlightedBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor
|
||||
self.highlightedBackgroundNode.alpha = 0.0
|
||||
|
||||
self.textNode = ImmediateTextNode()
|
||||
self.textNode.isAccessibilityElement = false
|
||||
self.textNode.isUserInteractionEnabled = false
|
||||
self.textNode.displaysAsynchronously = false
|
||||
self.textNode.attributedText = NSAttributedString(string: presentationData.strings.Conversation_ContextMenuDelete, font: textFont, textColor: presentationData.theme.contextMenu.destructiveColor)
|
||||
|
||||
self.textNode.maximumNumberOfLines = 1
|
||||
let statusNode = ImmediateTextNode()
|
||||
statusNode.isAccessibilityElement = false
|
||||
statusNode.isUserInteractionEnabled = false
|
||||
statusNode.displaysAsynchronously = false
|
||||
statusNode.attributedText = NSAttributedString(string: stringForRemainingTime(Int32(max(0.0, self.item.timestamp - Date().timeIntervalSince1970)), strings: presentationData.strings), font: subtextFont, textColor: presentationData.theme.contextMenu.destructiveColor)
|
||||
statusNode.maximumNumberOfLines = 1
|
||||
self.statusNode = statusNode
|
||||
|
||||
self.buttonNode = HighlightTrackingButtonNode()
|
||||
self.buttonNode.isAccessibilityElement = true
|
||||
self.buttonNode.accessibilityLabel = presentationData.strings.VoiceChat_StopRecording
|
||||
|
||||
self.iconNode = ASImageNode()
|
||||
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: presentationData.theme.actionSheet.destructiveActionTextColor)
|
||||
|
||||
self.textIconNode = ASImageNode()
|
||||
self.textIconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/SelfExpiring"), color: presentationData.theme.actionSheet.destructiveActionTextColor)
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.highlightedBackgroundNode)
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.statusNode)
|
||||
self.addSubnode(self.iconNode)
|
||||
self.addSubnode(self.textIconNode)
|
||||
self.addSubnode(self.buttonNode)
|
||||
|
||||
self.buttonNode.highligthedChanged = { [weak self] highligted in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if highligted {
|
||||
strongSelf.highlightedBackgroundNode.alpha = 1.0
|
||||
} else {
|
||||
strongSelf.highlightedBackgroundNode.alpha = 0.0
|
||||
strongSelf.highlightedBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
|
||||
}
|
||||
}
|
||||
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.timer?.invalidate()
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.pointerInteraction = PointerInteraction(node: self.buttonNode, style: .hover, willEnter: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.highlightedBackgroundNode.alpha = 0.75
|
||||
}
|
||||
}, willExit: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.highlightedBackgroundNode.alpha = 0.0
|
||||
}
|
||||
})
|
||||
|
||||
let timer = SwiftSignalKit.Timer(timeout: 0.5, repeat: true, completion: { [weak self] in
|
||||
self?.updateTime(transition: .immediate)
|
||||
}, queue: Queue.mainQueue())
|
||||
self.timer = timer
|
||||
timer.start()
|
||||
}
|
||||
|
||||
private var validLayout: CGSize?
|
||||
func updateTime(transition: ContainedViewLayoutTransition) {
|
||||
guard let size = self.validLayout else {
|
||||
return
|
||||
}
|
||||
|
||||
let subtextFont = Font.regular(self.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0)
|
||||
self.statusNode.attributedText = NSAttributedString(string: stringForRemainingTime(Int32(max(0.0, self.item.timestamp - Date().timeIntervalSince1970)), strings: presentationData.strings), font: subtextFont, textColor: presentationData.theme.contextMenu.destructiveColor)
|
||||
|
||||
let sideInset: CGFloat = 16.0
|
||||
let statusSize = self.statusNode.updateLayout(CGSize(width: size.width - sideInset - 32.0, height: .greatestFiniteMagnitude))
|
||||
transition.updateFrameAdditive(node: self.statusNode, frame: CGRect(origin: CGPoint(x: self.statusNode.frame.minX, y: self.statusNode.frame.minY), size: statusSize))
|
||||
}
|
||||
|
||||
func updateLayout(constrainedWidth: CGFloat) -> (CGSize, (CGSize, ContainedViewLayoutTransition) -> Void) {
|
||||
let sideInset: CGFloat = 16.0
|
||||
let iconSideInset: CGFloat = 12.0
|
||||
let verticalInset: CGFloat = 12.0
|
||||
|
||||
let iconSize: CGSize = self.iconNode.image?.size ?? CGSize(width: 10.0, height: 10.0)
|
||||
let textIconSize: CGSize = self.textIconNode.image?.size ?? CGSize(width: 2.0, height: 2.0)
|
||||
|
||||
let standardIconWidth: CGFloat = 32.0
|
||||
var rightTextInset: CGFloat = sideInset
|
||||
if !iconSize.width.isZero {
|
||||
rightTextInset = max(iconSize.width, standardIconWidth) + iconSideInset + sideInset
|
||||
}
|
||||
|
||||
let textSize = self.textNode.updateLayout(CGSize(width: constrainedWidth - sideInset - rightTextInset, height: .greatestFiniteMagnitude))
|
||||
let statusSize = self.statusNode.updateLayout(CGSize(width: constrainedWidth - sideInset - rightTextInset - textIconSize.width - 2.0, height: .greatestFiniteMagnitude))
|
||||
|
||||
let verticalSpacing: CGFloat = 2.0
|
||||
let combinedTextHeight = textSize.height + verticalSpacing + statusSize.height
|
||||
return (CGSize(width: max(textSize.width, statusSize.width) + sideInset + rightTextInset, height: verticalInset * 2.0 + combinedTextHeight), { size, transition in
|
||||
self.validLayout = size
|
||||
let verticalOrigin = floor((size.height - combinedTextHeight) / 2.0)
|
||||
let textFrame = CGRect(origin: CGPoint(x: sideInset, y: verticalOrigin), size: textSize)
|
||||
transition.updateFrameAdditive(node: self.textNode, frame: textFrame)
|
||||
|
||||
transition.updateFrame(node: self.textIconNode, frame: CGRect(origin: CGPoint(x: sideInset, y: verticalOrigin + verticalSpacing + textSize.height + floorToScreenPixels((statusSize.height - textIconSize.height) / 2.0) + 1.0), size: textIconSize))
|
||||
transition.updateFrameAdditive(node: self.statusNode, frame: CGRect(origin: CGPoint(x: sideInset + textIconSize.width + 2.0, y: verticalOrigin + verticalSpacing + textSize.height), size: statusSize))
|
||||
|
||||
if !iconSize.width.isZero {
|
||||
transition.updateFrameAdditive(node: self.iconNode, frame: CGRect(origin: CGPoint(x: size.width - standardIconWidth - iconSideInset + floor((standardIconWidth - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize))
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
|
||||
transition.updateFrame(node: self.highlightedBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
|
||||
transition.updateFrame(node: self.buttonNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
|
||||
})
|
||||
}
|
||||
|
||||
func updateTheme(presentationData: PresentationData) {
|
||||
self.backgroundNode.backgroundColor = presentationData.theme.contextMenu.itemBackgroundColor
|
||||
self.highlightedBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor
|
||||
|
||||
let textFont = Font.regular(presentationData.listsFontSize.baseDisplaySize)
|
||||
let subtextFont = Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0)
|
||||
|
||||
self.textNode.attributedText = NSAttributedString(string: self.textNode.attributedText?.string ?? "", font: textFont, textColor: presentationData.theme.contextMenu.primaryColor)
|
||||
self.statusNode.attributedText = NSAttributedString(string: self.statusNode.attributedText?.string ?? "", font: subtextFont, textColor: presentationData.theme.contextMenu.secondaryColor)
|
||||
}
|
||||
|
||||
@objc private func buttonPressed() {
|
||||
self.performAction()
|
||||
}
|
||||
|
||||
func performAction() {
|
||||
guard let controller = self.getController() else {
|
||||
return
|
||||
}
|
||||
self.item.action(controller, { [weak self] result in
|
||||
self?.actionSelected(result)
|
||||
})
|
||||
}
|
||||
|
||||
func setIsHighlighted(_ value: Bool) {
|
||||
if value {
|
||||
self.highlightedBackgroundNode.alpha = 1.0
|
||||
} else {
|
||||
self.highlightedBackgroundNode.alpha = 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func stringForRemainingTime(_ duration: Int32, strings: PresentationStrings) -> String {
|
||||
let days = duration / (3600 * 24)
|
||||
let hours = duration / 3600
|
||||
let minutes = duration / 60 % 60
|
||||
let seconds = duration % 60
|
||||
let durationString: String
|
||||
if days > 0 {
|
||||
return strings.Conversation_AutoremoveRemainingDays(days)
|
||||
} else if hours > 0 {
|
||||
durationString = String(format: "%d:%02d:%02d", hours, minutes, seconds)
|
||||
} else {
|
||||
durationString = String(format: "%d:%02d", minutes, seconds)
|
||||
}
|
||||
return strings.Conversation_AutoremoveRemainingTime(durationString).0
|
||||
}
|
||||
|
@ -773,7 +773,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
isReplyThread = true
|
||||
}
|
||||
|
||||
let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread)
|
||||
let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring)
|
||||
|
||||
var viaBotApply: (TextNodeLayout, () -> TextNode)?
|
||||
var replyInfoApply: (CGSize, () -> ChatMessageReplyInfoNode)?
|
||||
|
@ -577,7 +577,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
statusSizeAndApply = statusLayout(context, presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReactions, dateReplies, message.tags.contains(.pinned) && !associatedData.isInPinnedListMode && !isReplyThread)
|
||||
statusSizeAndApply = statusLayout(context, presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReactions, dateReplies, message.tags.contains(.pinned) && !associatedData.isInPinnedListMode && !isReplyThread, message.isSelfExpiring)
|
||||
}
|
||||
default:
|
||||
break
|
||||
|
@ -978,7 +978,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
forwardInfoLayout: (ChatPresentationData, PresentationStrings, ChatMessageForwardInfoType, Peer?, String?, String?, CGSize) -> (CGSize, (CGFloat) -> ChatMessageForwardInfoNode),
|
||||
replyInfoLayout: (ChatPresentationData, PresentationStrings, AccountContext, ChatMessageReplyInfoType, Message, CGSize) -> (CGSize, () -> ChatMessageReplyInfoNode),
|
||||
actionButtonsLayout: (AccountContext, ChatPresentationThemeData, PresentationChatBubbleCorners, PresentationStrings, ReplyMarkupMessageAttribute, Message, CGFloat) -> (minWidth: CGFloat, layout: (CGFloat) -> (CGSize, (Bool) -> ChatMessageActionButtonsNode)),
|
||||
mosaicStatusLayout: (AccountContext, ChatPresentationData, Bool, Int?, String, ChatMessageDateAndStatusType, CGSize, [MessageReaction], Int, Bool) -> (CGSize, (Bool) -> ChatMessageDateAndStatusNode),
|
||||
mosaicStatusLayout: (AccountContext, ChatPresentationData, Bool, Int?, String, ChatMessageDateAndStatusType, CGSize, [MessageReaction], Int, Bool, Bool) -> (CGSize, (Bool) -> ChatMessageDateAndStatusNode),
|
||||
currentShareButtonNode: HighlightableButtonNode?,
|
||||
layoutConstants: ChatMessageItemLayoutConstants,
|
||||
currentItem: ChatMessageItem?,
|
||||
@ -1564,7 +1564,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
isReplyThread = true
|
||||
}
|
||||
|
||||
mosaicStatusSizeAndApply = mosaicStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: 200.0, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread)
|
||||
mosaicStatusSizeAndApply = mosaicStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: 200.0, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, message.isSelfExpiring)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
isReplyThread = true
|
||||
}
|
||||
|
||||
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: constrainedSize.width, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread)
|
||||
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: constrainedSize.width, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring)
|
||||
statusSize = size
|
||||
statusApply = apply
|
||||
}
|
||||
|
@ -161,6 +161,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
private var reactionCountNode: TextNode?
|
||||
private var reactionButtonNode: HighlightTrackingButtonNode?
|
||||
private var repliesIcon: ASImageNode?
|
||||
private var selfExpiringIcon: ASImageNode?
|
||||
private var replyCountNode: TextNode?
|
||||
|
||||
private var type: ChatMessageDateAndStatusType?
|
||||
@ -202,7 +203,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
func asyncLayout() -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ edited: Bool, _ impressionCount: Int?, _ dateText: String, _ type: ChatMessageDateAndStatusType, _ constrainedSize: CGSize, _ reactions: [MessageReaction], _ replies: Int, _ isPinned: Bool) -> (CGSize, (Bool) -> Void) {
|
||||
func asyncLayout() -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ edited: Bool, _ impressionCount: Int?, _ dateText: String, _ type: ChatMessageDateAndStatusType, _ constrainedSize: CGSize, _ reactions: [MessageReaction], _ replies: Int, _ isPinned: Bool, _ hasAutoremove: Bool) -> (CGSize, (Bool) -> Void) {
|
||||
let dateLayout = TextNode.asyncLayout(self.dateNode)
|
||||
|
||||
var checkReadNode = self.checkReadNode
|
||||
@ -213,6 +214,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
var currentBackgroundNode = self.backgroundNode
|
||||
var currentImpressionIcon = self.impressionIcon
|
||||
var currentRepliesIcon = self.repliesIcon
|
||||
var currentSelfExpiringIcon = self.selfExpiringIcon
|
||||
|
||||
let currentType = self.type
|
||||
let currentTheme = self.theme
|
||||
@ -222,7 +224,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
|
||||
let previousLayoutSize = self.layoutSize
|
||||
|
||||
return { context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions, replyCount, isPinned in
|
||||
return { context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions, replyCount, isPinned, hasAutoremove in
|
||||
let dateColor: UIColor
|
||||
var backgroundImage: UIImage?
|
||||
var outgoingStatus: ChatMessageDateAndStatusOutgoingType?
|
||||
@ -234,6 +236,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
let clockMinImage: UIImage?
|
||||
var impressionImage: UIImage?
|
||||
var repliesImage: UIImage?
|
||||
var selfExpiringImage: UIImage?
|
||||
|
||||
let themeUpdated = presentationData.theme != currentTheme || type != currentType
|
||||
|
||||
@ -259,6 +262,9 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
} else if isPinned {
|
||||
repliesImage = graphics.incomingDateAndStatusPinnedIcon
|
||||
}
|
||||
if hasAutoremove {
|
||||
selfExpiringImage = graphics.incomingDateAndStatusSelfExpiringIcon
|
||||
}
|
||||
case let .BubbleOutgoing(status):
|
||||
dateColor = presentationData.theme.theme.chat.message.outgoing.secondaryTextColor
|
||||
outgoingStatus = status
|
||||
@ -275,6 +281,9 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
} else if isPinned {
|
||||
repliesImage = graphics.outgoingDateAndStatusPinnedIcon
|
||||
}
|
||||
if hasAutoremove {
|
||||
selfExpiringImage = graphics.outgoingDateAndStatusSelfExpiringIcon
|
||||
}
|
||||
case .ImageIncoming:
|
||||
dateColor = presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor
|
||||
backgroundImage = graphics.dateAndStatusMediaBackground
|
||||
@ -291,6 +300,9 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
} else if isPinned {
|
||||
repliesImage = graphics.mediaPinnedIcon
|
||||
}
|
||||
if hasAutoremove {
|
||||
selfExpiringImage = graphics.mediaSelfExpiringIcon
|
||||
}
|
||||
case let .ImageOutgoing(status):
|
||||
dateColor = presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor
|
||||
outgoingStatus = status
|
||||
@ -308,6 +320,9 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
} else if isPinned {
|
||||
repliesImage = graphics.mediaPinnedIcon
|
||||
}
|
||||
if hasAutoremove {
|
||||
selfExpiringImage = graphics.mediaSelfExpiringIcon
|
||||
}
|
||||
case .FreeIncoming:
|
||||
let serviceColor = serviceMessageColorComponents(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
||||
dateColor = serviceColor.primaryText
|
||||
@ -325,6 +340,9 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
} else if isPinned {
|
||||
repliesImage = graphics.freePinnedIcon
|
||||
}
|
||||
if hasAutoremove {
|
||||
selfExpiringImage = graphics.freeSelfExpiringIcon
|
||||
}
|
||||
case let .FreeOutgoing(status):
|
||||
let serviceColor = serviceMessageColorComponents(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
||||
dateColor = serviceColor.primaryText
|
||||
@ -343,6 +361,9 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
} else if isPinned {
|
||||
repliesImage = graphics.freePinnedIcon
|
||||
}
|
||||
if hasAutoremove {
|
||||
selfExpiringImage = graphics.freeSelfExpiringIcon
|
||||
}
|
||||
}
|
||||
|
||||
var updatedDateText = dateText
|
||||
@ -395,6 +416,20 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
currentRepliesIcon = nil
|
||||
}
|
||||
|
||||
var selfExpiringIconSize = CGSize()
|
||||
if let selfExpiringImage = selfExpiringImage {
|
||||
if currentSelfExpiringIcon == nil {
|
||||
let iconNode = ASImageNode()
|
||||
iconNode.isLayerBacked = true
|
||||
iconNode.displayWithoutProcessing = true
|
||||
iconNode.displaysAsynchronously = false
|
||||
currentSelfExpiringIcon = iconNode
|
||||
}
|
||||
selfExpiringIconSize = selfExpiringImage.size
|
||||
} else {
|
||||
currentSelfExpiringIcon = nil
|
||||
}
|
||||
|
||||
if let outgoingStatus = outgoingStatus {
|
||||
switch outgoingStatus {
|
||||
case .Sending:
|
||||
@ -549,6 +584,10 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
reactionInset += 12.0
|
||||
}
|
||||
|
||||
if !selfExpiringIconSize.width.isZero {
|
||||
reactionInset += selfExpiringIconSize.width + 1.0
|
||||
}
|
||||
|
||||
leftInset += reactionInset
|
||||
|
||||
let layoutSize = CGSize(width: leftInset + impressionWidth + date.size.width + statusWidth + backgroundInsets.left + backgroundInsets.right, height: date.size.height + backgroundInsets.top + backgroundInsets.bottom)
|
||||
@ -795,6 +834,34 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
if let currentSelfExpiringIcon = currentSelfExpiringIcon {
|
||||
currentSelfExpiringIcon.displaysAsynchronously = !presentationData.isPreview
|
||||
if currentSelfExpiringIcon.image !== selfExpiringImage {
|
||||
currentSelfExpiringIcon.image = selfExpiringImage
|
||||
}
|
||||
if currentSelfExpiringIcon.supernode == nil {
|
||||
strongSelf.selfExpiringIcon = currentSelfExpiringIcon
|
||||
strongSelf.addSubnode(currentSelfExpiringIcon)
|
||||
if animated {
|
||||
currentSelfExpiringIcon.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
|
||||
}
|
||||
}
|
||||
currentSelfExpiringIcon.frame = CGRect(origin: CGPoint(x: reactionOffset - 2.0, y: backgroundInsets.top + offset + floor((date.size.height - selfExpiringIconSize.height) / 2.0)), size: selfExpiringIconSize)
|
||||
reactionOffset += 9.0
|
||||
} else if let selfExpiringIcon = strongSelf.selfExpiringIcon {
|
||||
strongSelf.selfExpiringIcon = nil
|
||||
if animated {
|
||||
if let previousLayoutSize = previousLayoutSize {
|
||||
selfExpiringIcon.frame = selfExpiringIcon.frame.offsetBy(dx: layoutSize.width - previousLayoutSize.width, dy: 0.0)
|
||||
}
|
||||
selfExpiringIcon.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak selfExpiringIcon] _ in
|
||||
selfExpiringIcon?.removeFromSupernode()
|
||||
})
|
||||
} else {
|
||||
selfExpiringIcon.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
|
||||
if let (layout, apply) = replyCountLayoutAndApply {
|
||||
let node = apply()
|
||||
if strongSelf.replyCountNode !== node {
|
||||
@ -853,17 +920,17 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
static func asyncLayout(_ node: ChatMessageDateAndStatusNode?) -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ edited: Bool, _ impressionCount: Int?, _ dateText: String, _ type: ChatMessageDateAndStatusType, _ constrainedSize: CGSize, _ reactions: [MessageReaction], _ replies: Int, _ isPinned: Bool) -> (CGSize, (Bool) -> ChatMessageDateAndStatusNode) {
|
||||
static func asyncLayout(_ node: ChatMessageDateAndStatusNode?) -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ edited: Bool, _ impressionCount: Int?, _ dateText: String, _ type: ChatMessageDateAndStatusType, _ constrainedSize: CGSize, _ reactions: [MessageReaction], _ replies: Int, _ isPinned: Bool, _ hasAutoremove: Bool) -> (CGSize, (Bool) -> ChatMessageDateAndStatusNode) {
|
||||
let currentLayout = node?.asyncLayout()
|
||||
return { context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions, replies, isPinned in
|
||||
return { context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions, replies, isPinned, hasAutoremove in
|
||||
let resultNode: ChatMessageDateAndStatusNode
|
||||
let resultSizeAndApply: (CGSize, (Bool) -> Void)
|
||||
if let node = node, let currentLayout = currentLayout {
|
||||
resultNode = node
|
||||
resultSizeAndApply = currentLayout(context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions, replies, isPinned)
|
||||
resultSizeAndApply = currentLayout(context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions, replies, isPinned, hasAutoremove)
|
||||
} else {
|
||||
resultNode = ChatMessageDateAndStatusNode()
|
||||
resultSizeAndApply = resultNode.asyncLayout()(context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions, replies, isPinned)
|
||||
resultSizeAndApply = resultNode.asyncLayout()(context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions, replies, isPinned, hasAutoremove)
|
||||
}
|
||||
|
||||
return (resultSizeAndApply.0, { animated in
|
||||
|
@ -331,7 +331,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
|
||||
let dateText = stringForMessageTimestampStatus(accountPeerId: context.account.peerId, message: message, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, strings: presentationData.strings, reactionCount: dateReactionCount)
|
||||
|
||||
let (size, apply) = statusLayout(context, presentationData, edited, viewCount, dateText, statusType, constrainedSize, dateReactions, dateReplies, isPinned && !associatedData.isInPinnedListMode)
|
||||
let (size, apply) = statusLayout(context, presentationData, edited, viewCount, dateText, statusType, constrainedSize, dateReactions, dateReplies, isPinned && !associatedData.isInPinnedListMode, message.isSelfExpiring)
|
||||
statusSize = size
|
||||
statusApply = apply
|
||||
}
|
||||
|
@ -291,7 +291,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
isReplyThread = true
|
||||
}
|
||||
|
||||
let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited && !sentViaBot, viewCount, dateText, statusType, CGSize(width: max(1.0, maxDateAndStatusWidth), height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread)
|
||||
let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited && !sentViaBot, viewCount, dateText, statusType, CGSize(width: max(1.0, maxDateAndStatusWidth), height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring)
|
||||
|
||||
var contentSize = imageSize
|
||||
var dateAndStatusOverflow = false
|
||||
|
@ -251,7 +251,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
isReplyThread = true
|
||||
}
|
||||
|
||||
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: constrainedSize.width, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread)
|
||||
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: constrainedSize.width, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring)
|
||||
statusSize = size
|
||||
statusApply = apply
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
isReplyThread = true
|
||||
}
|
||||
|
||||
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: imageSize.width - 30.0, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread)
|
||||
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: imageSize.width - 30.0, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring)
|
||||
statusSize = size
|
||||
statusApply = apply
|
||||
}
|
||||
|
@ -1079,7 +1079,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
isReplyThread = true
|
||||
}
|
||||
|
||||
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread)
|
||||
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring)
|
||||
statusSize = size
|
||||
statusApply = apply
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
isReplyThread = true
|
||||
}
|
||||
|
||||
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && isReplyThread)
|
||||
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && isReplyThread, item.message.isSelfExpiring)
|
||||
statusSize = size
|
||||
statusApply = apply
|
||||
}
|
||||
|
@ -434,7 +434,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
isReplyThread = true
|
||||
}
|
||||
|
||||
let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread)
|
||||
let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring)
|
||||
|
||||
var viaBotApply: (TextNodeLayout, () -> TextNode)?
|
||||
var replyInfoApply: (CGSize, () -> ChatMessageReplyInfoNode)?
|
||||
|
@ -174,7 +174,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
isReplyThread = true
|
||||
}
|
||||
|
||||
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread)
|
||||
let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring)
|
||||
statusSize = size
|
||||
statusApply = apply
|
||||
}
|
||||
|
@ -544,6 +544,7 @@ private final class PeerInfoInteraction {
|
||||
let editingToggleMessageSignatures: (Bool) -> Void
|
||||
let openParticipantsSection: (PeerInfoParticipantsSection) -> Void
|
||||
let editingOpenPreHistorySetup: () -> Void
|
||||
let editingOpenAutoremoveMesages: () -> Void
|
||||
let openPermissions: () -> Void
|
||||
let editingOpenStickerPackSetup: () -> Void
|
||||
let openLocation: () -> Void
|
||||
@ -580,6 +581,7 @@ private final class PeerInfoInteraction {
|
||||
editingToggleMessageSignatures: @escaping (Bool) -> Void,
|
||||
openParticipantsSection: @escaping (PeerInfoParticipantsSection) -> Void,
|
||||
editingOpenPreHistorySetup: @escaping () -> Void,
|
||||
editingOpenAutoremoveMesages: @escaping () -> Void,
|
||||
openPermissions: @escaping () -> Void,
|
||||
editingOpenStickerPackSetup: @escaping () -> Void,
|
||||
openLocation: @escaping () -> Void,
|
||||
@ -615,6 +617,7 @@ private final class PeerInfoInteraction {
|
||||
self.editingToggleMessageSignatures = editingToggleMessageSignatures
|
||||
self.openParticipantsSection = openParticipantsSection
|
||||
self.editingOpenPreHistorySetup = editingOpenPreHistorySetup
|
||||
self.editingOpenAutoremoveMesages = editingOpenAutoremoveMesages
|
||||
self.openPermissions = openPermissions
|
||||
self.editingOpenStickerPackSetup = editingOpenStickerPackSetup
|
||||
self.openLocation = openLocation
|
||||
@ -1182,6 +1185,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
let ItemDiscussionGroup = 3
|
||||
let ItemSignMessages = 4
|
||||
let ItemSignMessagesHelp = 5
|
||||
let ItemAutoremove = 6
|
||||
|
||||
switch channel.info {
|
||||
case .broadcast:
|
||||
@ -1228,6 +1232,23 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
interaction.editingOpenDiscussionGroupSetup()
|
||||
}))
|
||||
|
||||
if channel.hasPermission(.changeInfo) {
|
||||
let timeoutString: String
|
||||
if case let .known(value) = (data.cachedData as? CachedChannelData)?.autoremoveTimeout {
|
||||
if let value = value {
|
||||
timeoutString = timeIntervalString(strings: presentationData.strings, value: value)
|
||||
} else {
|
||||
timeoutString = presentationData.strings.PeerInfo_AutoremoveMessagesDisabled
|
||||
}
|
||||
} else {
|
||||
timeoutString = ""
|
||||
}
|
||||
|
||||
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAutoremove, label: .text(timeoutString), text: presentationData.strings.PeerInfo_AutoremoveMessages, action: {
|
||||
interaction.editingOpenAutoremoveMesages()
|
||||
}))
|
||||
}
|
||||
|
||||
let messagesShouldHaveSignatures: Bool
|
||||
switch channel.info {
|
||||
case let .broadcast(info):
|
||||
@ -1250,6 +1271,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
let ItemLocationHeader = 7
|
||||
let ItemLocation = 8
|
||||
let ItemLocationSetup = 9
|
||||
let ItemAutoremove = 10
|
||||
|
||||
let isCreator = channel.flags.contains(.isCreator)
|
||||
let isPublic = channel.username != nil
|
||||
@ -1327,6 +1349,23 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
interaction.editingOpenPreHistorySetup()
|
||||
}))
|
||||
}
|
||||
|
||||
if channel.hasPermission(.changeInfo) {
|
||||
let timeoutString: String
|
||||
if case let .known(value) = cachedData.autoremoveTimeout {
|
||||
if let value = value {
|
||||
timeoutString = timeIntervalString(strings: presentationData.strings, value: value)
|
||||
} else {
|
||||
timeoutString = presentationData.strings.PeerInfo_AutoremoveMessagesDisabled
|
||||
}
|
||||
} else {
|
||||
timeoutString = ""
|
||||
}
|
||||
|
||||
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAutoremove, label: .text(timeoutString), text: presentationData.strings.PeerInfo_AutoremoveMessages, action: {
|
||||
interaction.editingOpenAutoremoveMesages()
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1371,6 +1410,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
let ItemPreHistory = 3
|
||||
let ItemPermissions = 4
|
||||
let ItemAdmins = 5
|
||||
let ItemAutoremove = 6
|
||||
|
||||
if case .creator = group.role {
|
||||
if let cachedData = data.cachedData as? CachedGroupData {
|
||||
@ -1395,6 +1435,25 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPreHistory, label: .text(presentationData.strings.GroupInfo_GroupHistoryHidden), text: presentationData.strings.GroupInfo_GroupHistory, action: {
|
||||
interaction.editingOpenPreHistorySetup()
|
||||
}))
|
||||
|
||||
let canChangeInfo = true
|
||||
if canChangeInfo {
|
||||
let timeoutString: String
|
||||
if case let .known(value) = (data.cachedData as? CachedGroupData)?.autoremoveTimeout {
|
||||
if let value = value {
|
||||
timeoutString = timeIntervalString(strings: presentationData.strings, value: value)
|
||||
} else {
|
||||
timeoutString = presentationData.strings.PeerInfo_AutoremoveMessagesDisabled
|
||||
}
|
||||
} else {
|
||||
timeoutString = ""
|
||||
}
|
||||
|
||||
items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAutoremove, label: .text(timeoutString), text: presentationData.strings.PeerInfo_AutoremoveMessages, action: {
|
||||
interaction.editingOpenAutoremoveMesages()
|
||||
}))
|
||||
}
|
||||
|
||||
var activePermissionCount: Int?
|
||||
if let defaultBannedRights = group.defaultBannedRights {
|
||||
var count = 0
|
||||
@ -1591,6 +1650,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
editingOpenPreHistorySetup: { [weak self] in
|
||||
self?.editingOpenPreHistorySetup()
|
||||
},
|
||||
editingOpenAutoremoveMesages: { [weak self] in
|
||||
self?.editingOpenAutoremoveMesages()
|
||||
},
|
||||
openPermissions: { [weak self] in
|
||||
self?.openPermissions()
|
||||
},
|
||||
@ -3796,6 +3858,10 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
}
|
||||
}
|
||||
|
||||
private func editingOpenAutoremoveMesages() {
|
||||
|
||||
}
|
||||
|
||||
private func openPermissions() {
|
||||
guard let data = self.data, let peer = data.peer else {
|
||||
return
|
||||
|
Loading…
x
Reference in New Issue
Block a user