diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 6ff2b8241a..0a83151415 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -14507,6 +14507,154 @@ Sorry for the inconvenience."; "Attachment.DiscardTodoAlertText" = "Discard checklist items?"; +"Auth.PremiumSignUp.ActionTitle" = "Sign up for %@"; +"Auth.PremiumSignUp.ActionSubtitle" = "Get Telegram Premium for 1 week"; + +"Chat.PostApproval.Status.AdminApproved" = "The message was approved"; +"Chat.PostApproval.Status.AdminRejected" = "The message was rejected"; +"Chat.PostApproval.Status.UserApproved" = "Your message was approved"; +"Chat.PostApproval.Status.UserRejected" = "Your message was rejected"; + +"Chat.PostApproval.DetailStatus.StarsAmount_1" = "# Star"; +"Chat.PostApproval.DetailStatus.StarsAmount_any" = "# Stars"; +"Chat.PostApproval.DetailStatus.TonAmount_1" = "# TON"; +"Chat.PostApproval.DetailStatus.TonAmount_any" = "# TON"; + +"Chat.PostApproval.DetailStatus.PostedPaid" = "**%1$@** received **%2$@** for publishing this post"; +"Chat.PostApproval.DetailStatus.UserFailedRefunded" = "Suggested post was refunded because you didn't have enough funds"; +"Chat.PostApproval.DetailStatus.AdminFailedRefunded" = "Suggested post was refunded because the user didn't have enough funds"; +"Chat.PostApproval.DetailStatus.FailedDeleted" = "Suggested post was refunded because the message was deleted"; + +"Chat.PostApproval.Message.UserAgreementPast" = "šŸ“… The post has been automatically published in **%1$@** **%2$@**."; +"Chat.PostApproval.Message.AdminAgreementPast" = "šŸ“… Your post has been automatically published in **%1$@** **%2$@**."; +"Chat.PostApproval.Message.UserAgreementFuture" = "šŸ“… The post will be automatically published in **%1$@** **%2$@**."; +"Chat.PostApproval.Message.AdminAgreementFuture" = "šŸ“… Your post will be automatically published in **%1$@** **%2$@**."; +"Chat.PostApproval.Message.UserAgreementNoTime" = "šŸ“… The post has been automatically published in **%1$@**."; +"Chat.PostApproval.Message.AdminAgreementNoTime" = "šŸ“… Your post has been automatically published in **%1$@**."; + +"Chat.PostApproval.Message.TitleApproved" = "šŸ¤ Agreement Reached!"; +"Chat.PostApproval.Message.AdminTitleRejected" = "āŒ You rejected the message."; +"Chat.PostApproval.Message.AdminTitleRejectedComment" = "āŒ You rejected the message with the comment:"; +"Chat.PostApproval.Message.AdminTitleFailedFunds" = "āš ļø **Transaction failed** because the user didn't have enough Stars."; +"Chat.PostApproval.Message.UserTitleRejected" = "āŒ **%@** rejected your message."; +"Chat.PostApproval.Message.UserTitleRejectedComment" = "āŒ **%@** rejected your message with the comment:"; +"Chat.PostApproval.Message.UserTitleFailedFunds" = "āš ļø **Transaction failed** because you didn't have enough Stars."; +"Chat.PostApproval.Message.BuyStars" = "Buy Stars"; + +"Chat.PostApproval.Message.UserAgreementPriceStars" = "šŸ’° You have been charged %1$@.\n\nāŒ› **%2$@** will receive the Stars once the post has been live for 24 hours.\n\nšŸ”„ If admins remove the post before it has been live for 24 hours, the your Stars will be refunded."; +"Chat.PostApproval.Message.UserAgreementPriceTon" = "šŸ’° You have been charged %1$@.\n\nāŒ› **%2$@** will receive the TON once the post has been live for 24 hours.\n\nšŸ”„ If admins the post before it has been live for 24 hours, your TON will be refunded."; +"Chat.PostApproval.Message.AdminAgreementPriceStars" = "šŸ’° The user have been charged %1$@.\n\nāŒ› **%2$@** will receive the Stars once the post has been live for 24 hours.\n\nšŸ”„ If you remove the post before it has been live for 24 hours, the user's Stars will be refunded."; +"Chat.PostApproval.Message.AdminAgreementPriceTon" = "šŸ’° The user have been charged %1$@.\n\nāŒ› **%2$@** will receive the TON once the post has been live for 24 hours.\n\nšŸ”„ If you remove the post before it has been live for 24 hours, the user's TON will be refunded."; +"Chat.PostApproval.Message.AdminDeclined" = "You declined the post."; +"Chat.PostApproval.Message.AdminDeclinedComment" = "You declined the post with the following comment:\n\n%@"; + +"Chat.PostApproval.Message.ActionApprove" = "Approve"; +"Chat.PostApproval.Message.ActionReject" = "Decline"; +"Chat.PostApproval.Message.ActionSuggestChanges" = "Suggest Changes"; + +"Chat.ReinstatePaidMessages" = "Charge Message Fee"; + +"Chat.PostSuggestion.TablePrice" = "Price"; +"Chat.PostSuggestion.TableTime" = "Time"; + +"Chat.PostSuggestion.PriceFree" = "Free"; +"Chat.PostSuggestion.TimeAny" = "Anytime"; + +"Chat.PostSuggestion.UserChangePTC" = "You suggest a new price,\ntime and contents for this message."; +"Chat.PostSuggestion.UserChangePTT" = "You suggest a new price,\ntime and text for this message."; +"Chat.PostSuggestion.UserChangePTA" = "You suggest a new price,\ntime and attachments for this message."; +"Chat.PostSuggestion.UserChangePT" = "You suggest a new price and time\nfor this message."; +"Chat.PostSuggestion.UserChangeP" = "You suggest a new price\nfor this message."; +"Chat.PostSuggestion.UserChangeT" = "You suggest a new time\nfor this message."; +"Chat.PostSuggestion.UserChange" = "You suggest changes\nfor this message."; + +"Chat.PostSuggestion.ChannelChangePTC" = "**%@** suggests a new price,\ntime and contents for this message."; +"Chat.PostSuggestion.ChannelChangePTT" = "**%@** suggests a new price,\ntime and text for this message."; +"Chat.PostSuggestion.ChannelChangePTA" = "**%@** suggests a new price,\ntime and attachments for this message."; +"Chat.PostSuggestion.ChannelChangePT" = "**%@** suggests a new price and time\nfor this message."; +"Chat.PostSuggestion.ChannelChangeP" = "**%@** suggests a new price\nfor this message."; +"Chat.PostSuggestion.ChannelChangeT" = "**%@** suggests a new time\nfor this message."; +"Chat.PostSuggestion.ChannelChange" = "**%@** suggests changes\nfor this message."; + +"Chat.PostSuggestion.UserPost" = "You suggest to post\nthis message."; +"Chat.PostSuggestion.ChannelPost" = "**%@** suggests to post\nthis message."; + +"Chat.PostSuggestion.Suggest.InputTitle" = "Suggest a post below"; +"Chat.PostSuggestion.Suggest.InputEditTitle" = "Suggest Changes"; +"Chat.PostSuggestion.Suggest.InputSubtitleEmpty" = "Tap to offer a price for publishing"; +"Chat.PostSuggestion.Suggest.InputSubtitleAnytime" = "%@ for publishing anytime"; + +"BalanceNeeded.FragmentTitle" = "%@ TON Needed"; +"BalanceNeeded.FragmentSubtitle" = "You can add funds to your balance via the third-party platform Fragment."; +"BalanceNeeded.FragmentAction" = "Add Funds via Fragment"; + +"Settings.MyTon" = "My TON"; +"Settings.Ton.Description" = "Use TON to submit post suggestions to channels on Telegram."; + +"Settings.TransactionsTon.Title" = "TON"; +"Settings.TransactionsTon.Subtitle" = "Use TON to submit post suggestions to channels on Telegram."; + +"Chat.DeletePaidMessageStars.Title" = "Stars Will Be Lost"; +"Chat.DeletePaidMessageStars.Text" = "You won't receive **Stars** for this post if you delete it now. The post must remain visible for at least **24 hours** after publication."; +"Chat.DeletePaidMessageTon.Title" = "TON Will Be Lost"; +"Chat.DeletePaidMessageTon.Text" = "You won't receive **TON** for this post if you delete it now. The post must remain visible for at least **24 hours** after publication."; +"Chat.DeletePaidMessage.Action" = "Delete Anyway"; + +"Chat.PostSuggestion.Reject.Title" = "Comment"; +"Chat.PostSuggestion.Reject.Placeholder" = "Optional"; + +"Chat.PostSuggestion.Approve.AdminConfirmationText" = "Do you really want to publish this post from **%@**?"; +"Chat.PostSuggestion.Approve.AdminConfirmationPriceStars" = "You will receive %1$@ Stars (%2$@%)\nfor publishing this post. It must remain visible for **24** hours after publication."; +"Chat.PostSuggestion.Approve.AdminConfirmationPriceTon" = "You will receive %1$@ TON (%2$@%)\nfor publishing this post. It must remain visible for **24** hours after publication."; + +"Chat.PostSuggestion.Approve.UserConfirmationText" = "Do you really want to publish this post?"; + +"Chat.PostSuggestion.Approve.Title" = "Accept Terms"; +"Chat.PostSuggestion.Approve.Action" = "Publish"; + +"Chat.PostSuggestion.ApproveTime.Title" = "Accept Terms"; +"Chat.PostSuggestion.ApproveTime.Text" = "Set the date and time you want\nthis message to be published."; +"Chat.PostSuggestion.ApproveTime.NoTimeAction" = "Post Now"; +"Chat.PostSuggestion.SetTime.Title" = "Time"; +"Chat.PostSuggestion.SetTime.Text" = "Set the date and time you want\nyour message to be published."; +"Chat.PostSuggestion.SetTime.NoTimeAction" = "Send Anytime"; + +"Chat.PostSuggestion.ApproveTime.AdminConfirmationPriceStars" = "You will receive %1$@ Stars (%2$@%)\nfor publishing this post."; +"Chat.PostSuggestion.ApproveTime.AdminConfirmationPriceTon" = "You will receive %1$@ TON (%2$@%)\nfor publishing this post."; + +"Chat.PostSuggestion.StarsDisclaimer" = "Transactions in **Stars** may be reversed by the payment provider within **21** days. Only accept Stars from people you trust."; + +"VoiceOver.SuggestPost" = "Suggest Post"; + +"Chat.ContextMenu.SuggestedPost.EditMessage" = "Edit Message"; +"Chat.ContextMenu.SuggestedPost.EditPrice" = "Edit Prive"; +"Chat.ContextMenu.SuggestedPost.EditTime" = "Edit Time"; +"Chat.ContextMenu.SuggestedPost.Create" = "Suggest Post"; + +"Chat.PostSuggestion.Suggest.TitleCreate" = "Suggest Terms"; +"Chat.PostSuggestion.Suggest.TitleEdit" = "Suggest Changes"; +"Chat.PostSuggestion.Suggest.PriceSectionStars" = "ENTER A PRICE IN STARS"; +"Chat.PostSuggestion.Suggest.PriceSectionTon" = "ENTER A PRICE IN TON"; +"Chat.PostSuggestion.Suggest.PricePlaceholder" = "Price"; +"Chat.PostSuggestion.Suggest.OfferStars" = "Offer Stars"; +"Chat.PostSuggestion.Suggest.OfferTon" = "Offer TON"; +"Chat.PostSuggestion.Suggest.RequestStars" = "Request Stars"; +"Chat.PostSuggestion.Suggest.RequestTon" = "Request TON"; +"Chat.PostSuggestion.Suggest.RequestDescriptionStars" = "Choose how many Stars you charge for the message."; +"Chat.PostSuggestion.Suggest.RequestDescriptionTon" = "Choose how many TON you charge for the message."; +"Chat.PostSuggestion.Suggest.OfferDescriptionStars" = "Choose how many Stars you want to offer %@ to publish this message."; +"Chat.PostSuggestion.Suggest.OfferDescriptionTon" = "Choose how many TON you want to offer %@ to publish this message."; +"Chat.PostSuggestion.Suggest.OfferDateDescription" = "Select the date and time you want your message to be published."; +"Chat.PostSuggestion.Suggest.EditDateDescription" = "Select the date and time you want to publish the message."; +"Chat.PostSuggestion.Suggest.OfferButtonPrice" = "Offer %@"; +"Chat.PostSuggestion.Suggest.OfferButtonFree" = "Offer for Free"; +"Chat.PostSuggestion.Suggest.UpdateButton" = "Update Terms"; + +"Chat.PostSuggestion.Suggest.AdminMinAmountStars.Text" = "You cannot request less than %@ Stars."; +"Chat.PostSuggestion.Suggest.UserMinAmountStars.Text" = "You cannot offer less than %@ Stars."; + +"Stars.SellGiftMinAmountToast.Text" = "You cannot sell gift for less than %@"; + "Premium.Week.SignUp" = "Sign up for %@"; "Premium.Week.SignUpInfo" = "Get Telegram Premium for 1 week"; diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 627bd470a1..980686598f 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -484,6 +484,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1645763991] = { return Api.InputStickerSet.parse_inputStickerSetID($0) } dict[-930399486] = { return Api.InputStickerSet.parse_inputStickerSetPremiumGifts($0) } dict[-2044933984] = { return Api.InputStickerSet.parse_inputStickerSetShortName($0) } + dict[485912992] = { return Api.InputStickerSet.parse_inputStickerSetTonGifts($0) } dict[853188252] = { return Api.InputStickerSetItem.parse_inputStickerSetItem($0) } dict[70813275] = { return Api.InputStickeredMedia.parse_inputStickeredMediaDocument($0) } dict[1251549527] = { return Api.InputStickeredMedia.parse_inputStickeredMediaPhoto($0) } @@ -1096,6 +1097,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1398708869] = { return Api.Update.parse_updateMessagePoll($0) } dict[619974263] = { return Api.Update.parse_updateMessagePollVote($0) } dict[506035194] = { return Api.Update.parse_updateMessageReactions($0) } + dict[-1618924792] = { return Api.Update.parse_updateMonoForumNoPaidException($0) } dict[-2030252155] = { return Api.Update.parse_updateMoveStickerSetToTop($0) } dict[-1991136273] = { return Api.Update.parse_updateNewAuthorization($0) } dict[1656358105] = { return Api.Update.parse_updateNewChannelMessage($0) } diff --git a/submodules/TelegramApi/Sources/Api12.swift b/submodules/TelegramApi/Sources/Api12.swift index 967020d8d7..69e3247e6c 100644 --- a/submodules/TelegramApi/Sources/Api12.swift +++ b/submodules/TelegramApi/Sources/Api12.swift @@ -755,6 +755,7 @@ public extension Api { case inputStickerSetID(id: Int64, accessHash: Int64) case inputStickerSetPremiumGifts case inputStickerSetShortName(shortName: String) + case inputStickerSetTonGifts public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -824,6 +825,12 @@ public extension Api { buffer.appendInt32(-2044933984) } serializeString(shortName, buffer: buffer, boxed: false) + break + case .inputStickerSetTonGifts: + if boxed { + buffer.appendInt32(485912992) + } + break } } @@ -852,6 +859,8 @@ public extension Api { return ("inputStickerSetPremiumGifts", []) case .inputStickerSetShortName(let shortName): return ("inputStickerSetShortName", [("shortName", shortName as Any)]) + case .inputStickerSetTonGifts: + return ("inputStickerSetTonGifts", []) } } @@ -915,6 +924,9 @@ public extension Api { return nil } } + public static func parse_inputStickerSetTonGifts(_ reader: BufferReader) -> InputStickerSet? { + return Api.InputStickerSet.inputStickerSetTonGifts + } } } diff --git a/submodules/TelegramApi/Sources/Api27.swift b/submodules/TelegramApi/Sources/Api27.swift index 0265253957..372c196121 100644 --- a/submodules/TelegramApi/Sources/Api27.swift +++ b/submodules/TelegramApi/Sources/Api27.swift @@ -129,6 +129,7 @@ public extension Api { case updateMessagePoll(flags: Int32, pollId: Int64, poll: Api.Poll?, results: Api.PollResults) case updateMessagePollVote(pollId: Int64, peer: Api.Peer, options: [Buffer], qts: Int32) case updateMessageReactions(flags: Int32, peer: Api.Peer, msgId: Int32, topMsgId: Int32?, savedPeerId: Api.Peer?, reactions: Api.MessageReactions) + case updateMonoForumNoPaidException(flags: Int32, channelId: Int64, savedPeerId: Api.Peer) case updateMoveStickerSetToTop(flags: Int32, stickerset: Int64) case updateNewAuthorization(flags: Int32, hash: Int64, date: Int32?, device: String?, location: String?) case updateNewChannelMessage(message: Api.Message, pts: Int32, ptsCount: Int32) @@ -920,6 +921,14 @@ public extension Api { if Int(flags) & Int(1 << 1) != 0 {savedPeerId!.serialize(buffer, true)} reactions.serialize(buffer, true) break + case .updateMonoForumNoPaidException(let flags, let channelId, let savedPeerId): + if boxed { + buffer.appendInt32(-1618924792) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(channelId, buffer: buffer, boxed: false) + savedPeerId.serialize(buffer, true) + break case .updateMoveStickerSetToTop(let flags, let stickerset): if boxed { buffer.appendInt32(-2030252155) @@ -1619,6 +1628,8 @@ public extension Api { return ("updateMessagePollVote", [("pollId", pollId as Any), ("peer", peer as Any), ("options", options as Any), ("qts", qts as Any)]) case .updateMessageReactions(let flags, let peer, let msgId, let topMsgId, let savedPeerId, let reactions): return ("updateMessageReactions", [("flags", flags as Any), ("peer", peer as Any), ("msgId", msgId as Any), ("topMsgId", topMsgId as Any), ("savedPeerId", savedPeerId as Any), ("reactions", reactions as Any)]) + case .updateMonoForumNoPaidException(let flags, let channelId, let savedPeerId): + return ("updateMonoForumNoPaidException", [("flags", flags as Any), ("channelId", channelId as Any), ("savedPeerId", savedPeerId as Any)]) case .updateMoveStickerSetToTop(let flags, let stickerset): return ("updateMoveStickerSetToTop", [("flags", flags as Any), ("stickerset", stickerset as Any)]) case .updateNewAuthorization(let flags, let hash, let date, let device, let location): @@ -3272,6 +3283,25 @@ public extension Api { return nil } } + public static func parse_updateMonoForumNoPaidException(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Api.Peer? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.Peer + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateMonoForumNoPaidException(flags: _1!, channelId: _2!, savedPeerId: _3!) + } + else { + return nil + } + } public static func parse_updateMoveStickerSetToTop(_ reader: BufferReader) -> Update? { var _1: Int32? _1 = reader.readInt32() diff --git a/submodules/TelegramCore/FlatSerialization/Models/StickerPackReference.fbs b/submodules/TelegramCore/FlatSerialization/Models/StickerPackReference.fbs index 5b38b086c9..a233490bd3 100644 --- a/submodules/TelegramCore/FlatSerialization/Models/StickerPackReference.fbs +++ b/submodules/TelegramCore/FlatSerialization/Models/StickerPackReference.fbs @@ -34,6 +34,9 @@ table StickerPackReference_IconTopicEmoji { table StickerPackReference_IconChannelStatusEmoji { } +table StickerPackReference_TonGifts { +} + union StickerPackReference_Value { StickerPackReference_Id, StickerPackReference_Name, @@ -44,7 +47,8 @@ union StickerPackReference_Value { StickerPackReference_EmojiGenericAnimations, StickerPackReference_IconStatusEmoji, StickerPackReference_IconTopicEmoji, - StickerPackReference_IconChannelStatusEmoji + StickerPackReference_IconChannelStatusEmoji, + StickerPackReference_TonGifts } table StickerPackReference { diff --git a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift index de69062dd6..209de31fba 100644 --- a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift +++ b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift @@ -133,6 +133,7 @@ enum AccountStateMutationOperation { case UpdateStarsRevenueStatus(peerId: PeerId, status: StarsRevenueStats.Balances) case UpdateStarsReactionsDefaultPrivacy(privacy: TelegramPaidReactionPrivacy) case ReportMessageDelivery([MessageId]) + case UpdateMonoForumNoPaidException(peerId: PeerId, threadId: Int64, isFree: Bool) } struct HoleFromPreviousState { @@ -707,9 +708,13 @@ struct AccountMutableState { self.addOperation(.ReportMessageDelivery(messageIds)) } + mutating func updateMonoForumNoPaidException(peerId: PeerId, threadId: Int64, isFree: Bool) { + self.addOperation(.UpdateMonoForumNoPaidException(peerId: peerId, threadId: threadId, isFree: isFree)) + } + mutating func addOperation(_ operation: AccountStateMutationOperation) { switch operation { - case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery, .UpdateMonoForumNoPaidException: break case let .AddMessages(messages, location): for message in messages { diff --git a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift index 070586f06c..ec98866a8a 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift @@ -1081,6 +1081,26 @@ extension StoreMessage { var threadId: Int64? if let savedPeerId { threadId = savedPeerId.peerId.toInt64() + + if chatPeerId.peerId.namespace == Namespaces.Peer.CloudChannel, let replyTo { + switch replyTo { + case let .messageReplyHeader(innerFlags, replyToMsgId, replyToPeerId, replyHeader, replyMedia, _, quoteText, quoteEntities, quoteOffset): + var quote: EngineMessageReplyQuote? + let isQuote = (innerFlags & (1 << 9)) != 0 + if quoteText != nil || replyMedia != nil { + quote = EngineMessageReplyQuote(text: quoteText ?? "", offset: quoteOffset.flatMap(Int.init), entities: messageTextEntitiesFromApiEntities(quoteEntities ?? []), media: textMediaAndExpirationTimerFromApiMedia(replyMedia, peerId).media) + } + + if let replyToMsgId = replyToMsgId { + let replyPeerId = replyToPeerId?.peerId ?? peerId + attributes.append(ReplyMessageAttribute(messageId: MessageId(peerId: replyPeerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId), threadMessageId: nil, quote: quote, isQuote: isQuote)) + } else if let replyHeader = replyHeader { + attributes.append(QuotedReplyMessageAttribute(apiHeader: replyHeader, quote: quote, isQuote: isQuote)) + } + case let .messageReplyStoryHeader(peer, storyId): + attributes.append(ReplyStoryAttribute(storyId: StoryId(peerId: peer.peerId, id: storyId))) + } + } } else if let replyTo = replyTo { var threadMessageId: MessageId? switch replyTo { diff --git a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift index 92beb9f3ff..965b629843 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift @@ -71,6 +71,8 @@ extension StickerPackReference { self = .iconChannelStatusEmoji case .inputStickerSetEmojiDefaultTopicIcons: self = .iconTopicEmoji + case .inputStickerSetTonGifts: + self = .tonGifts } } } diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index 838710b792..6cf06bcb67 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -1870,6 +1870,8 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox: mappedPrivacy = .peer(peerId) } updatedState.updateStarsReactionsDefaultPrivacy(privacy: mappedPrivacy) + case let .updateMonoForumNoPaidException(flags, channelId, savedPeerId): + updatedState.updateMonoForumNoPaidException(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), threadId: savedPeerId.peerId.toInt64(), isFree: (flags & (1 << 0)) != 0) default: break } @@ -3580,7 +3582,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation]) var currentAddQuickReplyMessages: OptimizeAddMessagesState? for operation in operations { switch operation { - case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery, .UpdateMonoForumNoPaidException: if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty { result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location)) } @@ -5180,6 +5182,14 @@ func replayFinalState( updatedStarsReactionsDefaultPrivacy = value case let .ReportMessageDelivery(messageIds): reportMessageDelivery = Set(messageIds) + case let .UpdateMonoForumNoPaidException(peerId, threadId, isFree): + if var data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.data.get(MessageHistoryThreadData.self) { + data.isMessageFeeRemoved = isFree + + if let entry = StoredMessageHistoryThreadInfo(data) { + transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: threadId, info: entry) + } + } } } diff --git a/submodules/TelegramCore/Sources/State/SynchronizeSavedStickersOperation.swift b/submodules/TelegramCore/Sources/State/SynchronizeSavedStickersOperation.swift index e81d831848..0cb157c0e5 100644 --- a/submodules/TelegramCore/Sources/State/SynchronizeSavedStickersOperation.swift +++ b/submodules/TelegramCore/Sources/State/SynchronizeSavedStickersOperation.swift @@ -62,7 +62,7 @@ public func addSavedSticker(postbox: Postbox, network: Network, file: TelegramMe if !found { fetchReference = packReference } - case .animatedEmoji, .animatedEmojiAnimations, .dice, .premiumGifts, .emojiGenericAnimations, .iconStatusEmoji, .iconChannelStatusEmoji, .iconTopicEmoji: + case .animatedEmoji, .animatedEmojiAnimations, .dice, .premiumGifts, .emojiGenericAnimations, .iconStatusEmoji, .iconChannelStatusEmoji, .iconTopicEmoji, .tonGifts: break } if let fetchReference = fetchReference { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift index 3695c1c33c..78a7f1ddb6 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift @@ -62,6 +62,7 @@ public struct Namespaces { public static let CloudIconStatusEmoji: Int32 = 10 public static let CloudIconTopicEmoji: Int32 = 11 public static let CloudIconChannelStatusEmoji: Int32 = 12 + public static let CloudTonGifts: Int32 = 13 } public struct OrderedItemList { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift index 570dd9e687..b80a115dd0 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift @@ -26,6 +26,7 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable { case iconStatusEmoji case iconTopicEmoji case iconChannelStatusEmoji + case tonGifts public init(decoder: PostboxDecoder) { switch decoder.decodeInt32ForKey("r", orElse: 0) { @@ -43,6 +44,8 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable { self = .premiumGifts case 6: self = .iconChannelStatusEmoji + case 7: + self = .tonGifts default: self = .name("") assertionFailure() @@ -68,6 +71,8 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable { self = .premiumGifts case 6: self = .iconChannelStatusEmoji + case 7: + self = .tonGifts default: self = .name("") assertionFailure() @@ -92,6 +97,8 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable { encoder.encodeInt32(4, forKey: "r") case .premiumGifts: encoder.encodeInt32(5, forKey: "r") + case .tonGifts: + encoder.encodeInt32(6, forKey: "r") case .emojiGenericAnimations, .iconStatusEmoji, .iconTopicEmoji, .iconChannelStatusEmoji: preconditionFailure() } @@ -117,7 +124,7 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable { try container.encode(4 as Int32, forKey: "r") case .premiumGifts: try container.encode(5 as Int32, forKey: "r") - case .emojiGenericAnimations, .iconStatusEmoji, .iconTopicEmoji, .iconChannelStatusEmoji: + case .emojiGenericAnimations, .iconStatusEmoji, .iconTopicEmoji, .iconChannelStatusEmoji, .tonGifts: preconditionFailure() } } @@ -153,6 +160,8 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable { self = .iconTopicEmoji case .stickerpackreferenceIconchannelstatusemoji: self = .iconChannelStatusEmoji + case .stickerpackreferenceTongifts: + self = .tonGifts case .none_: throw FlatBuffersError.missingRequiredField() } @@ -208,6 +217,10 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable { valueType = .stickerpackreferenceIconchannelstatusemoji let start = TelegramCore_StickerPackReference_IconChannelStatusEmoji.startStickerPackReference_IconChannelStatusEmoji(&builder) offset = TelegramCore_StickerPackReference_IconChannelStatusEmoji.endStickerPackReference_IconChannelStatusEmoji(&builder, start: start) + case .tonGifts: + valueType = .stickerpackreferenceTongifts + let start = TelegramCore_StickerPackReference_TonGifts.startStickerPackReference_TonGifts(&builder) + offset = TelegramCore_StickerPackReference_TonGifts.endStickerPackReference_TonGifts(&builder, start: start) } return TelegramCore_StickerPackReference.createStickerPackReference(&builder, valueType: valueType, valueOffset: offset) } @@ -250,6 +263,12 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable { } else { return false } + case .tonGifts: + if case .tonGifts = rhs { + return true + } else { + return false + } case .emojiGenericAnimations: if case .emojiGenericAnimations = rhs { return true diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/CachedStickerPack.swift b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/CachedStickerPack.swift index 5f59f46ce1..0acd1c999b 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/CachedStickerPack.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/CachedStickerPack.swift @@ -55,6 +55,9 @@ func cacheStickerPack(transaction: Transaction, info: StickerPackCollectionInfo, case .name: namespace = info.id.namespace id = info.id.id + case .tonGifts: + namespace = Namespaces.ItemCollection.CloudTonGifts + id = 0 } if let namespace = namespace, let id = id { transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))), entry: entry) @@ -159,6 +162,20 @@ func _internal_cachedStickerPack(postbox: Postbox, network: Network, reference: } else { return (.fetching, true, nil) } + case .tonGifts: + let namespace = Namespaces.ItemCollection.CloudTonGifts + let id: ItemCollectionId.Id = 0 + if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))))?.get(CachedStickerPack.self), let info = cached.info { + previousHash = cached.hash + let current: CachedStickerPackResult = .result(info, cached.items, false) + if cached.hash != info.hash { + return (current, true, previousHash) + } else { + return (current, false, previousHash) + } + } else { + return (.fetching, true, nil) + } case .emojiGenericAnimations: let namespace = Namespaces.ItemCollection.CloudEmojiGenericAnimations let id: ItemCollectionId.Id = 0 @@ -324,6 +341,18 @@ func cachedStickerPack(transaction: Transaction, reference: StickerPackReference if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))))?.get(CachedStickerPack.self), let info = cached.info { return (info, cached.items, false) } + case .tonGifts: + let namespace = Namespaces.ItemCollection.CloudTonGifts + let id: ItemCollectionId.Id = 0 + if let currentInfo = transaction.getItemCollectionInfo(collectionId: ItemCollectionId(namespace: namespace, id: id)) as? StickerPackCollectionInfo { + let items = transaction.getItemCollectionItems(collectionId: ItemCollectionId(namespace: namespace, id: id)) + if !items.isEmpty { + return (StickerPackCollectionInfo.Accessor(currentInfo), items.compactMap { $0 as? StickerPackItem }, true) + } + } + if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))))?.get(CachedStickerPack.self), let info = cached.info { + return (info, cached.items, false) + } case .emojiGenericAnimations: let namespace = Namespaces.ItemCollection.CloudEmojiGenericAnimations let id: ItemCollectionId.Id = 0 diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/LoadedStickerPack.swift b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/LoadedStickerPack.swift index 369d5a5c7f..b4be25de9d 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/LoadedStickerPack.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/LoadedStickerPack.swift @@ -30,6 +30,8 @@ extension StickerPackReference { return .inputStickerSetEmojiChannelDefaultStatuses case .iconTopicEmoji: return .inputStickerSetEmojiDefaultTopicIcons + case .tonGifts: + return .inputStickerSetTonGifts } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerSetInstallation.swift b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerSetInstallation.swift index db64fe57ab..a806edfb7c 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerSetInstallation.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerSetInstallation.swift @@ -58,6 +58,9 @@ func _internal_requestStickerSet(postbox: Postbox, network: Network, reference: case .iconTopicEmoji: collectionId = nil input = .inputStickerSetEmojiDefaultTopicIcons + case .tonGifts: + collectionId = nil + input = .inputStickerSetTonGifts } let localSignal: (ItemCollectionId) -> Signal<(ItemCollectionInfo, [ItemCollectionItem])?, NoError> = { collectionId in diff --git a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift index b6cb987544..b74a3e2cab 100644 --- a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift @@ -1425,7 +1425,6 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: attributes) } case let .suggestedPostApprovalStatus(status): - //TODO:localize var messageText = "" for attribute in message.attributes { if let attribute = attribute as? ReplyMessageAttribute, let message = message.associatedMessages[attribute.messageId] { @@ -1433,36 +1432,22 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, } } + let _ = messageText + let string: String if !message.flags.contains(.Incoming) { switch status { case .approved: - if messageText.isEmpty { - string = "The message was approved" - } else { - string = "The message \"\(messageText)\" was approved" - } + string = strings.Chat_PostApproval_Status_AdminApproved case .rejected: - if messageText.isEmpty { - string = "The message was declined" - } else { - string = "The message \"\(messageText)\" was declined" - } + string = strings.Chat_PostApproval_Status_AdminRejected } } else { switch status { case .approved: - if messageText.isEmpty { - string = "Your message was approved" - } else { - string = "Your message \"\(messageText)\" was approved" - } + string = strings.Chat_PostApproval_Status_UserApproved case .rejected: - if messageText.isEmpty { - string = "Your message was declined" - } else { - string = "Your message \"\(messageText)\" was declined" - } + string = strings.Chat_PostApproval_Status_UserRejected } } attributedString = NSAttributedString(string: string, font: titleFont, textColor: primaryTextColor) @@ -1477,19 +1462,14 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, } let _ = isUser - //TODO:localize let amountString: String switch amount.currency { case .stars: - if amount.amount.value == 1 { - amountString = "1 Star" - } else { - amountString = "\(amount.amount.value) Stars" - } + amountString = strings.Chat_PostApproval_DetailStatus_StarsAmount(Int32((amount.amount.value == 1 && amount.amount.nanos == 0) ? 1 : 100)).replacingOccurrences(of: "#", with: "\(amount.amount)") case .ton: - amountString = "\(formatTonAmountText(amount.amount.value, dateTimeFormat: dateTimeFormat, maxDecimalPositions: 3)) TON" + amountString = strings.Chat_PostApproval_DetailStatus_TonAmount(Int32((amount.amount.value == 1 * 1_000_000_000) ? 1 : 100)).replacingOccurrences(of: "#", with: "\(formatTonAmountText(amount.amount.value, dateTimeFormat: dateTimeFormat, maxDecimalPositions: 3))") } - attributedString = parseMarkdownIntoAttributedString("**\(channelName)** received **\(amountString)** for publishing this post", attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil })) + attributedString = parseMarkdownIntoAttributedString(strings.Chat_PostApproval_DetailStatus_PostedPaid("\(channelName)", amountString).string, attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil })) case let .suggestedPostRefund(info): var isUser = true var channelName: String = "" @@ -1501,15 +1481,14 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, } let _ = channelName - //TODO:localize if info.isUserInitiated { if isUser { - attributedString = NSAttributedString(string: "Suggested post was refunded because you didn't have enough funds", font: titleFont, textColor: primaryTextColor) + attributedString = NSAttributedString(string: strings.Chat_PostApproval_DetailStatus_UserFailedRefunded, font: titleFont, textColor: primaryTextColor) } else { - attributedString = NSAttributedString(string: "Suggested post was refunded because the user didn't have enough funds", font: titleFont, textColor: primaryTextColor) + attributedString = NSAttributedString(string: strings.Chat_PostApproval_DetailStatus_AdminFailedRefunded, font: titleFont, textColor: primaryTextColor) } } else { - attributedString = NSAttributedString(string: "Suggested post was refunded because the message was deleted", font: titleFont, textColor: primaryTextColor) + attributedString = NSAttributedString(string: strings.Chat_PostApproval_DetailStatus_FailedDeleted, font: titleFont, textColor: primaryTextColor) } case let .giftTon(currency, amount, _, _, _): attributedString = nil diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift index 1f898eb3df..af4cdc198c 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift @@ -258,7 +258,6 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { switch suggestedPost { case let .approved(timestamp, amount): - //TODO:localize let timeString = humanReadableStringForTimestamp(strings: item.presentationData.strings, dateTimeFormat: item.presentationData.dateTimeFormat, timestamp: timestamp ?? 0, alwaysShowTime: true, allowYesterday: false, format: HumanReadableStringFormat( dateFormatString: { value in return PresentationStrings.FormattedString(string: item.presentationData.strings.SuggestPost_SetTimeFormat_Date(value).string.lowercased(), ranges: []) @@ -279,23 +278,23 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { let amountString: String switch amount.currency { case .stars: - amountString = amount.amount.value == 1 ? "\(amount.amount) Star" : "\(amount.amount) Stars" + amountString = item.presentationData.strings.Chat_PostApproval_DetailStatus_StarsAmount(Int32((amount.amount.value == 1 && amount.amount.nanos == 0) ? 1 : 100)).replacingOccurrences(of: "#", with: "\(amount.amount)") case .ton: - amountString = "\(formatTonAmountText(amount.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat)) TON" + amountString = item.presentationData.strings.Chat_PostApproval_DetailStatus_TonAmount(Int32((amount.amount.value == 1 * 1_000_000_000) ? 1 : 100)).replacingOccurrences(of: "#", with: "\(formatTonAmountText(amount.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat, maxDecimalPositions: 3))") } switch amount.currency { case .stars: - if !isUser { - pricePart = "\n\nšŸ’° The user have been charged \(amountString).\n\nāŒ› **\(channelName)** will receive the Stars once the post has been live for 24 hours.\n\nšŸ”„ If your remove the post before it has been live for 24 hours, the user's Stars will be refunded." + if isUser { + pricePart = "\n\n" + item.presentationData.strings.Chat_PostApproval_Message_UserAgreementPriceStars(amountString, channelName).string } else { - pricePart = "\n\nšŸ’° You have been charged \(amountString).\n\nāŒ› **\(channelName)** will receive your Stars once the post has been live for 24 hours.\n\nšŸ”„ If **\(channelName)** removes the post before it has been live for 24 hours, your Stars will be refunded." + pricePart = "\n\n" + item.presentationData.strings.Chat_PostApproval_Message_AdminAgreementPriceStars(amountString, channelName).string } case .ton: - if !isUser { - pricePart = "\n\nšŸ’° The user have been charged \(amountString).\n\nāŒ› **\(channelName)** will receive TON once the post has been live for 24 hours.\n\nšŸ”„ If your remove the post before it has been live for 24 hours, the user's TON will be refunded." + if isUser { + pricePart = "\n\n" + item.presentationData.strings.Chat_PostApproval_Message_UserAgreementPriceTon(amountString, channelName).string } else { - pricePart = "\n\nšŸ’° You have been charged \(amountString).\n\nāŒ› **\(channelName)** will receive your TON once the post has been live for 24 hours.\n\nšŸ”„ If **\(channelName)** removes the post before it has been live for 24 hours, your TON will be refunded." + pricePart = "\n\n" + item.presentationData.strings.Chat_PostApproval_Message_AdminAgreementPriceTon(amountString, channelName).string } } } @@ -303,23 +302,23 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { let rawString: String if let timestamp { if Int32(Date().timeIntervalSince1970) >= timestamp { - if !isUser { - rawString = "šŸ“… The post has been automatically published in **\(channelName)** **\(timeString)**." + pricePart + if isUser { + rawString = item.presentationData.strings.Chat_PostApproval_Message_UserAgreementPast(channelName, timeString).string + pricePart } else { - rawString = "šŸ“… Your post has been automatically published in **\(channelName)** **\(timeString)**." + pricePart + rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminAgreementPast(channelName, timeString).string + pricePart } } else { - if !isUser { - rawString = "šŸ“… The post will be automatically published in **\(channelName)** **\(timeString)**." + pricePart + if isUser { + rawString = item.presentationData.strings.Chat_PostApproval_Message_UserAgreementFuture(channelName, timeString).string + pricePart } else { - rawString = "šŸ“… Your post will be automatically published in **\(channelName)** **\(timeString)**." + pricePart + rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminAgreementFuture(channelName, timeString).string + pricePart } } } else { - if !isUser { - rawString = "šŸ“… The post has been automatically published in **\(channelName)**." + pricePart + if isUser { + rawString = item.presentationData.strings.Chat_PostApproval_Message_UserAgreementNoTime(channelName).string + pricePart } else { - rawString = "šŸ“… Your post has been automatically published in **\(channelName)**." + pricePart + rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminAgreementNoTime(channelName).string + pricePart } } updatedAttributedString = parseMarkdownIntoAttributedString(rawString, attributes: MarkdownAttributes( @@ -336,9 +335,9 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { switch reason { case .generic: if let comment { - rawString = "You declined the post with the following comment:\n\n" + comment + rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminDeclinedComment(comment).string } else { - rawString = "You declined the post." + rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminDeclined } case .lowBalance: rawString = "" @@ -367,7 +366,6 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { } } - //TODO:localize var titleLayoutAndApply: (TextNodeLayout, () -> TextNode)? if let suggestedPost { let channelName: String @@ -381,32 +379,32 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { var smallFont = false switch suggestedPost { case .approved: - rawString = "šŸ¤ Agreement Reached!" + rawString = item.presentationData.strings.Chat_PostApproval_Message_TitleApproved case let .rejected(reason, comment): if !item.message.effectivelyIncoming(item.context.account.peerId) { switch reason { case .generic: if comment != nil { - rawString = "āŒ You rejected the message with the comment:" + rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminTitleRejectedComment } else { - rawString = "āŒ You rejected the message." + rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminTitleRejected smallFont = true } case .lowBalance: - rawString = "āš ļø **Transaction failed** because the user didn't have enough Stars." + rawString = item.presentationData.strings.Chat_PostApproval_Message_AdminTitleFailedFunds smallFont = true } } else { switch reason { case .generic: if comment != nil { - rawString = "āŒ **\(channelName)** rejected your message with the comment:" + rawString = item.presentationData.strings.Chat_PostApproval_Message_UserTitleRejectedComment(channelName).string } else { - rawString = "āŒ **\(channelName)** rejected your message." + rawString = item.presentationData.strings.Chat_PostApproval_Message_UserTitleRejected(channelName).string smallFont = true } case .lowBalance: - rawString = "āš ļø **Transaction failed** because you didn't have enough Stars." + rawString = item.presentationData.strings.Chat_PostApproval_Message_UserTitleFailedFunds smallFont = true } } @@ -499,9 +497,8 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { var buyStarsTitleLayoutAndApply: (TextNodeLayout, () -> TextNode)? var buyStarsButtonSize: CGSize? if hasBuyStarsButton { - //TODO:localize let serviceColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper) - let buyStarsTitleLayoutAndApplyValue = makeBuyStarsTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Buy Stars", font: Font.semibold(15.0), textColor: serviceColor.primaryText), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: constrainedSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: textAlignment, cutout: nil, insets: UIEdgeInsets())) + let buyStarsTitleLayoutAndApplyValue = makeBuyStarsTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Chat_PostApproval_Message_BuyStars, font: Font.semibold(15.0), textColor: serviceColor.primaryText), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: constrainedSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: textAlignment, cutout: nil, insets: UIEdgeInsets())) buyStarsTitleLayoutAndApply = buyStarsTitleLayoutAndApplyValue let buyStarsButtonSizeValue = CGSize(width: buyStarsTitleLayoutAndApplyValue.0.size.width + 20.0 * 2.0, height: buyStarsTitleLayoutAndApplyValue.0.size.height + 8.0 * 2.0) diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageAnimatedStickerItemNode/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageAnimatedStickerItemNode/Sources/ChatMessageAnimatedStickerItemNode.swift index 2e54b862be..bf0edc3bc7 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageAnimatedStickerItemNode/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageAnimatedStickerItemNode/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -1300,7 +1300,6 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { canApprove = false } - //TODO:localize var buttonDeclineValue: UInt8 = 0 let buttonDecline = MemoryBuffer(data: Data(bytes: &buttonDeclineValue, count: 1)) var buttonApproveValue: UInt8 = 1 @@ -1332,11 +1331,11 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { ReplyMarkupMessageAttribute( rows: [ ReplyMarkupRow(buttons: [ - ReplyMarkupButton(title: "Decline", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonDecline)), - ReplyMarkupButton(title: "Approve", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonApprove)) + ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionReject, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonDecline)), + ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionApprove, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonApprove)) ]), ReplyMarkupRow(buttons: [ - ReplyMarkupButton(title: "Suggest Changes", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonSuggestChanges)) + ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionSuggestChanges, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonSuggestChanges)) ]) ], flags: [], diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift index 1f786cf66a..db8fe19f70 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift @@ -2811,7 +2811,6 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI canApprove = false } - //TODO:localize var buttonDeclineValue: UInt8 = 0 let buttonDecline = MemoryBuffer(data: Data(bytes: &buttonDeclineValue, count: 1)) var buttonApproveValue: UInt8 = 1 @@ -2843,11 +2842,11 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI ReplyMarkupMessageAttribute( rows: [ ReplyMarkupRow(buttons: [ - ReplyMarkupButton(title: "Decline", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonDecline)), - ReplyMarkupButton(title: "Approve", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonApprove)) + ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionReject, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonDecline)), + ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionApprove, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonApprove)) ]), ReplyMarkupRow(buttons: [ - ReplyMarkupButton(title: "Suggest Changes", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonSuggestChanges)) + ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionSuggestChanges, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonSuggestChanges)) ]) ], flags: [], diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageStickerItemNode/Sources/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageStickerItemNode/Sources/ChatMessageStickerItemNode.swift index 55ad3cc6a7..c4465ef56e 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageStickerItemNode/Sources/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageStickerItemNode/Sources/ChatMessageStickerItemNode.swift @@ -861,7 +861,6 @@ public class ChatMessageStickerItemNode: ChatMessageItemView { canApprove = false } - //TODO:localize var buttonDeclineValue: UInt8 = 0 let buttonDecline = MemoryBuffer(data: Data(bytes: &buttonDeclineValue, count: 1)) var buttonApproveValue: UInt8 = 1 @@ -893,11 +892,11 @@ public class ChatMessageStickerItemNode: ChatMessageItemView { ReplyMarkupMessageAttribute( rows: [ ReplyMarkupRow(buttons: [ - ReplyMarkupButton(title: "Decline", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonDecline)), - ReplyMarkupButton(title: "Approve", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonApprove)) + ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionReject, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonDecline)), + ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionApprove, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonApprove)) ]), ReplyMarkupRow(buttons: [ - ReplyMarkupButton(title: "Suggest Changes", titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonSuggestChanges)) + ReplyMarkupButton(title: item.presentationData.strings.Chat_PostApproval_Message_ActionSuggestChanges, titleWhenForwarded: nil, action: .callback(requiresPassword: false, data: buttonSuggestChanges)) ]) ], flags: [], diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageSuggestedPostInfoNode/Sources/ChatMessageSuggestedPostInfoNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageSuggestedPostInfoNode/Sources/ChatMessageSuggestedPostInfoNode.swift index 573baf3a9a..d42fdd4fee 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageSuggestedPostInfoNode/Sources/ChatMessageSuggestedPostInfoNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageSuggestedPostInfoNode/Sources/ChatMessageSuggestedPostInfoNode.swift @@ -58,25 +58,16 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode { } } - //TODO:localize let amountString: String if let amount, amount.amount != .zero { switch amount.currency { case .stars: - if amount.amount.value == 1 { - amountString = "1 Star" - } else { - amountString = "\(amount.amount) Stars" - } + amountString = item.presentationData.strings.Chat_PostApproval_DetailStatus_StarsAmount(Int32((amount.amount.value == 1 && amount.amount.nanos == 0) ? 1 : 100)).replacingOccurrences(of: "#", with: "\(amount.amount)") case .ton: - if amount.amount.value == 1 { - amountString = "1 TON" - } else { - amountString = "\(formatTonAmountText(amount.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat)) TON" - } + amountString = item.presentationData.strings.Chat_PostApproval_DetailStatus_TonAmount(Int32((amount.amount.value == 1 * 1_000_000_000) ? 1 : 100)).replacingOccurrences(of: "#", with: "\(formatTonAmountText(amount.amount.value, dateTimeFormat: item.presentationData.dateTimeFormat, maxDecimalPositions: 3))") } } else { - amountString = "Free" + amountString = item.presentationData.strings.Chat_PostSuggestion_PriceFree } var timestampString: String @@ -86,12 +77,11 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode { timestampString = String(timestampString[timestampString.startIndex]).capitalized + timestampString[timestampString.index(after: timestampString.startIndex)...] } } else { - timestampString = "Anytime" + timestampString = item.presentationData.strings.Chat_PostSuggestion_TimeAny } let serviceColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper) - //TODO:localize let titleText: String if let attribute = item.message.attributes.first(where: { $0 is ReplyMessageAttribute }) as? ReplyMessageAttribute { var changedText = false @@ -131,19 +121,19 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode { if !item.message.effectivelyIncoming(item.context.account.peerId) { if changedText && changedMedia && changedPrice && changedTime { - titleText = "You suggest a new price,\ntime and contents for this message." + titleText = item.presentationData.strings.Chat_PostSuggestion_UserChangePTC } else if changedText && changedPrice && changedTime { - titleText = "You suggest a new price,\ntime and text for this message." + titleText = item.presentationData.strings.Chat_PostSuggestion_UserChangePTT } else if changedMedia && changedPrice && changedTime { - titleText = "You suggest a new price,\ntime and attachments for this message." + titleText = item.presentationData.strings.Chat_PostSuggestion_UserChangePTA } else if changedPrice && changedTime { - titleText = "You suggest a new price and time\nfor this message." + titleText = item.presentationData.strings.Chat_PostSuggestion_UserChangePT } else if changedPrice { - titleText = "You suggest a new price\nfor this message." + titleText = item.presentationData.strings.Chat_PostSuggestion_UserChangeP } else if changedTime { - titleText = "You suggest a new time\nfor this message." + titleText = item.presentationData.strings.Chat_PostSuggestion_UserChangeT } else { - titleText = "You suggest changes\nfor this message." + titleText = item.presentationData.strings.Chat_PostSuggestion_UserChange } } else { var channelName = "" @@ -151,26 +141,26 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode { channelName = item.message.author.flatMap(EnginePeer.init)?.compactDisplayTitle ?? " " } if changedText && changedMedia && changedPrice && changedTime { - titleText = "**\(channelName)** suggests a new price,\ntime and contents for this message." + titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChangePTC(channelName).string } else if changedText && changedPrice && changedTime { - titleText = "**\(channelName)** suggests a new price,\ntime and text for this message." + titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChangePTT(channelName).string } else if changedMedia && changedPrice && changedTime { - titleText = "**\(channelName)** suggests a new price,\ntime and attachments for this message." + titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChangePTA(channelName).string } else if changedPrice && changedTime { - titleText = "**\(channelName)** suggests a new price and time\nfor this message." + titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChangePT(channelName).string } else if changedPrice { - titleText = "**\(channelName)** suggests a new price\nfor this message." + titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChangeP(channelName).string } else if changedTime { - titleText = "**\(channelName)** suggests a new time\nfor this message." + titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChangeT(channelName).string } else { - titleText = "**\(channelName)** suggests changes\nfor this message." + titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelChange(channelName).string } } } else { if !item.message.effectivelyIncoming(item.context.account.peerId) { - titleText = "You suggest to post\nthis message." + titleText = item.presentationData.strings.Chat_PostSuggestion_UserPost } else { - titleText = "**\(item.message.author.flatMap(EnginePeer.init)?.compactDisplayTitle ?? " ")** suggests to post\nthis message." + titleText = item.presentationData.strings.Chat_PostSuggestion_ChannelPost(item.message.author.flatMap(EnginePeer.init)?.compactDisplayTitle ?? " ").string } } @@ -185,8 +175,8 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode { let titleLayout = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maxWidth - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) - let priceLabelLayout = makePriceLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Price", font: Font.regular(13.0), textColor: serviceColor.primaryText.withMultipliedAlpha(0.5)), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maxWidth - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) - let timeLabelLayout = makeTimeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Time", font: Font.regular(13.0), textColor: serviceColor.primaryText.withMultipliedAlpha(0.5)), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maxWidth - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + let priceLabelLayout = makePriceLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Chat_PostSuggestion_TablePrice, font: Font.regular(13.0), textColor: serviceColor.primaryText.withMultipliedAlpha(0.5)), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maxWidth - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + let timeLabelLayout = makeTimeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Chat_PostSuggestion_TableTime, font: Font.regular(13.0), textColor: serviceColor.primaryText.withMultipliedAlpha(0.5)), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maxWidth - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let priceValueLayout = makePriceValueLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: amountString, font: Font.semibold(13.0), textColor: serviceColor.primaryText), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maxWidth - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let timeValueLayout = makeTimeValueLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: timestampString, font: Font.semibold(13.0), textColor: serviceColor.primaryText), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maxWidth - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) diff --git a/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift b/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift index 673a9092d4..e891e4bc2e 100644 --- a/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift +++ b/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift @@ -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() - private let title = ComponentView() - private var selectorIcon: ComponentView? - - 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, 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 - 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, transition: ComponentTransition) -> CGSize { - return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) - } -} - final class HeaderContextReferenceContentSource: ContextReferenceContentSource { private let controller: ViewController private let sourceView: UIView diff --git a/submodules/TelegramUI/Components/Chat/ChatSideTopicsPanel/Sources/ChatSideTopicsPanel.swift b/submodules/TelegramUI/Components/Chat/ChatSideTopicsPanel/Sources/ChatSideTopicsPanel.swift index 2b4237275b..1abefd9b5c 100644 --- a/submodules/TelegramUI/Components/Chat/ChatSideTopicsPanel/Sources/ChatSideTopicsPanel.swift +++ b/submodules/TelegramUI/Components/Chat/ChatSideTopicsPanel/Sources/ChatSideTopicsPanel.swift @@ -1968,8 +1968,7 @@ public final class ChatSideTopicsPanel: Component { ).get() if let threadInfo, threadInfo.isMessageFeeRemoved { - //TODO:localize - items.append(.action(ContextMenuActionItem(text: "Charge Message Fee", textColor: .primary, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Rate"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in + items.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ReinstatePaidMessages, textColor: .primary, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Rate"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in guard let self, let component = self.component else { return } diff --git a/submodules/TelegramUI/Components/Chat/SuggestPostAccessoryPanelNode/Sources/SuggestPostAccessoryPanelNode.swift b/submodules/TelegramUI/Components/Chat/SuggestPostAccessoryPanelNode/Sources/SuggestPostAccessoryPanelNode.swift index ba2b0ba756..dfe08a10b5 100644 --- a/submodules/TelegramUI/Components/Chat/SuggestPostAccessoryPanelNode/Sources/SuggestPostAccessoryPanelNode.swift +++ b/submodules/TelegramUI/Components/Chat/SuggestPostAccessoryPanelNode/Sources/SuggestPostAccessoryPanelNode.swift @@ -226,12 +226,11 @@ public final class SuggestPostAccessoryPanelNode: AccessoryPanelNode { } } - //TODO:localize var titleText: [CompositeTextNode.Component] = [] if let postSuggestionState = interfaceState.interfaceState.postSuggestionState, postSuggestionState.editingOriginalMessageId != nil { - titleText.append(.text(NSAttributedString(string: "Suggest Changes", font: Font.medium(15.0), textColor: self.theme.chat.inputPanel.panelControlAccentColor))) + titleText.append(.text(NSAttributedString(string: self.strings.Chat_PostSuggestion_Suggest_InputEditTitle, font: Font.medium(15.0), textColor: self.theme.chat.inputPanel.panelControlAccentColor))) } else { - titleText.append(.text(NSAttributedString(string: "Suggest a post below", font: Font.medium(15.0), textColor: self.theme.chat.inputPanel.panelControlAccentColor))) + titleText.append(.text(NSAttributedString(string: self.strings.Chat_PostSuggestion_Suggest_InputTitle, font: Font.medium(15.0), textColor: self.theme.chat.inputPanel.panelControlAccentColor))) } self.titleNode.components = titleText @@ -269,10 +268,10 @@ public final class SuggestPostAccessoryPanelNode: AccessoryPanelNode { )).string textString = NSAttributedString(string: "\(currencySymbol)\(amountString) šŸ“… \(timeString)", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor) } else { - textString = NSAttributedString(string: "\(currencySymbol)\(amountString) for publishing anytime", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor) + textString = NSAttributedString(string: self.strings.Chat_PostSuggestion_Suggest_InputSubtitleAnytime("\(currencySymbol)\(amountString)").string, font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor) } } else { - textString = NSAttributedString(string: "Tap to offer a price for publishing", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor) + textString = NSAttributedString(string: self.strings.Chat_PostSuggestion_Suggest_InputSubtitleEmpty, font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor) } let mutableTextString = NSMutableAttributedString(attributedString: textString) diff --git a/submodules/TelegramUI/Components/ChatScheduleTimeController/Sources/ChatScheduleTimeControllerNode.swift b/submodules/TelegramUI/Components/ChatScheduleTimeController/Sources/ChatScheduleTimeControllerNode.swift index 8a1d60bce7..659def128e 100644 --- a/submodules/TelegramUI/Components/ChatScheduleTimeController/Sources/ChatScheduleTimeControllerNode.swift +++ b/submodules/TelegramUI/Components/ChatScheduleTimeController/Sources/ChatScheduleTimeControllerNode.swift @@ -112,16 +112,13 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel title = self.presentationData.strings.Conversation_SetReminder_Title case let .suggestPost(needsTime, isAdmin, funds): if needsTime { - //TODO:localize - title = "Accept Terms" - text = "Set the date and time you want\nthis message to be published." + title = self.presentationData.strings.Chat_PostSuggestion_ApproveTime_Title + text = self.presentationData.strings.Chat_PostSuggestion_ApproveTime_Text } else { - //TODO:localize - title = "Time" - text = "Set the date and time you want\nyour message to be published." + title = self.presentationData.strings.Chat_PostSuggestion_SetTime_Title + text = self.presentationData.strings.Chat_PostSuggestion_SetTime_Text } - //TODO:localize if let funds, isAdmin { var commissionValue: String commissionValue = "\(Double(funds.commissionPermille) * 0.1)" @@ -134,10 +131,10 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel switch funds.amount.currency { case .stars: let displayAmount = funds.amount.amount.totalValue * Double(funds.commissionPermille) / 1000.0 - subtitle = "You will receive \(displayAmount) Stars (\(commissionValue)%)\nfor publishing this post" + subtitle = self.presentationData.strings.Chat_PostSuggestion_ApproveTime_AdminConfirmationPriceStars("\(displayAmount)", "\(commissionValue)").string case .ton: let displayAmount = Double(funds.amount.amount.value) / 1000000000.0 * Double(funds.commissionPermille) / 1000.0 - subtitle = "You will receive \(displayAmount) TON (\(commissionValue)%)\nfor publishing this post" + subtitle = self.presentationData.strings.Chat_PostSuggestion_ApproveTime_AdminConfirmationPriceTon("\(displayAmount)", "\(commissionValue)").string } } } @@ -183,11 +180,10 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel self.onlineButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(backgroundColor: buttonColor, foregroundColor: buttonTextColor), font: .regular, height: 52.0, cornerRadius: 11.0, gloss: false) switch mode { case let .suggestPost(needsTime, _, _): - //TODO:localize if needsTime { - self.onlineButton.title = "Post Now" + self.onlineButton.title = self.presentationData.strings.Chat_PostSuggestion_ApproveTime_NoTimeAction } else { - self.onlineButton.title = "Send Anytime" + self.onlineButton.title = self.presentationData.strings.Chat_PostSuggestion_SetTime_NoTimeAction } default: self.onlineButton.title = self.presentationData.strings.Conversation_ScheduleMessage_SendWhenOnline @@ -589,7 +585,6 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel } let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white) let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white) - //TODO:localize let playOnce = ActionSlot() let toastSize = toast.update( transition: ComponentTransition(transition), @@ -602,7 +597,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel )), content: AnyComponent(VStack([ AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent( - text: .markdown(text: "Transactions in **Stars** may be reversed by the payment provider within **21** days. Only accept Stars from people you trust.", attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil })), + text: .markdown(text: self.presentationData.strings.Chat_PostSuggestion_StarsDisclaimer, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil })), maximumNumberOfLines: 0 ))) ], alignment: .left, spacing: 6.0)), diff --git a/submodules/TelegramUI/Components/Stars/BalanceNeededScreen/Sources/BalanceNeededScreen.swift b/submodules/TelegramUI/Components/Stars/BalanceNeededScreen/Sources/BalanceNeededScreen.swift index c3599c66b5..d712e9ea04 100644 --- a/submodules/TelegramUI/Components/Stars/BalanceNeededScreen/Sources/BalanceNeededScreen.swift +++ b/submodules/TelegramUI/Components/Stars/BalanceNeededScreen/Sources/BalanceNeededScreen.swift @@ -128,7 +128,7 @@ private final class BalanceNeededSheetContentComponent: Component { let titleSize = self.title.update( transition: transition, component: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString(string: "\(formatTonAmountText(component.amount.value, dateTimeFormat: component.context.sharedContext.currentPresentationData.with({ $0 }).dateTimeFormat)) TON Needed", font: Font.bold(24.0), textColor: environment.theme.list.itemPrimaryTextColor)), + text: .plain(NSAttributedString(string: environment.strings.BalanceNeeded_FragmentTitle(formatTonAmountText(component.amount.value, dateTimeFormat: component.context.sharedContext.currentPresentationData.with({ $0 }).dateTimeFormat)).string, font: Font.bold(24.0), textColor: environment.theme.list.itemPrimaryTextColor)), horizontalAlignment: .center, maximumNumberOfLines: 0 )), @@ -144,11 +144,10 @@ private final class BalanceNeededSheetContentComponent: Component { contentHeight += titleSize.height contentHeight += 14.0 - //TODO:localize let textSize = self.text.update( transition: transition, component: AnyComponent(BalancedTextComponent( - text: .plain(NSAttributedString(string: "You can add funds to your balance via the third-party platform Fragment.", font: Font.regular(15.0), textColor: environment.theme.list.itemPrimaryTextColor)), + text: .plain(NSAttributedString(string: environment.strings.BalanceNeeded_FragmentSubtitle, font: Font.regular(15.0), textColor: environment.theme.list.itemPrimaryTextColor)), horizontalAlignment: .center, maximumNumberOfLines: 0, lineSpacing: 0.18 @@ -165,7 +164,6 @@ private final class BalanceNeededSheetContentComponent: Component { contentHeight += textSize.height contentHeight += 24.0 - //TODO:localize let buttonSize = self.button.update( transition: transition, component: AnyComponent(ButtonComponent( @@ -175,7 +173,7 @@ private final class BalanceNeededSheetContentComponent: Component { pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8) ), content: AnyComponentWithIdentity(id: AnyHashable(0 as Int), component: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString(string: "Add Funds via Fragment", font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor)) + text: .plain(NSAttributedString(string: environment.strings.BalanceNeeded_FragmentAction, font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor)) ))), isEnabled: true, allowActionWhenDisabled: true, diff --git a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift index e1403e2888..35142a30df 100644 --- a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift @@ -212,24 +212,23 @@ private final class SheetContent: CombinedComponent { minAmount = StarsAmount(value: minAmountValue, nanos: 0) maxAmount = StarsAmount(value: resaleConfiguration.paidMessageMaxAmount, nanos: 0) case let .suggestedPost(mode, _, _, _): - //TODO:localize switch mode { case .sender: - titleString = "Suggest Terms" + titleString = environment.strings.Chat_PostSuggestion_Suggest_TitleCreate case .admin: - titleString = "Suggest Changes" + titleString = environment.strings.Chat_PostSuggestion_Suggest_TitleEdit } switch state.currency { case .stars: - amountTitle = "ENTER A PRICE IN STARS" + amountTitle = environment.strings.Chat_PostSuggestion_Suggest_PriceSectionStars maxAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMaxStarsAmount, nanos: 0) minAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMinStarsAmount, nanos: 0) case .ton: - amountTitle = "ENTER A PRICE IN TON" + amountTitle = environment.strings.Chat_PostSuggestion_Suggest_PriceSectionTon maxAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMaxTonAmount, nanos: 0) minAmount = StarsAmount(value: 0, nanos: 0) } - amountPlaceholder = "Price" + amountPlaceholder = environment.strings.Chat_PostSuggestion_Suggest_PricePlaceholder allowZero = true if let usdWithdrawRate = withdrawConfiguration.usdWithdrawRate, let tonUsdRate = withdrawConfiguration.tonUsdRate, let amount = state.amount, amount > StarsAmount.zero { @@ -330,17 +329,16 @@ private final class SheetContent: CombinedComponent { } if displayCurrencySelector { - //TODO:localize let selectedId: AnyHashable = state.currency == .stars ? AnyHashable(0 as Int) : AnyHashable(1 as Int) let starsTitle: String let tonTitle: String switch mode { case .sender: - starsTitle = "Offer Stars" - tonTitle = "Offer TON" + starsTitle = environment.strings.Chat_PostSuggestion_Suggest_OfferStars + tonTitle = environment.strings.Chat_PostSuggestion_Suggest_OfferTon case .admin: - starsTitle = "Request Stars" - tonTitle = "Request TON" + starsTitle = environment.strings.Chat_PostSuggestion_Suggest_RequestStars + tonTitle = environment.strings.Chat_PostSuggestion_Suggest_RequestTon } let currencyToggle = currencyToggle.update( @@ -474,21 +472,20 @@ private final class SheetContent: CombinedComponent { case let .suggestedPost(mode, _, _, _): switch mode { case let .sender(channel, isFromAdmin): - //TODO:localize let string: String if isFromAdmin { switch state.currency { case .stars: - string = "Choose how many Stars you charge for the message." + string = environment.strings.Chat_PostSuggestion_Suggest_RequestDescriptionStars case .ton: - string = "Choose how many TON you charge for the message." + string = environment.strings.Chat_PostSuggestion_Suggest_RequestDescriptionTon } } else { switch state.currency { case .stars: - string = "Choose how many Stars you want to offer \(channel.compactDisplayTitle) to publish this message." + string = environment.strings.Chat_PostSuggestion_Suggest_OfferDescriptionStars(channel.compactDisplayTitle).string case .ton: - string = "Choose how many TON you want to offer \(channel.compactDisplayTitle) to publish this message." + string = environment.strings.Chat_PostSuggestion_Suggest_OfferDescriptionTon(channel.compactDisplayTitle).string } } let amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString(string, attributes: amountMarkdownAttributes, textAlignment: .natural)) @@ -497,13 +494,12 @@ private final class SheetContent: CombinedComponent { maximumNumberOfLines: 0 )) case .admin: - //TODO:localize let string: String switch state.currency { case .stars: - string = "Choose how many Stars you charge for the message." + string = environment.strings.Chat_PostSuggestion_Suggest_RequestDescriptionStars case .ton: - string = "Choose how many TON you charge for the message." + string = environment.strings.Chat_PostSuggestion_Suggest_RequestDescriptionTon } let amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString(string, attributes: amountMarkdownAttributes, textAlignment: .natural)) amountFooter = AnyComponent(MultilineTextComponent( @@ -576,13 +572,12 @@ private final class SheetContent: CombinedComponent { if case let .suggestedPost(mode, _, _, _) = component.mode { contentSize.height += 24.0 - //TODO:localize let footerString: String switch mode { case .sender: - footerString = "Select the date and time you want your message to be published." + footerString = environment.strings.Chat_PostSuggestion_Suggest_OfferDateDescription case .admin: - footerString = "Select the date and time you want to publish the message." + footerString = environment.strings.Chat_PostSuggestion_Suggest_EditDateDescription } let timestampFooterString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString(footerString, attributes: amountMarkdownAttributes, textAlignment: .natural)) @@ -687,7 +682,6 @@ private final class SheetContent: CombinedComponent { } else if case .paidMessages = component.mode { buttonString = environment.strings.Stars_SendMessage_AdjustmentAction } else if case let .suggestedPost(mode, _, _, _) = component.mode { - //TODO:localize switch mode { case .sender: if let amount = state.amount, amount != .zero { @@ -701,12 +695,12 @@ private final class SheetContent: CombinedComponent { currencySymbol = "$" currencyAmount = formatTonAmountText(amount.value, dateTimeFormat: environment.dateTimeFormat) } - buttonString = "Offer \(currencySymbol) \(currencyAmount)" + buttonString = environment.strings.Chat_PostSuggestion_Suggest_OfferButtonPrice("\(currencySymbol) \(currencyAmount)").string } else { - buttonString = "Offer for Free" + buttonString = environment.strings.Chat_PostSuggestion_Suggest_OfferButtonFree } case .admin: - buttonString = "Update Terms" + buttonString = environment.strings.Chat_PostSuggestion_Suggest_UpdateButton } } else if let amount = state.amount { buttonString = "\(environment.strings.Stars_Withdraw_Withdraw) # \(presentationStringsFormattedNumber(amount, environment.dateTimeFormat.groupingSeparator))" @@ -1120,21 +1114,19 @@ public final class StarsWithdrawScreen: ViewControllerComponentContainer { let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } var text = presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(minAmount))).string if case .starGiftResell = self.mode { - //TODO:localize - text = "You cannot sell gift for less than \(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(minAmount)))." + text = presentationData.strings.Stars_SellGiftMinAmountToast_Text("\(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(minAmount)))").string } else if case let .suggestedPost(mode, _, _, _) = self.mode { let resaleConfiguration = StarsSubscriptionConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 }) switch currency { case .stars: - //TODO:localize switch mode { case .admin: - text = "You cannot request less than \(resaleConfiguration.channelMessageSuggestionMinStarsAmount) Stars." + text = presentationData.strings.Chat_PostSuggestion_Suggest_AdminMinAmountStars_Text("\(resaleConfiguration.channelMessageSuggestionMinStarsAmount)").string case let .sender(_, isFromAdmin): if isFromAdmin { - text = "You cannot request less than \(resaleConfiguration.channelMessageSuggestionMinStarsAmount) Stars." + text = presentationData.strings.Chat_PostSuggestion_Suggest_AdminMinAmountStars_Text("\(resaleConfiguration.channelMessageSuggestionMinStarsAmount)").string } else { - text = "You cannot offer less than \(resaleConfiguration.channelMessageSuggestionMinStarsAmount) Stars." + text = presentationData.strings.Chat_PostSuggestion_Suggest_UserMinAmountStars_Text("\(resaleConfiguration.channelMessageSuggestionMinStarsAmount)").string } } case .ton: diff --git a/submodules/TelegramUI/Components/SuggestedPostApproveAlert/Sources/SuggestedPostApproveAlert.swift b/submodules/TelegramUI/Components/SuggestedPostApproveAlert/Sources/SuggestedPostApproveAlert.swift index 76c1d318fc..8a39ab8130 100644 --- a/submodules/TelegramUI/Components/SuggestedPostApproveAlert/Sources/SuggestedPostApproveAlert.swift +++ b/submodules/TelegramUI/Components/SuggestedPostApproveAlert/Sources/SuggestedPostApproveAlert.swift @@ -359,7 +359,6 @@ private final class SuggestedPostAlertImpl: AlertController { } let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white) let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white) - //TODO:localize let playOnce = ActionSlot() let toastSize = toast.update( transition: ComponentTransition(transition), diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift index 5863cbb9d1..cc69b28488 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift @@ -1816,23 +1816,22 @@ extension ChatControllerImpl { guard let self else { return } - //TODO:localize let titleString: String let textString: String switch attribute.currency { case .stars: - titleString = "Stars Will Be Lost" - textString = "You won't receive **Stars** for this post if you delete it now. The post must remain visible for at least **24 hours** after publication." + titleString = self.presentationData.strings.Chat_DeletePaidMessageStars_Title + textString = self.presentationData.strings.Chat_DeletePaidMessageStars_Text case .ton: - titleString = "TON Will Be Lost" - textString = "You won't receive **TON** for this post if you delete it now. The post must remain visible for at least **24 hours** after publication." + titleString = self.presentationData.strings.Chat_DeletePaidMessageTon_Title + textString = self.presentationData.strings.Chat_DeletePaidMessageTon_Text } self.present(standardTextAlertController( theme: AlertControllerTheme(presentationData: self.presentationData), title: titleString, text: textString, actions: [ - TextAlertAction(type: .destructiveAction, title: "Delete Anyway", action: { [weak self] in + TextAlertAction(type: .destructiveAction, title: self.presentationData.strings.Chat_DeletePaidMessage_Action, action: { [weak self] in guard let self else { return } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index f66d3be0d0..f0f4ffbfcb 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -2352,8 +2352,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if message.effectivelyIncoming(strongSelf.context.account.peerId) { switch buttonType { case 0: - //TODO:localize - let promptController = promptController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: strongSelf.updatedPresentationData, text: "Comment", titleFont: .bold, value: "", placeholder: "Optional", characterLimit: 4096, apply: { value in + let promptController = promptController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: strongSelf.updatedPresentationData, text: strongSelf.presentationData.strings.Chat_PostSuggestion_Reject_Title, titleFont: .bold, value: "", placeholder: strongSelf.presentationData.strings.Chat_PostSuggestion_Reject_Placeholder, characterLimit: 4096, apply: { value in guard let self else { return } @@ -2393,10 +2392,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G timestamp = Int32(Date().timeIntervalSince1970) + 1 * 60 * 60 } else { - //TODO:localize var textString: String if isAdmin { - textString = "Do you really want to publish this post from **\((message.author.flatMap(EnginePeer.init))?.compactDisplayTitle ?? "")**?" + textString = strongSelf.presentationData.strings.Chat_PostSuggestion_Approve_AdminConfirmationText(message.author.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "").string if let funds { var commissionValue: String @@ -2412,25 +2410,25 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G switch funds.amount.currency { case .stars: let displayAmount = funds.amount.amount.totalValue * Double(funds.commissionPermille) / 1000.0 - textString += "You will receive \(displayAmount) Stars (\(commissionValue)%)\nfor publishing this post. It must remain visible for **24** hours after publication." + textString += strongSelf.presentationData.strings.Chat_PostSuggestion_Approve_AdminConfirmationPriceStars("\(displayAmount)", "\(commissionValue)").string case .ton: let displayAmount = Double(funds.amount.amount.value) / 1000000000.0 * Double(funds.commissionPermille) / 1000.0 - textString += "You will receive \(displayAmount) TON (\(commissionValue)%)\nfor publishing this post. It must remain visible for **24** hours after publication." + textString += strongSelf.presentationData.strings.Chat_PostSuggestion_Approve_AdminConfirmationPriceTon("\(displayAmount)", "\(commissionValue)").string } } } else { - textString = "Do you really want to publish this post?" + textString = strongSelf.presentationData.strings.Chat_PostSuggestion_Approve_UserConfirmationText } - strongSelf.present(SuggestedPostApproveAlert(presentationData: strongSelf.presentationData, title: "Accept Terms", text: textString, actions: [ - TextAlertAction(type: .defaultAction, title: "Publish", action: { [weak strongSelf] in + strongSelf.present(SuggestedPostApproveAlert(presentationData: strongSelf.presentationData, title: strongSelf.presentationData.strings.Chat_PostSuggestion_Approve_Title, text: textString, actions: [ + TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Chat_PostSuggestion_Approve_Action, action: { [weak strongSelf] in guard let strongSelf else { return } let _ = strongSelf.context.engine.messages.monoforumPerformSuggestedPostAction(id: message.id, action: .approve(timestamp: timestamp)).startStandalone() }), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}) - ], actionLayout: .vertical, parseMarkdown: true, toastText: funds?.amount.currency == .ton ? "Transactions in **Stars** may be reversed by the payment provider within **21** days. Only accept Stars from people you trust." : nil), in: .window(.root)) + ], actionLayout: .vertical, parseMarkdown: true, toastText: funds?.amount.currency == .stars ? strongSelf.presentationData.strings.Chat_PostSuggestion_StarsDisclaimer : nil), in: .window(.root)) } case 2: strongSelf.interfaceInteraction?.openSuggestPost(message, .default) diff --git a/submodules/TelegramUI/Sources/ChatControllerAdminBanUsers.swift b/submodules/TelegramUI/Sources/ChatControllerAdminBanUsers.swift index cf28fe7d9a..6369734e00 100644 --- a/submodules/TelegramUI/Sources/ChatControllerAdminBanUsers.swift +++ b/submodules/TelegramUI/Sources/ChatControllerAdminBanUsers.swift @@ -394,23 +394,22 @@ extension ChatControllerImpl { guard let self else { return } - //TODO:localize let titleString: String let textString: String switch attribute.currency { case .stars: - titleString = "Stars Will Be Lost" - textString = "You won't receive **Stars** for this post if you delete it now. The post must remain visible for at least **24 hours** after publication." + titleString = self.presentationData.strings.Chat_DeletePaidMessageStars_Title + textString = self.presentationData.strings.Chat_DeletePaidMessageStars_Text case .ton: - titleString = "TON Will Be Lost" - textString = "You won't receive **TON** for this post if you delete it now. The post must remain visible for at least **24 hours** after publication." + titleString = self.presentationData.strings.Chat_DeletePaidMessageTon_Title + textString = self.presentationData.strings.Chat_DeletePaidMessageTon_Text } self.present(standardTextAlertController( theme: AlertControllerTheme(presentationData: self.presentationData), title: titleString, text: textString, actions: [ - TextAlertAction(type: .destructiveAction, title: "Delete Anyway", action: { [weak self] in + TextAlertAction(type: .destructiveAction, title: self.presentationData.strings.Chat_DeletePaidMessage_Action, action: { [weak self] in guard let self else { return } diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index 5423350bac..7c90e73501 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -1520,23 +1520,22 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState } if canSuggestPost { - //TODO:localize if message.attributes.contains(where: { $0 is SuggestedPostMessageAttribute }) { - actions.append(.action(ContextMenuActionItem(text: "Edit Message", icon: { theme in + actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Chat_ContextMenu_SuggestedPost_EditMessage, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.actionSheet.primaryTextColor) }, action: { c, _ in c?.dismiss(completion: { interfaceInteraction.openSuggestPost(message, .editMessage) }) }))) - actions.append(.action(ContextMenuActionItem(text: "Edit Time", icon: { theme in + actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Chat_ContextMenu_SuggestedPost_EditTime, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Calendar"), color: theme.actionSheet.primaryTextColor) }, action: { c, _ in c?.dismiss(completion: { interfaceInteraction.openSuggestPost(message, .editTime) }) }))) - actions.append(.action(ContextMenuActionItem(text: "Edit Price", icon: { theme in + actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Chat_ContextMenu_SuggestedPost_EditPrice, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/PriceTag"), color: theme.actionSheet.primaryTextColor) }, action: { c, _ in c?.dismiss(completion: { @@ -1544,7 +1543,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState }) }))) } else { - actions.append(.action(ContextMenuActionItem(text: "Suggest a Post", icon: { theme in + actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Chat_ContextMenu_SuggestedPost_Create, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Customize"), color: theme.actionSheet.primaryTextColor) }, action: { c, _ in c?.dismiss(completion: { diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index a336b54b98..3a6d8dc44e 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -159,8 +159,7 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode { return (PresentationResourcesChat.chatInputTextFieldSilentPostOffImage(theme), nil, strings.VoiceOver_SilentPostOff, 1.0, UIEdgeInsets()) } case .suggestPost: - //TODO:localize - return (PresentationResourcesChat.chatInputTextFieldSuggestPostImage(theme), nil, "Suggest post", 1.0, UIEdgeInsets()) + return (PresentationResourcesChat.chatInputTextFieldSuggestPostImage(theme), nil, strings.VoiceOver_SuggestPost, 1.0, UIEdgeInsets()) case let .messageAutoremoveTimeout(timeout): if let timeout = timeout { return (nil, shortTimeIntervalString(strings: strings, value: timeout), strings.VoiceOver_SelfDestructTimerOn(timeIntervalString(strings: strings, value: timeout)).string, 1.0, UIEdgeInsets())