Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2025-06-29 19:18:27 +02:00
commit 43091b01d2
33 changed files with 426 additions and 360 deletions

View File

@ -14507,6 +14507,154 @@ Sorry for the inconvenience.";
"Attachment.DiscardTodoAlertText" = "Discard checklist items?";
"Auth.PremiumSignUp.ActionTitle" = "Sign up for %@";
"Auth.PremiumSignUp.ActionSubtitle" = "Get Telegram Premium for 1 week";
"Chat.PostApproval.Status.AdminApproved" = "The message was approved";
"Chat.PostApproval.Status.AdminRejected" = "The message was rejected";
"Chat.PostApproval.Status.UserApproved" = "Your message was approved";
"Chat.PostApproval.Status.UserRejected" = "Your message was rejected";
"Chat.PostApproval.DetailStatus.StarsAmount_1" = "# Star";
"Chat.PostApproval.DetailStatus.StarsAmount_any" = "# Stars";
"Chat.PostApproval.DetailStatus.TonAmount_1" = "# TON";
"Chat.PostApproval.DetailStatus.TonAmount_any" = "# TON";
"Chat.PostApproval.DetailStatus.PostedPaid" = "**%1$@** received **%2$@** for publishing this post";
"Chat.PostApproval.DetailStatus.UserFailedRefunded" = "Suggested post was refunded because you didn't have enough funds";
"Chat.PostApproval.DetailStatus.AdminFailedRefunded" = "Suggested post was refunded because the user didn't have enough funds";
"Chat.PostApproval.DetailStatus.FailedDeleted" = "Suggested post was refunded because the message was deleted";
"Chat.PostApproval.Message.UserAgreementPast" = "📅 The post has been automatically published in **%1$@** **%2$@**.";
"Chat.PostApproval.Message.AdminAgreementPast" = "📅 Your post has been automatically published in **%1$@** **%2$@**.";
"Chat.PostApproval.Message.UserAgreementFuture" = "📅 The post will be automatically published in **%1$@** **%2$@**.";
"Chat.PostApproval.Message.AdminAgreementFuture" = "📅 Your post will be automatically published in **%1$@** **%2$@**.";
"Chat.PostApproval.Message.UserAgreementNoTime" = "📅 The post has been automatically published in **%1$@**.";
"Chat.PostApproval.Message.AdminAgreementNoTime" = "📅 Your post has been automatically published in **%1$@**.";
"Chat.PostApproval.Message.TitleApproved" = "🤝 Agreement Reached!";
"Chat.PostApproval.Message.AdminTitleRejected" = "❌ You rejected the message.";
"Chat.PostApproval.Message.AdminTitleRejectedComment" = "❌ You rejected the message with the comment:";
"Chat.PostApproval.Message.AdminTitleFailedFunds" = "⚠️ **Transaction failed** because the user didn't have enough Stars.";
"Chat.PostApproval.Message.UserTitleRejected" = "❌ **%@** rejected your message.";
"Chat.PostApproval.Message.UserTitleRejectedComment" = "❌ **%@** rejected your message with the comment:";
"Chat.PostApproval.Message.UserTitleFailedFunds" = "⚠️ **Transaction failed** because you didn't have enough Stars.";
"Chat.PostApproval.Message.BuyStars" = "Buy Stars";
"Chat.PostApproval.Message.UserAgreementPriceStars" = "💰 You have been charged %1$@.\n\n⌛ **%2$@** will receive the Stars once the post has been live for 24 hours.\n\n🔄 If admins remove the post before it has been live for 24 hours, the your Stars will be refunded.";
"Chat.PostApproval.Message.UserAgreementPriceTon" = "💰 You have been charged %1$@.\n\n⌛ **%2$@** will receive the TON once the post has been live for 24 hours.\n\n🔄 If admins the post before it has been live for 24 hours, your TON will be refunded.";
"Chat.PostApproval.Message.AdminAgreementPriceStars" = "💰 The user have been charged %1$@.\n\n⌛ **%2$@** will receive the Stars once the post has been live for 24 hours.\n\n🔄 If you remove the post before it has been live for 24 hours, the user's Stars will be refunded.";
"Chat.PostApproval.Message.AdminAgreementPriceTon" = "💰 The user have been charged %1$@.\n\n⌛ **%2$@** will receive the TON once the post has been live for 24 hours.\n\n🔄 If you remove the post before it has been live for 24 hours, the user's TON will be refunded.";
"Chat.PostApproval.Message.AdminDeclined" = "You declined the post.";
"Chat.PostApproval.Message.AdminDeclinedComment" = "You declined the post with the following comment:\n\n%@";
"Chat.PostApproval.Message.ActionApprove" = "Approve";
"Chat.PostApproval.Message.ActionReject" = "Decline";
"Chat.PostApproval.Message.ActionSuggestChanges" = "Suggest Changes";
"Chat.ReinstatePaidMessages" = "Charge Message Fee";
"Chat.PostSuggestion.TablePrice" = "Price";
"Chat.PostSuggestion.TableTime" = "Time";
"Chat.PostSuggestion.PriceFree" = "Free";
"Chat.PostSuggestion.TimeAny" = "Anytime";
"Chat.PostSuggestion.UserChangePTC" = "You suggest a new price,\ntime and contents for this message.";
"Chat.PostSuggestion.UserChangePTT" = "You suggest a new price,\ntime and text for this message.";
"Chat.PostSuggestion.UserChangePTA" = "You suggest a new price,\ntime and attachments for this message.";
"Chat.PostSuggestion.UserChangePT" = "You suggest a new price and time\nfor this message.";
"Chat.PostSuggestion.UserChangeP" = "You suggest a new price\nfor this message.";
"Chat.PostSuggestion.UserChangeT" = "You suggest a new time\nfor this message.";
"Chat.PostSuggestion.UserChange" = "You suggest changes\nfor this message.";
"Chat.PostSuggestion.ChannelChangePTC" = "**%@** suggests a new price,\ntime and contents for this message.";
"Chat.PostSuggestion.ChannelChangePTT" = "**%@** suggests a new price,\ntime and text for this message.";
"Chat.PostSuggestion.ChannelChangePTA" = "**%@** suggests a new price,\ntime and attachments for this message.";
"Chat.PostSuggestion.ChannelChangePT" = "**%@** suggests a new price and time\nfor this message.";
"Chat.PostSuggestion.ChannelChangeP" = "**%@** suggests a new price\nfor this message.";
"Chat.PostSuggestion.ChannelChangeT" = "**%@** suggests a new time\nfor this message.";
"Chat.PostSuggestion.ChannelChange" = "**%@** suggests changes\nfor this message.";
"Chat.PostSuggestion.UserPost" = "You suggest to post\nthis message.";
"Chat.PostSuggestion.ChannelPost" = "**%@** suggests to post\nthis message.";
"Chat.PostSuggestion.Suggest.InputTitle" = "Suggest a post below";
"Chat.PostSuggestion.Suggest.InputEditTitle" = "Suggest Changes";
"Chat.PostSuggestion.Suggest.InputSubtitleEmpty" = "Tap to offer a price for publishing";
"Chat.PostSuggestion.Suggest.InputSubtitleAnytime" = "%@ for publishing anytime";
"BalanceNeeded.FragmentTitle" = "%@ TON Needed";
"BalanceNeeded.FragmentSubtitle" = "You can add funds to your balance via the third-party platform Fragment.";
"BalanceNeeded.FragmentAction" = "Add Funds via Fragment";
"Settings.MyTon" = "My TON";
"Settings.Ton.Description" = "Use TON to submit post suggestions to channels on Telegram.";
"Settings.TransactionsTon.Title" = "TON";
"Settings.TransactionsTon.Subtitle" = "Use TON to submit post suggestions to channels on Telegram.";
"Chat.DeletePaidMessageStars.Title" = "Stars Will Be Lost";
"Chat.DeletePaidMessageStars.Text" = "You won't receive **Stars** for this post if you delete it now. The post must remain visible for at least **24 hours** after publication.";
"Chat.DeletePaidMessageTon.Title" = "TON Will Be Lost";
"Chat.DeletePaidMessageTon.Text" = "You won't receive **TON** for this post if you delete it now. The post must remain visible for at least **24 hours** after publication.";
"Chat.DeletePaidMessage.Action" = "Delete Anyway";
"Chat.PostSuggestion.Reject.Title" = "Comment";
"Chat.PostSuggestion.Reject.Placeholder" = "Optional";
"Chat.PostSuggestion.Approve.AdminConfirmationText" = "Do you really want to publish this post from **%@**?";
"Chat.PostSuggestion.Approve.AdminConfirmationPriceStars" = "You will receive %1$@ Stars (%2$@%)\nfor publishing this post. It must remain visible for **24** hours after publication.";
"Chat.PostSuggestion.Approve.AdminConfirmationPriceTon" = "You will receive %1$@ TON (%2$@%)\nfor publishing this post. It must remain visible for **24** hours after publication.";
"Chat.PostSuggestion.Approve.UserConfirmationText" = "Do you really want to publish this post?";
"Chat.PostSuggestion.Approve.Title" = "Accept Terms";
"Chat.PostSuggestion.Approve.Action" = "Publish";
"Chat.PostSuggestion.ApproveTime.Title" = "Accept Terms";
"Chat.PostSuggestion.ApproveTime.Text" = "Set the date and time you want\nthis message to be published.";
"Chat.PostSuggestion.ApproveTime.NoTimeAction" = "Post Now";
"Chat.PostSuggestion.SetTime.Title" = "Time";
"Chat.PostSuggestion.SetTime.Text" = "Set the date and time you want\nyour message to be published.";
"Chat.PostSuggestion.SetTime.NoTimeAction" = "Send Anytime";
"Chat.PostSuggestion.ApproveTime.AdminConfirmationPriceStars" = "You will receive %1$@ Stars (%2$@%)\nfor publishing this post.";
"Chat.PostSuggestion.ApproveTime.AdminConfirmationPriceTon" = "You will receive %1$@ TON (%2$@%)\nfor publishing this post.";
"Chat.PostSuggestion.StarsDisclaimer" = "Transactions in **Stars** may be reversed by the payment provider within **21** days. Only accept Stars from people you trust.";
"VoiceOver.SuggestPost" = "Suggest Post";
"Chat.ContextMenu.SuggestedPost.EditMessage" = "Edit Message";
"Chat.ContextMenu.SuggestedPost.EditPrice" = "Edit Prive";
"Chat.ContextMenu.SuggestedPost.EditTime" = "Edit Time";
"Chat.ContextMenu.SuggestedPost.Create" = "Suggest Post";
"Chat.PostSuggestion.Suggest.TitleCreate" = "Suggest Terms";
"Chat.PostSuggestion.Suggest.TitleEdit" = "Suggest Changes";
"Chat.PostSuggestion.Suggest.PriceSectionStars" = "ENTER A PRICE IN STARS";
"Chat.PostSuggestion.Suggest.PriceSectionTon" = "ENTER A PRICE IN TON";
"Chat.PostSuggestion.Suggest.PricePlaceholder" = "Price";
"Chat.PostSuggestion.Suggest.OfferStars" = "Offer Stars";
"Chat.PostSuggestion.Suggest.OfferTon" = "Offer TON";
"Chat.PostSuggestion.Suggest.RequestStars" = "Request Stars";
"Chat.PostSuggestion.Suggest.RequestTon" = "Request TON";
"Chat.PostSuggestion.Suggest.RequestDescriptionStars" = "Choose how many Stars you charge for the message.";
"Chat.PostSuggestion.Suggest.RequestDescriptionTon" = "Choose how many TON you charge for the message.";
"Chat.PostSuggestion.Suggest.OfferDescriptionStars" = "Choose how many Stars you want to offer %@ to publish this message.";
"Chat.PostSuggestion.Suggest.OfferDescriptionTon" = "Choose how many TON you want to offer %@ to publish this message.";
"Chat.PostSuggestion.Suggest.OfferDateDescription" = "Select the date and time you want your message to be published.";
"Chat.PostSuggestion.Suggest.EditDateDescription" = "Select the date and time you want to publish the message.";
"Chat.PostSuggestion.Suggest.OfferButtonPrice" = "Offer %@";
"Chat.PostSuggestion.Suggest.OfferButtonFree" = "Offer for Free";
"Chat.PostSuggestion.Suggest.UpdateButton" = "Update Terms";
"Chat.PostSuggestion.Suggest.AdminMinAmountStars.Text" = "You cannot request less than %@ Stars.";
"Chat.PostSuggestion.Suggest.UserMinAmountStars.Text" = "You cannot offer less than %@ Stars.";
"Stars.SellGiftMinAmountToast.Text" = "You cannot sell gift for less than %@";
"Premium.Week.SignUp" = "Sign up for %@";
"Premium.Week.SignUpInfo" = "Get Telegram Premium for 1 week";

View File

@ -484,6 +484,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1645763991] = { return Api.InputStickerSet.parse_inputStickerSetID($0) }
dict[-930399486] = { return Api.InputStickerSet.parse_inputStickerSetPremiumGifts($0) }
dict[-2044933984] = { return Api.InputStickerSet.parse_inputStickerSetShortName($0) }
dict[485912992] = { return Api.InputStickerSet.parse_inputStickerSetTonGifts($0) }
dict[853188252] = { return Api.InputStickerSetItem.parse_inputStickerSetItem($0) }
dict[70813275] = { return Api.InputStickeredMedia.parse_inputStickeredMediaDocument($0) }
dict[1251549527] = { return Api.InputStickeredMedia.parse_inputStickeredMediaPhoto($0) }
@ -1096,6 +1097,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1398708869] = { return Api.Update.parse_updateMessagePoll($0) }
dict[619974263] = { return Api.Update.parse_updateMessagePollVote($0) }
dict[506035194] = { return Api.Update.parse_updateMessageReactions($0) }
dict[-1618924792] = { return Api.Update.parse_updateMonoForumNoPaidException($0) }
dict[-2030252155] = { return Api.Update.parse_updateMoveStickerSetToTop($0) }
dict[-1991136273] = { return Api.Update.parse_updateNewAuthorization($0) }
dict[1656358105] = { return Api.Update.parse_updateNewChannelMessage($0) }

View File

@ -755,6 +755,7 @@ public extension Api {
case inputStickerSetID(id: Int64, accessHash: Int64)
case inputStickerSetPremiumGifts
case inputStickerSetShortName(shortName: String)
case inputStickerSetTonGifts
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
@ -824,6 +825,12 @@ public extension Api {
buffer.appendInt32(-2044933984)
}
serializeString(shortName, buffer: buffer, boxed: false)
break
case .inputStickerSetTonGifts:
if boxed {
buffer.appendInt32(485912992)
}
break
}
}
@ -852,6 +859,8 @@ public extension Api {
return ("inputStickerSetPremiumGifts", [])
case .inputStickerSetShortName(let shortName):
return ("inputStickerSetShortName", [("shortName", shortName as Any)])
case .inputStickerSetTonGifts:
return ("inputStickerSetTonGifts", [])
}
}
@ -915,6 +924,9 @@ public extension Api {
return nil
}
}
public static func parse_inputStickerSetTonGifts(_ reader: BufferReader) -> InputStickerSet? {
return Api.InputStickerSet.inputStickerSetTonGifts
}
}
}

View File

@ -129,6 +129,7 @@ public extension Api {
case updateMessagePoll(flags: Int32, pollId: Int64, poll: Api.Poll?, results: Api.PollResults)
case updateMessagePollVote(pollId: Int64, peer: Api.Peer, options: [Buffer], qts: Int32)
case updateMessageReactions(flags: Int32, peer: Api.Peer, msgId: Int32, topMsgId: Int32?, savedPeerId: Api.Peer?, reactions: Api.MessageReactions)
case updateMonoForumNoPaidException(flags: Int32, channelId: Int64, savedPeerId: Api.Peer)
case updateMoveStickerSetToTop(flags: Int32, stickerset: Int64)
case updateNewAuthorization(flags: Int32, hash: Int64, date: Int32?, device: String?, location: String?)
case updateNewChannelMessage(message: Api.Message, pts: Int32, ptsCount: Int32)
@ -920,6 +921,14 @@ public extension Api {
if Int(flags) & Int(1 << 1) != 0 {savedPeerId!.serialize(buffer, true)}
reactions.serialize(buffer, true)
break
case .updateMonoForumNoPaidException(let flags, let channelId, let savedPeerId):
if boxed {
buffer.appendInt32(-1618924792)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(channelId, buffer: buffer, boxed: false)
savedPeerId.serialize(buffer, true)
break
case .updateMoveStickerSetToTop(let flags, let stickerset):
if boxed {
buffer.appendInt32(-2030252155)
@ -1619,6 +1628,8 @@ public extension Api {
return ("updateMessagePollVote", [("pollId", pollId as Any), ("peer", peer as Any), ("options", options as Any), ("qts", qts as Any)])
case .updateMessageReactions(let flags, let peer, let msgId, let topMsgId, let savedPeerId, let reactions):
return ("updateMessageReactions", [("flags", flags as Any), ("peer", peer as Any), ("msgId", msgId as Any), ("topMsgId", topMsgId as Any), ("savedPeerId", savedPeerId as Any), ("reactions", reactions as Any)])
case .updateMonoForumNoPaidException(let flags, let channelId, let savedPeerId):
return ("updateMonoForumNoPaidException", [("flags", flags as Any), ("channelId", channelId as Any), ("savedPeerId", savedPeerId as Any)])
case .updateMoveStickerSetToTop(let flags, let stickerset):
return ("updateMoveStickerSetToTop", [("flags", flags as Any), ("stickerset", stickerset as Any)])
case .updateNewAuthorization(let flags, let hash, let date, let device, let location):
@ -3272,6 +3283,25 @@ public extension Api {
return nil
}
}
public static func parse_updateMonoForumNoPaidException(_ reader: BufferReader) -> Update? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
var _3: Api.Peer?
if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.Peer
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.Update.updateMonoForumNoPaidException(flags: _1!, channelId: _2!, savedPeerId: _3!)
}
else {
return nil
}
}
public static func parse_updateMoveStickerSetToTop(_ reader: BufferReader) -> Update? {
var _1: Int32?
_1 = reader.readInt32()

View File

@ -34,6 +34,9 @@ table StickerPackReference_IconTopicEmoji {
table StickerPackReference_IconChannelStatusEmoji {
}
table StickerPackReference_TonGifts {
}
union StickerPackReference_Value {
StickerPackReference_Id,
StickerPackReference_Name,
@ -44,7 +47,8 @@ union StickerPackReference_Value {
StickerPackReference_EmojiGenericAnimations,
StickerPackReference_IconStatusEmoji,
StickerPackReference_IconTopicEmoji,
StickerPackReference_IconChannelStatusEmoji
StickerPackReference_IconChannelStatusEmoji,
StickerPackReference_TonGifts
}
table StickerPackReference {

View File

@ -133,6 +133,7 @@ enum AccountStateMutationOperation {
case UpdateStarsRevenueStatus(peerId: PeerId, status: StarsRevenueStats.Balances)
case UpdateStarsReactionsDefaultPrivacy(privacy: TelegramPaidReactionPrivacy)
case ReportMessageDelivery([MessageId])
case UpdateMonoForumNoPaidException(peerId: PeerId, threadId: Int64, isFree: Bool)
}
struct HoleFromPreviousState {
@ -707,9 +708,13 @@ struct AccountMutableState {
self.addOperation(.ReportMessageDelivery(messageIds))
}
mutating func updateMonoForumNoPaidException(peerId: PeerId, threadId: Int64, isFree: Bool) {
self.addOperation(.UpdateMonoForumNoPaidException(peerId: peerId, threadId: threadId, isFree: isFree))
}
mutating func addOperation(_ operation: AccountStateMutationOperation) {
switch operation {
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery:
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery, .UpdateMonoForumNoPaidException:
break
case let .AddMessages(messages, location):
for message in messages {

View File

@ -1081,6 +1081,26 @@ extension StoreMessage {
var threadId: Int64?
if let savedPeerId {
threadId = savedPeerId.peerId.toInt64()
if chatPeerId.peerId.namespace == Namespaces.Peer.CloudChannel, let replyTo {
switch replyTo {
case let .messageReplyHeader(innerFlags, replyToMsgId, replyToPeerId, replyHeader, replyMedia, _, quoteText, quoteEntities, quoteOffset):
var quote: EngineMessageReplyQuote?
let isQuote = (innerFlags & (1 << 9)) != 0
if quoteText != nil || replyMedia != nil {
quote = EngineMessageReplyQuote(text: quoteText ?? "", offset: quoteOffset.flatMap(Int.init), entities: messageTextEntitiesFromApiEntities(quoteEntities ?? []), media: textMediaAndExpirationTimerFromApiMedia(replyMedia, peerId).media)
}
if let replyToMsgId = replyToMsgId {
let replyPeerId = replyToPeerId?.peerId ?? peerId
attributes.append(ReplyMessageAttribute(messageId: MessageId(peerId: replyPeerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId), threadMessageId: nil, quote: quote, isQuote: isQuote))
} else if let replyHeader = replyHeader {
attributes.append(QuotedReplyMessageAttribute(apiHeader: replyHeader, quote: quote, isQuote: isQuote))
}
case let .messageReplyStoryHeader(peer, storyId):
attributes.append(ReplyStoryAttribute(storyId: StoryId(peerId: peer.peerId, id: storyId)))
}
}
} else if let replyTo = replyTo {
var threadMessageId: MessageId?
switch replyTo {

View File

@ -71,6 +71,8 @@ extension StickerPackReference {
self = .iconChannelStatusEmoji
case .inputStickerSetEmojiDefaultTopicIcons:
self = .iconTopicEmoji
case .inputStickerSetTonGifts:
self = .tonGifts
}
}
}

View File

@ -1870,6 +1870,8 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
mappedPrivacy = .peer(peerId)
}
updatedState.updateStarsReactionsDefaultPrivacy(privacy: mappedPrivacy)
case let .updateMonoForumNoPaidException(flags, channelId, savedPeerId):
updatedState.updateMonoForumNoPaidException(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), threadId: savedPeerId.peerId.toInt64(), isFree: (flags & (1 << 0)) != 0)
default:
break
}
@ -3580,7 +3582,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
var currentAddQuickReplyMessages: OptimizeAddMessagesState?
for operation in operations {
switch operation {
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery:
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery, .UpdateMonoForumNoPaidException:
if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
}
@ -5180,6 +5182,14 @@ func replayFinalState(
updatedStarsReactionsDefaultPrivacy = value
case let .ReportMessageDelivery(messageIds):
reportMessageDelivery = Set(messageIds)
case let .UpdateMonoForumNoPaidException(peerId, threadId, isFree):
if var data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.data.get(MessageHistoryThreadData.self) {
data.isMessageFeeRemoved = isFree
if let entry = StoredMessageHistoryThreadInfo(data) {
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: threadId, info: entry)
}
}
}
}

View File

@ -62,7 +62,7 @@ public func addSavedSticker(postbox: Postbox, network: Network, file: TelegramMe
if !found {
fetchReference = packReference
}
case .animatedEmoji, .animatedEmojiAnimations, .dice, .premiumGifts, .emojiGenericAnimations, .iconStatusEmoji, .iconChannelStatusEmoji, .iconTopicEmoji:
case .animatedEmoji, .animatedEmojiAnimations, .dice, .premiumGifts, .emojiGenericAnimations, .iconStatusEmoji, .iconChannelStatusEmoji, .iconTopicEmoji, .tonGifts:
break
}
if let fetchReference = fetchReference {

View File

@ -62,6 +62,7 @@ public struct Namespaces {
public static let CloudIconStatusEmoji: Int32 = 10
public static let CloudIconTopicEmoji: Int32 = 11
public static let CloudIconChannelStatusEmoji: Int32 = 12
public static let CloudTonGifts: Int32 = 13
}
public struct OrderedItemList {

View File

@ -26,6 +26,7 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable {
case iconStatusEmoji
case iconTopicEmoji
case iconChannelStatusEmoji
case tonGifts
public init(decoder: PostboxDecoder) {
switch decoder.decodeInt32ForKey("r", orElse: 0) {
@ -43,6 +44,8 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable {
self = .premiumGifts
case 6:
self = .iconChannelStatusEmoji
case 7:
self = .tonGifts
default:
self = .name("")
assertionFailure()
@ -68,6 +71,8 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable {
self = .premiumGifts
case 6:
self = .iconChannelStatusEmoji
case 7:
self = .tonGifts
default:
self = .name("")
assertionFailure()
@ -92,6 +97,8 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable {
encoder.encodeInt32(4, forKey: "r")
case .premiumGifts:
encoder.encodeInt32(5, forKey: "r")
case .tonGifts:
encoder.encodeInt32(6, forKey: "r")
case .emojiGenericAnimations, .iconStatusEmoji, .iconTopicEmoji, .iconChannelStatusEmoji:
preconditionFailure()
}
@ -117,7 +124,7 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable {
try container.encode(4 as Int32, forKey: "r")
case .premiumGifts:
try container.encode(5 as Int32, forKey: "r")
case .emojiGenericAnimations, .iconStatusEmoji, .iconTopicEmoji, .iconChannelStatusEmoji:
case .emojiGenericAnimations, .iconStatusEmoji, .iconTopicEmoji, .iconChannelStatusEmoji, .tonGifts:
preconditionFailure()
}
}
@ -153,6 +160,8 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable {
self = .iconTopicEmoji
case .stickerpackreferenceIconchannelstatusemoji:
self = .iconChannelStatusEmoji
case .stickerpackreferenceTongifts:
self = .tonGifts
case .none_:
throw FlatBuffersError.missingRequiredField()
}
@ -208,6 +217,10 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable {
valueType = .stickerpackreferenceIconchannelstatusemoji
let start = TelegramCore_StickerPackReference_IconChannelStatusEmoji.startStickerPackReference_IconChannelStatusEmoji(&builder)
offset = TelegramCore_StickerPackReference_IconChannelStatusEmoji.endStickerPackReference_IconChannelStatusEmoji(&builder, start: start)
case .tonGifts:
valueType = .stickerpackreferenceTongifts
let start = TelegramCore_StickerPackReference_TonGifts.startStickerPackReference_TonGifts(&builder)
offset = TelegramCore_StickerPackReference_TonGifts.endStickerPackReference_TonGifts(&builder, start: start)
}
return TelegramCore_StickerPackReference.createStickerPackReference(&builder, valueType: valueType, valueOffset: offset)
}
@ -250,6 +263,12 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable {
} else {
return false
}
case .tonGifts:
if case .tonGifts = rhs {
return true
} else {
return false
}
case .emojiGenericAnimations:
if case .emojiGenericAnimations = rhs {
return true

View File

@ -55,6 +55,9 @@ func cacheStickerPack(transaction: Transaction, info: StickerPackCollectionInfo,
case .name:
namespace = info.id.namespace
id = info.id.id
case .tonGifts:
namespace = Namespaces.ItemCollection.CloudTonGifts
id = 0
}
if let namespace = namespace, let id = id {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))), entry: entry)
@ -159,6 +162,20 @@ func _internal_cachedStickerPack(postbox: Postbox, network: Network, reference:
} else {
return (.fetching, true, nil)
}
case .tonGifts:
let namespace = Namespaces.ItemCollection.CloudTonGifts
let id: ItemCollectionId.Id = 0
if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))))?.get(CachedStickerPack.self), let info = cached.info {
previousHash = cached.hash
let current: CachedStickerPackResult = .result(info, cached.items, false)
if cached.hash != info.hash {
return (current, true, previousHash)
} else {
return (current, false, previousHash)
}
} else {
return (.fetching, true, nil)
}
case .emojiGenericAnimations:
let namespace = Namespaces.ItemCollection.CloudEmojiGenericAnimations
let id: ItemCollectionId.Id = 0
@ -324,6 +341,18 @@ func cachedStickerPack(transaction: Transaction, reference: StickerPackReference
if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))))?.get(CachedStickerPack.self), let info = cached.info {
return (info, cached.items, false)
}
case .tonGifts:
let namespace = Namespaces.ItemCollection.CloudTonGifts
let id: ItemCollectionId.Id = 0
if let currentInfo = transaction.getItemCollectionInfo(collectionId: ItemCollectionId(namespace: namespace, id: id)) as? StickerPackCollectionInfo {
let items = transaction.getItemCollectionItems(collectionId: ItemCollectionId(namespace: namespace, id: id))
if !items.isEmpty {
return (StickerPackCollectionInfo.Accessor(currentInfo), items.compactMap { $0 as? StickerPackItem }, true)
}
}
if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))))?.get(CachedStickerPack.self), let info = cached.info {
return (info, cached.items, false)
}
case .emojiGenericAnimations:
let namespace = Namespaces.ItemCollection.CloudEmojiGenericAnimations
let id: ItemCollectionId.Id = 0

View File

@ -30,6 +30,8 @@ extension StickerPackReference {
return .inputStickerSetEmojiChannelDefaultStatuses
case .iconTopicEmoji:
return .inputStickerSetEmojiDefaultTopicIcons
case .tonGifts:
return .inputStickerSetTonGifts
}
}
}

View File

@ -58,6 +58,9 @@ func _internal_requestStickerSet(postbox: Postbox, network: Network, reference:
case .iconTopicEmoji:
collectionId = nil
input = .inputStickerSetEmojiDefaultTopicIcons
case .tonGifts:
collectionId = nil
input = .inputStickerSetTonGifts
}
let localSignal: (ItemCollectionId) -> Signal<(ItemCollectionInfo, [ItemCollectionItem])?, NoError> = { collectionId in

View File

@ -1425,7 +1425,6 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: attributes)
}
case let .suggestedPostApprovalStatus(status):
//TODO:localize
var messageText = ""
for attribute in message.attributes {
if let attribute = attribute as? ReplyMessageAttribute, let message = message.associatedMessages[attribute.messageId] {
@ -1433,36 +1432,22 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
}
}
let _ = messageText
let string: String
if !message.flags.contains(.Incoming) {
switch status {
case .approved:
if messageText.isEmpty {
string = "The message was approved"
} else {
string = "The message \"\(messageText)\" was approved"
}
string = strings.Chat_PostApproval_Status_AdminApproved
case .rejected:
if messageText.isEmpty {
string = "The message was declined"
} else {
string = "The message \"\(messageText)\" was declined"
}
string = strings.Chat_PostApproval_Status_AdminRejected
}
} else {
switch status {
case .approved:
if messageText.isEmpty {
string = "Your message was approved"
} else {
string = "Your message \"\(messageText)\" was approved"
}
string = strings.Chat_PostApproval_Status_UserApproved
case .rejected:
if messageText.isEmpty {
string = "Your message was declined"
} else {
string = "Your message \"\(messageText)\" was declined"
}
string = strings.Chat_PostApproval_Status_UserRejected
}
}
attributedString = NSAttributedString(string: string, font: titleFont, textColor: primaryTextColor)
@ -1477,19 +1462,14 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
}
let _ = isUser
//TODO:localize
let amountString: String
switch amount.currency {
case .stars:
if amount.amount.value == 1 {
amountString = "1 Star"
} else {
amountString = "\(amount.amount.value) Stars"
}
amountString = strings.Chat_PostApproval_DetailStatus_StarsAmount(Int32((amount.amount.value == 1 && amount.amount.nanos == 0) ? 1 : 100)).replacingOccurrences(of: "#", with: "\(amount.amount)")
case .ton:
amountString = "\(formatTonAmountText(amount.amount.value, dateTimeFormat: dateTimeFormat, maxDecimalPositions: 3)) TON"
amountString = strings.Chat_PostApproval_DetailStatus_TonAmount(Int32((amount.amount.value == 1 * 1_000_000_000) ? 1 : 100)).replacingOccurrences(of: "#", with: "\(formatTonAmountText(amount.amount.value, dateTimeFormat: dateTimeFormat, maxDecimalPositions: 3))")
}
attributedString = parseMarkdownIntoAttributedString("**\(channelName)** received **\(amountString)** for publishing this post", attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil }))
attributedString = parseMarkdownIntoAttributedString(strings.Chat_PostApproval_DetailStatus_PostedPaid("\(channelName)", amountString).string, attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil }))
case let .suggestedPostRefund(info):
var isUser = true
var channelName: String = ""
@ -1501,15 +1481,14 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
}
let _ = channelName
//TODO:localize
if info.isUserInitiated {
if isUser {
attributedString = NSAttributedString(string: "Suggested post was refunded because you didn't have enough funds", font: titleFont, textColor: primaryTextColor)
attributedString = NSAttributedString(string: strings.Chat_PostApproval_DetailStatus_UserFailedRefunded, font: titleFont, textColor: primaryTextColor)
} else {
attributedString = NSAttributedString(string: "Suggested post was refunded because the user didn't have enough funds", font: titleFont, textColor: primaryTextColor)
attributedString = NSAttributedString(string: strings.Chat_PostApproval_DetailStatus_AdminFailedRefunded, font: titleFont, textColor: primaryTextColor)
}
} else {
attributedString = NSAttributedString(string: "Suggested post was refunded because the message was deleted", font: titleFont, textColor: primaryTextColor)
attributedString = NSAttributedString(string: strings.Chat_PostApproval_DetailStatus_FailedDeleted, font: titleFont, textColor: primaryTextColor)
}
case let .giftTon(currency, amount, _, _, _):
attributedString = nil

View File

@ -258,7 +258,6 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
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.lowercased(), ranges: [])
@ -279,23 +278,23 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
let amountString: String
switch amount.currency {
case .stars:
amountString = amount.amount.value == 1 ? "\(amount.amount) Star" : "\(amount.amount) Stars"
amountString = item.presentationData.strings.Chat_PostApproval_DetailStatus_StarsAmount(Int32((amount.amount.value == 1 && amount.amount.nanos == 0) ? 1 : 100)).replacingOccurrences(of: "#", with: "\(amount.amount)")
case .ton:
amountString = "\(formatTonAmountText(amount.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat)) TON"
amountString = item.presentationData.strings.Chat_PostApproval_DetailStatus_TonAmount(Int32((amount.amount.value == 1 * 1_000_000_000) ? 1 : 100)).replacingOccurrences(of: "#", with: "\(formatTonAmountText(amount.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat, maxDecimalPositions: 3))")
}
switch amount.currency {
case .stars:
if !isUser {
pricePart = "\n\n💰 The user have been charged \(amountString).\n\n⌛ **\(channelName)** will receive the Stars once the post has been live for 24 hours.\n\n🔄 If your remove the post before it has been live for 24 hours, the user's Stars will be refunded."
if isUser {
pricePart = "\n\n" + item.presentationData.strings.Chat_PostApproval_Message_UserAgreementPriceStars(amountString, channelName).string
} else {
pricePart = "\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."
pricePart = "\n\n" + item.presentationData.strings.Chat_PostApproval_Message_AdminAgreementPriceStars(amountString, channelName).string
}
case .ton:
if !isUser {
pricePart = "\n\n💰 The user have been charged \(amountString).\n\n⌛ **\(channelName)** will receive TON once the post has been live for 24 hours.\n\n🔄 If your remove the post before it has been live for 24 hours, the user's TON will be refunded."
if isUser {
pricePart = "\n\n" + item.presentationData.strings.Chat_PostApproval_Message_UserAgreementPriceTon(amountString, channelName).string
} else {
pricePart = "\n\n💰 You have been charged \(amountString).\n\n⌛ **\(channelName)** will receive your TON 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 TON will be refunded."
pricePart = "\n\n" + item.presentationData.strings.Chat_PostApproval_Message_AdminAgreementPriceTon(amountString, channelName).string
}
}
}
@ -303,23 +302,23 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
let rawString: String
if let timestamp {
if Int32(Date().timeIntervalSince1970) >= timestamp {
if !isUser {
rawString = "📅 The post has been automatically published in **\(channelName)** **\(timeString)**." + pricePart
if isUser {
rawString = item.presentationData.strings.Chat_PostApproval_Message_UserAgreementPast(channelName, timeString).string + pricePart
} else {
rawString = "📅 Your post has been automatically published in **\(channelName)** **\(timeString)**." + pricePart
rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminAgreementPast(channelName, timeString).string + pricePart
}
} else {
if !isUser {
rawString = "📅 The post will be automatically published in **\(channelName)** **\(timeString)**." + pricePart
if isUser {
rawString = item.presentationData.strings.Chat_PostApproval_Message_UserAgreementFuture(channelName, timeString).string + pricePart
} else {
rawString = "📅 Your post will be automatically published in **\(channelName)** **\(timeString)**." + pricePart
rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminAgreementFuture(channelName, timeString).string + pricePart
}
}
} else {
if !isUser {
rawString = "📅 The post has been automatically published in **\(channelName)**." + pricePart
if isUser {
rawString = item.presentationData.strings.Chat_PostApproval_Message_UserAgreementNoTime(channelName).string + pricePart
} else {
rawString = "📅 Your post has been automatically published in **\(channelName)**." + pricePart
rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminAgreementNoTime(channelName).string + pricePart
}
}
updatedAttributedString = parseMarkdownIntoAttributedString(rawString, attributes: MarkdownAttributes(
@ -336,9 +335,9 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
switch reason {
case .generic:
if let comment {
rawString = "You declined the post with the following comment:\n\n" + comment
rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminDeclinedComment(comment).string
} else {
rawString = "You declined the post."
rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminDeclined
}
case .lowBalance:
rawString = ""
@ -367,7 +366,6 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
}
}
//TODO:localize
var titleLayoutAndApply: (TextNodeLayout, () -> TextNode)?
if let suggestedPost {
let channelName: String
@ -381,32 +379,32 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
var smallFont = false
switch suggestedPost {
case .approved:
rawString = "🤝 Agreement Reached!"
rawString = item.presentationData.strings.Chat_PostApproval_Message_TitleApproved
case let .rejected(reason, comment):
if !item.message.effectivelyIncoming(item.context.account.peerId) {
switch reason {
case .generic:
if comment != nil {
rawString = "❌ You rejected the message with the comment:"
rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminTitleRejectedComment
} else {
rawString = "❌ You rejected the message."
rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminTitleRejected
smallFont = true
}
case .lowBalance:
rawString = "⚠️ **Transaction failed** because the user didn't have enough Stars."
rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminTitleFailedFunds
smallFont = true
}
} else {
switch reason {
case .generic:
if comment != nil {
rawString = "❌ **\(channelName)** rejected your message with the comment:"
rawString = item.presentationData.strings.Chat_PostApproval_Message_UserTitleRejectedComment(channelName).string
} else {
rawString = "❌ **\(channelName)** rejected your message."
rawString = item.presentationData.strings.Chat_PostApproval_Message_UserTitleRejected(channelName).string
smallFont = true
}
case .lowBalance:
rawString = "⚠️ **Transaction failed** because you didn't have enough Stars."
rawString = item.presentationData.strings.Chat_PostApproval_Message_UserTitleFailedFunds
smallFont = true
}
}
@ -499,9 +497,8 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
var buyStarsTitleLayoutAndApply: (TextNodeLayout, () -> TextNode)?
var buyStarsButtonSize: CGSize?
if hasBuyStarsButton {
//TODO:localize
let serviceColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper)
let buyStarsTitleLayoutAndApplyValue = makeBuyStarsTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Buy Stars", font: Font.semibold(15.0), textColor: serviceColor.primaryText), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: constrainedSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: textAlignment, cutout: nil, insets: UIEdgeInsets()))
let buyStarsTitleLayoutAndApplyValue = makeBuyStarsTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Chat_PostApproval_Message_BuyStars, font: Font.semibold(15.0), textColor: serviceColor.primaryText), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: constrainedSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: textAlignment, cutout: nil, insets: UIEdgeInsets()))
buyStarsTitleLayoutAndApply = buyStarsTitleLayoutAndApplyValue
let buyStarsButtonSizeValue = CGSize(width: buyStarsTitleLayoutAndApplyValue.0.size.width + 20.0 * 2.0, height: buyStarsTitleLayoutAndApplyValue.0.size.height + 8.0 * 2.0)

View File

@ -1300,7 +1300,6 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
canApprove = false
}
//TODO:localize
var buttonDeclineValue: UInt8 = 0
let buttonDecline = MemoryBuffer(data: Data(bytes: &buttonDeclineValue, count: 1))
var buttonApproveValue: UInt8 = 1
@ -1332,11 +1331,11 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
ReplyMarkupMessageAttribute(
rows: [
ReplyMarkupRow(buttons: [
ReplyMarkupButton(title: "Decline", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonDecline)),
ReplyMarkupButton(title: "Approve", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonApprove))
ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionReject, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonDecline)),
ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionApprove, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonApprove))
]),
ReplyMarkupRow(buttons: [
ReplyMarkupButton(title: "Suggest Changes", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonSuggestChanges))
ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionSuggestChanges, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonSuggestChanges))
])
],
flags: [],

View File

@ -2811,7 +2811,6 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
canApprove = false
}
//TODO:localize
var buttonDeclineValue: UInt8 = 0
let buttonDecline = MemoryBuffer(data: Data(bytes: &buttonDeclineValue, count: 1))
var buttonApproveValue: UInt8 = 1
@ -2843,11 +2842,11 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
ReplyMarkupMessageAttribute(
rows: [
ReplyMarkupRow(buttons: [
ReplyMarkupButton(title: "Decline", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonDecline)),
ReplyMarkupButton(title: "Approve", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonApprove))
ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionReject, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonDecline)),
ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionApprove, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonApprove))
]),
ReplyMarkupRow(buttons: [
ReplyMarkupButton(title: "Suggest Changes", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonSuggestChanges))
ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionSuggestChanges, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonSuggestChanges))
])
],
flags: [],

View File

@ -861,7 +861,6 @@ public class ChatMessageStickerItemNode: ChatMessageItemView {
canApprove = false
}
//TODO:localize
var buttonDeclineValue: UInt8 = 0
let buttonDecline = MemoryBuffer(data: Data(bytes: &buttonDeclineValue, count: 1))
var buttonApproveValue: UInt8 = 1
@ -893,11 +892,11 @@ public class ChatMessageStickerItemNode: ChatMessageItemView {
ReplyMarkupMessageAttribute(
rows: [
ReplyMarkupRow(buttons: [
ReplyMarkupButton(title: "Decline", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonDecline)),
ReplyMarkupButton(title: "Approve", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonApprove))
ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionReject, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonDecline)),
ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionApprove, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonApprove))
]),
ReplyMarkupRow(buttons: [
ReplyMarkupButton(title: "Suggest Changes", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonSuggestChanges))
ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionSuggestChanges, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonSuggestChanges))
])
],
flags: [],

View File

@ -58,25 +58,16 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode {
}
}
//TODO:localize
let amountString: String
if let amount, amount.amount != .zero {
switch amount.currency {
case .stars:
if amount.amount.value == 1 {
amountString = "1 Star"
} else {
amountString = "\(amount.amount) Stars"
}
amountString = item.presentationData.strings.Chat_PostApproval_DetailStatus_StarsAmount(Int32((amount.amount.value == 1 && amount.amount.nanos == 0) ? 1 : 100)).replacingOccurrences(of: "#", with: "\(amount.amount)")
case .ton:
if amount.amount.value == 1 {
amountString = "1 TON"
} else {
amountString = "\(formatTonAmountText(amount.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat)) TON"
}
amountString = item.presentationData.strings.Chat_PostApproval_DetailStatus_TonAmount(Int32((amount.amount.value == 1 * 1_000_000_000) ? 1 : 100)).replacingOccurrences(of: "#", with: "\(formatTonAmountText(amount.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat, maxDecimalPositions: 3))")
}
} else {
amountString = "Free"
amountString = item.presentationData.strings.Chat_PostSuggestion_PriceFree
}
var timestampString: String
@ -86,12 +77,11 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode {
timestampString = String(timestampString[timestampString.startIndex]).capitalized + timestampString[timestampString.index(after: timestampString.startIndex)...]
}
} else {
timestampString = "Anytime"
timestampString = item.presentationData.strings.Chat_PostSuggestion_TimeAny
}
let serviceColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper)
//TODO:localize
let titleText: String
if let attribute = item.message.attributes.first(where: { $0 is ReplyMessageAttribute }) as? ReplyMessageAttribute {
var changedText = false
@ -131,19 +121,19 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode {
if !item.message.effectivelyIncoming(item.context.account.peerId) {
if changedText && changedMedia && changedPrice && changedTime {
titleText = "You suggest a new price,\ntime and contents for this message."
titleText = item.presentationData.strings.Chat_PostSuggestion_UserChangePTC
} else if changedText && changedPrice && changedTime {
titleText = "You suggest a new price,\ntime and text for this message."
titleText = item.presentationData.strings.Chat_PostSuggestion_UserChangePTT
} else if changedMedia && changedPrice && changedTime {
titleText = "You suggest a new price,\ntime and attachments for this message."
titleText = item.presentationData.strings.Chat_PostSuggestion_UserChangePTA
} else if changedPrice && changedTime {
titleText = "You suggest a new price and time\nfor this message."
titleText = item.presentationData.strings.Chat_PostSuggestion_UserChangePT
} else if changedPrice {
titleText = "You suggest a new price\nfor this message."
titleText = item.presentationData.strings.Chat_PostSuggestion_UserChangeP
} else if changedTime {
titleText = "You suggest a new time\nfor this message."
titleText = item.presentationData.strings.Chat_PostSuggestion_UserChangeT
} else {
titleText = "You suggest changes\nfor this message."
titleText = item.presentationData.strings.Chat_PostSuggestion_UserChange
}
} else {
var channelName = ""
@ -151,26 +141,26 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode {
channelName = item.message.author.flatMap(EnginePeer.init)?.compactDisplayTitle ?? " "
}
if changedText && changedMedia && changedPrice && changedTime {
titleText = "**\(channelName)** suggests a new price,\ntime and contents for this message."
titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChangePTC(channelName).string
} else if changedText && changedPrice && changedTime {
titleText = "**\(channelName)** suggests a new price,\ntime and text for this message."
titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChangePTT(channelName).string
} else if changedMedia && changedPrice && changedTime {
titleText = "**\(channelName)** suggests a new price,\ntime and attachments for this message."
titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChangePTA(channelName).string
} else if changedPrice && changedTime {
titleText = "**\(channelName)** suggests a new price and time\nfor this message."
titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChangePT(channelName).string
} else if changedPrice {
titleText = "**\(channelName)** suggests a new price\nfor this message."
titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChangeP(channelName).string
} else if changedTime {
titleText = "**\(channelName)** suggests a new time\nfor this message."
titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChangeT(channelName).string
} else {
titleText = "**\(channelName)** suggests changes\nfor this message."
titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChange(channelName).string
}
}
} else {
if !item.message.effectivelyIncoming(item.context.account.peerId) {
titleText = "You suggest to post\nthis message."
titleText = item.presentationData.strings.Chat_PostSuggestion_UserPost
} else {
titleText = "**\(item.message.author.flatMap(EnginePeer.init)?.compactDisplayTitle ?? " ")** suggests to post\nthis message."
titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelPost(item.message.author.flatMap(EnginePeer.init)?.compactDisplayTitle ?? " ").string
}
}
@ -185,8 +175,8 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode {
let titleLayout = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedText, 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 priceLabelLayout = makePriceLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Chat_PostSuggestion_TablePrice, 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: item.presentationData.strings.Chat_PostSuggestion_TableTime, 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()))

View File

@ -3115,166 +3115,6 @@ private final class PeerSelectorBadgeComponent: Component {
}
}
private final class TimeSelectorBadgeComponent: Component {
let context: AccountContext
let theme: PresentationTheme
let strings: PresentationStrings
let timestamp: Int32?
let action: ((UIView) -> Void)?
init(
context: AccountContext,
theme: PresentationTheme,
strings: PresentationStrings,
timestamp: Int32?,
action: ((UIView) -> Void)?
) {
self.context = context
self.theme = theme
self.strings = strings
self.timestamp = timestamp
self.action = action
}
static func ==(lhs: TimeSelectorBadgeComponent, rhs: TimeSelectorBadgeComponent) -> Bool {
if lhs.context !== rhs.context {
return false
}
if lhs.theme !== rhs.theme {
return false
}
if lhs.strings !== rhs.strings {
return false
}
if lhs.timestamp != rhs.timestamp {
return false
}
if (lhs.action == nil) != (rhs.action == nil) {
return false
}
return true
}
final class View: HighlightableButton {
private let background = ComponentView<Empty>()
private let title = ComponentView<Empty>()
private var selectorIcon: ComponentView<Empty>?
private var component: TimeSelectorBadgeComponent?
override init(frame: CGRect) {
super.init(frame: frame)
self.addTarget(self, action: #selector(self.pressed), for: .touchUpInside)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func pressed() {
guard let component = self.component else {
return
}
component.action?(self)
}
func update(component: TimeSelectorBadgeComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.component = component
self.isEnabled = component.action != nil
let height: CGFloat = 32.0
let leftTextInset: CGFloat = 12.0
let rightTextInset: CGFloat = component.action != nil ? (leftTextInset + 14.0) : leftTextInset
var titleString: String
//TODO:localize
if let timestamp = component.timestamp {
titleString = humanReadableStringForTimestamp(strings: component.strings, dateTimeFormat: PresentationDateTimeFormat(), timestamp: timestamp, alwaysShowTime: true).string
if titleString.count > 1 {
titleString = String(titleString[titleString.startIndex]).capitalized + titleString[titleString.index(after: titleString.startIndex)...]
}
} else {
titleString = "Anytime"
}
let titleSize = self.title.update(
transition: .immediate,
component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: titleString, font: Font.medium(15.0), textColor: component.theme.list.itemPrimaryTextColor))
)),
environment: {},
containerSize: CGSize(width: availableSize.width - leftTextInset - rightTextInset, height: 100.0)
)
if let titleView = self.title.view {
if titleView.superview == nil {
titleView.isUserInteractionEnabled = false
self.addSubview(titleView)
}
titleView.frame = CGRect(origin: CGPoint(x: leftTextInset, y: floorToScreenPixels((height - titleSize.height) * 0.5)), size: titleSize)
}
let size = CGSize(width: leftTextInset + rightTextInset + titleSize.width, height: height)
if component.action != nil {
let selectorIcon: ComponentView<Empty>
if let current = self.selectorIcon {
selectorIcon = current
} else {
selectorIcon = ComponentView()
self.selectorIcon = selectorIcon
}
let selectorIconSize = selectorIcon.update(
transition: transition,
component: AnyComponent(BundleIconComponent(
name: "Item List/ExpandableSelectorArrows", tintColor: component.theme.list.itemInputField.primaryColor.withMultipliedAlpha(0.5))),
environment: {},
containerSize: CGSize(width: 100.0, height: 100.0)
)
let selectorIconFrame = CGRect(origin: CGPoint(x: size.width - 8.0 - selectorIconSize.width, y: floorToScreenPixels((size.height - selectorIconSize.height) * 0.5)), size: selectorIconSize)
if let selectorIconView = selectorIcon.view {
if selectorIconView.superview == nil {
selectorIconView.isUserInteractionEnabled = false
self.addSubview(selectorIconView)
}
transition.setFrame(view: selectorIconView, frame: selectorIconFrame)
}
} else if let selectorIcon = self.selectorIcon {
self.selectorIcon = nil
selectorIcon.view?.removeFromSuperview()
}
let _ = self.background.update(
transition: transition,
component: AnyComponent(FilledRoundedRectangleComponent(
color: component.theme.list.itemInputField.backgroundColor,
cornerRadius: .minEdge,
smoothCorners: false
)),
environment: {},
containerSize: size
)
if let backgroundView = self.background.view {
if backgroundView.superview == nil {
backgroundView.isUserInteractionEnabled = false
self.insertSubview(backgroundView, at: 0)
}
transition.setFrame(view: backgroundView, frame: CGRect(origin: CGPoint(), size: size))
}
return size
}
}
func makeView() -> View {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
final class HeaderContextReferenceContentSource: ContextReferenceContentSource {
private let controller: ViewController
private let sourceView: UIView

View File

@ -1968,8 +1968,7 @@ public final class ChatSideTopicsPanel: Component {
).get()
if let threadInfo, threadInfo.isMessageFeeRemoved {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Charge Message Fee", textColor: .primary, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Rate"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ReinstatePaidMessages, textColor: .primary, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Rate"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
guard let self, let component = self.component else {
return
}

View File

@ -226,12 +226,11 @@ public final class SuggestPostAccessoryPanelNode: AccessoryPanelNode {
}
}
//TODO:localize
var titleText: [CompositeTextNode.Component] = []
if let postSuggestionState = interfaceState.interfaceState.postSuggestionState, postSuggestionState.editingOriginalMessageId != nil {
titleText.append(.text(NSAttributedString(string: "Suggest Changes", font: Font.medium(15.0), textColor: self.theme.chat.inputPanel.panelControlAccentColor)))
titleText.append(.text(NSAttributedString(string: self.strings.Chat_PostSuggestion_Suggest_InputEditTitle, font: Font.medium(15.0), textColor: self.theme.chat.inputPanel.panelControlAccentColor)))
} else {
titleText.append(.text(NSAttributedString(string: "Suggest a post below", font: Font.medium(15.0), textColor: self.theme.chat.inputPanel.panelControlAccentColor)))
titleText.append(.text(NSAttributedString(string: self.strings.Chat_PostSuggestion_Suggest_InputTitle, font: Font.medium(15.0), textColor: self.theme.chat.inputPanel.panelControlAccentColor)))
}
self.titleNode.components = titleText
@ -269,10 +268,10 @@ public final class SuggestPostAccessoryPanelNode: AccessoryPanelNode {
)).string
textString = NSAttributedString(string: "\(currencySymbol)\(amountString) 📅 \(timeString)", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor)
} else {
textString = NSAttributedString(string: "\(currencySymbol)\(amountString) for publishing anytime", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor)
textString = NSAttributedString(string: self.strings.Chat_PostSuggestion_Suggest_InputSubtitleAnytime("\(currencySymbol)\(amountString)").string, font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor)
}
} else {
textString = NSAttributedString(string: "Tap to offer a price for publishing", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor)
textString = NSAttributedString(string: self.strings.Chat_PostSuggestion_Suggest_InputSubtitleEmpty, font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor)
}
let mutableTextString = NSMutableAttributedString(attributedString: textString)

View File

@ -112,16 +112,13 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
title = self.presentationData.strings.Conversation_SetReminder_Title
case let .suggestPost(needsTime, isAdmin, funds):
if needsTime {
//TODO:localize
title = "Accept Terms"
text = "Set the date and time you want\nthis message to be published."
title = self.presentationData.strings.Chat_PostSuggestion_ApproveTime_Title
text = self.presentationData.strings.Chat_PostSuggestion_ApproveTime_Text
} else {
//TODO:localize
title = "Time"
text = "Set the date and time you want\nyour message to be published."
title = self.presentationData.strings.Chat_PostSuggestion_SetTime_Title
text = self.presentationData.strings.Chat_PostSuggestion_SetTime_Text
}
//TODO:localize
if let funds, isAdmin {
var commissionValue: String
commissionValue = "\(Double(funds.commissionPermille) * 0.1)"
@ -134,10 +131,10 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
switch funds.amount.currency {
case .stars:
let displayAmount = funds.amount.amount.totalValue * Double(funds.commissionPermille) / 1000.0
subtitle = "You will receive \(displayAmount) Stars (\(commissionValue)%)\nfor publishing this post"
subtitle = self.presentationData.strings.Chat_PostSuggestion_ApproveTime_AdminConfirmationPriceStars("\(displayAmount)", "\(commissionValue)").string
case .ton:
let displayAmount = Double(funds.amount.amount.value) / 1000000000.0 * Double(funds.commissionPermille) / 1000.0
subtitle = "You will receive \(displayAmount) TON (\(commissionValue)%)\nfor publishing this post"
subtitle = self.presentationData.strings.Chat_PostSuggestion_ApproveTime_AdminConfirmationPriceTon("\(displayAmount)", "\(commissionValue)").string
}
}
}
@ -183,11 +180,10 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
self.onlineButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(backgroundColor: buttonColor, foregroundColor: buttonTextColor), font: .regular, height: 52.0, cornerRadius: 11.0, gloss: false)
switch mode {
case let .suggestPost(needsTime, _, _):
//TODO:localize
if needsTime {
self.onlineButton.title = "Post Now"
self.onlineButton.title = self.presentationData.strings.Chat_PostSuggestion_ApproveTime_NoTimeAction
} else {
self.onlineButton.title = "Send Anytime"
self.onlineButton.title = self.presentationData.strings.Chat_PostSuggestion_SetTime_NoTimeAction
}
default:
self.onlineButton.title = self.presentationData.strings.Conversation_ScheduleMessage_SendWhenOnline
@ -589,7 +585,6 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
}
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
//TODO:localize
let playOnce = ActionSlot<Void>()
let toastSize = toast.update(
transition: ComponentTransition(transition),
@ -602,7 +597,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
)),
content: AnyComponent(VStack([
AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent(
text: .markdown(text: "Transactions in **Stars** may be reversed by the payment provider within **21** days. Only accept Stars from people you trust.", attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil })),
text: .markdown(text: self.presentationData.strings.Chat_PostSuggestion_StarsDisclaimer, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil })),
maximumNumberOfLines: 0
)))
], alignment: .left, spacing: 6.0)),

View File

@ -128,7 +128,7 @@ private final class BalanceNeededSheetContentComponent: Component {
let titleSize = self.title.update(
transition: transition,
component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "\(formatTonAmountText(component.amount.value, dateTimeFormat: component.context.sharedContext.currentPresentationData.with({ $0 }).dateTimeFormat)) TON Needed", font: Font.bold(24.0), textColor: environment.theme.list.itemPrimaryTextColor)),
text: .plain(NSAttributedString(string: environment.strings.BalanceNeeded_FragmentTitle(formatTonAmountText(component.amount.value, dateTimeFormat: component.context.sharedContext.currentPresentationData.with({ $0 }).dateTimeFormat)).string, font: Font.bold(24.0), textColor: environment.theme.list.itemPrimaryTextColor)),
horizontalAlignment: .center,
maximumNumberOfLines: 0
)),
@ -144,11 +144,10 @@ private final class BalanceNeededSheetContentComponent: Component {
contentHeight += titleSize.height
contentHeight += 14.0
//TODO:localize
let textSize = self.text.update(
transition: transition,
component: AnyComponent(BalancedTextComponent(
text: .plain(NSAttributedString(string: "You can add funds to your balance via the third-party platform Fragment.", font: Font.regular(15.0), textColor: environment.theme.list.itemPrimaryTextColor)),
text: .plain(NSAttributedString(string: environment.strings.BalanceNeeded_FragmentSubtitle, font: Font.regular(15.0), textColor: environment.theme.list.itemPrimaryTextColor)),
horizontalAlignment: .center,
maximumNumberOfLines: 0,
lineSpacing: 0.18
@ -165,7 +164,6 @@ private final class BalanceNeededSheetContentComponent: Component {
contentHeight += textSize.height
contentHeight += 24.0
//TODO:localize
let buttonSize = self.button.update(
transition: transition,
component: AnyComponent(ButtonComponent(
@ -175,7 +173,7 @@ private final class BalanceNeededSheetContentComponent: Component {
pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8)
),
content: AnyComponentWithIdentity(id: AnyHashable(0 as Int), component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "Add Funds via Fragment", font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor))
text: .plain(NSAttributedString(string: environment.strings.BalanceNeeded_FragmentAction, font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor))
))),
isEnabled: true,
allowActionWhenDisabled: true,

View File

@ -212,24 +212,23 @@ private final class SheetContent: CombinedComponent {
minAmount = StarsAmount(value: minAmountValue, nanos: 0)
maxAmount = StarsAmount(value: resaleConfiguration.paidMessageMaxAmount, nanos: 0)
case let .suggestedPost(mode, _, _, _):
//TODO:localize
switch mode {
case .sender:
titleString = "Suggest Terms"
titleString = environment.strings.Chat_PostSuggestion_Suggest_TitleCreate
case .admin:
titleString = "Suggest Changes"
titleString = environment.strings.Chat_PostSuggestion_Suggest_TitleEdit
}
switch state.currency {
case .stars:
amountTitle = "ENTER A PRICE IN STARS"
amountTitle = environment.strings.Chat_PostSuggestion_Suggest_PriceSectionStars
maxAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMaxStarsAmount, nanos: 0)
minAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMinStarsAmount, nanos: 0)
case .ton:
amountTitle = "ENTER A PRICE IN TON"
amountTitle = environment.strings.Chat_PostSuggestion_Suggest_PriceSectionTon
maxAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMaxTonAmount, nanos: 0)
minAmount = StarsAmount(value: 0, nanos: 0)
}
amountPlaceholder = "Price"
amountPlaceholder = environment.strings.Chat_PostSuggestion_Suggest_PricePlaceholder
allowZero = true
if let usdWithdrawRate = withdrawConfiguration.usdWithdrawRate, let tonUsdRate = withdrawConfiguration.tonUsdRate, let amount = state.amount, amount > StarsAmount.zero {
@ -330,17 +329,16 @@ private final class SheetContent: CombinedComponent {
}
if displayCurrencySelector {
//TODO:localize
let selectedId: AnyHashable = state.currency == .stars ? AnyHashable(0 as Int) : AnyHashable(1 as Int)
let starsTitle: String
let tonTitle: String
switch mode {
case .sender:
starsTitle = "Offer Stars"
tonTitle = "Offer TON"
starsTitle = environment.strings.Chat_PostSuggestion_Suggest_OfferStars
tonTitle = environment.strings.Chat_PostSuggestion_Suggest_OfferTon
case .admin:
starsTitle = "Request Stars"
tonTitle = "Request TON"
starsTitle = environment.strings.Chat_PostSuggestion_Suggest_RequestStars
tonTitle = environment.strings.Chat_PostSuggestion_Suggest_RequestTon
}
let currencyToggle = currencyToggle.update(
@ -474,21 +472,20 @@ private final class SheetContent: CombinedComponent {
case let .suggestedPost(mode, _, _, _):
switch mode {
case let .sender(channel, isFromAdmin):
//TODO:localize
let string: String
if isFromAdmin {
switch state.currency {
case .stars:
string = "Choose how many Stars you charge for the message."
string = environment.strings.Chat_PostSuggestion_Suggest_RequestDescriptionStars
case .ton:
string = "Choose how many TON you charge for the message."
string = environment.strings.Chat_PostSuggestion_Suggest_RequestDescriptionTon
}
} else {
switch state.currency {
case .stars:
string = "Choose how many Stars you want to offer \(channel.compactDisplayTitle) to publish this message."
string = environment.strings.Chat_PostSuggestion_Suggest_OfferDescriptionStars(channel.compactDisplayTitle).string
case .ton:
string = "Choose how many TON you want to offer \(channel.compactDisplayTitle) to publish this message."
string = environment.strings.Chat_PostSuggestion_Suggest_OfferDescriptionTon(channel.compactDisplayTitle).string
}
}
let amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString(string, attributes: amountMarkdownAttributes, textAlignment: .natural))
@ -497,13 +494,12 @@ private final class SheetContent: CombinedComponent {
maximumNumberOfLines: 0
))
case .admin:
//TODO:localize
let string: String
switch state.currency {
case .stars:
string = "Choose how many Stars you charge for the message."
string = environment.strings.Chat_PostSuggestion_Suggest_RequestDescriptionStars
case .ton:
string = "Choose how many TON you charge for the message."
string = environment.strings.Chat_PostSuggestion_Suggest_RequestDescriptionTon
}
let amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString(string, attributes: amountMarkdownAttributes, textAlignment: .natural))
amountFooter = AnyComponent(MultilineTextComponent(
@ -576,13 +572,12 @@ private final class SheetContent: CombinedComponent {
if case let .suggestedPost(mode, _, _, _) = component.mode {
contentSize.height += 24.0
//TODO:localize
let footerString: String
switch mode {
case .sender:
footerString = "Select the date and time you want your message to be published."
footerString = environment.strings.Chat_PostSuggestion_Suggest_OfferDateDescription
case .admin:
footerString = "Select the date and time you want to publish the message."
footerString = environment.strings.Chat_PostSuggestion_Suggest_EditDateDescription
}
let timestampFooterString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString(footerString, attributes: amountMarkdownAttributes, textAlignment: .natural))
@ -687,7 +682,6 @@ private final class SheetContent: CombinedComponent {
} else if case .paidMessages = component.mode {
buttonString = environment.strings.Stars_SendMessage_AdjustmentAction
} else if case let .suggestedPost(mode, _, _, _) = component.mode {
//TODO:localize
switch mode {
case .sender:
if let amount = state.amount, amount != .zero {
@ -701,12 +695,12 @@ private final class SheetContent: CombinedComponent {
currencySymbol = "$"
currencyAmount = formatTonAmountText(amount.value, dateTimeFormat: environment.dateTimeFormat)
}
buttonString = "Offer \(currencySymbol) \(currencyAmount)"
buttonString = environment.strings.Chat_PostSuggestion_Suggest_OfferButtonPrice("\(currencySymbol) \(currencyAmount)").string
} else {
buttonString = "Offer for Free"
buttonString = environment.strings.Chat_PostSuggestion_Suggest_OfferButtonFree
}
case .admin:
buttonString = "Update Terms"
buttonString = environment.strings.Chat_PostSuggestion_Suggest_UpdateButton
}
} else if let amount = state.amount {
buttonString = "\(environment.strings.Stars_Withdraw_Withdraw) # \(presentationStringsFormattedNumber(amount, environment.dateTimeFormat.groupingSeparator))"
@ -1120,21 +1114,19 @@ public final class StarsWithdrawScreen: ViewControllerComponentContainer {
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
var text = presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(minAmount))).string
if case .starGiftResell = self.mode {
//TODO:localize
text = "You cannot sell gift for less than \(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(minAmount)))."
text = presentationData.strings.Stars_SellGiftMinAmountToast_Text("\(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(minAmount)))").string
} else if case let .suggestedPost(mode, _, _, _) = self.mode {
let resaleConfiguration = StarsSubscriptionConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 })
switch currency {
case .stars:
//TODO:localize
switch mode {
case .admin:
text = "You cannot request less than \(resaleConfiguration.channelMessageSuggestionMinStarsAmount) Stars."
text = presentationData.strings.Chat_PostSuggestion_Suggest_AdminMinAmountStars_Text("\(resaleConfiguration.channelMessageSuggestionMinStarsAmount)").string
case let .sender(_, isFromAdmin):
if isFromAdmin {
text = "You cannot request less than \(resaleConfiguration.channelMessageSuggestionMinStarsAmount) Stars."
text = presentationData.strings.Chat_PostSuggestion_Suggest_AdminMinAmountStars_Text("\(resaleConfiguration.channelMessageSuggestionMinStarsAmount)").string
} else {
text = "You cannot offer less than \(resaleConfiguration.channelMessageSuggestionMinStarsAmount) Stars."
text = presentationData.strings.Chat_PostSuggestion_Suggest_UserMinAmountStars_Text("\(resaleConfiguration.channelMessageSuggestionMinStarsAmount)").string
}
}
case .ton:

View File

@ -359,7 +359,6 @@ private final class SuggestedPostAlertImpl: AlertController {
}
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
//TODO:localize
let playOnce = ActionSlot<Void>()
let toastSize = toast.update(
transition: ComponentTransition(transition),

View File

@ -1816,23 +1816,22 @@ extension ChatControllerImpl {
guard let self else {
return
}
//TODO:localize
let titleString: String
let textString: String
switch attribute.currency {
case .stars:
titleString = "Stars Will Be Lost"
textString = "You won't receive **Stars** for this post if you delete it now. The post must remain visible for at least **24 hours** after publication."
titleString = self.presentationData.strings.Chat_DeletePaidMessageStars_Title
textString = self.presentationData.strings.Chat_DeletePaidMessageStars_Text
case .ton:
titleString = "TON Will Be Lost"
textString = "You won't receive **TON** for this post if you delete it now. The post must remain visible for at least **24 hours** after publication."
titleString = self.presentationData.strings.Chat_DeletePaidMessageTon_Title
textString = self.presentationData.strings.Chat_DeletePaidMessageTon_Text
}
self.present(standardTextAlertController(
theme: AlertControllerTheme(presentationData: self.presentationData),
title: titleString,
text: textString,
actions: [
TextAlertAction(type: .destructiveAction, title: "Delete Anyway", action: { [weak self] in
TextAlertAction(type: .destructiveAction, title: self.presentationData.strings.Chat_DeletePaidMessage_Action, action: { [weak self] in
guard let self else {
return
}

View File

@ -2352,8 +2352,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if message.effectivelyIncoming(strongSelf.context.account.peerId) {
switch buttonType {
case 0:
//TODO:localize
let promptController = promptController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: strongSelf.updatedPresentationData, text: "Comment", titleFont: .bold, value: "", placeholder: "Optional", characterLimit: 4096, apply: { value in
let promptController = promptController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: strongSelf.updatedPresentationData, text: strongSelf.presentationData.strings.Chat_PostSuggestion_Reject_Title, titleFont: .bold, value: "", placeholder: strongSelf.presentationData.strings.Chat_PostSuggestion_Reject_Placeholder, characterLimit: 4096, apply: { value in
guard let self else {
return
}
@ -2393,10 +2392,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
timestamp = Int32(Date().timeIntervalSince1970) + 1 * 60 * 60
} else {
//TODO:localize
var textString: String
if isAdmin {
textString = "Do you really want to publish this post from **\((message.author.flatMap(EnginePeer.init))?.compactDisplayTitle ?? "")**?"
textString = strongSelf.presentationData.strings.Chat_PostSuggestion_Approve_AdminConfirmationText(message.author.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "").string
if let funds {
var commissionValue: String
@ -2412,25 +2410,25 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
switch funds.amount.currency {
case .stars:
let displayAmount = funds.amount.amount.totalValue * Double(funds.commissionPermille) / 1000.0
textString += "You will receive \(displayAmount) Stars (\(commissionValue)%)\nfor publishing this post. It must remain visible for **24** hours after publication."
textString += strongSelf.presentationData.strings.Chat_PostSuggestion_Approve_AdminConfirmationPriceStars("\(displayAmount)", "\(commissionValue)").string
case .ton:
let displayAmount = Double(funds.amount.amount.value) / 1000000000.0 * Double(funds.commissionPermille) / 1000.0
textString += "You will receive \(displayAmount) TON (\(commissionValue)%)\nfor publishing this post. It must remain visible for **24** hours after publication."
textString += strongSelf.presentationData.strings.Chat_PostSuggestion_Approve_AdminConfirmationPriceTon("\(displayAmount)", "\(commissionValue)").string
}
}
} else {
textString = "Do you really want to publish this post?"
textString = strongSelf.presentationData.strings.Chat_PostSuggestion_Approve_UserConfirmationText
}
strongSelf.present(SuggestedPostApproveAlert(presentationData: strongSelf.presentationData, title: "Accept Terms", text: textString, actions: [
TextAlertAction(type: .defaultAction, title: "Publish", action: { [weak strongSelf] in
strongSelf.present(SuggestedPostApproveAlert(presentationData: strongSelf.presentationData, title: strongSelf.presentationData.strings.Chat_PostSuggestion_Approve_Title, text: textString, actions: [
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Chat_PostSuggestion_Approve_Action, action: { [weak strongSelf] in
guard let strongSelf else {
return
}
let _ = strongSelf.context.engine.messages.monoforumPerformSuggestedPostAction(id: message.id, action: .approve(timestamp: timestamp)).startStandalone()
}),
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {})
], actionLayout: .vertical, parseMarkdown: true, toastText: funds?.amount.currency == .ton ? "Transactions in **Stars** may be reversed by the payment provider within **21** days. Only accept Stars from people you trust." : nil), in: .window(.root))
], actionLayout: .vertical, parseMarkdown: true, toastText: funds?.amount.currency == .stars ? strongSelf.presentationData.strings.Chat_PostSuggestion_StarsDisclaimer : nil), in: .window(.root))
}
case 2:
strongSelf.interfaceInteraction?.openSuggestPost(message, .default)

View File

@ -394,23 +394,22 @@ extension ChatControllerImpl {
guard let self else {
return
}
//TODO:localize
let titleString: String
let textString: String
switch attribute.currency {
case .stars:
titleString = "Stars Will Be Lost"
textString = "You won't receive **Stars** for this post if you delete it now. The post must remain visible for at least **24 hours** after publication."
titleString = self.presentationData.strings.Chat_DeletePaidMessageStars_Title
textString = self.presentationData.strings.Chat_DeletePaidMessageStars_Text
case .ton:
titleString = "TON Will Be Lost"
textString = "You won't receive **TON** for this post if you delete it now. The post must remain visible for at least **24 hours** after publication."
titleString = self.presentationData.strings.Chat_DeletePaidMessageTon_Title
textString = self.presentationData.strings.Chat_DeletePaidMessageTon_Text
}
self.present(standardTextAlertController(
theme: AlertControllerTheme(presentationData: self.presentationData),
title: titleString,
text: textString,
actions: [
TextAlertAction(type: .destructiveAction, title: "Delete Anyway", action: { [weak self] in
TextAlertAction(type: .destructiveAction, title: self.presentationData.strings.Chat_DeletePaidMessage_Action, action: { [weak self] in
guard let self else {
return
}

View File

@ -1520,23 +1520,22 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
}
if canSuggestPost {
//TODO:localize
if message.attributes.contains(where: { $0 is SuggestedPostMessageAttribute }) {
actions.append(.action(ContextMenuActionItem(text: "Edit Message", icon: { theme in
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Chat_ContextMenu_SuggestedPost_EditMessage, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.actionSheet.primaryTextColor)
}, action: { c, _ in
c?.dismiss(completion: {
interfaceInteraction.openSuggestPost(message, .editMessage)
})
})))
actions.append(.action(ContextMenuActionItem(text: "Edit Time", icon: { theme in
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Chat_ContextMenu_SuggestedPost_EditTime, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Calendar"), color: theme.actionSheet.primaryTextColor)
}, action: { c, _ in
c?.dismiss(completion: {
interfaceInteraction.openSuggestPost(message, .editTime)
})
})))
actions.append(.action(ContextMenuActionItem(text: "Edit Price", icon: { theme in
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Chat_ContextMenu_SuggestedPost_EditPrice, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/PriceTag"), color: theme.actionSheet.primaryTextColor)
}, action: { c, _ in
c?.dismiss(completion: {
@ -1544,7 +1543,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
})
})))
} else {
actions.append(.action(ContextMenuActionItem(text: "Suggest a Post", icon: { theme in
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Chat_ContextMenu_SuggestedPost_Create, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Customize"), color: theme.actionSheet.primaryTextColor)
}, action: { c, _ in
c?.dismiss(completion: {

View File

@ -159,8 +159,7 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
return (PresentationResourcesChat.chatInputTextFieldSilentPostOffImage(theme), nil, strings.VoiceOver_SilentPostOff, 1.0, UIEdgeInsets())
}
case .suggestPost:
//TODO:localize
return (PresentationResourcesChat.chatInputTextFieldSuggestPostImage(theme), nil, "Suggest post", 1.0, UIEdgeInsets())
return (PresentationResourcesChat.chatInputTextFieldSuggestPostImage(theme), nil, strings.VoiceOver_SuggestPost, 1.0, UIEdgeInsets())
case let .messageAutoremoveTimeout(timeout):
if let timeout = timeout {
return (nil, shortTimeIntervalString(strings: strings, value: timeout), strings.VoiceOver_SelfDestructTimerOn(timeIntervalString(strings: strings, value: timeout)).string, 1.0, UIEdgeInsets())