From c4731d8b8dc23b20da54bb275f3b791e8de1b6a7 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 24 Apr 2025 21:12:40 +0400 Subject: [PATCH] Various improvements --- .../Telegram-iOS/en.lproj/Localizable.strings | 65 ++++++++++++++ .../Sources/MediaPickerScreen.swift | 8 +- .../MtProtoKit/Sources/MTApiEnvironment.m | 2 + .../TelegramEngine/Payments/StarGifts.swift | 29 ++++-- .../Sources/ServiceMessageStrings.swift | 8 +- .../Sources/GiftSetupScreen.swift | 4 +- .../GiftAttributeListContextItem.swift | 11 +-- .../Sources/GiftStoreScreen.swift | 89 +++++-------------- .../Sources/GiftViewScreen.swift | 44 ++++----- .../Sources/PeerInfoGiftsPaneNode.swift | 3 +- .../Sources/StarsWithdrawalScreen.swift | 19 ++-- .../DeviceModel/Sources/DeviceModel.swift | 5 ++ .../WebAppSecureStorageTransferScreen.swift | 1 - 13 files changed, 164 insertions(+), 124 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 3ed169d2fb..e8b14c3c91 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -14225,3 +14225,68 @@ Sorry for the inconvenience."; "Notification.StarsGift.Bought.Stars_1" = "%@ Star"; "Notification.StarsGift.Bought.Stars_any" = "%@ Stars"; "Notification.StarsGift.BoughtYou" = "You gifted %1$@ for %2$@"; +"Notification.StarsGift.BoughtForYouself" = "You bought this gift for %1$@"; + +"Gift.View.Context.ChangePrice" = "Change Price"; +"Gift.View.Context.ViewInProfile" = "View in Profile"; + +"Gift.View.Sell" = "sell"; +"Gift.View.Unlist" = "unlist"; + +"Gift.View.BuyFor" = "Buy for"; +"Gift.View.SellingGiftInfo" = "%@ is selling this gift and you can buy it."; + +"Gift.View.Resale.Success.Title" = "Gift Sent"; +"Gift.View.Resale.Success.Text" = "%@ has been notified about your gift."; +"Gift.View.Resale.SuccessYou.Title" = "Gift Acquired"; +"Gift.View.Resale.SuccessYou.Text" = "%@ is now yours."; + +"Gift.View.Resale.Unlist.Title" = "Unlist This Item?"; +"Gift.View.Resale.Unlist.Text" = "It will no longer be for sale."; +"Gift.View.Resale.Unlist.Unlist" = "Unlist"; +"Gift.View.Resale.Unlist.Success" = "%@ is removed from sale."; +"Gift.View.Resale.List.Success" = "%@ is now for sale!"; +"Gift.View.Resale.Relist.Success" = "%1$@ is relisted for %2$@."; +"Gift.View.Resale.Relist.Success.Stars_1" = "%@ Star"; +"Gift.View.Resale.Relist.Success.Stars_any" = "%@ Stars"; + +"Stars.SellGift.Title" = "Sell Gift"; +"Stars.SellGift.EditTitle" = "Edit Price"; +"Stars.SellGift.AmountTitle" = "PRICE IN STARS"; +"Stars.SellGift.AmountPlaceholder" = "Enter Price"; +"Stars.SellGift.AmountInfo" = "You will receive **%@**."; +"Stars.SellGift.AmountInfo.Stars_1" = "%@ Star"; +"Stars.SellGift.AmountInfo.Stars_any" = "%@ Stars"; +"Stars.SellGift.Sell" = "Sell"; +"Stars.SellGift.SellFor" = "Sell for"; + +"PeerInfo.Gifts.Sale" = "sale"; + +"Gift.Store.ForResale_1" = "%@ for resale"; +"Gift.Store.ForResale_any" = "%@ for resale"; +"Gift.Store.Sort.Price" = "Price"; +"Gift.Store.Sort.Date" = "Date"; +"Gift.Store.Sort.Number" = "Number"; +"Gift.Store.SortByPrice" = "Sort By Price"; +"Gift.Store.SortByDate" = "Sort By Date"; +"Gift.Store.SortByNumber" = "Sort By Number"; +"Gift.Store.Filter.Model" = "Model"; +"Gift.Store.Filter.Backdrop" = "Backdrop"; +"Gift.Store.Filter.Symbol" = "Symbol"; +"Gift.Store.Filter.Selected.Model_1" = "%@ Model"; +"Gift.Store.Filter.Selected.Model_any" = "%@ Models"; +"Gift.Store.Filter.Selected.Backdrop_1" = "%@ Backdrop"; +"Gift.Store.Filter.Selected.Backdrop_any" = "%@ Backdrops"; +"Gift.Store.Filter.Selected.Symbol_1" = "%@ Symbol"; +"Gift.Store.Filter.Selected.Symbol_any" = "%@ Symbols"; +"Gift.Store.Search" = "Search"; +"Gift.Store.SelectAll" = "Select All"; +"Gift.Store.NoResults" = "No Results"; +"Gift.Store.EmptyResults" = "No Matching Gifts"; +"Gift.Store.ClearFilters" = "Clear Filters"; + +"Gift.Send.AvailableForResale" = "Available for Resale"; + +"MediaPicker.CreateStory_1" = "Create %@ Story"; +"MediaPicker.CreateStory_any" = "Create %@ Stories"; +"MediaPicker.CombineIntoCollage" = "Combine into Collage"; diff --git a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift index 9ea769f836..03575c9fc2 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift @@ -2395,15 +2395,11 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att transition.updateTransformScale(node: self.moreButtonNode.iconNode, scale: moreIsVisible ? 1.0 : 0.1) if case .assets(_, .story) = self.subject, self.selectionCount > 0 { - //TODO:localize - var text = "Create 1 Story" - if self.selectionCount > 1 { - text = "Create \(self.selectionCount) Stories" - } + let text = self.presentationData.strings.MediaPicker_CreateStory(self.selectionCount) self.mainButtonStatePromise.set(.single(AttachmentMainButtonState(text: text, badge: nil, font: .bold, background: .color(self.presentationData.theme.actionSheet.controlAccentColor), textColor: self.presentationData.theme.list.itemCheckColors.foregroundColor, isVisible: true, progress: .none, isEnabled: true, hasShimmer: false, position: .top))) if self.selectionCount > 1 && self.selectionCount <= 6 { - self.secondaryButtonStatePromise.set(.single(AttachmentMainButtonState(text: "Combine into Collage", badge: nil, font: .regular, background: .color(.clear), textColor: self.presentationData.theme.actionSheet.controlAccentColor, isVisible: true, progress: .none, isEnabled: true, hasShimmer: false, iconName: "Media Editor/Collage", smallSpacing: true, position: .bottom))) + self.secondaryButtonStatePromise.set(.single(AttachmentMainButtonState(text: self.presentationData.strings.MediaPicker_CombineIntoCollage, badge: nil, font: .regular, background: .color(.clear), textColor: self.presentationData.theme.actionSheet.controlAccentColor, isVisible: true, progress: .none, isEnabled: true, hasShimmer: false, iconName: "Media Editor/Collage", smallSpacing: true, position: .bottom))) } else { self.secondaryButtonStatePromise.set(.single(nil)) } diff --git a/submodules/MtProtoKit/Sources/MTApiEnvironment.m b/submodules/MtProtoKit/Sources/MTApiEnvironment.m index 399acc5097..a7eea0c54c 100644 --- a/submodules/MtProtoKit/Sources/MTApiEnvironment.m +++ b/submodules/MtProtoKit/Sources/MTApiEnvironment.m @@ -542,6 +542,8 @@ NSString *suffix = @""; return @"iPhone 16 Pro"; if ([platform isEqualToString:@"iPhone17,2"]) return @"iPhone 16 Pro Max"; + if ([platform isEqualToString:@"iPhone17,5"]) + return @"iPhone 16e"; if ([platform hasPrefix:@"iPod1"]) return @"iPod touch 1G"; diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift index 67ef375658..32aa9cdc41 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift @@ -1534,13 +1534,28 @@ private final class ProfileGiftsContextImpl { guard let self else { return EmptyDisposable } + + var saveToProfile = false + if let gift = self.gifts.first(where: { $0.reference == reference }) { + if !gift.savedToProfile { + saveToProfile = true + } + } else if let gift = self.filteredGifts.first(where: { $0.reference == reference }) { + if !gift.savedToProfile { + saveToProfile = true + } + } + + var signal = _internal_updateStarGiftResalePrice(account: self.account, reference: reference, price: price) + if saveToProfile { + signal = _internal_updateStarGiftAddedToProfile(account: self.account, reference: reference, added: true) + |> castError(UpdateStarGiftPriceError.self) + |> then(signal) + } + let disposable = MetaDisposable() disposable.set( - (_internal_updateStarGiftResalePrice( - account: self.account, - reference: reference, - price: price - ) + (signal |> deliverOn(self.queue)).startStrict(error: { error in subscriber.putError(error) }, completed: { @@ -1562,7 +1577,7 @@ private final class ProfileGiftsContextImpl { }) { if case let .unique(uniqueGift) = self.gifts[index].gift { let updatedUniqueGift = uniqueGift.withResellStars(price) - let updatedGift = self.gifts[index].withGift(.unique(updatedUniqueGift)) + let updatedGift = self.gifts[index].withGift(.unique(updatedUniqueGift)).withSavedToProfile(true) self.gifts[index] = updatedGift } } @@ -1585,7 +1600,7 @@ private final class ProfileGiftsContextImpl { }) { if case let .unique(uniqueGift) = self.filteredGifts[index].gift { let updatedUniqueGift = uniqueGift.withResellStars(price) - let updatedGift = self.filteredGifts[index].withGift(.unique(updatedUniqueGift)) + let updatedGift = self.filteredGifts[index].withGift(.unique(updatedUniqueGift)).withSavedToProfile(true) self.filteredGifts[index] = updatedGift } } diff --git a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift index f83833adcc..812d3a26ff 100644 --- a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift @@ -1190,8 +1190,12 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, } else if message.author?.id == accountPeerId { if let resaleStars { let starsString = strings.Notification_StarsGift_Bought_Stars(Int32(resaleStars)) - let giftTitle = "\(gift.title) #\(presentationStringsFormattedNumber(gift.number, dateTimeFormat.groupingSeparator))" - attributedString = addAttributesToStringWithRanges(strings.Notification_StarsGift_BoughtYou(giftTitle, starsString)._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes, 1: boldAttributes]) + if message.id.peerId == accountPeerId { + attributedString = addAttributesToStringWithRanges(strings.Notification_StarsGift_BoughtForYouself(starsString)._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes]) + } else { + let giftTitle = "\(gift.title) #\(presentationStringsFormattedNumber(gift.number, dateTimeFormat.groupingSeparator))" + attributedString = addAttributesToStringWithRanges(strings.Notification_StarsGift_BoughtYou(giftTitle, starsString)._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes, 1: boldAttributes]) + } } else { attributedString = NSAttributedString(string: strings.Notification_StarsGift_TransferYou, font: titleFont, textColor: primaryTextColor) } diff --git a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift index d4c2e9837a..3c325c54bb 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift @@ -801,7 +801,7 @@ final class GiftSetupScreenComponent: Component { title: AnyComponent(VStack([ AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent( MultilineTextComponent( - text: .plain(NSAttributedString(string: "Available for Resale", font: Font.regular(presentationData.listsFontSize.baseDisplaySize), textColor: environment.theme.list.itemPrimaryTextColor)) + text: .plain(NSAttributedString(string: environment.strings.Gift_Send_AvailableForResale, font: Font.regular(presentationData.listsFontSize.baseDisplaySize), textColor: environment.theme.list.itemPrimaryTextColor)) ) )), ], alignment: .left, spacing: 2.0)), @@ -1770,6 +1770,8 @@ public final class GiftSetupScreen: ViewControllerComponentContainer { self.title = "" + self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.context.sharedContext.currentPresentationData.with { $0 }.strings.Common_Back, style: .plain, target: nil, action: nil) + self.scrollToTop = { [weak self] in guard let self, let componentView = self.node.hostView.componentView as? GiftSetupScreenComponent.View else { return diff --git a/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftAttributeListContextItem.swift b/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftAttributeListContextItem.swift index a55122afa6..bbb4658b85 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftAttributeListContextItem.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftAttributeListContextItem.swift @@ -218,8 +218,7 @@ private final class GiftAttributeListContextItemNode: ASDisplayNode, ContextMenu let selectedAttributes = Set(item.selectedAttributes) - //TODO:localize - let selectAllAction = ContextMenuActionItem(text: "Select All", icon: { theme in + let selectAllAction = ContextMenuActionItem(text: presentationData.strings.Gift_Store_SelectAll, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor) }, iconPosition: .left, action: { _, f in getController()?.dismiss(result: .dismissWithoutContent, completion: nil) @@ -248,7 +247,7 @@ private final class GiftAttributeListContextItemNode: ASDisplayNode, ContextMenu } let nopAction: ((ContextControllerProtocol?, @escaping (ContextMenuActionResult) -> Void) -> Void)? = nil - let emptyResultsAction = ContextMenuActionItem(text: "No Results", textFont: .small, icon: { _ in return nil }, action: nopAction) + let emptyResultsAction = ContextMenuActionItem(text: presentationData.strings.Gift_Store_NoResults, textFont: .small, icon: { _ in return nil }, action: nopAction) let emptyResultsActionNode = ContextControllerActionsListActionItemNode(context: item.context, getController: getController, requestDismiss: actionSelected, requestUpdateAction: { _, _ in }, item: emptyResultsAction) actionNodes.append(emptyResultsActionNode) @@ -412,12 +411,6 @@ private final class GiftAttributeListContextItemNode: ASDisplayNode, ContextMenu } func actionNode(at point: CGPoint) -> ContextActionNodeProtocol { -// for actionNode in self.actionNodes { -// let frame = actionNode.convert(actionNode.bounds, to: self) -// if frame.contains(point) { -// return actionNode -// } -// } return self } diff --git a/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftStoreScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftStoreScreen.swift index 0b2912e02c..8ac35acf59 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftStoreScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftStoreScreen.swift @@ -302,7 +302,7 @@ final class GiftStoreScreenComponent: Component { PlainButtonComponent( content: AnyComponent( MultilineTextComponent( - text: .plain(NSAttributedString(string: "Clear Filters", font: Font.regular(17.0), textColor: environment.theme.list.itemAccentColor)), + text: .plain(NSAttributedString(string: environment.strings.Gift_Store_ClearFilters, font: Font.regular(17.0), textColor: environment.theme.list.itemAccentColor)), horizontalAlignment: .center, maximumNumberOfLines: 0 ) @@ -349,7 +349,7 @@ final class GiftStoreScreenComponent: Component { transition: .immediate, component: AnyComponent( MultilineTextComponent( - text: .plain(NSAttributedString(string: "No Matching Gifts", font: Font.semibold(17.0), textColor: environment.theme.list.itemPrimaryTextColor)), + text: .plain(NSAttributedString(string: environment.strings.Gift_Store_EmptyResults, font: Font.semibold(17.0), textColor: environment.theme.list.itemPrimaryTextColor)), horizontalAlignment: .center ) ), @@ -441,21 +441,21 @@ final class GiftStoreScreenComponent: Component { let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } var items: [ContextMenuItem] = [] - items.append(.action(ContextMenuActionItem(text: "Sort by Price", icon: { theme in + items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_Store_SortByPrice, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SortValue"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in f(.default) self?.state?.starGiftsContext.updateSorting(.value) }))) - items.append(.action(ContextMenuActionItem(text: "Sort by Date", icon: { theme in + items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_Store_SortByDate, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SortDate"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in f(.default) self?.state?.starGiftsContext.updateSorting(.date) }))) - items.append(.action(ContextMenuActionItem(text: "Sort by Number", icon: { theme in + items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_Store_SortByNumber, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SortNumber"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in f(.default) @@ -493,12 +493,11 @@ final class GiftStoreScreenComponent: Component { } } - //TODO:localize var items: [ContextMenuItem] = [] if modelAttributes.count >= 8 { items.append(.custom(SearchContextItem( context: component.context, - placeholder: "Search", + placeholder: presentationData.strings.Gift_Store_Search, value: "", valueChanged: { value in searchQueryPromise.set(value) @@ -585,12 +584,11 @@ final class GiftStoreScreenComponent: Component { } } - //TODO:localize var items: [ContextMenuItem] = [] if backdropAttributes.count >= 8 { items.append(.custom(SearchContextItem( context: component.context, - placeholder: "Search", + placeholder: presentationData.strings.Gift_Store_Search, value: "", valueChanged: { value in searchQueryPromise.set(value) @@ -677,12 +675,11 @@ final class GiftStoreScreenComponent: Component { } } - //TODO:localize var items: [ContextMenuItem] = [] if patternAttributes.count >= 8 { items.append(.custom(SearchContextItem( context: component.context, - placeholder: "Search", + placeholder: presentationData.strings.Gift_Store_Search, value: "", valueChanged: { value in searchQueryPromise.set(value) @@ -814,35 +811,7 @@ final class GiftStoreScreenComponent: Component { transition.setFrame(view: topPanelView, frame: topPanelFrame) transition.setFrame(view: topSeparatorView, frame: topSeparatorFrame) } - -// let cancelButtonSize = self.cancelButton.update( -// transition: transition, -// component: AnyComponent( -// PlainButtonComponent( -// content: AnyComponent( -// MultilineTextComponent( -// text: .plain(NSAttributedString(string: strings.Common_Cancel, font: Font.regular(17.0), textColor: theme.rootController.navigationBar.accentTextColor)), -// horizontalAlignment: .center -// ) -// ), -// effectAlignment: .center, -// action: { -// controller()?.dismiss() -// }, -// animateScale: false -// ) -// ), -// environment: {}, -// containerSize: CGSize(width: availableSize.width, height: 100.0) -// ) -// let cancelButtonFrame = CGRect(origin: CGPoint(x: environment.safeInsets.left + 16.0, y: environment.statusBarHeight + (environment.navigationHeight - environment.statusBarHeight) / 2.0 - cancelButtonSize.height / 2.0), size: cancelButtonSize) -// if let cancelButtonView = self.cancelButton.view { -// if cancelButtonView.superview == nil { -// self.addSubview(cancelButtonView) -// } -// transition.setFrame(view: cancelButtonView, frame: cancelButtonFrame) -// } - + let balanceTitleSize = self.balanceTitle.update( transition: .immediate, component: AnyComponent(MultilineTextComponent( @@ -922,7 +891,7 @@ final class GiftStoreScreenComponent: Component { let subtitleSize = self.subtitle.update( transition: transition, component: AnyComponent(BalancedTextComponent( - text: .plain(NSAttributedString(string: "\(effectiveCount) for resale", font: Font.regular(13.0), textColor: theme.rootController.navigationBar.secondaryTextColor)), + text: .plain(NSAttributedString(string: environment.strings.Gift_Store_ForResale(effectiveCount), font: Font.regular(13.0), textColor: theme.rootController.navigationBar.secondaryTextColor)), horizontalAlignment: .center, maximumNumberOfLines: 1 )), @@ -940,18 +909,18 @@ final class GiftStoreScreenComponent: Component { let optionSpacing: CGFloat = 10.0 let optionWidth = (availableSize.width - sideInset * 2.0 - optionSpacing * 2.0) / 3.0 - var sortingTitle = "Date" + var sortingTitle = environment.strings.Gift_Store_Sort_Date var sortingIcon: String = "Peer Info/SortDate" if let sorting = self.state?.starGiftsState?.sorting { switch sorting { case .date: - sortingTitle = "Date" + sortingTitle = environment.strings.Gift_Store_Sort_Date sortingIcon = "Peer Info/SortDate" case .value: - sortingTitle = "Price" + sortingTitle = environment.strings.Gift_Store_Sort_Price sortingIcon = "Peer Info/SortValue" case .number: - sortingTitle = "Number" + sortingTitle = environment.strings.Gift_Store_Sort_Number sortingIcon = "Peer Info/SortNumber" } } @@ -968,13 +937,13 @@ final class GiftStoreScreenComponent: Component { } )) - var modelTitle = "Model" - var backdropTitle = "Backdrop" - var symbolTitle = "Symbol" + var modelTitle = environment.strings.Gift_Store_Filter_Model + var backdropTitle = environment.strings.Gift_Store_Filter_Backdrop + var symbolTitle = environment.strings.Gift_Store_Filter_Symbol if let filterAttributes = self.state?.starGiftsState?.filterAttributes { - var modelCount = 0 - var backdropCount = 0 - var symbolCount = 0 + var modelCount: Int32 = 0 + var backdropCount: Int32 = 0 + var symbolCount: Int32 = 0 for attribute in filterAttributes { switch attribute { @@ -988,25 +957,13 @@ final class GiftStoreScreenComponent: Component { } if modelCount > 0 { - if modelCount > 1 { - modelTitle = "\(modelCount) Models" - } else { - modelTitle = "1 Model" - } + modelTitle = environment.strings.Gift_Store_Filter_Selected_Model(modelCount) } if backdropCount > 0 { - if backdropCount > 1 { - backdropTitle = "\(backdropCount) Backdrops" - } else { - backdropTitle = "1 Backdrop" - } + backdropTitle = environment.strings.Gift_Store_Filter_Selected_Backdrop(modelCount) } if symbolCount > 0 { - if symbolCount > 1 { - symbolTitle = "\(symbolCount) Symbols" - } else { - symbolTitle = "1 Symbol" - } + symbolTitle = environment.strings.Gift_Store_Filter_Selected_Symbol(modelCount) } } diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift index e4b0550757..3442c6f6f6 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift @@ -407,7 +407,6 @@ private final class GiftViewSheetContent: CombinedComponent { let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } let mode = ContactSelectionControllerMode.starsGifting(birthdays: nil, hasActions: false, showSelf: true, selfSubtitle: presentationData.strings.Premium_Gift_ContactSelection_BuySelf) - //TODO:localize let controller = self.context.sharedContext.makeContactSelectionController(ContactSelectionControllerParams( context: context, mode: mode, @@ -476,14 +475,13 @@ private final class GiftViewSheetContent: CombinedComponent { controllers = controllers.filter({ !($0 is GiftViewScreen) }) navigationController.setViewControllers(controllers, animated: true) - //TODO:localize navigationController.view.addSubview(ConfettiView(frame: navigationController.view.bounds)) Queue.mainQueue().after(0.5, { if let lastController = navigationController.viewControllers.last as? ViewController, let animationFile { let resultController = UndoOverlayController( presentationData: presentationData, - content: .sticker(context: context, file: animationFile, loop: false, title: "Gift Acquired", text: "\(giftTitle) is now yours.", undoText: nil, customAction: nil), + content: .sticker(context: context, file: animationFile, loop: false, title: presentationData.strings.Gift_View_Resale_SuccessYou_Title, text: presentationData.strings.Gift_View_Resale_SuccessYou_Text(giftTitle).string, undoText: nil, customAction: nil), elevatedLayout: lastController is ChatController, action: { _ in return true @@ -505,7 +503,7 @@ private final class GiftViewSheetContent: CombinedComponent { if let peer, let lastController = navigationController?.viewControllers.last as? ViewController, let animationFile { let resultController = UndoOverlayController( presentationData: presentationData, - content: .sticker(context: context, file: animationFile, loop: false, title: "Gift Sent", text: "\(peer.compactDisplayTitle) has been notified about your gift.", undoText: nil, customAction: nil), + content: .sticker(context: context, file: animationFile, loop: false, title: presentationData.strings.Gift_View_Resale_Success_Title, text: presentationData.strings.Gift_View_Resale_Success_Text(peer.compactDisplayTitle).string, undoText: nil, customAction: nil), elevatedLayout: lastController is ChatController, action: { _ in return true @@ -1848,12 +1846,11 @@ private final class GiftViewSheetContent: CombinedComponent { ) buttonOriginX += buttonWidth + buttonSpacing - //TODO:localize let resellButton = resellButton.update( component: PlainButtonComponent( content: AnyComponent( HeaderButtonComponent( - title: uniqueGift.resellStars == nil ? "sell" : "unlist", + title: uniqueGift.resellStars == nil ? strings.Gift_View_Sell : strings.Gift_View_Unlist, iconName: uniqueGift.resellStars == nil ? "Premium/Collectible/Sell" : "Premium/Collectible/Unlist" ) ), @@ -2250,7 +2247,7 @@ private final class GiftViewSheetContent: CombinedComponent { ) } if case let .uniqueGift(_, recipientPeerId) = component.subject, recipientPeerId != nil { - } else { + } else if ownerPeerId != component.context.account.peerId { selling = true } } @@ -2264,14 +2261,13 @@ private final class GiftViewSheetContent: CombinedComponent { var addressToOpen: String? var descriptionText: String if let uniqueGift, selling { - //TODO:localize let ownerName: String if case let .peerId(peerId) = uniqueGift.owner { ownerName = state.peerMap[peerId]?.compactDisplayTitle ?? "" } else { ownerName = "" } - descriptionText = "\(ownerName) is selling this gift and you can buy it." + descriptionText = strings.Gift_View_SellingGiftInfo(ownerName).string } else if let uniqueGift, let address = uniqueGift.giftAddress, case .address = uniqueGift.owner { addressToOpen = address descriptionText = strings.Gift_View_TonGiftAddressInfo @@ -2568,8 +2564,7 @@ private final class GiftViewSheetContent: CombinedComponent { if state.cachedStarImage == nil || state.cachedStarImage?.1 !== theme { state.cachedStarImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/PremiumIcon"), color: theme.list.itemCheckColors.foregroundColor)!, theme) } - //TODO:localize - var upgradeString = "Buy for" + var upgradeString = strings.Gift_View_BuyFor upgradeString += " # \(presentationStringsFormattedNumber(Int32(resellStars), environment.dateTimeFormat.groupingSeparator))" let buttonTitle = subject.arguments?.upgradeStars != nil ? strings.Gift_Upgrade_Confirm : upgradeString @@ -3412,14 +3407,13 @@ public class GiftViewScreen: ViewControllerComponentContainer { let giftTitle = "\(gift.title) #\(presentationStringsFormattedNumber(gift.number, presentationData.dateTimeFormat.groupingSeparator))" let reference = arguments.reference ?? .slug(slug: gift.slug) - //TODO:localize if let resellStars = gift.resellStars, resellStars > 0, !update { let alertController = textAlertController( context: context, - title: "Unlist This Item?", - text: "It will no longer be for sale.", + title: presentationData.strings.Gift_View_Resale_Unlist_Title, + text: presentationData.strings.Gift_View_Resale_Unlist_Text, actions: [ - TextAlertAction(type: .defaultAction, title: "Unlist", action: { [weak self] in + TextAlertAction(type: .defaultAction, title: presentationData.strings.Gift_View_Resale_Unlist_Unlist, action: { [weak self] in guard let self else { return } @@ -3436,7 +3430,7 @@ public class GiftViewScreen: ViewControllerComponentContainer { break } - let text = "\(giftTitle) is removed from sale." + let text = presentationData.strings.Gift_View_Resale_Unlist_Success(giftTitle).string let tooltipController = UndoOverlayController( presentationData: presentationData, content: .universalImage( @@ -3486,9 +3480,10 @@ public class GiftViewScreen: ViewControllerComponentContainer { break } - var text = "\(giftTitle) is now for sale!" + var text = presentationData.strings.Gift_View_Resale_List_Success(giftTitle).string if update { - text = "\(giftTitle) is relisted for \(presentationStringsFormattedNumber(Int32(price), presentationData.dateTimeFormat.groupingSeparator)) Stars." + let starsString = presentationData.strings.Gift_View_Resale_Relist_Success_Stars(Int32(price)) + text = presentationData.strings.Gift_View_Resale_Relist_Success(giftTitle, starsString).string } let tooltipController = UndoOverlayController( @@ -3588,6 +3583,16 @@ public class GiftViewScreen: ViewControllerComponentContainer { }))) } + if case let .unique(gift) = arguments.gift, let resellStars = gift.resellStars, resellStars > 0 { + items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_ChangePrice, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Media Grid/Paid"), color: theme.contextMenu.primaryColor) + }, action: { c, _ in + c?.dismiss(completion: nil) + + resellGiftImpl?(true) + }))) + } + items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_CopyLink, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in @@ -3625,8 +3630,7 @@ public class GiftViewScreen: ViewControllerComponentContainer { } if let _ = arguments.resellStars, case let .uniqueGift(uniqueGift, recipientPeerId) = subject, let _ = recipientPeerId { - //TODO:localize - items.append(.action(ContextMenuActionItem(text: "View in Profile", icon: { theme in + items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_ViewInProfile, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/ShowIcon"), color: theme.contextMenu.primaryColor) }, action: { c, _ in c?.dismiss(completion: nil) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift index 2c7db7f507..9dcf4c1f25 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift @@ -502,8 +502,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr resellPrice = gift.resellStars if let _ = resellPrice { - //TODO:localize - ribbonText = "sale" + ribbonText = params.presentationData.strings.PeerInfo_Gifts_Sale ribbonFont = .larger ribbonColor = .green ribbonOutline = params.presentationData.theme.list.blocksBackgroundColor diff --git a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift index 0ea0dd5b11..3956966391 100644 --- a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift @@ -148,10 +148,9 @@ private final class SheetContent: CombinedComponent { maxAmount = withdrawConfiguration.maxPaidMediaAmount.flatMap { StarsAmount(value: $0, nanos: 0) } amountLabel = nil case let .starGiftResell(update): - //TODO:localize - titleString = update ? "Edit Price" : "Sell Gift" - amountTitle = "PRICE IN STARS" - amountPlaceholder = "Enter Price" + titleString = update ? environment.strings.Stars_SellGift_EditTitle : environment.strings.Stars_SellGift_Title + amountTitle = environment.strings.Stars_SellGift_AmountTitle + amountPlaceholder = environment.strings.Stars_SellGift_AmountPlaceholder minAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMinAmount, nanos: 0) maxAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMaxAmount, nanos: 0) @@ -269,12 +268,13 @@ private final class SheetContent: CombinedComponent { maximumNumberOfLines: 0 )) case .starGiftResell: - //TODO:localize let amountInfoString: NSAttributedString if let value = state.amount?.value, value > 0 { - amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString("You will receive **\(Int32(floor(Float(value) * 0.8))) Stars**.", attributes: amountMarkdownAttributes, textAlignment: .natural)) + let starsValue = Int32(floor(Float(value) * Float(resaleConfiguration.paidMessageCommissionPermille) / 1000.0)) + let starsString = environment.strings.Stars_SellGift_AmountInfo_Stars(starsValue) + amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString(environment.strings.Stars_SellGift_AmountInfo(starsString).string, attributes: amountMarkdownAttributes, textAlignment: .natural)) } else { - amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString("You will receive **80%**.", attributes: amountMarkdownAttributes, textAlignment: .natural)) + amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString(environment.strings.Stars_SellGift_AmountInfo("\(resaleConfiguration.paidMessageCommissionPermille / 10)%").string, attributes: amountMarkdownAttributes, textAlignment: .natural)) } amountFooter = AnyComponent(MultilineTextComponent( text: .plain(amountInfoString), @@ -334,11 +334,10 @@ private final class SheetContent: CombinedComponent { if case .paidMedia = component.mode { buttonString = environment.strings.Stars_PaidContent_Create } else if case .starGiftResell = component.mode { - //TODO:localize if let amount = state.amount, amount.value > 0 { - buttonString = "Sell for # \(presentationStringsFormattedNumber(amount, environment.dateTimeFormat.groupingSeparator))" + buttonString = "\(environment.strings.Stars_SellGift_SellFor) # \(presentationStringsFormattedNumber(amount, environment.dateTimeFormat.groupingSeparator))" } else { - buttonString = "Sell" + buttonString = environment.strings.Stars_SellGift_Sell } } else if let amount = state.amount { buttonString = "\(environment.strings.Stars_Withdraw_Withdraw) # \(presentationStringsFormattedNumber(amount, environment.dateTimeFormat.groupingSeparator))" diff --git a/submodules/Utils/DeviceModel/Sources/DeviceModel.swift b/submodules/Utils/DeviceModel/Sources/DeviceModel.swift index e74039e14e..572a05d9ae 100644 --- a/submodules/Utils/DeviceModel/Sources/DeviceModel.swift +++ b/submodules/Utils/DeviceModel/Sources/DeviceModel.swift @@ -124,6 +124,7 @@ public enum DeviceModel: CaseIterable, Equatable { case iPhone16Plus case iPhone16Pro case iPhone16ProMax + case iPhone16e case unknown(String) @@ -235,6 +236,8 @@ public enum DeviceModel: CaseIterable, Equatable { return ["iPhone17,1"] case .iPhone16ProMax: return ["iPhone17,2"] + case .iPhone16e: + return ["iPhone17,5"] case let .unknown(modelId): return [modelId] } @@ -348,6 +351,8 @@ public enum DeviceModel: CaseIterable, Equatable { return "iPhone 16 Pro" case .iPhone16ProMax: return "iPhone 16 Pro Max" + case .iPhone16e: + return "iPhone 16e" case let .unknown(modelId): if modelId.hasPrefix("iPhone") { return "Unknown iPhone" diff --git a/submodules/WebUI/Sources/WebAppSecureStorageTransferScreen.swift b/submodules/WebUI/Sources/WebAppSecureStorageTransferScreen.swift index e64a909355..d3245faa72 100644 --- a/submodules/WebUI/Sources/WebAppSecureStorageTransferScreen.swift +++ b/submodules/WebUI/Sources/WebAppSecureStorageTransferScreen.swift @@ -103,7 +103,6 @@ private final class SheetContent: CombinedComponent { .position(CGPoint(x: environment.safeInsets.left + 16.0 + closeButton.size.width / 2.0, y: 28.0)) ) - //TODO:localize let title = title.update( component: MultilineTextComponent( text: .plain(NSAttributedString(string: strings.WebApp_ImportData_Title, font: titleFont, textColor: textColor)),