diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 8abf2049b6..6816843e53 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -10151,3 +10151,150 @@ Sorry for the inconvenience."; "Stats.Boosts.ShowMoreBoosts_1" = "Show %@ More Boost"; "Stats.Boosts.ShowMoreBoosts_any" = "Show %@ More Boosts"; + +"ReassignBoost.Title" = "Reassign Boosts"; +"ReassignBoost.Description" = "To boost **%1$@**, reassign a previous boost or gift **Telegram Premium** to a friend to get **%2$@** additional boosts."; +"ReassignBoost.ReassignBoosts" = "Reassign Boosts"; +"ReassignBoost.AvailableIn" = "Available in %@"; +"ReassignBoost.ExpiresOn" = "Boost expires on %@"; +"ReassignBoost.WaitForCooldown" = "Wait until the boost is available or get **%1$@** more boosts by gifting a **Telegram Premium** subscription."; + +"ReassignBoost.Success" = "Wait until the boost is available or get **%1$@** more boosts by gifting a **Telegram Premium** subscription."; + +//"\(replacedBoosts) boosts are reassigned from \(inChannels) other channel." + +"ChannelBoost.MoreBoosts.Title" = "More Boosts Needed"; +"ChannelBoost.MoreBoosts.Text" = "To boost **%1$@** again, gift **Telegram Premium** to a friend and get **%2$@** additional boosts."; + +"BoostGift.Title" = "Boosts via Gifts"; +"BoostGift.Description" = "Get more boosts for your channel by gifting\nPremium to your subscribers."; +"BoostGift.PrepaidGiveawayTitle" = "PREPAID GIVEAWAY"; +"BoostGift.PrepaidGiveawayCount_1" = "%@ Telegram Premium"; +"BoostGift.PrepaidGiveawayCount_any" = "%@ Telegram Premium"; +"BoostGift.PrepaidGiveawayMonths" = "%@-month subscriptions"; +"BoostGift.CreateGiveaway" = "Create Giveaway"; +"BoostGift.CreateGiveawayInfo" = "winners are chosen randomly"; +"BoostGift.AwardSpecificUsers" = "Award Specific Users"; +"BoostGift.SelectRecipients" = "select recipients"; +"BoostGift.QuantityTitle" = "QUANTITY OF PRIZES"; +"BoostGift.QuantityBoosts_1" = "%@ BOOST"; +"BoostGift.QuantityBoosts_any" = "%@ BOOSTS"; +"BoostGift.QuantityInfo" = "Choose how many Premium subscriptions to give away and boosts to receive."; +"BoostGift.ChannelsTitle" = "CHANNELS INCLUDED IN THE GIVEAWAY"; +"BoostGift.AddChannel" = "Add Channel"; +"BoostGift.ChannelsBoosts_1" = "this channel will receive %@ boost"; +"BoostGift.ChannelsBoosts_any" = "this channel will receive %@ boosts"; +"BoostGift.ChannelsInfo" = "Choose the channels users need to be subscribed to take part in the giveaway"; +"BoostGift.UsersTitle" = "USERS ELIGIBLE FOR THE GIVEAWAY"; +"BoostGift.FromCountries_1" = "from %@ country"; +"BoostGift.FromCountries_any" = "from %@ countries"; +"BoostGift.FromTwoCountries" = "from %1$@ and %2$@"; +"BoostGift.FromOneCountry" = "from %1$@"; +"BoostGift.FromAllCountries" = "from all countries"; +"BoostGift.AllSubscribers" = "All subscribers"; +"BoostGift.OnlyNewSubscribers" = "Only new subscribers"; +"BoostGift.LimitSubscribersInfo" = "Choose if you want to limit the giveaway only to those who joined the channel after the giveaway started."; +"BoostGift.DateTitle" = "DATE WHEN GIVEAWAY ENDS"; +"BoostGift.DateEnds" = "Ends"; +"BoostGift.DateInfo" = "Choose when %1$@ of your channel will be randomly selected to receive Telegram Premium."; +"BoostGift.DateInfoSubscribers_1" = "%@ subscriber"; +"BoostGift.DateInfoSubscribers_any" = "%@ subscribers"; +"BoostGift.DurationTitle" = "DURATION OF PREMIUM SUBSCRIPTIONS"; +"BoostGift.PremiumInfo" = "You can review the list of features and terms of use for Telegram Premium [here]()."; +"BoostGift.GiftPremium" = "Gift Premium"; +"BoostGift.StartGiveaway" = "Start Giveaway"; +"BoostGift.ReduceQuantity.Title" = "Reduce Quantity"; +"BoostGift.ReduceQuantity.Text" = "You can't acquire %1$@ %2$@-month subscriptions in the app. Do you want to reduce quantity to %3$@?"; +"BoostGift.ReduceQuantity.Reduce" = "Reduce"; +"BoostGift.GiveawayCreated.Title" = "Giveaway Created"; +"BoostGift.GiveawayCreated.Text" = "Check your channel's [Statistics]() to see how this giveaway boosted your channel."; +"BoostGift.PremiumGifted.Title" = "Premium Subscriptions Gifted"; +"BoostGift.PremiumGifted.Text" = "Check your channel's [Statistics]() to see how gifts boosted your channel."; + +"BoostGift.Subscribers.Title" = "Gift Premium"; +"BoostGift.Subscribers.Subtitle" = "select up to %@ subscribers"; +"BoostGift.Subscribers.SectionTitle" = "SUBSCRIBERS"; +"BoostGift.Subscribers.Joined" = "joined %@"; +"BoostGift.Subscribers.Search" = "Search Subscribers"; +"BoostGift.Subscribers.MaximumReached" = "You can select maximum %@ subscribers."; +"BoostGift.Subscribers.Save" = "Save Recipients"; + +"BoostGift.Channels.Title" = "Add Channels"; +"BoostGift.Channels.Subtitle" = "select up to %@ channels"; +"BoostGift.Channels.SectionTitle" = "CHANNELS"; +"BoostGift.Channels.Search" = "Search Channels"; +"BoostGift.Channels.MaximumReached" = "You can select maximum %@ channels."; +"BoostGift.Channels.PrivateChannel.Title" = "Channel is Private"; +"BoostGift.Channels.PrivateChannel.Text" = "Are you sure you want to add a private channel? Users won't be able to join it without an invite link."; +"BoostGift.Channels.PrivateChannel.Add" = "Add"; +"BoostGift.Channels.Save" = "Save Channels"; + +"Stats.Boosts.PrepaidGiveawaysTitle" = "PREPAID GIVEAWAYS"; +"Stats.Boosts.PrepaidGiveawayCount_any" = "%@ Telegram Premium"; +"Stats.Boosts.PrepaidGiveawayMonths" = "%@-month subscriptions"; +"Stats.Boosts.PrepaidGiveawaysInfo" = "Select a giveaway you already paid for to set it up."; +"Stats.Boosts.ShortMonth" = "%@m"; +"Stats.Boosts.Giveaway" = "Giveaway"; +"Stats.Boosts.Gift" = "Gift"; +"Stats.Boosts.TabBoosts_1" = "%@ Boost"; +"Stats.Boosts.TabBoosts_any" = "%@ Boosts"; +"Stats.Boosts.TabGifts_1" = "%@ Boost"; +"Stats.Boosts.TabGifts_any" = "%@ Boosts"; +"Stats.Boosts.ToBeDistributed" = "To Be Distributed"; +"Stats.Boosts.Unclaimed" = "Unclaimed"; +"Stats.Boosts.GetBoosts" = "Get Boosts via Gifts"; +"Stats.Boosts.GetBoostsInfo" = "Get more boosts for your channel by gifting Premium to your subscribers."; + +"Notification.PremiumPrize.Title" = "Congratulations!"; +"Notification.PremiumPrize.UnclaimedText" = "You have an unclaimed prize from a giveaway by **%1$@**.\n\nThis prize is a **Telegram Premium** subscription for %2$@."; +"Notification.PremiumPrize.GiveawayText" = "You won a prize in a giveaway organized by **%1$@**.\n\nYour prize is a **Telegram Premium** subscription for %2$@."; +"Notification.PremiumPrize.GiftText" = "You've received a gift from **%1$@**.\n\nYour gift is a **Telegram Premium** subscription for %2$@."; +"Notification.PremiumPrize.Months_1" = "**%@** month"; +"Notification.PremiumPrize.Months_any" = "**%@** months"; +"Notification.PremiumPrize.View" = "Open Gift Link"; +"Notification.PremiumPrize.Unclaimed" = "Unclaimed Prize"; + +"Story.SlideToSeek" = "Slide left or right to seek"; +"Story.Guide.Title" = "Watching Stories"; +"Story.Guide.Description" = "You can use these gestures to control playback."; +"Story.Guide.ForwardTitle" = "Go forward"; +"Story.Guide.ForwardDescription" = "Tap the screen"; +"Story.Guide.PauseTitle" = "Pause and Seek"; +"Story.Guide.PauseDescription" = "Hold and move sideways"; +"Story.Guide.BackTitle" = "Go back"; +"Story.Guide.BackDescription" = "Tap the left edge"; +"Story.Guide.MoveTitle" = "Move between stories"; +"Story.Guide.MoveDescription" = "Swipe left or right"; +"Story.Guide.Proceed" = "Tap to keep watching"; + +"Chat.Giveaway.Info.Title" = "About This Giveaway"; +"Chat.Giveaway.Info.EndedTitle" = "Giveaway Ended"; + +"Chat.Giveaway.Info.AlmostOver" = "The giveaway is almost over."; + +"Chat.Giveaway.Info.Subscriptions_1" = "**%@ Telegram Premium** subscription"; +"Chat.Giveaway.Info.Subscriptions_any" = "**%@ Telegram Premium** subscriptions"; + +"Chat.Giveaway.Info.RandomUsers_1" = "**%@** random user"; +"Chat.Giveaway.Info.RandomUsers_any" = "**%@** random user"; + +"Chat.Giveaway.Info.RandomSubscribers_1" = "**%@** random subscriber"; +"Chat.Giveaway.Info.RandomSubscribers_any" = "**%@** random subscribers"; + +"Chat.Giveaway.Info.Months_1" = "**%@** month"; +"Chat.Giveaway.Info.Months_any" = "**%@** months"; + +"Chat.Giveaway.Info.ActivatedLinks_1" = "%@ winner already used their gift link."; +"Chat.Giveaway.Info.ActivatedLinks_any" = "%@ of the winners already used their gift links."; + +"Chat.Giveaway.Info.Refunded" = "The channel cancelled the prizes by reversing the payment for them."; +"Chat.Giveaway.Info.Won" = "You won a prize in this giveaway. %@"; +"Chat.Giveaway.Info.DidntWin" = "You didn't win a prize in this giveaway."; +"Chat.Giveaway.Info.ViewPrize" = "View My Prize"; + +"Chat.Giveaway.Toast.NotAllowed" = "You can't participate in this giveaway."; +"Chat.Giveaway.Toast.Participating" = "You are participating in this giveaway."; +"Chat.Giveaway.Toast.NotQualified" = "You are not qualified for this giveaway yet."; +"Chat.Giveaway.Toast.AlmostOver" = "The giveaway is almost over."; +"Chat.Giveaway.Toast.Ended" = "The giveaway is ended."; +"Chat.Giveaway.Toast.LearnMore" = "Learn More"; diff --git a/submodules/PremiumUI/BUILD b/submodules/PremiumUI/BUILD index 4f360fed21..b6cff081e2 100644 --- a/submodules/PremiumUI/BUILD +++ b/submodules/PremiumUI/BUILD @@ -109,6 +109,7 @@ swift_library( "//submodules/CountrySelectionUI", "//submodules/TelegramUI/Components/Stories/PeerListItemComponent", "//submodules/InvisibleInkDustNode", + "//submodules/AlertUI", ], visibility = [ "//visibility:public", diff --git a/submodules/PremiumUI/Sources/CreateGiveawayController.swift b/submodules/PremiumUI/Sources/CreateGiveawayController.swift index fde0cc2f57..817742e941 100644 --- a/submodules/PremiumUI/Sources/CreateGiveawayController.swift +++ b/submodules/PremiumUI/Sources/CreateGiveawayController.swift @@ -377,8 +377,7 @@ private enum CreateGiveawayEntry: ItemListNodeEntry { case let .channelsHeader(_, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .channel(_, _, peer, boosts, isRevealed): - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: presentationData.nameDisplayOrder, context: arguments.context, peer: peer, presence: nil, text: boosts.flatMap { .text("this channel will receive \($0) boosts", .secondary) } ?? .none, label: .none, editing: ItemListPeerItemEditing(editable: boosts == nil, editing: false, revealed: isRevealed), switchValue: nil, enabled: true, selectable: peer.id != arguments.context.account.peerId, sectionId: self.section, action: { -// arguments.openPeer(peer) + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: presentationData.nameDisplayOrder, context: arguments.context, peer: peer, presence: nil, text: boosts.flatMap { .text(presentationData.strings.BoostGift_ChannelsBoosts($0), .secondary) } ?? .none, label: .none, editing: ItemListPeerItemEditing(editable: boosts == nil, editing: false, revealed: isRevealed), switchValue: nil, enabled: true, selectable: peer.id != arguments.context.account.peerId, sectionId: self.section, action: { }, setPeerIdWithRevealedOptions: { lhs, rhs in arguments.setItemIdWithRevealedOptions(lhs, rhs) }, removePeer: { id in @@ -433,7 +432,7 @@ private enum CreateGiveawayEntry: ItemListNodeEntry { } else { text = presentationData.strings.InviteLink_Create_TimeLimitExpiryDateNever } - return ItemListDisclosureItem(presentationData: presentationData, title: "Ends", label: text, labelStyle: active ? .coloredText(theme.list.itemAccentColor) : .text, sectionId: self.section, style: .blocks, disclosureStyle: .none, action: { + return ItemListDisclosureItem(presentationData: presentationData, title: presentationData.strings.BoostGift_DateEnds, label: text, labelStyle: active ? .coloredText(theme.list.itemAccentColor) : .text, sectionId: self.section, style: .blocks, disclosureStyle: .none, action: { arguments.dismissInput() var focus = false arguments.updateState { state in @@ -515,7 +514,7 @@ private func createGiveawayControllerEntries( switch subject { case .generic: - entries.append(.createGiveaway(presentationData.theme, "Create Giveaway", "winners are chosen randomly", state.mode == .giveaway)) + entries.append(.createGiveaway(presentationData.theme, presentationData.strings.BoostGift_CreateGiveaway, presentationData.strings.BoostGift_CreateGiveawayInfo, state.mode == .giveaway)) let recipientsText: String if !state.peers.isEmpty { @@ -533,22 +532,22 @@ private func createGiveawayControllerEntries( recipientsText = presentationData.strings.PremiumGift_LabelRecipients(Int32(peersCount)) } } else { - recipientsText = "select recipients" + recipientsText = presentationData.strings.BoostGift_SelectRecipients } - entries.append(.awardUsers(presentationData.theme, "Award Specific Users", recipientsText, state.mode == .gift)) + entries.append(.awardUsers(presentationData.theme, presentationData.strings.BoostGift_AwardSpecificUsers, recipientsText, state.mode == .gift)) case let .prepaid(prepaidGiveaway): - entries.append(.prepaidHeader(presentationData.theme, "PREPAID GIVEAWAY")) - entries.append(.prepaid(presentationData.theme, "\(prepaidGiveaway.quantity) Telegram Premium", "\(prepaidGiveaway.months)-month subscriptions", prepaidGiveaway)) + entries.append(.prepaidHeader(presentationData.theme, presentationData.strings.BoostGift_PrepaidGiveawayTitle)) + entries.append(.prepaid(presentationData.theme, presentationData.strings.BoostGift_PrepaidGiveawayCount(prepaidGiveaway.quantity), presentationData.strings.BoostGift_PrepaidGiveawayMonths("\(prepaidGiveaway.months)").string, prepaidGiveaway)) } if case .giveaway = state.mode { if case .generic = subject { - entries.append(.subscriptionsHeader(presentationData.theme, "QUANTITY OF PRIZES".uppercased(), "\(state.subscriptions * 4) BOOSTS")) + entries.append(.subscriptionsHeader(presentationData.theme, presentationData.strings.BoostGift_QuantityTitle.uppercased(), presentationData.strings.BoostGift_QuantityBoosts(state.subscriptions * 4))) entries.append(.subscriptions(presentationData.theme, state.subscriptions)) - entries.append(.subscriptionsInfo(presentationData.theme, "Choose how many Premium subscriptions to give away and boosts to receive.")) + entries.append(.subscriptionsInfo(presentationData.theme, presentationData.strings.BoostGift_QuantityInfo)) } - entries.append(.channelsHeader(presentationData.theme, "CHANNELS INCLUDED IN THE GIVEAWAY".uppercased())) + entries.append(.channelsHeader(presentationData.theme, presentationData.strings.BoostGift_ChannelsTitle.uppercased())) var index: Int32 = 0 let channels = [peerId] + state.channels for channelId in channels { @@ -557,35 +556,44 @@ private func createGiveawayControllerEntries( } index += 1 } - entries.append(.channelAdd(presentationData.theme, "Add Channel")) - entries.append(.channelsInfo(presentationData.theme, "Choose the channels users need to be subscribed to take part in the giveaway")) + entries.append(.channelAdd(presentationData.theme, presentationData.strings.BoostGift_AddChannel)) + entries.append(.channelsInfo(presentationData.theme, presentationData.strings.BoostGift_ChannelsInfo)) - entries.append(.usersHeader(presentationData.theme, "USERS ELIGIBLE FOR THE GIVEAWAY".uppercased())) + entries.append(.usersHeader(presentationData.theme, presentationData.strings.BoostGift_UsersTitle.uppercased())) let countriesText: String if state.countries.count > 2 { - countriesText = "from \(state.countries.count) countries" + countriesText = presentationData.strings.BoostGift_FromCountries(Int32(state.countries.count)) } else if !state.countries.isEmpty { - let allCountries = state.countries.map { locale.localizedString(forRegionCode: $0) ?? $0 }.joined(separator: " and ") - countriesText = "from \(allCountries)" + if state.countries.count == 2 { + let firstCountryCode = state.countries.first ?? "" + let secondCountryCode = state.countries.last ?? "" + let firstCountryName = locale.localizedString(forRegionCode: firstCountryCode) ?? firstCountryCode + let secondCountryName = locale.localizedString(forRegionCode: secondCountryCode) ?? secondCountryCode + countriesText = presentationData.strings.BoostGift_FromTwoCountries(firstCountryName, secondCountryName).string + } else { + let countryCode = state.countries.first ?? "" + let countryName = locale.localizedString(forRegionCode: countryCode) ?? countryCode + countriesText = presentationData.strings.BoostGift_FromOneCountry(countryName).string + } } else { - countriesText = "from all countries" + countriesText = presentationData.strings.BoostGift_FromAllCountries } - entries.append(.usersAll(presentationData.theme, "All subscribers", countriesText, !state.onlyNewEligible)) - entries.append(.usersNew(presentationData.theme, "Only new subscribers", countriesText, state.onlyNewEligible)) - entries.append(.usersInfo(presentationData.theme, "Choose if you want to limit the giveaway only to those who joined the channel after the giveaway started.")) + entries.append(.usersAll(presentationData.theme, presentationData.strings.BoostGift_AllSubscribers, countriesText, !state.onlyNewEligible)) + entries.append(.usersNew(presentationData.theme, presentationData.strings.BoostGift_OnlyNewSubscribers, countriesText, state.onlyNewEligible)) + entries.append(.usersInfo(presentationData.theme, presentationData.strings.BoostGift_LimitSubscribersInfo)) - entries.append(.timeHeader(presentationData.theme, "DATE WHEN GIVEAWAY ENDS".uppercased())) + entries.append(.timeHeader(presentationData.theme, presentationData.strings.BoostGift_DateTitle.uppercased())) entries.append(.timeExpiryDate(presentationData.theme, presentationData.dateTimeFormat, state.time, state.pickingTimeLimit)) if state.pickingTimeLimit { entries.append(.timeCustomPicker(presentationData.theme, presentationData.dateTimeFormat, state.time, minDate, maxDate)) } - entries.append(.timeInfo(presentationData.theme, "Choose when \(state.subscriptions) subscribers of your channel will be randomly selected to receive Telegram Premium.")) + entries.append(.timeInfo(presentationData.theme, presentationData.strings.BoostGift_DateInfo(presentationData.strings.BoostGift_DateInfoSubscribers(Int32(state.subscriptions))).string)) } if case .generic = subject { - entries.append(.durationHeader(presentationData.theme, "DURATION OF PREMIUM SUBSCRIPTIONS".uppercased())) + entries.append(.durationHeader(presentationData.theme, presentationData.strings.BoostGift_DurationTitle.uppercased())) let recipientCount: Int switch state.mode { @@ -628,7 +636,7 @@ private func createGiveawayControllerEntries( i += 1 } - entries.append(.durationInfo(presentationData.theme, "You can review the list of features and terms of use for Telegram Premium [here]().")) + entries.append(.durationInfo(presentationData.theme, presentationData.strings.BoostGift_PremiumInfo)) } return entries @@ -776,7 +784,7 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio let (state, peersMap) = stateAndPeersMap - let headerItem = CreateGiveawayHeaderItem(theme: presentationData.theme, title: "Boosts via Gifts", text: "Get more boosts for your channel by gifting\nPremium to your subscribers.", cancel: { + let headerItem = CreateGiveawayHeaderItem(theme: presentationData.theme, strings: presentationData.strings, title: presentationData.strings.BoostGift_Title, text: presentationData.strings.BoostGift_Description, cancel: { dismissImpl?() }) @@ -787,7 +795,7 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio case .gift: badgeCount = Int32(state.peers.count) } - let footerItem = CreateGiveawayFooterItem(theme: presentationData.theme, title: state.mode == .gift ? "Gift Premium" : "Start Giveaway", badgeCount: badgeCount, isLoading: state.updating, action: { + let footerItem = CreateGiveawayFooterItem(theme: presentationData.theme, title: state.mode == .gift ? presentationData.strings.BoostGift_GiftPremium : presentationData.strings.BoostGift_StartGiveaway, badgeCount: badgeCount, isLoading: state.updating, action: { buyActionImpl?() }) let leftNavigationButton = ItemListNavigationButton(content: .none, style: .regular, enabled: false, action: {}) @@ -857,7 +865,7 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio } guard let selectedProduct else { - let alertController = textAlertController(context: context, title: "Reduce Quantity", text: "You can't acquire \(state.subscriptions) \(selectedMonths)-month subscriptions in the app. Do you want to reduce quantity to 25?", actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: "Reduce", action: { + let alertController = textAlertController(context: context, title: presentationData.strings.BoostGift_ReduceQuantity_Title, text: presentationData.strings.BoostGift_ReduceQuantity_Text("\(state.subscriptions)", "\(selectedMonths)", "\(25)").string, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.BoostGift_ReduceQuantity_Reduce, action: { updateState { state in var updatedState = state updatedState.subscriptions = 25 @@ -915,11 +923,11 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio let text: String switch state.mode { case .giveaway: - title = "Giveaway Created" - text = "Check your channel's [Statistics]() to see how this giveaway boosted your channel." + title = presentationData.strings.BoostGift_GiveawayCreated_Title + text = presentationData.strings.BoostGift_GiveawayCreated_Text case .gift: - title = "Premium Subscriptions Gifted" - text = "Check your channel's [Statistics]() to see how gifts boosted your channel." + title = presentationData.strings.BoostGift_PremiumGifted_Title + text = presentationData.strings.BoostGift_PremiumGifted_Text } let tooltipController = UndoOverlayController(presentationData: presentationData, content: .premiumPaywall(title: title, text: text, customUndoText: nil, timeout: nil, linkAction: { [weak navigationController] _ in @@ -992,8 +1000,8 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio controllers.removeLast(count) navigationController.setViewControllers(controllers, animated: true) - let title = "Giveaway Created" - let text = "Check your channel's [Statistics]() to see how this giveaway boosted your channel." + let title = presentationData.strings.BoostGift_GiveawayCreated_Title + let text = presentationData.strings.BoostGift_GiveawayCreated_Text let tooltipController = UndoOverlayController(presentationData: presentationData, content: .premiumPaywall(title: title, text: text, customUndoText: nil, timeout: nil, linkAction: { [weak navigationController] _ in let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.StatsDatacenterId(id: peerId)) diff --git a/submodules/PremiumUI/Sources/CreateGiveawayHeaderItem.swift b/submodules/PremiumUI/Sources/CreateGiveawayHeaderItem.swift index 7e540dbaa5..daeb42a2e0 100644 --- a/submodules/PremiumUI/Sources/CreateGiveawayHeaderItem.swift +++ b/submodules/PremiumUI/Sources/CreateGiveawayHeaderItem.swift @@ -11,12 +11,14 @@ import ComponentFlow final class CreateGiveawayHeaderItem: ItemListControllerHeaderItem { let theme: PresentationTheme + let strings: PresentationStrings let title: String let text: String let cancel: () -> Void - init(theme: PresentationTheme, title: String, text: String, cancel: @escaping () -> Void) { + init(theme: PresentationTheme, strings: PresentationStrings, title: String, text: String, cancel: @escaping () -> Void) { self.theme = theme + self.strings = strings self.title = title self.text = text self.cancel = cancel @@ -132,7 +134,7 @@ class CreateGiveawayHeaderItemNode: ItemListControllerHeaderItemNode { self.titleNode.attributedText = attributedTitle self.textNode.attributedText = attributedText - self.cancelNode.setAttributedTitle(NSAttributedString(string: "Cancel", font: Font.regular(17.0), textColor: self.item.theme.rootController.navigationBar.accentTextColor), for: .normal) + self.cancelNode.setAttributedTitle(NSAttributedString(string: self.item.strings.Common_Cancel, font: Font.regular(17.0), textColor: self.item.theme.rootController.navigationBar.accentTextColor), for: .normal) } override func updateContentOffset(_ contentOffset: CGFloat, transition: ContainedViewLayoutTransition) { diff --git a/submodules/TelegramUI/Sources/GiveawayInfoAlertController.swift b/submodules/PremiumUI/Sources/GiveawayInfoController.swift similarity index 57% rename from submodules/TelegramUI/Sources/GiveawayInfoAlertController.swift rename to submodules/PremiumUI/Sources/GiveawayInfoController.swift index 8234b52419..63f22ffc38 100644 --- a/submodules/TelegramUI/Sources/GiveawayInfoAlertController.swift +++ b/submodules/PremiumUI/Sources/GiveawayInfoController.swift @@ -4,12 +4,161 @@ import AsyncDisplayKit import Display import SwiftSignalKit import TelegramCore -import TelegramPresentationData -import TextFormat import AccountContext -import AlertUI -import PresentationDataUtils +import TelegramStringFormatting +import TelegramPresentationData import Markdown +import AlertUI + +public func giveawayInfoController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, message: EngineMessage, giveawayInfo: PremiumGiveawayInfo) -> ViewController? { + guard let giveaway = message.media.first(where: { $0 is TelegramMediaGiveaway }) as? TelegramMediaGiveaway else { + return nil + } + + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + + var peerName = "" + if let peerId = giveaway.channelPeerIds.first, let peer = message.peers[peerId] { + peerName = EnginePeer(peer).compactDisplayTitle + } + + let untilDate = stringForDate(timestamp: giveaway.untilDate, strings: presentationData.strings) + + let title: String + let text: String + var warning: String? + + var dismissImpl: (() -> Void)? + + var actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: { + dismissImpl?() + })] + + switch giveawayInfo { + case let .ongoing(start, status): + let startDate = stringForDate(timestamp: start, strings: presentationData.strings) + + title = presentationData.strings.Chat_Giveaway_Info_Title + + let intro: String + if case .almostOver = status { + intro = "The giveaway was sponsored by the admins of **\(peerName)**, who acquired **\(giveaway.quantity) Telegram Premium** subscriptions for **\(giveaway.months)** months for its followers." + } else { + intro = "The giveaway is sponsored by the admins of **\(peerName)**, who acquired **\(giveaway.quantity) Telegram Premium** subscriptions for **\(giveaway.months)** months for its followers." + } + + let ending: String + if giveaway.flags.contains(.onlyNewSubscribers) { + if giveaway.channelPeerIds.count > 1 { + ending = "On **\(untilDate)**, Telegram will automatically select **\(giveaway.quantity)** random users that joined **\(peerName)** and **\(giveaway.channelPeerIds.count - 1)** other listed channels after **\(startDate)**." + } else { + ending = "On **\(untilDate)**, Telegram will automatically select **\(giveaway.quantity)** random users that joined **\(peerName)** after **\(startDate)**." + } + } else { + if giveaway.channelPeerIds.count > 1 { + ending = "On **\(untilDate)**, Telegram will automatically select **\(giveaway.quantity)** random subscribers of **\(peerName)** and **\(giveaway.channelPeerIds.count - 1)** other listed channels." + } else { + ending = "On **\(untilDate)**, Telegram will automatically select **\(giveaway.quantity)** random subscribers of **\(peerName)**." + } + } + + var participation: String + switch status { + case .notQualified: + if giveaway.channelPeerIds.count > 1 { + participation = "To take part in this giveaway please join the channel **\(peerName)** (**\(giveaway.channelPeerIds.count - 1)** other listed channels) before **\(untilDate)**." + } else { + participation = "To take part in this giveaway please join the channel **\(peerName)** before **\(untilDate)**." + } + case let .notAllowed(reason): + switch reason { + case let .joinedTooEarly(joinedOn): + let joinDate = stringForDate(timestamp: joinedOn, strings: presentationData.strings) + participation = "You are not eligible to participate in this giveaway, because you joined this channel on **\(joinDate)**, which is before the contest started." + case let .channelAdmin(adminId): + let _ = adminId + participation = "You are not eligible to participate in this giveaway, because you are an admin of participating channel (**\(peerName)**)." + case let .disallowedCountry(countryCode): + let _ = countryCode + participation = "You are not eligible to participate in this giveaway, because your country is not included in the terms of the giveaway." + } + case .participating: + if giveaway.channelPeerIds.count > 1 { + participation = "You are participating in this giveaway, because you have joined the channel **\(peerName)** (**\(giveaway.channelPeerIds.count - 1)** other listed channels)." + } else { + participation = "You are participating in this giveaway, because you have joined the channel **\(peerName)**." + } + case .almostOver: + participation = presentationData.strings.Chat_Giveaway_Info_AlmostOver + } + + if !participation.isEmpty { + participation = "\n\n\(participation)" + } + + text = "\(intro)\n\n\(ending)\(participation)" + case let .finished(status, start, finish, _, activatedCount): + let startDate = stringForDate(timestamp: start, strings: presentationData.strings) + let finishDate = stringForDate(timestamp: finish, strings: presentationData.strings) + title = presentationData.strings.Chat_Giveaway_Info_EndedTitle + + let intro = "The giveaway was sponsored by the admins of **\(peerName)**, who acquired **\(giveaway.quantity) Telegram Premium** subscriptions for **\(giveaway.months)** months for its followers." + + var ending: String + if giveaway.flags.contains(.onlyNewSubscribers) { + if giveaway.channelPeerIds.count > 1 { + ending = "On **\(finishDate)**, Telegram automatically selected **\(giveaway.quantity)** random users that joined **\(peerName)** and other listed channels after **\(startDate)**." + } else { + ending = "On **\(finishDate)**, Telegram automatically selected **\(giveaway.quantity)** random users that joined **\(peerName)** after **\(startDate)**." + } + } else { + if giveaway.channelPeerIds.count > 1 { + ending = "On **\(finishDate)**, Telegram automatically selected **\(giveaway.quantity)** random subscribers of **\(peerName)** and other listed channels." + } else { + ending = "On **\(finishDate)**, Telegram automatically selected **\(giveaway.quantity)** random subscribers of **\(peerName)**." + } + } + + if activatedCount > 0 { + ending += " " + presentationData.strings.Chat_Giveaway_Info_ActivatedLinks(activatedCount) + } + + var result: String + switch status { + case .refunded: + result = "" + warning = presentationData.strings.Chat_Giveaway_Info_Refunded + actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Close, action: { + dismissImpl?() + })] + case .notWon: + result = "\n\n" + presentationData.strings.Chat_Giveaway_Info_DidntWin + case let .won(slug): + result = "\n\n" + presentationData.strings.Chat_Giveaway_Info_Won("🏆").string + let _ = slug + actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Chat_Giveaway_Info_ViewPrize, action: { + dismissImpl?() + }), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { + dismissImpl?() + })] + } + + text = "\(intro)\n\n\(ending)\(result)" + } + + let alertController = giveawayInfoAlertController( + context: context, + updatedPresentationData: updatedPresentationData, + title: title, + text: text, + warning: warning, + actions: actions + ) + dismissImpl = { [weak alertController] in + alertController?.dismissAnimated() + } + return alertController +} private final class GiveawayInfoAlertContentNode: AlertContentNode { private let title: String @@ -229,7 +378,7 @@ private final class GiveawayInfoAlertContentNode: AlertContentNode { } } -func giveawayInfoAlertController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, title: String, text: String, warning: String?, actions: [TextAlertAction]) -> AlertController { +private func giveawayInfoAlertController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, title: String, text: String, warning: String?, actions: [TextAlertAction]) -> AlertController { let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 } let contentNode = GiveawayInfoAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), ptheme: presentationData.theme, title: title, text: text, warning: warning, actions: actions) diff --git a/submodules/PremiumUI/Sources/PremiumBoostScreen.swift b/submodules/PremiumUI/Sources/PremiumBoostScreen.swift index 7c553d8ab9..43e9185b8d 100644 --- a/submodules/PremiumUI/Sources/PremiumBoostScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumBoostScreen.swift @@ -186,8 +186,8 @@ public func PremiumBoostScreen( let controller = textAlertController( sharedContext: context.sharedContext, updatedPresentationData: nil, - title: "More Boosts Needed", - text: "To boost **\(peer.compactDisplayTitle)** again, gift **Telegram Premium** to a friend and get **\(premiumConfiguration.boostsPerGiftCount)** additional boosts.", + title: presentationData.strings.ChannelBoost_MoreBoosts_Title, + text: presentationData.strings.ChannelBoost_MoreBoosts_Text(peer.compactDisplayTitle, "\(premiumConfiguration.boostsPerGiftCount)").string, actions: [ TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {}) ], diff --git a/submodules/PremiumUI/Sources/PremiumGiftCodeScreen.swift b/submodules/PremiumUI/Sources/PremiumGiftCodeScreen.swift index 359dbbe29e..e0b8045319 100644 --- a/submodules/PremiumUI/Sources/PremiumGiftCodeScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumGiftCodeScreen.swift @@ -22,6 +22,7 @@ import TelegramStringFormatting import UndoUI import InvisibleInkDustNode +//TODO:localize private final class PremiumGiftCodeSheetContent: CombinedComponent { typealias EnvironmentType = ViewControllerComponentContainer.Environment diff --git a/submodules/PremiumUI/Sources/ReplaceBoostScreen.swift b/submodules/PremiumUI/Sources/ReplaceBoostScreen.swift index 4091d712b8..b87262f2c0 100644 --- a/submodules/PremiumUI/Sources/ReplaceBoostScreen.swift +++ b/submodules/PremiumUI/Sources/ReplaceBoostScreen.swift @@ -19,8 +19,6 @@ import PeerListItemComponent import TelegramStringFormatting import AvatarNode -//TODO:localize - private final class ReplaceBoostScreenComponent: CombinedComponent { typealias EnvironmentType = ViewControllerComponentContainer.Environment @@ -172,7 +170,7 @@ private final class ReplaceBoostScreenComponent: CombinedComponent { if channelName.count > 48 { channelName = "\(channelName.prefix(48))..." } - let descriptionString = "To boost **\(channelName)**, reassign a previous boost or gift **Telegram Premium** to a friend to get **\(premiumConfiguration.boostsPerGiftCount)** additional boosts." + let descriptionString = strings.ReassignBoost_Description(channelName, "\(premiumConfiguration.boostsPerGiftCount)").string let description = description.update( component: MultilineTextComponent( @@ -204,11 +202,11 @@ private final class ReplaceBoostScreenComponent: CombinedComponent { if let cooldownUntil = boost.cooldownUntil, cooldownUntil > state.currentTime { let duration = cooldownUntil - state.currentTime let durationValue = stringForDuration(duration, position: nil) - subtitle = "Available in \(durationValue)" + subtitle = strings.ReassignBoost_AvailableIn(durationValue).string isEnabled = false } else { let expiresValue = stringForDate(timestamp: boost.expires, strings: strings) - subtitle = "Boost expires on \(expiresValue)" + subtitle = strings.ReassignBoost_ExpiresOn(expiresValue).string } let accountContext = context.component.context @@ -245,7 +243,8 @@ private final class ReplaceBoostScreenComponent: CombinedComponent { selectedSlotsUpdated(state.selectedSlots) } else { let presentationData = accountContext.sharedContext.currentPresentationData.with { $0 } - let undoController = UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: "Wait until the boost is available or get **3** more boosts by gifting a **Telegram Premium** subscription.", timeout: nil, customUndoText: nil), elevatedLayout: false, position: .top, action: { _ in return true }) + + let undoController = UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: strings.ReassignBoost_WaitForCooldown("\(premiumConfiguration.boostsPerGiftCount)").string, timeout: nil, customUndoText: nil), elevatedLayout: false, position: .top, action: { _ in return true }) presentController(undoController) } }) @@ -559,7 +558,7 @@ public class ReplaceBoostScreen: ViewController { let footerInsets = UIEdgeInsets(top: 0.0, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.safeInsets.right) transition.setFrame(view: self.footerView, frame: CGRect(origin: CGPoint(x: 0.0, y: -topInset), size: layout.size)) - self.footerHeight = self.footerView.update(size: layout.size, insets: footerInsets, theme: self.presentationData.theme, count: Int32(self.selectedSlots.count)) + self.footerHeight = self.footerView.update(size: layout.size, insets: footerInsets, theme: self.presentationData.theme, strings: self.presentationData.strings, count: Int32(self.selectedSlots.count)) if !hadLayout { self.updateFooterAlpha() @@ -838,9 +837,9 @@ public class ReplaceBoostScreen: ViewController { presentControllerImpl?(c) })) - self.title = "Reassign Boosts" + self.title = presentationData.strings.ReassignBoost_Title - self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Close, style: .plain, target: self, action: #selector(self.cancelPressed)) + self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed)) self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait) @@ -984,10 +983,10 @@ private final class FooterView: UIView { fileprivate var inProgress = false - private var currentLayout: (CGSize, UIEdgeInsets, PresentationTheme, Int32)? - func update(size: CGSize, insets: UIEdgeInsets, theme: PresentationTheme, count: Int32) -> CGFloat { + private var currentLayout: (CGSize, UIEdgeInsets, PresentationTheme, PresentationStrings, Int32)? + func update(size: CGSize, insets: UIEdgeInsets, theme: PresentationTheme, strings: PresentationStrings, count: Int32) -> CGFloat { let hadLayout = self.currentLayout != nil - self.currentLayout = (size, insets, theme, count) + self.currentLayout = (size, insets, theme, strings, count) self.backgroundNode.updateColor(color: theme.rootController.tabBar.backgroundColor, transition: .immediate) self.separatorView.backgroundColor = theme.rootController.tabBar.separatorColor @@ -1019,7 +1018,7 @@ private final class FooterView: UIView { content: AnyComponentWithIdentity( id: AnyHashable(0), component: AnyComponent(ButtonTextContentComponent( - text: "Reassign Boosts", + text: strings.ReassignBoost_ReassignBoosts, badge: Int(count), textColor: theme.list.itemCheckColors.foregroundColor, badgeBackground: theme.list.itemCheckColors.foregroundColor, @@ -1036,8 +1035,8 @@ private final class FooterView: UIView { return } self.inProgress = true - if let (size, insets, theme, count) = self.currentLayout { - let _ = self.update(size: size, insets: insets, theme: theme, count: count) + if let (size, insets, theme, strings, count) = self.currentLayout { + let _ = self.update(size: size, insets: insets, theme: theme, strings: strings, count: count) } self.action() } diff --git a/submodules/StatisticsUI/Sources/ChannelStatsController.swift b/submodules/StatisticsUI/Sources/ChannelStatsController.swift index 22e1f4084a..30fb591c75 100644 --- a/submodules/StatisticsUI/Sources/ChannelStatsController.swift +++ b/submodules/StatisticsUI/Sources/ChannelStatsController.swift @@ -554,15 +554,15 @@ private enum StatsEntry: ItemListNodeEntry { let expiresString: String let durationMonths = Int32(round(Float(boost.expires - boost.date) / (86400.0 * 30.0))) - let durationString = "\(durationMonths)m" - + let durationString = presentationData.strings.Stats_Boosts_ShortMonth("\(durationMonths)").string + let title: String let icon: GiftOptionItem.Icon var label: String? if boost.flags.contains(.isGiveaway) { - label = "🏆 Giveaway" + label = "🏆 \(presentationData.strings.Stats_Boosts_Giveaway)" } else if boost.flags.contains(.isGift) { - label = "🎁 Gift" + label = "🎁 \(presentationData.strings.Stats_Boosts_Gift)" } let color: GiftOptionItem.Icon.Color @@ -575,7 +575,7 @@ private enum StatsEntry: ItemListNodeEntry { } if boost.flags.contains(.isUnclaimed) { - title = "Unclaimed" + title = presentationData.strings.Stats_Boosts_Unclaimed icon = .image(color: color, name: "Premium/Unclaimed") expiresString = "\(durationString) • \(expiresValue)" } else if let peer = boost.peer { @@ -588,10 +588,10 @@ private enum StatsEntry: ItemListNodeEntry { } } else { if boost.flags.contains(.isUnclaimed) { - title = "Unclaimed" + title = presentationData.strings.Stats_Boosts_Unclaimed icon = .image(color: color, name: "Premium/Unclaimed") } else if boost.flags.contains(.isGiveaway) { - title = "To be distributed" + title = presentationData.strings.Stats_Boosts_ToBeDistributed icon = .image(color: color, name: "Premium/ToBeDistributed") } else { title = "Unknown" @@ -774,15 +774,14 @@ private func channelStatsControllerEntries(state: ChannelStatsControllerState, p entries.append(.boostOverviewTitle(presentationData.theme, presentationData.strings.Stats_Boosts_OverviewHeader)) entries.append(.boostOverview(presentationData.theme, boostData)) -//TODO:localize if !boostData.prepaidGiveaways.isEmpty { - entries.append(.boostPrepaidTitle(presentationData.theme, "PREPAID GIVEAWAYS")) + entries.append(.boostPrepaidTitle(presentationData.theme, presentationData.strings.Stats_Boosts_PrepaidGiveawaysTitle)) var i: Int32 = 0 for giveaway in boostData.prepaidGiveaways { - entries.append(.boostPrepaid(i, presentationData.theme, "\(giveaway.quantity) Telegram Premium", "\(giveaway.months)-month subscriptions", giveaway)) + entries.append(.boostPrepaid(i, presentationData.theme, presentationData.strings.Stats_Boosts_PrepaidGiveawayCount(giveaway.quantity), presentationData.strings.Stats_Boosts_PrepaidGiveawayMonths("\(giveaway.months)").string, giveaway)) i += 1 } - entries.append(.boostPrepaidInfo(presentationData.theme, "Select a giveaway you already paid for to set it up.")) + entries.append(.boostPrepaidInfo(presentationData.theme, presentationData.strings.Stats_Boosts_PrepaidGiveawaysInfo)) } let boostersTitle: String @@ -813,7 +812,7 @@ private func channelStatsControllerEntries(state: ChannelStatsControllerState, p } if boostsCount > 0 && giftsCount > 0 && boostsCount != giftsCount { - entries.append(.boosterTabs(presentationData.theme, "\(boostsCount) Boosts", "\(giftsCount) Gifts", state.giftsSelected)) + entries.append(.boosterTabs(presentationData.theme, presentationData.strings.Stats_Boosts_TabBoosts(boostsCount), presentationData.strings.Stats_Boosts_TabGifts(giftsCount), state.giftsSelected)) } let selectedState: ChannelBoostersContext.State? @@ -853,8 +852,8 @@ private func channelStatsControllerEntries(state: ChannelStatsControllerState, p entries.append(.boostLinkInfo(presentationData.theme, presentationData.strings.Stats_Boosts_LinkInfo)) if giveawayAvailable { - entries.append(.gifts(presentationData.theme, "Get Boosts via Gifts")) - entries.append(.giftsInfo(presentationData.theme, "Get more boosts for your channel by gifting Premium to your subscribers.")) + entries.append(.gifts(presentationData.theme, presentationData.strings.Stats_Boosts_GetBoosts)) + entries.append(.giftsInfo(presentationData.theme, presentationData.strings.Stats_Boosts_GetBoostsInfo)) } } } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift index c1adef884e..a66d96e2dc 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift @@ -189,7 +189,6 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { } } - //TODO:localize override public func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { let makeLabelLayout = TextNode.asyncLayout(self.labelNode) let makeTitleLayout = TextNode.asyncLayout(self.titleNode) @@ -226,24 +225,24 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { textSpacing += 13.0 if unclaimed { - title = "Unclaimed Prize" + title = item.presentationData.strings.Notification_PremiumPrize_Unclaimed } else { - title = "Congratulations!" + title = item.presentationData.strings.Notification_PremiumPrize_Title } var peerName = "" if let channelId, let channel = item.message.peers[channelId] { peerName = EnginePeer(channel).compactDisplayTitle } if unclaimed { - text = "You have an unclaimed prize from a giveaway by **\(peerName)**.\n\nThis prize is a **Telegram Premium** subscription for **\(monthsValue)** months." + text = item.presentationData.strings.Notification_PremiumPrize_UnclaimedText(peerName, item.presentationData.strings.Notification_PremiumPrize_Months(monthsValue)).string } else if fromGiveaway { - text = "You won a prize in a giveaway organized by **\(peerName)**.\n\nYour prize is a **Telegram Premium** subscription for **\(monthsValue)** months." + text = item.presentationData.strings.Notification_PremiumPrize_GiveawayText(peerName, item.presentationData.strings.Notification_PremiumPrize_Months(monthsValue)).string } else { - text = "You've received a gift from **\(peerName)**.\n\nYour gift is a **Telegram Premium** subscription for **\(monthsValue)** months." + text = item.presentationData.strings.Notification_PremiumPrize_GiftText(peerName, item.presentationData.strings.Notification_PremiumPrize_Months(monthsValue)).string } months = monthsValue - buttonTitle = "Open Gift Link" + buttonTitle = item.presentationData.strings.Notification_PremiumPrize_View hasServiceMessage = false default: break diff --git a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift index c16977a4f9..c30cf65537 100644 --- a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift +++ b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift @@ -25,7 +25,6 @@ import TelegramUIPreferences import UndoUI import TelegramStringFormatting -//TODO:localize final class ShareWithPeersScreenComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment @@ -941,9 +940,9 @@ final class ShareWithPeersScreenComponent: Component { sectionTitle = environment.strings.Story_Privacy_WhoCanViewHeader } else if section.id == 1 { if case .members = component.stateContext.subject { - sectionTitle = "SUBSCRIBERS" + sectionTitle = environment.strings.BoostGift_Subscribers_SectionTitle } else if case .channels = component.stateContext.subject { - sectionTitle = "CHANNELS" + sectionTitle = environment.strings.BoostGift_Channels_SectionTitle } else { sectionTitle = environment.strings.Story_Privacy_ContactsHeader } @@ -1390,7 +1389,7 @@ final class ShareWithPeersScreenComponent: Component { } else { if case .members = component.stateContext.subject { if let invitedAt = stateValue.invitedAt[peer.id] { - subtitle = "joined \(stringForMediumDate(timestamp: invitedAt, strings: environment.strings, dateTimeFormat: environment.dateTimeFormat))" + subtitle = environment.strings.BoostGift_Subscribers_Joined(stringForMediumDate(timestamp: invitedAt, strings: environment.strings, dateTimeFormat: environment.dateTimeFormat)).string } else { subtitle = nil } @@ -1445,7 +1444,7 @@ final class ShareWithPeersScreenComponent: Component { self.hapticFeedback.error() let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } - controller.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: "You can select maximum \(component.context.userLimits.maxGiveawayChannelsCount) channels.", timeout: nil, customUndoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false }), in: .current) + controller.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: environment.strings.BoostGift_Channels_MaximumReached("\(component.context.userLimits.maxGiveawayChannelsCount)").string, timeout: nil, customUndoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false }), in: .current) return } if case .channels = component.stateContext.subject { @@ -1453,11 +1452,11 @@ final class ShareWithPeersScreenComponent: Component { let alertController = textAlertController( context: component.context, forceTheme: environment.theme, - title: "Channel is Private", - text: "Are you sure you want to add a private channel? Users won't be able to join it without an invite link.", + title: environment.strings.BoostGift_Channels_PrivateChannel_Title, + text: environment.strings.BoostGift_Channels_PrivateChannel_Text, actions: [ TextAlertAction(type: .genericAction, title: environment.strings.Common_Cancel, action: {}), - TextAlertAction(type: .defaultAction, title: "Add", action: { + TextAlertAction(type: .defaultAction, title: environment.strings.BoostGift_Channels_PrivateChannel_Add, action: { togglePeer() }) ] @@ -1475,7 +1474,7 @@ final class ShareWithPeersScreenComponent: Component { self.hapticFeedback.error() let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } - controller.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: "You can select maximum 10 subscribers.", timeout: nil, customUndoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false }), in: .current) + controller.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: environment.strings.BoostGift_Subscribers_MaximumReached("\(10)").string, timeout: nil, customUndoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false }), in: .current) return } togglePeer() @@ -2018,9 +2017,9 @@ final class ShareWithPeersScreenComponent: Component { let placeholder: String switch component.stateContext.subject { case .members: - placeholder = "Search Subscribers" + placeholder = environment.strings.BoostGift_Subscribers_Search case .channels: - placeholder = "Search Channels" + placeholder = environment.strings.BoostGift_Channels_Search case .chats: placeholder = environment.strings.Story_Privacy_SearchChats default: @@ -2367,13 +2366,13 @@ final class ShareWithPeersScreenComponent: Component { case .contactsSearch: title = "" case .members: - title = "Gift Premium" - actionButtonTitle = "Save Recipients" - subtitle = "select up to 10 subscribers" + title = environment.strings.BoostGift_Subscribers_Title + subtitle = environment.strings.BoostGift_Subscribers_Subtitle("\(10)").string + actionButtonTitle = environment.strings.BoostGift_Subscribers_Save case .channels: - title = "Add Channels" - actionButtonTitle = "Save Channels" - subtitle = "select up to \(component.context.userLimits.maxGiveawayChannelsCount) channels" + title = environment.strings.BoostGift_Channels_Title + subtitle = environment.strings.BoostGift_Channels_Subtitle("\(component.context.userLimits.maxGiveawayChannelsCount)").string + actionButtonTitle = environment.strings.BoostGift_Channels_Save } let titleComponent: AnyComponent diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/MediaNavigationStripComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/MediaNavigationStripComponent.swift index eaed466fe9..1fad133d46 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/MediaNavigationStripComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/MediaNavigationStripComponent.swift @@ -180,8 +180,6 @@ final class MediaNavigationStripComponent: Component { let itemHeight: CGFloat = 2.0 let minItemWidth: CGFloat = 2.0 - var size = CGSize(width: availableSize.width, height: itemHeight) - var didSetCompletion = false var validIndices: [Int] = [] @@ -223,7 +221,6 @@ final class MediaNavigationStripComponent: Component { var itemFrame = CGRect(origin: CGPoint(x: -globalOffset + CGFloat(i) * (itemWidth + spacing), y: 0.0), size: CGSize(width: itemWidth, height: itemHeight)) if component.isSeeking { itemFrame = CGRect(origin: .zero, size: CGSize(width: availableSize.width, height: 6.0)) - size.height = itemFrame.height } if itemFrame.maxX < 0.0 || itemFrame.minX >= availableSize.width { continue diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift index cd9f452654..7f2e080d87 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift @@ -546,6 +546,14 @@ private final class StoryContainerScreenComponent: Component { } self.initialSeekTimestamp = nil self.previousSeekTime = nil + + guard let stateValue = self.stateValue, let slice = stateValue.slice, let itemSetView = self.visibleItemSetViews[slice.peer.id], let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View else { + return + } + guard let visibleItemView = itemSetComponentView.visibleItems[slice.item.storyItem.id]?.view.view as? StoryItemContentComponent.View else { + return + } + visibleItemView.seekEnded() } longPressRecognizer.shouldBegin = { [weak self] touch in guard let self else { diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryInteractionGuideComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryInteractionGuideComponent.swift index b4f5af595d..197632cb9f 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryInteractionGuideComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryInteractionGuideComponent.swift @@ -95,12 +95,13 @@ final class StoryInteractionGuideComponent: Component { self.component = component self.state = state + let strings = component.strings + let sideInset: CGFloat = 48.0 -//TODO:localize let titleSize = self.titleLabel.update( transition: .immediate, - component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: "Watching Stories", font: Font.semibold(20.0), textColor: .white, paragraphAlignment: .center)))), + component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: strings.Story_Guide_Title, font: Font.semibold(20.0), textColor: .white, paragraphAlignment: .center)))), environment: {}, containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: availableSize.height) ) @@ -114,7 +115,7 @@ final class StoryInteractionGuideComponent: Component { let textSize = self.descriptionLabel.update( transition: .immediate, - component: AnyComponent(BalancedTextComponent(text: .plain(NSAttributedString(string: "You can use these gestures to control playback.", font: Font.regular(15.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.6), paragraphAlignment: .center)), maximumNumberOfLines: 0, lineSpacing: 0.2)), + component: AnyComponent(BalancedTextComponent(text: .plain(NSAttributedString(string: strings.Story_Guide_Description, font: Font.regular(15.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.6), paragraphAlignment: .center)), maximumNumberOfLines: 0, lineSpacing: 0.2)), environment: {}, containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: availableSize.height) ) @@ -132,8 +133,8 @@ final class StoryInteractionGuideComponent: Component { component: AnyComponent( GuideItemComponent( context: component.context, - title: "Go forward", - text: "Tap the screen", + title: strings.Story_Guide_ForwardTitle, + text: strings.Story_Guide_ForwardDescription, animationName: "story_forward", isPlaying: self.currentIndex == 0, playbackCompleted: { [weak self] in @@ -151,8 +152,8 @@ final class StoryInteractionGuideComponent: Component { component: AnyComponent( GuideItemComponent( context: component.context, - title: "Pause and Seek", - text: "Hold and move sideways", + title: strings.Story_Guide_PauseTitle, + text: strings.Story_Guide_PauseDescription, animationName: "story_pause", isPlaying: self.currentIndex == 1, playbackCompleted: { [weak self] in @@ -170,8 +171,8 @@ final class StoryInteractionGuideComponent: Component { component: AnyComponent( GuideItemComponent( context: component.context, - title: "Go back", - text: "Tap the left edge", + title: strings.Story_Guide_BackTitle, + text: strings.Story_Guide_BackDescription, animationName: "story_back", isPlaying: self.currentIndex == 2, playbackCompleted: { [weak self] in @@ -189,8 +190,8 @@ final class StoryInteractionGuideComponent: Component { component: AnyComponent( GuideItemComponent( context: component.context, - title: "Move between stories", - text: "Swipe left or right", + title: strings.Story_Guide_MoveTitle, + text: strings.Story_Guide_MoveDescription, animationName: "story_move", isPlaying: self.currentIndex == 3, playbackCompleted: { [weak self] in @@ -222,7 +223,7 @@ final class StoryInteractionGuideComponent: Component { let buttonSize = self.proceedButton.update( transition: .immediate, component: AnyComponent(Button( - content: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: "Tap to keep watching", font: Font.semibold(17.0), textColor: .white, paragraphAlignment: .center)))), + content: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: strings.Story_Guide_Proceed, font: Font.semibold(17.0), textColor: .white, paragraphAlignment: .center)))), action: { [weak self] in self?.handleTap() } diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemContentComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemContentComponent.swift index 40ec787d68..33a5a51fc0 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemContentComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemContentComponent.swift @@ -277,7 +277,9 @@ final class StoryItemContentComponent: Component { } self.videoPlaybackStatus = status - self.updateVideoPlaybackProgress() + if !self.isSeeking { + self.updateVideoPlaybackProgress() + } }) } } @@ -360,7 +362,9 @@ final class StoryItemContentComponent: Component { } if case .file = self.currentMessageMedia { - self.updateVideoPlaybackProgress() + if !self.isSeeking { + self.updateVideoPlaybackProgress() + } } else { if !self.markedAsSeen { self.markedAsSeen = true @@ -536,6 +540,7 @@ final class StoryItemContentComponent: Component { ) } + private var isSeeking = false func seekTo(_ timestamp: Double, apply: Bool) { guard let videoNode = self.videoNode else { return @@ -543,8 +548,13 @@ final class StoryItemContentComponent: Component { if apply { videoNode.seek(timestamp) } + self.isSeeking = true self.updateVideoPlaybackProgress(timestamp) } + + func seekEnded() { + self.isSeeking = false + } func update(component: StoryItemContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: Transition) -> CGSize { let previousItem = self.component?.item diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift index ecdbe06690..53df5ab689 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift @@ -4710,7 +4710,7 @@ public final class StoryItemSetContainerComponent: Component { let seekLabelSize = self.seekLabel.update( transition: .immediate, - component: AnyComponent(Text(text: "Slide left or right to seek", font: Font.semibold(14.0), color: .white)), + component: AnyComponent(Text(text: component.strings.Story_SlideToSeek, font: Font.semibold(14.0), color: .white)), environment: {}, containerSize: availableSize ) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 979a556a53..2e567d1c09 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -4787,17 +4787,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G case let .ongoing(_, status): switch status { case .notAllowed: - content = .info(title: nil, text: "You can't participate in this giveaway.", timeout: nil, customUndoText: "Learn More") + content = .info(title: nil, text: self.presentationData.strings.Chat_Giveaway_Toast_NotAllowed, timeout: nil, customUndoText: self.presentationData.strings.Chat_Giveaway_Toast_LearnMore) case .participating: - content = .succeed(text: "You are participating in this giveaway.", timeout: nil, customUndoText: "Learn More") + content = .succeed(text: self.presentationData.strings.Chat_Giveaway_Toast_Participating, timeout: nil, customUndoText: self.presentationData.strings.Chat_Giveaway_Toast_LearnMore) case .notQualified: - content = .info(title: nil, text: "You are not qualified for this giveaway yet.", timeout: nil, customUndoText: "Learn More") + content = .info(title: nil, text: self.presentationData.strings.Chat_Giveaway_Toast_NotQualified, timeout: nil, customUndoText: self.presentationData.strings.Chat_Giveaway_Toast_LearnMore) case .almostOver: - content = .info(title: nil, text: "The giveaway is almost over.", timeout: nil, customUndoText: "Learn More") + content = .info(title: nil, text: self.presentationData.strings.Chat_Giveaway_Toast_AlmostOver, timeout: nil, customUndoText: self.presentationData.strings.Chat_Giveaway_Toast_LearnMore) } - case let .finished(status, _, _, _, _): - let _ = status - content = .info(title: nil, text: "The giveaway is ended.", timeout: nil, customUndoText: "Learn More") + case .finished: + content = .info(title: nil, text: self.presentationData.strings.Chat_Giveaway_Toast_Ended, timeout: nil, customUndoText: self.presentationData.strings.Chat_Giveaway_Toast_LearnMore) } let controller = UndoOverlayController(presentationData: self.presentationData, content: content, elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { [weak self] action in if case .undo = action, let self { @@ -19563,150 +19562,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G func displayGiveawayStatusInfo(messageId: EngineMessage.Id, giveawayInfo: PremiumGiveawayInfo) { let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: messageId)) |> deliverOnMainQueue).startStandalone(next: { [weak self] message in - guard let self, let message, let giveaway = message.media.first(where: { $0 is TelegramMediaGiveaway }) as? TelegramMediaGiveaway else { + guard let self, let message else { return } - var peerName = "" - if let peerId = giveaway.channelPeerIds.first, let peer = message.peers[peerId] { - peerName = EnginePeer(peer).compactDisplayTitle - } - - let untilDate = stringForDate(timestamp: giveaway.untilDate, strings: self.presentationData.strings) - - let title: String - let text: String - var warning: String? - - var dismissImpl: (() -> Void)? - - var actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: { - dismissImpl?() - })] - - switch giveawayInfo { - case let .ongoing(start, status): - let startDate = stringForDate(timestamp: start, strings: self.presentationData.strings) - - title = "About This Giveaway" - - let intro: String - if case .almostOver = status { - intro = "The giveaway was sponsored by the admins of **\(peerName)**, who acquired **\(giveaway.quantity) Telegram Premium** subscriptions for **\(giveaway.months)** months for its followers." - } else { - intro = "The giveaway is sponsored by the admins of **\(peerName)**, who acquired **\(giveaway.quantity) Telegram Premium** subscriptions for **\(giveaway.months)** months for its followers." - } - - let ending: String - if giveaway.flags.contains(.onlyNewSubscribers) { - if giveaway.channelPeerIds.count > 1 { - ending = "On **\(untilDate)**, Telegram will automatically select **\(giveaway.quantity)** random users that joined **\(peerName)** and **\(giveaway.channelPeerIds.count - 1)** other listed channels after **\(startDate)**." - } else { - ending = "On **\(untilDate)**, Telegram will automatically select **\(giveaway.quantity)** random users that joined **\(peerName)** after **\(startDate)**." - } - } else { - if giveaway.channelPeerIds.count > 1 { - ending = "On **\(untilDate)**, Telegram will automatically select **\(giveaway.quantity)** random subscribers of **\(peerName)** and **\(giveaway.channelPeerIds.count - 1)** other listed channels." - } else { - ending = "On **\(untilDate)**, Telegram will automatically select **\(giveaway.quantity)** random subscribers of **\(peerName)**." - } - } - - var participation: String - switch status { - case .notQualified: - if giveaway.channelPeerIds.count > 1 { - participation = "To take part in this giveaway please join the channel **\(peerName)** (**\(giveaway.channelPeerIds.count - 1)** other listed channels) before **\(untilDate)**." - } else { - participation = "To take part in this giveaway please join the channel **\(peerName)** before **\(untilDate)**." - } - case let .notAllowed(reason): - switch reason { - case let .joinedTooEarly(joinedOn): - let joinDate = stringForDate(timestamp: joinedOn, strings: self.presentationData.strings) - participation = "You are not eligible to participate in this giveaway, because you joined this channel on **\(joinDate)**, which is before the contest started." - case let .channelAdmin(adminId): - let _ = adminId - participation = "You are not eligible to participate in this giveaway, because you are an admin of participating channel (**\(peerName)**)." - case let .disallowedCountry(countryCode): - let _ = countryCode - participation = "You are not eligible to participate in this giveaway, because your country is not included in the terms of the giveaway." - } - case .participating: - if giveaway.channelPeerIds.count > 1 { - participation = "You are participating in this giveaway, because you have joined the channel **\(peerName)** (**\(giveaway.channelPeerIds.count - 1)** other listed channels)." - } else { - participation = "You are participating in this giveaway, because you have joined the channel **\(peerName)**." - } - case .almostOver: - participation = "The giveaway is over, preparing results." - } - - if !participation.isEmpty { - participation = "\n\n\(participation)" - } - - text = "\(intro)\n\n\(ending)\(participation)" - case let .finished(status, start, finish, _, activatedCount): - let startDate = stringForDate(timestamp: start, strings: self.presentationData.strings) - let finishDate = stringForDate(timestamp: finish, strings: self.presentationData.strings) - title = "Giveaway Ended" - - let intro = "The giveaway was sponsored by the admins of **\(peerName)**, who acquired **\(giveaway.quantity) Telegram Premium** subscriptions for **\(giveaway.months)** months for its followers." - - var ending: String - if giveaway.flags.contains(.onlyNewSubscribers) { - if giveaway.channelPeerIds.count > 1 { - ending = "On **\(finishDate)**, Telegram automatically selected **\(giveaway.quantity)** random users that joined **\(peerName)** and other listed channels after **\(startDate)**." - } else { - ending = "On **\(finishDate)**, Telegram automatically selected **\(giveaway.quantity)** random users that joined **\(peerName)** after **\(startDate)**." - } - } else { - if giveaway.channelPeerIds.count > 1 { - ending = "On **\(finishDate)**, Telegram automatically selected **\(giveaway.quantity)** random subscribers of **\(peerName)** and other listed channels." - } else { - ending = "On **\(finishDate)**, Telegram automatically selected **\(giveaway.quantity)** random subscribers of **\(peerName)**." - } - } - - if activatedCount > 0 { - ending += " \(activatedCount) of the winners already used their gift links." - } - - var result: String - switch status { - case .refunded: - result = "" - warning = "The channel cancelled the prizes by reversing the payment for them." - actions = [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_Close, action: { - dismissImpl?() - })] - case .notWon: - result = "\n\nYou didn't win a prize in this giveaway." - case let .won(slug): - result = "\n\nYou won a prize in this giveaway. 🏆" - let _ = slug - actions = [TextAlertAction(type: .defaultAction, title: "View My Prize", action: { - dismissImpl?() - }), TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: { - dismissImpl?() - })] - } - - text = "\(intro)\n\n\(ending)\(result)" - } - - let alertController = giveawayInfoAlertController( - context: self.context, - updatedPresentationData: self.updatedPresentationData, - title: title, - text: text, - warning: warning, - actions: actions - ) - self.present(alertController, in: .window(.root)) - - dismissImpl = { [weak alertController] in - alertController?.dismissAnimated() + if let controller = giveawayInfoController(context: self.context, updatedPresentationData: self.updatedPresentationData, message: message, giveawayInfo: giveawayInfo) { + self.present(controller, in: .window(.root)) } }) }