mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-06 17:00:13 +00:00
Update API [skip ci]
This commit is contained in:
parent
76a24167d9
commit
f1b98f6dd8
@ -607,7 +607,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1192749220] = { return Api.MessageAction.parse_messageActionStarGift($0) }
|
||||
dict[775611918] = { return Api.MessageAction.parse_messageActionStarGiftUnique($0) }
|
||||
dict[1474192222] = { return Api.MessageAction.parse_messageActionSuggestProfilePhoto($0) }
|
||||
dict[866770590] = { return Api.MessageAction.parse_messageActionSuggestedPostApproval($0) }
|
||||
dict[-1354584535] = { return Api.MessageAction.parse_messageActionSuggestedPostApproval($0) }
|
||||
dict[-940721021] = { return Api.MessageAction.parse_messageActionTodoAppendTasks($0) }
|
||||
dict[-864265079] = { return Api.MessageAction.parse_messageActionTodoCompletions($0) }
|
||||
dict[228168278] = { return Api.MessageAction.parse_messageActionTopicCreate($0) }
|
||||
|
||||
@ -395,7 +395,7 @@ public extension Api {
|
||||
case messageActionStarGift(flags: Int32, gift: Api.StarGift, message: Api.TextWithEntities?, convertStars: Int64?, upgradeMsgId: Int32?, upgradeStars: Int64?, fromId: Api.Peer?, peer: Api.Peer?, savedId: Int64?)
|
||||
case messageActionStarGiftUnique(flags: Int32, gift: Api.StarGift, canExportAt: Int32?, transferStars: Int64?, fromId: Api.Peer?, peer: Api.Peer?, savedId: Int64?, resaleStars: Int64?, canTransferAt: Int32?, canResellAt: Int32?)
|
||||
case messageActionSuggestProfilePhoto(photo: Api.Photo)
|
||||
case messageActionSuggestedPostApproval(flags: Int32)
|
||||
case messageActionSuggestedPostApproval(flags: Int32, rejectComment: String?, scheduleDate: Int32?, starsAmount: Int64?)
|
||||
case messageActionTodoAppendTasks(list: [Api.TodoItem])
|
||||
case messageActionTodoCompletions(completed: [Int32], incompleted: [Int32])
|
||||
case messageActionTopicCreate(flags: Int32, title: String, iconColor: Int32, iconEmojiId: Int64?)
|
||||
@ -804,11 +804,14 @@ public extension Api {
|
||||
}
|
||||
photo.serialize(buffer, true)
|
||||
break
|
||||
case .messageActionSuggestedPostApproval(let flags):
|
||||
case .messageActionSuggestedPostApproval(let flags, let rejectComment, let scheduleDate, let starsAmount):
|
||||
if boxed {
|
||||
buffer.appendInt32(866770590)
|
||||
buffer.appendInt32(-1354584535)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 2) != 0 {serializeString(rejectComment!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 3) != 0 {serializeInt32(scheduleDate!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 4) != 0 {serializeInt64(starsAmount!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
case .messageActionTodoAppendTasks(let list):
|
||||
if boxed {
|
||||
@ -966,8 +969,8 @@ public extension Api {
|
||||
return ("messageActionStarGiftUnique", [("flags", flags as Any), ("gift", gift as Any), ("canExportAt", canExportAt as Any), ("transferStars", transferStars as Any), ("fromId", fromId as Any), ("peer", peer as Any), ("savedId", savedId as Any), ("resaleStars", resaleStars as Any), ("canTransferAt", canTransferAt as Any), ("canResellAt", canResellAt as Any)])
|
||||
case .messageActionSuggestProfilePhoto(let photo):
|
||||
return ("messageActionSuggestProfilePhoto", [("photo", photo as Any)])
|
||||
case .messageActionSuggestedPostApproval(let flags):
|
||||
return ("messageActionSuggestedPostApproval", [("flags", flags as Any)])
|
||||
case .messageActionSuggestedPostApproval(let flags, let rejectComment, let scheduleDate, let starsAmount):
|
||||
return ("messageActionSuggestedPostApproval", [("flags", flags as Any), ("rejectComment", rejectComment as Any), ("scheduleDate", scheduleDate as Any), ("starsAmount", starsAmount as Any)])
|
||||
case .messageActionTodoAppendTasks(let list):
|
||||
return ("messageActionTodoAppendTasks", [("list", list as Any)])
|
||||
case .messageActionTodoCompletions(let completed, let incompleted):
|
||||
@ -1770,9 +1773,18 @@ public extension Api {
|
||||
public static func parse_messageActionSuggestedPostApproval(_ reader: BufferReader) -> MessageAction? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: String?
|
||||
if Int(_1!) & Int(1 << 2) != 0 {_2 = parseString(reader) }
|
||||
var _3: Int32?
|
||||
if Int(_1!) & Int(1 << 3) != 0 {_3 = reader.readInt32() }
|
||||
var _4: Int64?
|
||||
if Int(_1!) & Int(1 << 4) != 0 {_4 = reader.readInt64() }
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.MessageAction.messageActionSuggestedPostApproval(flags: _1!)
|
||||
let _c2 = (Int(_1!) & Int(1 << 2) == 0) || _2 != nil
|
||||
let _c3 = (Int(_1!) & Int(1 << 3) == 0) || _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 4) == 0) || _4 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 {
|
||||
return Api.MessageAction.messageActionSuggestedPostApproval(flags: _1!, rejectComment: _2, scheduleDate: _3, starsAmount: _4)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
||||
@ -8909,14 +8909,15 @@ public extension Api.functions.messages {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.messages {
|
||||
static func toggleSuggestedPostApproval(flags: Int32, peer: Api.InputPeer, msgId: Int32, scheduleDate: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
static func toggleSuggestedPostApproval(flags: Int32, peer: Api.InputPeer, msgId: Int32, scheduleDate: Int32?, rejectComment: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(806598987)
|
||||
buffer.appendInt32(-2130229924)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
peer.serialize(buffer, true)
|
||||
serializeInt32(msgId, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(scheduleDate!, buffer: buffer, boxed: false)}
|
||||
return (FunctionDescription(name: "messages.toggleSuggestedPostApproval", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("msgId", String(describing: msgId)), ("scheduleDate", String(describing: scheduleDate))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
if Int(flags) & Int(1 << 2) != 0 {serializeString(rejectComment!, buffer: buffer, boxed: false)}
|
||||
return (FunctionDescription(name: "messages.toggleSuggestedPostApproval", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("msgId", String(describing: msgId)), ("scheduleDate", String(describing: scheduleDate)), ("rejectComment", String(describing: rejectComment))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
|
||||
@ -228,7 +228,7 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
|
||||
return TelegramMediaAction(action: .todoCompletions(completed: completed, incompleted: incompleted))
|
||||
case let .messageActionTodoAppendTasks(list):
|
||||
return TelegramMediaAction(action: .todoAppendTasks(list.map { TelegramMediaTodo.Item(apiItem: $0) }))
|
||||
case let .messageActionSuggestedPostApproval(flags):
|
||||
case let .messageActionSuggestedPostApproval(flags, rejectComment, scheduleDate, starsAmount):
|
||||
let status: TelegramMediaActionType.SuggestedPostApprovalStatus
|
||||
if (flags & (1 << 0)) != 0 {
|
||||
let reason: TelegramMediaActionType.SuggestedPostApprovalStatus.RejectionReason
|
||||
@ -237,9 +237,9 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
|
||||
} else {
|
||||
reason = .generic
|
||||
}
|
||||
status = .rejected(reason: reason)
|
||||
status = .rejected(reason: reason, comment: rejectComment)
|
||||
} else {
|
||||
status = .approved
|
||||
status = .approved(timestamp: scheduleDate, amount: starsAmount ?? 0)
|
||||
}
|
||||
return TelegramMediaAction(action: .suggestedPostApprovalStatus(status: status))
|
||||
}
|
||||
|
||||
@ -117,13 +117,16 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
case lowBalance
|
||||
}
|
||||
|
||||
case approved
|
||||
case rejected(reason: RejectionReason)
|
||||
case approved(timestamp: Int32?, amount: Int64)
|
||||
case rejected(reason: RejectionReason, comment: String?)
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
switch decoder.decodeInt32ForKey("_t", orElse: 0) {
|
||||
case 0:
|
||||
self = .approved
|
||||
self = .approved(
|
||||
timestamp: decoder.decodeOptionalInt32ForKey("ts"),
|
||||
amount: decoder.decodeInt64ForKey("am", orElse: 0)
|
||||
)
|
||||
case 1:
|
||||
let reason: RejectionReason
|
||||
switch decoder.decodeInt32ForKey("rs", orElse: 0) {
|
||||
@ -135,18 +138,24 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
assertionFailure()
|
||||
reason = .generic
|
||||
}
|
||||
self = .rejected(reason: reason)
|
||||
self = .rejected(reason: reason, comment: decoder.decodeOptionalStringForKey("com"))
|
||||
default:
|
||||
assertionFailure()
|
||||
self = .rejected(reason: .generic)
|
||||
self = .rejected(reason: .generic, comment: nil)
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
switch self {
|
||||
case .approved:
|
||||
case let .approved(timestamp, amount):
|
||||
encoder.encodeInt32(0, forKey: "_t")
|
||||
case let .rejected(reason):
|
||||
if let timestamp {
|
||||
encoder.encodeInt32(timestamp, forKey: "ts")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "ts")
|
||||
}
|
||||
encoder.encodeInt64(amount, forKey: "am")
|
||||
case let .rejected(reason, comment):
|
||||
encoder.encodeInt32(1, forKey: "_t")
|
||||
switch reason {
|
||||
case .generic:
|
||||
@ -154,6 +163,11 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
case .lowBalance:
|
||||
encoder.encodeInt32(1, forKey: "rs")
|
||||
}
|
||||
if let comment {
|
||||
encoder.encodeString(comment, forKey: "com")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "com")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -356,7 +370,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
)
|
||||
case 51:
|
||||
let status: SuggestedPostApprovalStatus? = decoder.decodeObjectForKey("st", decoder: { SuggestedPostApprovalStatus(decoder: $0) }) as? SuggestedPostApprovalStatus
|
||||
self = .suggestedPostApprovalStatus(status: status ?? .rejected(reason: .generic))
|
||||
self = .suggestedPostApprovalStatus(status: status ?? .rejected(reason: .generic, comment: nil))
|
||||
default:
|
||||
self = .unknown
|
||||
}
|
||||
|
||||
@ -1588,13 +1588,18 @@ public extension TelegramEngine {
|
||||
return _internal_requestMessageAuthor(account: self.account, id: id)
|
||||
}
|
||||
|
||||
public func monoforumPerformSuggestedPostAction(id: EngineMessage.Id, approve: Bool, timestamp: Int32?) -> Signal<Never, NoError> {
|
||||
return _internal_monoforumPerformSuggestedPostAction(account: self.account, id: id, approve: approve, timestamp: timestamp)
|
||||
public enum MonoforumSuggestedPostAction {
|
||||
case approve(timestamp: Int32?)
|
||||
case reject(comment: String?)
|
||||
}
|
||||
|
||||
public func monoforumPerformSuggestedPostAction(id: EngineMessage.Id, action: MonoforumSuggestedPostAction) -> Signal<Never, NoError> {
|
||||
return _internal_monoforumPerformSuggestedPostAction(account: self.account, id: id, action: action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_monoforumPerformSuggestedPostAction(account: Account, id: EngineMessage.Id, approve: Bool, timestamp: Int32?) -> Signal<Never, NoError> {
|
||||
func _internal_monoforumPerformSuggestedPostAction(account: Account, id: EngineMessage.Id, action: TelegramEngine.Messages.MonoforumSuggestedPostAction) -> Signal<Never, NoError> {
|
||||
return account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(id.peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
@ -1607,13 +1612,22 @@ func _internal_monoforumPerformSuggestedPostAction(account: Account, id: EngineM
|
||||
}
|
||||
|
||||
var flags: Int32 = 0
|
||||
if !approve {
|
||||
var timestamp: Int32?
|
||||
var rejectComment: String?
|
||||
switch action {
|
||||
case let .approve(timestampValue):
|
||||
timestamp = timestampValue
|
||||
if timestamp != nil {
|
||||
flags |= 1 << 0
|
||||
}
|
||||
case let .reject(commentValue):
|
||||
flags |= 1 << 1
|
||||
rejectComment = commentValue
|
||||
if rejectComment != nil {
|
||||
flags |= 1 << 2
|
||||
}
|
||||
}
|
||||
if timestamp != nil {
|
||||
flags |= 1 << 0
|
||||
}
|
||||
return account.network.request(Api.functions.messages.toggleSuggestedPostApproval(flags: flags, peer: inputPeer, msgId: id.id, scheduleDate: timestamp))
|
||||
return account.network.request(Api.functions.messages.toggleSuggestedPostApproval(flags: flags, peer: inputPeer, msgId: id.id, scheduleDate: timestamp, rejectComment: rejectComment))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
|
||||
return .single(nil)
|
||||
|
||||
@ -31,6 +31,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/TextNodeWithEntities",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
|
||||
"//submodules/Markdown",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
||||
@ -21,6 +21,7 @@ import InvisibleInkDustNode
|
||||
import TextNodeWithEntities
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
import Markdown
|
||||
|
||||
private func attributedServiceMessageString(theme: ChatPresentationThemeData, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: Message, messageCount: Int? = nil, accountPeerId: PeerId, forForumOverview: Bool) -> NSAttributedString? {
|
||||
return universalServiceMessageString(presentationData: (theme.theme, theme.wallpaper), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: EngineMessage(message), messageCount: messageCount, accountPeerId: accountPeerId, forChatList: false, forForumOverview: forForumOverview)
|
||||
@ -29,6 +30,7 @@ private func attributedServiceMessageString(theme: ChatPresentationThemeData, st
|
||||
public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
public var expandHighlightingNode: LinkHighlightingNode?
|
||||
|
||||
public var titleNode: TextNode?
|
||||
public let labelNode: TextNodeWithEntities
|
||||
private var dustNode: InvisibleInkDustNode?
|
||||
public var backgroundNode: WallpaperBubbleBackgroundNode?
|
||||
@ -155,6 +157,7 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
|
||||
override public func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
|
||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||
let makeLabelLayout = TextNodeWithEntities.asyncLayout(self.labelNode)
|
||||
|
||||
let cachedMaskBackgroundImage = self.cachedMaskBackgroundImage
|
||||
@ -184,11 +187,14 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
var image: TelegramMediaImage?
|
||||
var story: TelegramMediaStory?
|
||||
var suggestedPost: TelegramMediaActionType.SuggestedPostApprovalStatus?
|
||||
for media in item.message.media {
|
||||
if let action = media as? TelegramMediaAction {
|
||||
switch action.action {
|
||||
case let .photoUpdated(img):
|
||||
image = img
|
||||
case let .suggestedPostApprovalStatus(status):
|
||||
suggestedPost = status
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -206,7 +212,94 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
updatedAttributedString = mutableString
|
||||
}
|
||||
|
||||
let (labelLayout, apply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: updatedAttributedString, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: constrainedSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
var textAlignment: NSTextAlignment = .center
|
||||
|
||||
let primaryTextColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).primaryText
|
||||
|
||||
if let suggestedPost {
|
||||
textAlignment = .left
|
||||
|
||||
let channelName: String
|
||||
if let peer = item.message.peers[item.message.id.peerId] as? TelegramChannel, peer.isMonoForum, let linkedMonoforumId = peer.linkedMonoforumId, let mainChannel = item.message.peers[linkedMonoforumId] as? TelegramChannel {
|
||||
channelName = EnginePeer(mainChannel).compactDisplayTitle
|
||||
} else {
|
||||
channelName = " "
|
||||
}
|
||||
|
||||
switch suggestedPost {
|
||||
case let .approved(timestamp, amount):
|
||||
//TODO:localize
|
||||
let timeString = humanReadableStringForTimestamp(strings: item.presentationData.strings, dateTimeFormat: item.presentationData.dateTimeFormat, timestamp: timestamp ?? 0, alwaysShowTime: true, allowYesterday: false, format: HumanReadableStringFormat(
|
||||
dateFormatString: { value in
|
||||
return PresentationStrings.FormattedString(string: item.presentationData.strings.SuggestPost_SetTimeFormat_Date(value).string, ranges: [])
|
||||
},
|
||||
tomorrowFormatString: { value in
|
||||
return PresentationStrings.FormattedString(string: item.presentationData.strings.SuggestPost_SetTimeFormat_TomorrowAt(value).string, ranges: [])
|
||||
},
|
||||
todayFormatString: { value in
|
||||
return PresentationStrings.FormattedString(string: item.presentationData.strings.SuggestPost_SetTimeFormat_TodayAt(value).string, ranges: [])
|
||||
},
|
||||
yesterdayFormatString: { value in
|
||||
return PresentationStrings.FormattedString(string: item.presentationData.strings.SuggestPost_SetTimeFormat_TodayAt(value).string, ranges: [])
|
||||
}
|
||||
)).string
|
||||
|
||||
let amountString = amount == 1 ? "\(amount) Star" : "\(amount) Stars"
|
||||
|
||||
let rawString = "📅 Your post will be automatically published on **\(channelName)** **\(timeString)**.\n\n💰 You have been charged \(amountString).\n\n⌛ **\(channelName)** will receive your Stars once the post has been live for 24 hours.\n\n🔄 If **\(channelName)** removes the post before it has been live for 24 hours, your Stars will be refunded."
|
||||
updatedAttributedString = parseMarkdownIntoAttributedString(rawString, attributes: MarkdownAttributes(
|
||||
body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: primaryTextColor),
|
||||
bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: primaryTextColor),
|
||||
link: MarkdownAttributeSet(font: Font.regular(13.0), textColor: primaryTextColor),
|
||||
linkAttribute: { url in
|
||||
return ("URL", url)
|
||||
}
|
||||
))
|
||||
case let .rejected(reason, comment):
|
||||
let rawString: String
|
||||
switch reason {
|
||||
case .generic:
|
||||
if let comment {
|
||||
rawString = "**\(channelName)** declined your post with the following comment:\n\n" + comment
|
||||
} else {
|
||||
rawString = "**\(channelName)** declined your post."
|
||||
}
|
||||
case .lowBalance:
|
||||
rawString = "**\(channelName)** was unable to post your message, because you did not have enough Stars."
|
||||
}
|
||||
updatedAttributedString = parseMarkdownIntoAttributedString(rawString, attributes: MarkdownAttributes(
|
||||
body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: primaryTextColor),
|
||||
bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: primaryTextColor),
|
||||
link: MarkdownAttributeSet(font: Font.regular(13.0), textColor: primaryTextColor),
|
||||
linkAttribute: { url in
|
||||
return ("URL", url)
|
||||
}
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
var titleLayoutAndApply: (TextNodeLayout, () -> TextNode)?
|
||||
if let suggestedPost {
|
||||
let rawString: String
|
||||
switch suggestedPost {
|
||||
case .approved:
|
||||
rawString = "🤝 Agreement Reached!"
|
||||
case .rejected:
|
||||
rawString = "Declined"
|
||||
}
|
||||
let titleString = parseMarkdownIntoAttributedString(rawString, attributes: MarkdownAttributes(
|
||||
body: MarkdownAttributeSet(font: Font.semibold(15.0), textColor: primaryTextColor),
|
||||
bold: MarkdownAttributeSet(font: Font.bold(15.0), textColor: primaryTextColor),
|
||||
link: MarkdownAttributeSet(font: Font.semibold(15.0), textColor: primaryTextColor),
|
||||
linkAttribute: { url in
|
||||
return ("URL", url)
|
||||
}
|
||||
))
|
||||
|
||||
titleLayoutAndApply = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: constrainedSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: textAlignment, cutout: nil, insets: UIEdgeInsets()))
|
||||
}
|
||||
|
||||
let (labelLayout, apply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: updatedAttributedString, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: constrainedSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: textAlignment, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
var labelRects = labelLayout.linesRects()
|
||||
if labelRects.count > 1 {
|
||||
@ -231,20 +324,47 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
let backgroundMaskImage: (CGPoint, UIImage)?
|
||||
var backgroundMaskUpdated = false
|
||||
if let (currentOffset, currentImage, currentRects) = cachedMaskBackgroundImage, currentRects == labelRects {
|
||||
backgroundMaskImage = (currentOffset, currentImage)
|
||||
if suggestedPost != nil {
|
||||
backgroundMaskImage = nil
|
||||
if cachedMaskBackgroundImage != nil {
|
||||
backgroundMaskUpdated = true
|
||||
}
|
||||
} else {
|
||||
backgroundMaskImage = LinkHighlightingNode.generateImage(color: .white, inset: 0.0, innerRadius: 10.0, outerRadius: 10.0, rects: labelRects, useModernPathCalculation: false)
|
||||
backgroundMaskUpdated = true
|
||||
if let (currentOffset, currentImage, currentRects) = cachedMaskBackgroundImage, currentRects == labelRects {
|
||||
backgroundMaskImage = (currentOffset, currentImage)
|
||||
} else {
|
||||
backgroundMaskImage = LinkHighlightingNode.generateImage(color: .white, inset: 0.0, innerRadius: 10.0, outerRadius: 10.0, rects: labelRects, useModernPathCalculation: false)
|
||||
backgroundMaskUpdated = true
|
||||
}
|
||||
}
|
||||
|
||||
var backgroundSize = CGSize(width: labelLayout.size.width + 8.0 + 8.0, height: labelLayout.size.height + 4.0)
|
||||
var backgroundSize = CGSize(width: labelLayout.size.width, height: labelLayout.size.height)
|
||||
if let _ = image {
|
||||
backgroundSize.width = imageSize.width + 2.0
|
||||
backgroundSize.height += imageSize.height + 10.0
|
||||
}
|
||||
|
||||
let titleSpacing: CGFloat = 18.0
|
||||
|
||||
var contentInsets = UIEdgeInsets()
|
||||
var contentOuterInsets = UIEdgeInsets()
|
||||
|
||||
if let titleLayoutAndApply {
|
||||
backgroundSize.width = max(backgroundSize.width, titleLayoutAndApply.0.size.width)
|
||||
backgroundSize.height += titleSpacing + titleLayoutAndApply.0.size.height
|
||||
|
||||
contentInsets = UIEdgeInsets(top: 16.0, left: 16.0, bottom: 16.0, right: 16.0)
|
||||
contentOuterInsets = UIEdgeInsets(top: 8.0, left: 0.0, bottom: 8.0, right: 0.0)
|
||||
|
||||
backgroundSize.width += contentInsets.left + contentInsets.right
|
||||
backgroundSize.height += contentInsets.top + contentInsets.bottom
|
||||
} else {
|
||||
backgroundSize.width += 8.0 + 8.0
|
||||
backgroundSize.height += 4.0
|
||||
}
|
||||
|
||||
return (backgroundSize.width, { boundingWidth in
|
||||
return (CGSize(width: boundingWidth, height: backgroundSize.height), { [weak self] animation, synchronousLoads, _ in
|
||||
return (CGSize(width: boundingWidth, height: backgroundSize.height + contentOuterInsets.top + contentOuterInsets.bottom), { [weak self] animation, synchronousLoads, _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.item = item
|
||||
|
||||
@ -330,7 +450,31 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
attemptSynchronous: synchronousLoads
|
||||
))
|
||||
|
||||
let labelFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((boundingWidth - labelLayout.size.width) / 2.0) - 1.0, y: image != nil ? 2.0 : floorToScreenPixels((backgroundSize.height - labelLayout.size.height) / 2.0) - 1.0), size: labelLayout.size)
|
||||
let labelFrame: CGRect
|
||||
let contentFrame: CGRect
|
||||
|
||||
if let (titleLayout, titleApply) = titleLayoutAndApply {
|
||||
contentFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((boundingWidth - backgroundSize.width) * 0.5), y: contentOuterInsets.top), size: backgroundSize)
|
||||
|
||||
let titleFrame = CGRect(origin: CGPoint(x: contentFrame.minX + floor((contentFrame.width - titleLayout.size.width) * 0.5), y: contentFrame.minY + contentInsets.top), size: titleLayout.size)
|
||||
labelFrame = CGRect(origin: CGPoint(x: contentFrame.minX + contentInsets.left, y: titleFrame.maxY + titleSpacing), size: labelLayout.size)
|
||||
|
||||
let titleNode = titleApply()
|
||||
if strongSelf.titleNode !== titleNode {
|
||||
strongSelf.titleNode?.removeFromSupernode()
|
||||
strongSelf.titleNode = titleNode
|
||||
strongSelf.addSubnode(titleNode)
|
||||
titleNode.anchorPoint = CGPoint()
|
||||
|
||||
titleNode.frame = titleFrame
|
||||
} else {
|
||||
animation.animator.updatePosition(layer: titleNode.layer, position: titleFrame.origin, completion: nil)
|
||||
titleNode.bounds = CGRect(origin: CGPoint(), size: titleFrame.size)
|
||||
}
|
||||
} else {
|
||||
labelFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((boundingWidth - labelLayout.size.width) / 2.0) - 1.0, y: image != nil ? 2.0 : floorToScreenPixels((backgroundSize.height - labelLayout.size.height) / 2.0) - 1.0), size: labelLayout.size)
|
||||
contentFrame = labelFrame
|
||||
}
|
||||
|
||||
if story != nil {
|
||||
let leadingIconView: UIImageView
|
||||
@ -395,7 +539,59 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
strongSelf.expandHighlightingNode = nil
|
||||
}
|
||||
|
||||
if let (offset, image) = backgroundMaskImage {
|
||||
if suggestedPost != nil {
|
||||
let backgroundFrame = contentFrame
|
||||
|
||||
if item.context.sharedContext.energyUsageSettings.fullTranslucency {
|
||||
if strongSelf.backgroundNode == nil {
|
||||
if let backgroundNode = item.controllerInteraction.presentationContext.backgroundNode?.makeBubbleBackground(for: .free) {
|
||||
strongSelf.backgroundNode = backgroundNode
|
||||
backgroundNode.addSubnode(strongSelf.backgroundColorNode)
|
||||
strongSelf.insertSubnode(backgroundNode, at: 0)
|
||||
}
|
||||
}
|
||||
strongSelf.backgroundColorNode.isHidden = true
|
||||
} else {
|
||||
if strongSelf.backgroundMaskNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.backgroundMaskNode, at: 0)
|
||||
}
|
||||
}
|
||||
|
||||
if let backgroundNode = strongSelf.backgroundNode {
|
||||
backgroundNode.clipsToBounds = true
|
||||
backgroundNode.cornerRadius = min(backgroundFrame.height * 0.5, 22.0)
|
||||
backgroundNode.view.mask = nil
|
||||
|
||||
animation.animator.updateFrame(layer: backgroundNode.layer, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY), size: backgroundFrame.size), completion: nil)
|
||||
|
||||
if let (rect, size) = strongSelf.absoluteRect {
|
||||
strongSelf.updateAbsoluteRect(rect, within: size)
|
||||
}
|
||||
strongSelf.backgroundMaskNode.frame = CGRect(origin: CGPoint(), size: backgroundFrame.size)
|
||||
strongSelf.backgroundMaskNode.layer.layerTintColor = nil
|
||||
} else {
|
||||
animation.animator.updateFrame(layer: strongSelf.backgroundMaskNode.layer, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY), size: backgroundFrame.size), completion: nil)
|
||||
strongSelf.backgroundMaskNode.layer.layerTintColor = selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).cgColor
|
||||
}
|
||||
|
||||
strongSelf.backgroundMaskNode.image = nil
|
||||
|
||||
animation.animator.updateFrame(layer: strongSelf.backgroundColorNode.layer, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size), completion: nil)
|
||||
|
||||
strongSelf.cachedMaskBackgroundImage = nil
|
||||
|
||||
switch strongSelf.visibility {
|
||||
case .none:
|
||||
strongSelf.labelNode.visibilityRect = nil
|
||||
//strongSelf.spoilerTextNode?.visibilityRect = nil
|
||||
case let .visible(_, subRect):
|
||||
var subRect = subRect
|
||||
subRect.origin.x = 0.0
|
||||
subRect.size.width = 10000.0
|
||||
strongSelf.labelNode.visibilityRect = subRect
|
||||
//strongSelf.spoilerTextNode?.visibilityRect = subRect
|
||||
}
|
||||
} else if let (offset, image) = backgroundMaskImage {
|
||||
if item.context.sharedContext.energyUsageSettings.fullTranslucency {
|
||||
if strongSelf.backgroundNode == nil {
|
||||
if let backgroundNode = item.controllerInteraction.presentationContext.backgroundNode?.makeBubbleBackground(for: .free) {
|
||||
@ -415,7 +611,7 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
if let backgroundNode = strongSelf.backgroundNode {
|
||||
if labelRects.count == 1 {
|
||||
backgroundNode.clipsToBounds = true
|
||||
backgroundNode.cornerRadius = labelRects[0].height / 2.0
|
||||
backgroundNode.cornerRadius = min(32.0, labelRects[0].height / 2.0)
|
||||
backgroundNode.view.mask = nil
|
||||
} else {
|
||||
backgroundNode.clipsToBounds = false
|
||||
|
||||
@ -91,6 +91,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/LottieMetal",
|
||||
"//submodules/TelegramStringFormatting",
|
||||
"//submodules/AvatarNode",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageSuggestedPostInfoNode",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
||||
@ -80,6 +80,7 @@ import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import LottieMetal
|
||||
import AvatarNode
|
||||
import ChatMessageSuggestedPostInfoNode
|
||||
|
||||
private struct BubbleItemAttributes {
|
||||
var index: Int?
|
||||
@ -625,6 +626,8 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
private let shadowNode: ChatMessageShadowNode
|
||||
private var clippingNode: ChatMessageBubbleClippingNode
|
||||
|
||||
private var suggestedPostInfoNode: ChatMessageSuggestedPostInfoNode?
|
||||
|
||||
override public var extractedBackgroundNode: ASDisplayNode? {
|
||||
return self.shadowNode
|
||||
}
|
||||
@ -1432,6 +1435,8 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
|
||||
let weakSelf = Weak(self)
|
||||
|
||||
let makeSuggestedPostInfoNodeLayout: ChatMessageSuggestedPostInfoNode.AsyncLayout = ChatMessageSuggestedPostInfoNode.asyncLayout(self.suggestedPostInfoNode)
|
||||
|
||||
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params, presentationData: item.presentationData)
|
||||
return ChatMessageBubbleItemNode.beginLayout(
|
||||
@ -1454,6 +1459,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
unlockButtonLayout: unlockButtonLayout,
|
||||
mediaInfoLayout: mediaInfoLayout,
|
||||
mosaicStatusLayout: mosaicStatusLayout,
|
||||
makeSuggestedPostInfoNodeLayout: makeSuggestedPostInfoNodeLayout,
|
||||
layoutConstants: layoutConstants,
|
||||
currentItem: currentItem,
|
||||
currentForwardInfo: currentForwardInfo,
|
||||
@ -1482,6 +1488,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
unlockButtonLayout: (ChatMessageUnlockMediaNode.Arguments) -> (CGSize, (Bool) -> ChatMessageUnlockMediaNode),
|
||||
mediaInfoLayout: (ChatMessageStarsMediaInfoNode.Arguments) -> (CGSize, (Bool) -> ChatMessageStarsMediaInfoNode),
|
||||
mosaicStatusLayout: (ChatMessageDateAndStatusNode.Arguments) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> ChatMessageDateAndStatusNode)),
|
||||
makeSuggestedPostInfoNodeLayout: ChatMessageSuggestedPostInfoNode.AsyncLayout,
|
||||
layoutConstants: ChatMessageItemLayoutConstants,
|
||||
currentItem: ChatMessageItem?,
|
||||
currentForwardInfo: (Peer?, String?)?,
|
||||
@ -3039,7 +3046,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
var totalContentNodesHeight: CGFloat = 0.0
|
||||
var currentContainerGroupOverlap: CGFloat = 0.0
|
||||
var detachedContentNodesHeight: CGFloat = 0.0
|
||||
let additionalTopHeight: CGFloat = 0.0
|
||||
var additionalTopHeight: CGFloat = 0.0
|
||||
|
||||
var mosaicStatusOrigin: CGPoint?
|
||||
var unlockButtonPosition: CGPoint?
|
||||
@ -3215,6 +3222,18 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
}
|
||||
reactionButtonsSizeAndApply = reactionButtonsFinalize(maxContentWidth)
|
||||
}
|
||||
|
||||
var suggestedPostInfoNodeLayout: (CGSize, () -> ChatMessageSuggestedPostInfoNode)?
|
||||
for attribute in item.message.attributes {
|
||||
if let _ = attribute as? SuggestedPostMessageAttribute {
|
||||
let suggestedPostInfoNodeLayoutValue = makeSuggestedPostInfoNodeLayout(item, baseWidth)
|
||||
suggestedPostInfoNodeLayout = suggestedPostInfoNodeLayoutValue
|
||||
}
|
||||
}
|
||||
|
||||
if let suggestedPostInfoNodeLayout {
|
||||
additionalTopHeight += 4.0 + suggestedPostInfoNodeLayout.0.height + 8.0
|
||||
}
|
||||
|
||||
let minimalContentSize: CGSize
|
||||
if hideBackground {
|
||||
@ -3352,6 +3371,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
avatarOffset: avatarOffset,
|
||||
hidesHeaders: hidesHeaders,
|
||||
disablesComments: disablesComments,
|
||||
suggestedPostInfoNodeLayout: suggestedPostInfoNodeLayout,
|
||||
alignment: alignment,
|
||||
isSidePanelOpen: isSidePanelOpen
|
||||
)
|
||||
@ -3415,6 +3435,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
avatarOffset: CGFloat?,
|
||||
hidesHeaders: Bool,
|
||||
disablesComments: Bool,
|
||||
suggestedPostInfoNodeLayout: (CGSize, () -> ChatMessageSuggestedPostInfoNode)?,
|
||||
alignment: ChatMessageBubbleContentAlignment,
|
||||
isSidePanelOpen: Bool
|
||||
) -> Void {
|
||||
@ -3499,6 +3520,22 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
let previousBackgroundFrame = strongSelf.backgroundNode.backgroundFrame
|
||||
strongSelf.backgroundNode.backgroundFrame = backgroundFrame
|
||||
|
||||
if let (suggestedPostInfoSize, suggestedPostInfoApply) = suggestedPostInfoNodeLayout {
|
||||
let suggestedPostInfoNode = suggestedPostInfoApply()
|
||||
if suggestedPostInfoNode !== strongSelf.suggestedPostInfoNode {
|
||||
strongSelf.suggestedPostInfoNode?.removeFromSupernode()
|
||||
strongSelf.suggestedPostInfoNode = suggestedPostInfoNode
|
||||
strongSelf.mainContextSourceNode.contentNode.addSubnode(suggestedPostInfoNode)
|
||||
|
||||
let suggestedPostInfoFrame = CGRect(origin: CGPoint(x: floor((params.width - suggestedPostInfoSize.width) * 0.5), y: 4.0), size: suggestedPostInfoSize)
|
||||
suggestedPostInfoNode.frame = suggestedPostInfoFrame
|
||||
//animation.animator.updateFrame(layer: suggestedPostInfoNode.layer, frame: suggestedPostInfoFrame, completion: nil)
|
||||
}
|
||||
} else if let suggestedPostInfoNode = strongSelf.suggestedPostInfoNode {
|
||||
strongSelf.suggestedPostInfoNode = nil
|
||||
suggestedPostInfoNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
if let avatarOffset {
|
||||
strongSelf.updateAttachedAvatarNodeOffset(offset: avatarOffset, transition: .animated(duration: 0.3, curve: .spring))
|
||||
}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "ChatMessageSuggestedPostInfoNode",
|
||||
module_name = "ChatMessageSuggestedPostInfoNode",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit",
|
||||
"//submodules/Display",
|
||||
"//submodules/SSignalKit/SwiftSignalKit",
|
||||
"//submodules/Postbox",
|
||||
"//submodules/TelegramCore",
|
||||
"//submodules/TelegramPresentationData",
|
||||
"//submodules/TelegramUIPreferences",
|
||||
"//submodules/TextFormat",
|
||||
"//submodules/AccountContext",
|
||||
"//submodules/WallpaperBackgroundNode",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageItem",
|
||||
"//submodules/TelegramStringFormatting",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
@ -0,0 +1,171 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import TextFormat
|
||||
import AccountContext
|
||||
import WallpaperBackgroundNode
|
||||
import ChatMessageItem
|
||||
import TelegramStringFormatting
|
||||
|
||||
public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode {
|
||||
private var titleNode: TextNode?
|
||||
private var priceLabelNode: TextNode?
|
||||
private var priceValueNode: TextNode?
|
||||
private var timeLabelNode: TextNode?
|
||||
private var timeValueNode: TextNode?
|
||||
|
||||
private var backgroundNode: WallpaperBubbleBackgroundNode?
|
||||
|
||||
override public init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
public typealias AsyncLayout = (ChatMessageItem, CGFloat) -> (CGSize, () -> ChatMessageSuggestedPostInfoNode)
|
||||
|
||||
public static func asyncLayout(_ node: ChatMessageSuggestedPostInfoNode?) -> (ChatMessageItem, CGFloat) -> (CGSize, () -> ChatMessageSuggestedPostInfoNode) {
|
||||
let makeTitleLayout = TextNode.asyncLayout(node?.titleNode)
|
||||
let makePriceLabelLayout = TextNode.asyncLayout(node?.priceLabelNode)
|
||||
let makePriceValueLayout = TextNode.asyncLayout(node?.priceValueNode)
|
||||
let makeTimeLabelLayout = TextNode.asyncLayout(node?.timeLabelNode)
|
||||
let makeTimeValueLayout = TextNode.asyncLayout(node?.timeValueNode)
|
||||
|
||||
return { item, maxWidth in
|
||||
let insets = UIEdgeInsets(
|
||||
top: 12.0,
|
||||
left: 12.0,
|
||||
bottom: 12.0,
|
||||
right: 12.0
|
||||
)
|
||||
|
||||
let titleSpacing: CGFloat = 8.0
|
||||
let labelSpacing: CGFloat = 8.0
|
||||
let valuesVerticalSpacing: CGFloat = 2.0
|
||||
|
||||
var amount: Int64 = 0
|
||||
var timestamp: Int32?
|
||||
|
||||
for attribute in item.message.attributes {
|
||||
if let attribute = attribute as? SuggestedPostMessageAttribute {
|
||||
amount = attribute.amount
|
||||
timestamp = attribute.timestamp
|
||||
}
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
let amountString: String
|
||||
if amount == 0 {
|
||||
amountString = "Free"
|
||||
} else if amount == 1 {
|
||||
amountString = "1 Star"
|
||||
} else {
|
||||
amountString = "\(amount) Stars"
|
||||
}
|
||||
|
||||
var timestampString: String
|
||||
if let timestamp {
|
||||
timestampString = humanReadableStringForTimestamp(strings: item.presentationData.strings, dateTimeFormat: PresentationDateTimeFormat(), timestamp: timestamp, alwaysShowTime: true).string
|
||||
if timestampString.count > 1 {
|
||||
timestampString = String(timestampString[timestampString.startIndex]).capitalized + timestampString[timestampString.index(after: timestampString.startIndex)...]
|
||||
}
|
||||
} else {
|
||||
timestampString = "Anytime"
|
||||
}
|
||||
|
||||
let serviceColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper)
|
||||
|
||||
//TODO:localize
|
||||
let titleText: String
|
||||
if !item.message.effectivelyIncoming(item.context.account.peerId) {
|
||||
titleText = "You suggest to post\nthis message."
|
||||
} else {
|
||||
titleText = "\(item.message.author.flatMap(EnginePeer.init)?.compactDisplayTitle ?? " ") suggests to post\nthis message."
|
||||
}
|
||||
|
||||
let titleLayout = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: titleText, font: Font.regular(13.0), textColor: serviceColor.primaryText), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maxWidth - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let priceLabelLayout = makePriceLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Price", font: Font.regular(13.0), textColor: serviceColor.primaryText.withMultipliedAlpha(0.5)), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maxWidth - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
let timeLabelLayout = makeTimeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Time", font: Font.regular(13.0), textColor: serviceColor.primaryText.withMultipliedAlpha(0.5)), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maxWidth - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let priceValueLayout = makePriceValueLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: amountString, font: Font.semibold(13.0), textColor: serviceColor.primaryText), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maxWidth - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
let timeValueLayout = makeTimeValueLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: timestampString, font: Font.semibold(13.0), textColor: serviceColor.primaryText), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maxWidth - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
var maxContentWidth: CGFloat = 0.0
|
||||
var contentHeight: CGFloat = 0.0
|
||||
|
||||
maxContentWidth = max(maxContentWidth, titleLayout.0.size.width)
|
||||
|
||||
contentHeight += titleLayout.0.size.height
|
||||
contentHeight += titleSpacing
|
||||
|
||||
maxContentWidth = max(maxContentWidth, priceLabelLayout.0.size.width + labelSpacing + priceValueLayout.0.size.width)
|
||||
contentHeight += priceLabelLayout.0.size.height + valuesVerticalSpacing
|
||||
|
||||
maxContentWidth = max(maxContentWidth, timeLabelLayout.0.size.width + labelSpacing + timeValueLayout.0.size.width)
|
||||
contentHeight += timeLabelLayout.0.size.height
|
||||
|
||||
let size = CGSize(width: insets.left + insets.right + maxContentWidth, height: insets.top + insets.bottom + contentHeight)
|
||||
|
||||
return (size, {
|
||||
let node = node ?? ChatMessageSuggestedPostInfoNode()
|
||||
|
||||
if node.backgroundNode == nil {
|
||||
if let backgroundNode = item.controllerInteraction.presentationContext.backgroundNode?.makeBubbleBackground(for: .free) {
|
||||
node.backgroundNode = backgroundNode
|
||||
backgroundNode.layer.masksToBounds = true
|
||||
backgroundNode.layer.cornerRadius = 15.0
|
||||
node.insertSubnode(backgroundNode, at: 0)
|
||||
}
|
||||
}
|
||||
|
||||
if let backgroundNode = node.backgroundNode {
|
||||
backgroundNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
}
|
||||
|
||||
let titleNode = titleLayout.1()
|
||||
if node.titleNode !== titleNode {
|
||||
node.titleNode = titleNode
|
||||
node.addSubnode(titleNode)
|
||||
}
|
||||
let priceLabelNode = priceLabelLayout.1()
|
||||
if node.priceLabelNode !== priceLabelNode {
|
||||
node.priceLabelNode = priceLabelNode
|
||||
node.addSubnode(priceLabelNode)
|
||||
}
|
||||
let priceValueNode = priceValueLayout.1()
|
||||
if node.priceValueNode !== priceValueNode {
|
||||
node.priceValueNode = priceValueNode
|
||||
node.addSubnode(priceValueNode)
|
||||
}
|
||||
let timeLabelNode = timeLabelLayout.1()
|
||||
if node.timeLabelNode !== timeLabelNode {
|
||||
node.timeLabelNode = timeLabelNode
|
||||
node.addSubnode(timeLabelNode)
|
||||
}
|
||||
let timeValueNode = timeValueLayout.1()
|
||||
if node.timeValueNode !== timeValueNode {
|
||||
node.timeValueNode = timeValueNode
|
||||
node.addSubnode(timeValueNode)
|
||||
}
|
||||
|
||||
let titleFrame = CGRect(origin: CGPoint(x: floor((size.width - titleLayout.0.size.width) * 0.5), y: insets.top), size: titleLayout.0.size)
|
||||
titleNode.frame = titleFrame
|
||||
|
||||
let priceLabelFrame = CGRect(origin: CGPoint(x: insets.left, y: titleFrame.maxY + titleSpacing), size: priceLabelLayout.0.size)
|
||||
priceLabelNode.frame = priceLabelFrame
|
||||
priceValueNode.frame = CGRect(origin: CGPoint(x: priceLabelFrame.maxX + labelSpacing, y: priceLabelFrame.minY), size: priceValueLayout.0.size)
|
||||
|
||||
let timeLabelFrame = CGRect(origin: CGPoint(x: insets.left, y: priceLabelFrame.maxY + valuesVerticalSpacing), size: timeLabelLayout.0.size)
|
||||
timeLabelNode.frame = timeLabelFrame
|
||||
timeValueNode.frame = CGRect(origin: CGPoint(x: timeLabelFrame.maxX + labelSpacing, y: timeLabelFrame.minY), size: timeValueLayout.0.size)
|
||||
|
||||
return node
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2331,13 +2331,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if message.effectivelyIncoming(strongSelf.context.account.peerId) {
|
||||
switch buttonType {
|
||||
case 0:
|
||||
let _ = strongSelf.context.engine.messages.monoforumPerformSuggestedPostAction(id: message.id, approve: false, timestamp: nil).startStandalone()
|
||||
let _ = strongSelf.context.engine.messages.monoforumPerformSuggestedPostAction(id: message.id, action: .reject(comment: nil)).startStandalone()
|
||||
case 1:
|
||||
var timestamp: Int32?
|
||||
if attribute.timestamp == nil {
|
||||
timestamp = Int32(Date().timeIntervalSince1970) + 1 * 60 * 60
|
||||
}
|
||||
let _ = strongSelf.context.engine.messages.monoforumPerformSuggestedPostAction(id: message.id, approve: true, timestamp: timestamp).startStandalone()
|
||||
let _ = strongSelf.context.engine.messages.monoforumPerformSuggestedPostAction(id: message.id, action: .approve(timestamp: timestamp)).startStandalone()
|
||||
case 2:
|
||||
//suggest changes
|
||||
break
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user