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?"; "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.SignUp" = "Sign up for %@";
"Premium.Week.SignUpInfo" = "Get Telegram Premium for 1 week"; "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[-1645763991] = { return Api.InputStickerSet.parse_inputStickerSetID($0) }
dict[-930399486] = { return Api.InputStickerSet.parse_inputStickerSetPremiumGifts($0) } dict[-930399486] = { return Api.InputStickerSet.parse_inputStickerSetPremiumGifts($0) }
dict[-2044933984] = { return Api.InputStickerSet.parse_inputStickerSetShortName($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[853188252] = { return Api.InputStickerSetItem.parse_inputStickerSetItem($0) }
dict[70813275] = { return Api.InputStickeredMedia.parse_inputStickeredMediaDocument($0) } dict[70813275] = { return Api.InputStickeredMedia.parse_inputStickeredMediaDocument($0) }
dict[1251549527] = { return Api.InputStickeredMedia.parse_inputStickeredMediaPhoto($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[-1398708869] = { return Api.Update.parse_updateMessagePoll($0) }
dict[619974263] = { return Api.Update.parse_updateMessagePollVote($0) } dict[619974263] = { return Api.Update.parse_updateMessagePollVote($0) }
dict[506035194] = { return Api.Update.parse_updateMessageReactions($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[-2030252155] = { return Api.Update.parse_updateMoveStickerSetToTop($0) }
dict[-1991136273] = { return Api.Update.parse_updateNewAuthorization($0) } dict[-1991136273] = { return Api.Update.parse_updateNewAuthorization($0) }
dict[1656358105] = { return Api.Update.parse_updateNewChannelMessage($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 inputStickerSetID(id: Int64, accessHash: Int64)
case inputStickerSetPremiumGifts case inputStickerSetPremiumGifts
case inputStickerSetShortName(shortName: String) case inputStickerSetShortName(shortName: String)
case inputStickerSetTonGifts
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
@ -824,6 +825,12 @@ public extension Api {
buffer.appendInt32(-2044933984) buffer.appendInt32(-2044933984)
} }
serializeString(shortName, buffer: buffer, boxed: false) serializeString(shortName, buffer: buffer, boxed: false)
break
case .inputStickerSetTonGifts:
if boxed {
buffer.appendInt32(485912992)
}
break break
} }
} }
@ -852,6 +859,8 @@ public extension Api {
return ("inputStickerSetPremiumGifts", []) return ("inputStickerSetPremiumGifts", [])
case .inputStickerSetShortName(let shortName): case .inputStickerSetShortName(let shortName):
return ("inputStickerSetShortName", [("shortName", shortName as Any)]) return ("inputStickerSetShortName", [("shortName", shortName as Any)])
case .inputStickerSetTonGifts:
return ("inputStickerSetTonGifts", [])
} }
} }
@ -915,6 +924,9 @@ public extension Api {
return nil 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 updateMessagePoll(flags: Int32, pollId: Int64, poll: Api.Poll?, results: Api.PollResults)
case updateMessagePollVote(pollId: Int64, peer: Api.Peer, options: [Buffer], qts: Int32) 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 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 updateMoveStickerSetToTop(flags: Int32, stickerset: Int64)
case updateNewAuthorization(flags: Int32, hash: Int64, date: Int32?, device: String?, location: String?) case updateNewAuthorization(flags: Int32, hash: Int64, date: Int32?, device: String?, location: String?)
case updateNewChannelMessage(message: Api.Message, pts: Int32, ptsCount: Int32) 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)} if Int(flags) & Int(1 << 1) != 0 {savedPeerId!.serialize(buffer, true)}
reactions.serialize(buffer, true) reactions.serialize(buffer, true)
break 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): case .updateMoveStickerSetToTop(let flags, let stickerset):
if boxed { if boxed {
buffer.appendInt32(-2030252155) 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)]) 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): 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)]) 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): case .updateMoveStickerSetToTop(let flags, let stickerset):
return ("updateMoveStickerSetToTop", [("flags", flags as Any), ("stickerset", stickerset as Any)]) return ("updateMoveStickerSetToTop", [("flags", flags as Any), ("stickerset", stickerset as Any)])
case .updateNewAuthorization(let flags, let hash, let date, let device, let location): case .updateNewAuthorization(let flags, let hash, let date, let device, let location):
@ -3272,6 +3283,25 @@ public extension Api {
return nil 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? { public static func parse_updateMoveStickerSetToTop(_ reader: BufferReader) -> Update? {
var _1: Int32? var _1: Int32?
_1 = reader.readInt32() _1 = reader.readInt32()

View File

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

View File

@ -133,6 +133,7 @@ enum AccountStateMutationOperation {
case UpdateStarsRevenueStatus(peerId: PeerId, status: StarsRevenueStats.Balances) case UpdateStarsRevenueStatus(peerId: PeerId, status: StarsRevenueStats.Balances)
case UpdateStarsReactionsDefaultPrivacy(privacy: TelegramPaidReactionPrivacy) case UpdateStarsReactionsDefaultPrivacy(privacy: TelegramPaidReactionPrivacy)
case ReportMessageDelivery([MessageId]) case ReportMessageDelivery([MessageId])
case UpdateMonoForumNoPaidException(peerId: PeerId, threadId: Int64, isFree: Bool)
} }
struct HoleFromPreviousState { struct HoleFromPreviousState {
@ -707,9 +708,13 @@ struct AccountMutableState {
self.addOperation(.ReportMessageDelivery(messageIds)) 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) { mutating func addOperation(_ operation: AccountStateMutationOperation) {
switch operation { 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 break
case let .AddMessages(messages, location): case let .AddMessages(messages, location):
for message in messages { for message in messages {

View File

@ -1081,6 +1081,26 @@ extension StoreMessage {
var threadId: Int64? var threadId: Int64?
if let savedPeerId { if let savedPeerId {
threadId = savedPeerId.peerId.toInt64() 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 { } else if let replyTo = replyTo {
var threadMessageId: MessageId? var threadMessageId: MessageId?
switch replyTo { switch replyTo {

View File

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

View File

@ -1870,6 +1870,8 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
mappedPrivacy = .peer(peerId) mappedPrivacy = .peer(peerId)
} }
updatedState.updateStarsReactionsDefaultPrivacy(privacy: mappedPrivacy) 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: default:
break break
} }
@ -3580,7 +3582,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
var currentAddQuickReplyMessages: OptimizeAddMessagesState? var currentAddQuickReplyMessages: OptimizeAddMessagesState?
for operation in operations { for operation in operations {
switch operation { 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 { if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location)) result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
} }
@ -5180,6 +5182,14 @@ func replayFinalState(
updatedStarsReactionsDefaultPrivacy = value updatedStarsReactionsDefaultPrivacy = value
case let .ReportMessageDelivery(messageIds): case let .ReportMessageDelivery(messageIds):
reportMessageDelivery = Set(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 { if !found {
fetchReference = packReference fetchReference = packReference
} }
case .animatedEmoji, .animatedEmojiAnimations, .dice, .premiumGifts, .emojiGenericAnimations, .iconStatusEmoji, .iconChannelStatusEmoji, .iconTopicEmoji: case .animatedEmoji, .animatedEmojiAnimations, .dice, .premiumGifts, .emojiGenericAnimations, .iconStatusEmoji, .iconChannelStatusEmoji, .iconTopicEmoji, .tonGifts:
break break
} }
if let fetchReference = fetchReference { if let fetchReference = fetchReference {

View File

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

View File

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

View File

@ -55,6 +55,9 @@ func cacheStickerPack(transaction: Transaction, info: StickerPackCollectionInfo,
case .name: case .name:
namespace = info.id.namespace namespace = info.id.namespace
id = info.id.id id = info.id.id
case .tonGifts:
namespace = Namespaces.ItemCollection.CloudTonGifts
id = 0
} }
if let namespace = namespace, let id = id { 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) 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 { } else {
return (.fetching, true, nil) 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: case .emojiGenericAnimations:
let namespace = Namespaces.ItemCollection.CloudEmojiGenericAnimations let namespace = Namespaces.ItemCollection.CloudEmojiGenericAnimations
let id: ItemCollectionId.Id = 0 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 { 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) 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: case .emojiGenericAnimations:
let namespace = Namespaces.ItemCollection.CloudEmojiGenericAnimations let namespace = Namespaces.ItemCollection.CloudEmojiGenericAnimations
let id: ItemCollectionId.Id = 0 let id: ItemCollectionId.Id = 0

View File

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

View File

@ -58,6 +58,9 @@ func _internal_requestStickerSet(postbox: Postbox, network: Network, reference:
case .iconTopicEmoji: case .iconTopicEmoji:
collectionId = nil collectionId = nil
input = .inputStickerSetEmojiDefaultTopicIcons input = .inputStickerSetEmojiDefaultTopicIcons
case .tonGifts:
collectionId = nil
input = .inputStickerSetTonGifts
} }
let localSignal: (ItemCollectionId) -> Signal<(ItemCollectionInfo, [ItemCollectionItem])?, NoError> = { collectionId in 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) attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: attributes)
} }
case let .suggestedPostApprovalStatus(status): case let .suggestedPostApprovalStatus(status):
//TODO:localize
var messageText = "" var messageText = ""
for attribute in message.attributes { for attribute in message.attributes {
if let attribute = attribute as? ReplyMessageAttribute, let message = message.associatedMessages[attribute.messageId] { 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 let string: String
if !message.flags.contains(.Incoming) { if !message.flags.contains(.Incoming) {
switch status { switch status {
case .approved: case .approved:
if messageText.isEmpty { string = strings.Chat_PostApproval_Status_AdminApproved
string = "The message was approved"
} else {
string = "The message \"\(messageText)\" was approved"
}
case .rejected: case .rejected:
if messageText.isEmpty { string = strings.Chat_PostApproval_Status_AdminRejected
string = "The message was declined"
} else {
string = "The message \"\(messageText)\" was declined"
}
} }
} else { } else {
switch status { switch status {
case .approved: case .approved:
if messageText.isEmpty { string = strings.Chat_PostApproval_Status_UserApproved
string = "Your message was approved"
} else {
string = "Your message \"\(messageText)\" was approved"
}
case .rejected: case .rejected:
if messageText.isEmpty { string = strings.Chat_PostApproval_Status_UserRejected
string = "Your message was declined"
} else {
string = "Your message \"\(messageText)\" was declined"
}
} }
} }
attributedString = NSAttributedString(string: string, font: titleFont, textColor: primaryTextColor) attributedString = NSAttributedString(string: string, font: titleFont, textColor: primaryTextColor)
@ -1477,19 +1462,14 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
} }
let _ = isUser let _ = isUser
//TODO:localize
let amountString: String let amountString: String
switch amount.currency { switch amount.currency {
case .stars: case .stars:
if amount.amount.value == 1 { amountString = strings.Chat_PostApproval_DetailStatus_StarsAmount(Int32((amount.amount.value == 1 && amount.amount.nanos == 0) ? 1 : 100)).replacingOccurrences(of: "#", with: "\(amount.amount)")
amountString = "1 Star"
} else {
amountString = "\(amount.amount.value) Stars"
}
case .ton: 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): case let .suggestedPostRefund(info):
var isUser = true var isUser = true
var channelName: String = "" var channelName: String = ""
@ -1501,15 +1481,14 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
} }
let _ = channelName let _ = channelName
//TODO:localize
if info.isUserInitiated { if info.isUserInitiated {
if isUser { 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 { } 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 { } 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, _, _, _): case let .giftTon(currency, amount, _, _, _):
attributedString = nil attributedString = nil

View File

@ -258,7 +258,6 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
switch suggestedPost { switch suggestedPost {
case let .approved(timestamp, amount): 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( let timeString = humanReadableStringForTimestamp(strings: item.presentationData.strings, dateTimeFormat: item.presentationData.dateTimeFormat, timestamp: timestamp ?? 0, alwaysShowTime: true, allowYesterday: false, format: HumanReadableStringFormat(
dateFormatString: { value in dateFormatString: { value in
return PresentationStrings.FormattedString(string: item.presentationData.strings.SuggestPost_SetTimeFormat_Date(value).string.lowercased(), ranges: []) 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 let amountString: String
switch amount.currency { switch amount.currency {
case .stars: 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: 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 { switch amount.currency {
case .stars: case .stars:
if !isUser { 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." pricePart = "\n\n" + item.presentationData.strings.Chat_PostApproval_Message_UserAgreementPriceStars(amountString, channelName).string
} else { } 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: case .ton:
if !isUser { 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." pricePart = "\n\n" + item.presentationData.strings.Chat_PostApproval_Message_UserAgreementPriceTon(amountString, channelName).string
} else { } 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 let rawString: String
if let timestamp { if let timestamp {
if Int32(Date().timeIntervalSince1970) >= timestamp { if Int32(Date().timeIntervalSince1970) >= timestamp {
if !isUser { if isUser {
rawString = "📅 The post has been automatically published in **\(channelName)** **\(timeString)**." + pricePart rawString = item.presentationData.strings.Chat_PostApproval_Message_UserAgreementPast(channelName, timeString).string + pricePart
} else { } 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 { } else {
if !isUser { if isUser {
rawString = "📅 The post will be automatically published in **\(channelName)** **\(timeString)**." + pricePart rawString = item.presentationData.strings.Chat_PostApproval_Message_UserAgreementFuture(channelName, timeString).string + pricePart
} else { } 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 { } else {
if !isUser { if isUser {
rawString = "📅 The post has been automatically published in **\(channelName)**." + pricePart rawString = item.presentationData.strings.Chat_PostApproval_Message_UserAgreementNoTime(channelName).string + pricePart
} else { } 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( updatedAttributedString = parseMarkdownIntoAttributedString(rawString, attributes: MarkdownAttributes(
@ -336,9 +335,9 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
switch reason { switch reason {
case .generic: case .generic:
if let comment { 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 { } else {
rawString = "You declined the post." rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminDeclined
} }
case .lowBalance: case .lowBalance:
rawString = "" rawString = ""
@ -367,7 +366,6 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
} }
} }
//TODO:localize
var titleLayoutAndApply: (TextNodeLayout, () -> TextNode)? var titleLayoutAndApply: (TextNodeLayout, () -> TextNode)?
if let suggestedPost { if let suggestedPost {
let channelName: String let channelName: String
@ -381,32 +379,32 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
var smallFont = false var smallFont = false
switch suggestedPost { switch suggestedPost {
case .approved: case .approved:
rawString = "🤝 Agreement Reached!" rawString = item.presentationData.strings.Chat_PostApproval_Message_TitleApproved
case let .rejected(reason, comment): case let .rejected(reason, comment):
if !item.message.effectivelyIncoming(item.context.account.peerId) { if !item.message.effectivelyIncoming(item.context.account.peerId) {
switch reason { switch reason {
case .generic: case .generic:
if comment != nil { if comment != nil {
rawString = "❌ You rejected the message with the comment:" rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminTitleRejectedComment
} else { } else {
rawString = "❌ You rejected the message." rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminTitleRejected
smallFont = true smallFont = true
} }
case .lowBalance: case .lowBalance:
rawString = "⚠️ **Transaction failed** because the user didn't have enough Stars." rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminTitleFailedFunds
smallFont = true smallFont = true
} }
} else { } else {
switch reason { switch reason {
case .generic: case .generic:
if comment != nil { if comment != nil {
rawString = "❌ **\(channelName)** rejected your message with the comment:" rawString = item.presentationData.strings.Chat_PostApproval_Message_UserTitleRejectedComment(channelName).string
} else { } else {
rawString = "❌ **\(channelName)** rejected your message." rawString = item.presentationData.strings.Chat_PostApproval_Message_UserTitleRejected(channelName).string
smallFont = true smallFont = true
} }
case .lowBalance: case .lowBalance:
rawString = "⚠️ **Transaction failed** because you didn't have enough Stars." rawString = item.presentationData.strings.Chat_PostApproval_Message_UserTitleFailedFunds
smallFont = true smallFont = true
} }
} }
@ -499,9 +497,8 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
var buyStarsTitleLayoutAndApply: (TextNodeLayout, () -> TextNode)? var buyStarsTitleLayoutAndApply: (TextNodeLayout, () -> TextNode)?
var buyStarsButtonSize: CGSize? var buyStarsButtonSize: CGSize?
if hasBuyStarsButton { if hasBuyStarsButton {
//TODO:localize
let serviceColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper) 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 buyStarsTitleLayoutAndApply = buyStarsTitleLayoutAndApplyValue
let buyStarsButtonSizeValue = CGSize(width: buyStarsTitleLayoutAndApplyValue.0.size.width + 20.0 * 2.0, height: buyStarsTitleLayoutAndApplyValue.0.size.height + 8.0 * 2.0) 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 canApprove = false
} }
//TODO:localize
var buttonDeclineValue: UInt8 = 0 var buttonDeclineValue: UInt8 = 0
let buttonDecline = MemoryBuffer(data: Data(bytes: &buttonDeclineValue, count: 1)) let buttonDecline = MemoryBuffer(data: Data(bytes: &buttonDeclineValue, count: 1))
var buttonApproveValue: UInt8 = 1 var buttonApproveValue: UInt8 = 1
@ -1332,11 +1331,11 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
ReplyMarkupMessageAttribute( ReplyMarkupMessageAttribute(
rows: [ rows: [
ReplyMarkupRow(buttons: [ ReplyMarkupRow(buttons: [
ReplyMarkupButton(title: "Decline", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonDecline)), ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionReject, 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_ActionApprove, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonApprove))
]), ]),
ReplyMarkupRow(buttons: [ 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: [], flags: [],

View File

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

View File

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

View File

@ -58,25 +58,16 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode {
} }
} }
//TODO:localize
let amountString: String let amountString: String
if let amount, amount.amount != .zero { if let amount, amount.amount != .zero {
switch amount.currency { switch amount.currency {
case .stars: case .stars:
if amount.amount.value == 1 { amountString = item.presentationData.strings.Chat_PostApproval_DetailStatus_StarsAmount(Int32((amount.amount.value == 1 && amount.amount.nanos == 0) ? 1 : 100)).replacingOccurrences(of: "#", with: "\(amount.amount)")
amountString = "1 Star"
} else {
amountString = "\(amount.amount) Stars"
}
case .ton: case .ton:
if amount.amount.value == 1 { 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))")
amountString = "1 TON"
} else {
amountString = "\(formatTonAmountText(amount.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat)) TON"
}
} }
} else { } else {
amountString = "Free" amountString = item.presentationData.strings.Chat_PostSuggestion_PriceFree
} }
var timestampString: String var timestampString: String
@ -86,12 +77,11 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode {
timestampString = String(timestampString[timestampString.startIndex]).capitalized + timestampString[timestampString.index(after: timestampString.startIndex)...] timestampString = String(timestampString[timestampString.startIndex]).capitalized + timestampString[timestampString.index(after: timestampString.startIndex)...]
} }
} else { } else {
timestampString = "Anytime" timestampString = item.presentationData.strings.Chat_PostSuggestion_TimeAny
} }
let serviceColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper) let serviceColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper)
//TODO:localize
let titleText: String let titleText: String
if let attribute = item.message.attributes.first(where: { $0 is ReplyMessageAttribute }) as? ReplyMessageAttribute { if let attribute = item.message.attributes.first(where: { $0 is ReplyMessageAttribute }) as? ReplyMessageAttribute {
var changedText = false var changedText = false
@ -131,19 +121,19 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode {
if !item.message.effectivelyIncoming(item.context.account.peerId) { if !item.message.effectivelyIncoming(item.context.account.peerId) {
if changedText && changedMedia && changedPrice && changedTime { 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 { } 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 { } 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 { } 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 { } else if changedPrice {
titleText = "You suggest a new price\nfor this message." titleText = item.presentationData.strings.Chat_PostSuggestion_UserChangeP
} else if changedTime { } else if changedTime {
titleText = "You suggest a new time\nfor this message." titleText = item.presentationData.strings.Chat_PostSuggestion_UserChangeT
} else { } else {
titleText = "You suggest changes\nfor this message." titleText = item.presentationData.strings.Chat_PostSuggestion_UserChange
} }
} else { } else {
var channelName = "" var channelName = ""
@ -151,26 +141,26 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode {
channelName = item.message.author.flatMap(EnginePeer.init)?.compactDisplayTitle ?? " " channelName = item.message.author.flatMap(EnginePeer.init)?.compactDisplayTitle ?? " "
} }
if changedText && changedMedia && changedPrice && changedTime { 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 { } 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 { } 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 { } 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 { } else if changedPrice {
titleText = "**\(channelName)** suggests a new price\nfor this message." titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChangeP(channelName).string
} else if changedTime { } else if changedTime {
titleText = "**\(channelName)** suggests a new time\nfor this message." titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChangeT(channelName).string
} else { } else {
titleText = "**\(channelName)** suggests changes\nfor this message." titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChange(channelName).string
} }
} }
} else { } else {
if !item.message.effectivelyIncoming(item.context.account.peerId) { if !item.message.effectivelyIncoming(item.context.account.peerId) {
titleText = "You suggest to post\nthis message." titleText = item.presentationData.strings.Chat_PostSuggestion_UserPost
} else { } 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 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 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: "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 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 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())) 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 { final class HeaderContextReferenceContentSource: ContextReferenceContentSource {
private let controller: ViewController private let controller: ViewController
private let sourceView: UIView private let sourceView: UIView

View File

@ -1968,8 +1968,7 @@ public final class ChatSideTopicsPanel: Component {
).get() ).get()
if let threadInfo, threadInfo.isMessageFeeRemoved { if let threadInfo, threadInfo.isMessageFeeRemoved {
//TODO:localize 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
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
guard let self, let component = self.component else { guard let self, let component = self.component else {
return return
} }

View File

@ -226,12 +226,11 @@ public final class SuggestPostAccessoryPanelNode: AccessoryPanelNode {
} }
} }
//TODO:localize
var titleText: [CompositeTextNode.Component] = [] var titleText: [CompositeTextNode.Component] = []
if let postSuggestionState = interfaceState.interfaceState.postSuggestionState, postSuggestionState.editingOriginalMessageId != nil { 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 { } 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 self.titleNode.components = titleText
@ -269,10 +268,10 @@ public final class SuggestPostAccessoryPanelNode: AccessoryPanelNode {
)).string )).string
textString = NSAttributedString(string: "\(currencySymbol)\(amountString) 📅 \(timeString)", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor) textString = NSAttributedString(string: "\(currencySymbol)\(amountString) 📅 \(timeString)", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor)
} else { } 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 { } 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) let mutableTextString = NSMutableAttributedString(attributedString: textString)

View File

@ -112,16 +112,13 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
title = self.presentationData.strings.Conversation_SetReminder_Title title = self.presentationData.strings.Conversation_SetReminder_Title
case let .suggestPost(needsTime, isAdmin, funds): case let .suggestPost(needsTime, isAdmin, funds):
if needsTime { if needsTime {
//TODO:localize title = self.presentationData.strings.Chat_PostSuggestion_ApproveTime_Title
title = "Accept Terms" text = self.presentationData.strings.Chat_PostSuggestion_ApproveTime_Text
text = "Set the date and time you want\nthis message to be published."
} else { } else {
//TODO:localize title = self.presentationData.strings.Chat_PostSuggestion_SetTime_Title
title = "Time" text = self.presentationData.strings.Chat_PostSuggestion_SetTime_Text
text = "Set the date and time you want\nyour message to be published."
} }
//TODO:localize
if let funds, isAdmin { if let funds, isAdmin {
var commissionValue: String var commissionValue: String
commissionValue = "\(Double(funds.commissionPermille) * 0.1)" commissionValue = "\(Double(funds.commissionPermille) * 0.1)"
@ -134,10 +131,10 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
switch funds.amount.currency { switch funds.amount.currency {
case .stars: case .stars:
let displayAmount = funds.amount.amount.totalValue * Double(funds.commissionPermille) / 1000.0 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: case .ton:
let displayAmount = Double(funds.amount.amount.value) / 1000000000.0 * Double(funds.commissionPermille) / 1000.0 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) self.onlineButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(backgroundColor: buttonColor, foregroundColor: buttonTextColor), font: .regular, height: 52.0, cornerRadius: 11.0, gloss: false)
switch mode { switch mode {
case let .suggestPost(needsTime, _, _): case let .suggestPost(needsTime, _, _):
//TODO:localize
if needsTime { if needsTime {
self.onlineButton.title = "Post Now" self.onlineButton.title = self.presentationData.strings.Chat_PostSuggestion_ApproveTime_NoTimeAction
} else { } else {
self.onlineButton.title = "Send Anytime" self.onlineButton.title = self.presentationData.strings.Chat_PostSuggestion_SetTime_NoTimeAction
} }
default: default:
self.onlineButton.title = self.presentationData.strings.Conversation_ScheduleMessage_SendWhenOnline 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 body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white) let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
//TODO:localize
let playOnce = ActionSlot<Void>() let playOnce = ActionSlot<Void>()
let toastSize = toast.update( let toastSize = toast.update(
transition: ComponentTransition(transition), transition: ComponentTransition(transition),
@ -602,7 +597,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
)), )),
content: AnyComponent(VStack([ content: AnyComponent(VStack([
AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent( 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 maximumNumberOfLines: 0
))) )))
], alignment: .left, spacing: 6.0)), ], alignment: .left, spacing: 6.0)),

View File

@ -128,7 +128,7 @@ private final class BalanceNeededSheetContentComponent: Component {
let titleSize = self.title.update( let titleSize = self.title.update(
transition: transition, transition: transition,
component: AnyComponent(MultilineTextComponent( 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, horizontalAlignment: .center,
maximumNumberOfLines: 0 maximumNumberOfLines: 0
)), )),
@ -144,11 +144,10 @@ private final class BalanceNeededSheetContentComponent: Component {
contentHeight += titleSize.height contentHeight += titleSize.height
contentHeight += 14.0 contentHeight += 14.0
//TODO:localize
let textSize = self.text.update( let textSize = self.text.update(
transition: transition, transition: transition,
component: AnyComponent(BalancedTextComponent( 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, horizontalAlignment: .center,
maximumNumberOfLines: 0, maximumNumberOfLines: 0,
lineSpacing: 0.18 lineSpacing: 0.18
@ -165,7 +164,6 @@ private final class BalanceNeededSheetContentComponent: Component {
contentHeight += textSize.height contentHeight += textSize.height
contentHeight += 24.0 contentHeight += 24.0
//TODO:localize
let buttonSize = self.button.update( let buttonSize = self.button.update(
transition: transition, transition: transition,
component: AnyComponent(ButtonComponent( component: AnyComponent(ButtonComponent(
@ -175,7 +173,7 @@ private final class BalanceNeededSheetContentComponent: Component {
pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8) pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8)
), ),
content: AnyComponentWithIdentity(id: AnyHashable(0 as Int), component: AnyComponent(MultilineTextComponent( 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, isEnabled: true,
allowActionWhenDisabled: true, allowActionWhenDisabled: true,

View File

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

View File

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

View File

@ -1816,23 +1816,22 @@ extension ChatControllerImpl {
guard let self else { guard let self else {
return return
} }
//TODO:localize
let titleString: String let titleString: String
let textString: String let textString: String
switch attribute.currency { switch attribute.currency {
case .stars: case .stars:
titleString = "Stars Will Be Lost" titleString = self.presentationData.strings.Chat_DeletePaidMessageStars_Title
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." textString = self.presentationData.strings.Chat_DeletePaidMessageStars_Text
case .ton: case .ton:
titleString = "TON Will Be Lost" titleString = self.presentationData.strings.Chat_DeletePaidMessageTon_Title
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." textString = self.presentationData.strings.Chat_DeletePaidMessageTon_Text
} }
self.present(standardTextAlertController( self.present(standardTextAlertController(
theme: AlertControllerTheme(presentationData: self.presentationData), theme: AlertControllerTheme(presentationData: self.presentationData),
title: titleString, title: titleString,
text: textString, text: textString,
actions: [ 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 { guard let self else {
return return
} }

View File

@ -2352,8 +2352,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if message.effectivelyIncoming(strongSelf.context.account.peerId) { if message.effectivelyIncoming(strongSelf.context.account.peerId) {
switch buttonType { switch buttonType {
case 0: case 0:
//TODO:localize 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
let promptController = promptController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: strongSelf.updatedPresentationData, text: "Comment", titleFont: .bold, value: "", placeholder: "Optional", characterLimit: 4096, apply: { value in
guard let self else { guard let self else {
return return
} }
@ -2393,10 +2392,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
timestamp = Int32(Date().timeIntervalSince1970) + 1 * 60 * 60 timestamp = Int32(Date().timeIntervalSince1970) + 1 * 60 * 60
} else { } else {
//TODO:localize
var textString: String var textString: String
if isAdmin { 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 { if let funds {
var commissionValue: String var commissionValue: String
@ -2412,25 +2410,25 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
switch funds.amount.currency { switch funds.amount.currency {
case .stars: case .stars:
let displayAmount = funds.amount.amount.totalValue * Double(funds.commissionPermille) / 1000.0 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: case .ton:
let displayAmount = Double(funds.amount.amount.value) / 1000000000.0 * Double(funds.commissionPermille) / 1000.0 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 { } 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: [ strongSelf.present(SuggestedPostApproveAlert(presentationData: strongSelf.presentationData, title: strongSelf.presentationData.strings.Chat_PostSuggestion_Approve_Title, text: textString, actions: [
TextAlertAction(type: .defaultAction, title: "Publish", action: { [weak strongSelf] in TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Chat_PostSuggestion_Approve_Action, action: { [weak strongSelf] in
guard let strongSelf else { guard let strongSelf else {
return return
} }
let _ = strongSelf.context.engine.messages.monoforumPerformSuggestedPostAction(id: message.id, action: .approve(timestamp: timestamp)).startStandalone() let _ = strongSelf.context.engine.messages.monoforumPerformSuggestedPostAction(id: message.id, action: .approve(timestamp: timestamp)).startStandalone()
}), }),
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}) 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: case 2:
strongSelf.interfaceInteraction?.openSuggestPost(message, .default) strongSelf.interfaceInteraction?.openSuggestPost(message, .default)

View File

@ -394,23 +394,22 @@ extension ChatControllerImpl {
guard let self else { guard let self else {
return return
} }
//TODO:localize
let titleString: String let titleString: String
let textString: String let textString: String
switch attribute.currency { switch attribute.currency {
case .stars: case .stars:
titleString = "Stars Will Be Lost" titleString = self.presentationData.strings.Chat_DeletePaidMessageStars_Title
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." textString = self.presentationData.strings.Chat_DeletePaidMessageStars_Text
case .ton: case .ton:
titleString = "TON Will Be Lost" titleString = self.presentationData.strings.Chat_DeletePaidMessageTon_Title
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." textString = self.presentationData.strings.Chat_DeletePaidMessageTon_Text
} }
self.present(standardTextAlertController( self.present(standardTextAlertController(
theme: AlertControllerTheme(presentationData: self.presentationData), theme: AlertControllerTheme(presentationData: self.presentationData),
title: titleString, title: titleString,
text: textString, text: textString,
actions: [ 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 { guard let self else {
return return
} }

View File

@ -1520,23 +1520,22 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
} }
if canSuggestPost { if canSuggestPost {
//TODO:localize
if message.attributes.contains(where: { $0 is SuggestedPostMessageAttribute }) { 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) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.actionSheet.primaryTextColor)
}, action: { c, _ in }, action: { c, _ in
c?.dismiss(completion: { c?.dismiss(completion: {
interfaceInteraction.openSuggestPost(message, .editMessage) 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) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Calendar"), color: theme.actionSheet.primaryTextColor)
}, action: { c, _ in }, action: { c, _ in
c?.dismiss(completion: { c?.dismiss(completion: {
interfaceInteraction.openSuggestPost(message, .editTime) 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) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/PriceTag"), color: theme.actionSheet.primaryTextColor)
}, action: { c, _ in }, action: { c, _ in
c?.dismiss(completion: { c?.dismiss(completion: {
@ -1544,7 +1543,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
}) })
}))) })))
} else { } 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) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Customize"), color: theme.actionSheet.primaryTextColor)
}, action: { c, _ in }, action: { c, _ in
c?.dismiss(completion: { 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()) return (PresentationResourcesChat.chatInputTextFieldSilentPostOffImage(theme), nil, strings.VoiceOver_SilentPostOff, 1.0, UIEdgeInsets())
} }
case .suggestPost: case .suggestPost:
//TODO:localize return (PresentationResourcesChat.chatInputTextFieldSuggestPostImage(theme), nil, strings.VoiceOver_SuggestPost, 1.0, UIEdgeInsets())
return (PresentationResourcesChat.chatInputTextFieldSuggestPostImage(theme), nil, "Suggest post", 1.0, UIEdgeInsets())
case let .messageAutoremoveTimeout(timeout): case let .messageAutoremoveTimeout(timeout):
if let timeout = timeout { if let timeout = timeout {
return (nil, shortTimeIntervalString(strings: strings, value: timeout), strings.VoiceOver_SelfDestructTimerOn(timeIntervalString(strings: strings, value: timeout)).string, 1.0, UIEdgeInsets()) return (nil, shortTimeIntervalString(strings: strings, value: timeout), strings.VoiceOver_SelfDestructTimerOn(timeIntervalString(strings: strings, value: timeout)).string, 1.0, UIEdgeInsets())