From e7e2fa1e83773614ce83d8e46533a3a12b3804de Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sun, 20 Jul 2025 12:18:17 +0100 Subject: [PATCH] Various fixes --- .../Telegram-iOS/en.lproj/Localizable.strings | 43 +++++++++++++++++++ .../Sources/AgeVerificationScreen.swift | 11 ++--- .../Sources/FaceScanScreen.swift | 17 ++++++-- .../FaceScanScreen/Sources/FrameView.swift | 27 ++++++------ .../Sources/GiftOptionsScreen.swift | 4 +- .../Sources/PeerInfoScreen.swift | 33 +++++++------- .../Sources/AddGiftsScreen.swift | 13 +----- .../Sources/GiftsListView.swift | 7 ++- .../Sources/PeerInfoGiftsPaneNode.swift | 31 +++++++------ .../ChatControllerOpenTodoContextMenu.swift | 2 +- 10 files changed, 116 insertions(+), 72 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index bf3f23fa3b..4b38240318 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -14700,5 +14700,48 @@ Sorry for the inconvenience."; "AccessDenied.AgeVerificationCamera" = "Telegram needs access to your camera for age verification.\n\nOpen your device's Settings > Privacy > Camera and set Telegram to ON."; +"PeerInfo.Gifts.AddGiftsButton" = "Add Gifts"; + +"PeerInfo.Gifts.AddCollection" = "Add Collection"; +"PeerInfo.Gifts.AddGifts" = "Add Gifts"; +"PeerInfo.Gifts.RenameCollection" = "Rename"; +"PeerInfo.Gifts.ShareCollection" = "Share"; +"PeerInfo.Gifts.DeleteCollection" = "Delete Collection"; + +"PeerInfo.Gifts.CreateCollection.Title" = "Create a New Collection"; +"PeerInfo.Gifts.CreateCollection.Text" = "Choose a name for your collection and start adding your gifts there."; +"PeerInfo.Gifts.CreateCollection.Placeholder" = "Title"; + +"PeerInfo.Gifts.RenameCollection.Title" = "Create a New Collection"; + +"PeerInfo.Gifts.Context.AddToCollection" = "Add to Collection"; +"PeerInfo.Gifts.Context.NewCollection" = "New Collection"; +"PeerInfo.Gifts.Context.RemoveFromCollection" = "Remove from Collection"; + +"PeerInfo.Gifts.CollectionLimitReached.Title" = "Limit Reached"; +"PeerInfo.Gifts.CollectionLimitReached.Text" = "Please remove one of the existing collections to add a new one."; + "PeerInfo.Gifts.RemoveCollectionConfirmation" = "This will remove the collection."; "PeerInfo.Gifts.RemoveCollectionAction" = "Remove"; + +"PeerInfo.Gifts.EmptyCollection.Title" = "Organize Your Gifts"; +"PeerInfo.Gifts.EmptyCollection.Text" = "Add some gifts to this collection."; +"PeerInfo.Gifts.EmptyCollection.Action" = "Add to Collection"; + +"AddGifts.Title" = "Add Gifts"; +"AddGifts.AddGifts_1" = "Add %@ Gift"; +"AddGifts.AddGifts_any" = "Add %@ Gifts"; + +"Gift.Options.Gift.BuyLimitReached_1" = "You've already sent %@ of these gifts, and it's the limit."; +"Gift.Options.Gift.BuyLimitReached_any" = "You've already sent %@ of these gifts, and it's the limit."; + +"AgeVerification.Title" = "Age Verification"; +"AgeVerification.Text" = "To access this content, you must confirm you are at least **18** years old as required by UK law.\n\nThis is a one-time process using your phone's camera. Your selfie will not be stored by Telegram."; +"AgeVerification.Text.gb" = "To access this content, you must confirm you are at least **18** years old as required by UK law.\n\nThis is a one-time process using your phone's camera. Your selfie will not be stored by Telegram."; +"AgeVerification.Verify" = "Verify My Age"; + +"AgeVerification.Success.Title" = "Age check passed!"; +"AgeVerification.Success.Text" = "You can now view this content."; + +"AgeVerification.Fail.Title" = "Age check failed"; +"AgeVerification.Fail.Text" = "Sorry, you can't view this content."; diff --git a/submodules/TelegramUI/Components/FaceScanScreen/Sources/AgeVerificationScreen.swift b/submodules/TelegramUI/Components/FaceScanScreen/Sources/AgeVerificationScreen.swift index 3db2875d86..f04f01ed90 100644 --- a/submodules/TelegramUI/Components/FaceScanScreen/Sources/AgeVerificationScreen.swift +++ b/submodules/TelegramUI/Components/FaceScanScreen/Sources/AgeVerificationScreen.swift @@ -84,7 +84,7 @@ private final class SheetContent: CombinedComponent { let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } let theme = presentationData.theme - //let strings = presentationData.strings + let strings = presentationData.strings var contentSize = CGSize(width: context.availableSize.width, height: 18.0) @@ -144,7 +144,7 @@ private final class SheetContent: CombinedComponent { contentSize.height += 124.0 let title = title.update( - component: Text(text: "Age Verification", font: Font.bold(24.0), color: theme.list.itemPrimaryTextColor), + component: Text(text: strings.AgeVerification_Title, font: Font.bold(24.0), color: theme.list.itemPrimaryTextColor), availableSize: CGSize(width: constrainedTitleWidth, height: context.availableSize.height), transition: .immediate ) @@ -162,6 +162,7 @@ private final class SheetContent: CombinedComponent { return (TelegramTextAttributes.URL, contents) }) + //TODO:localize let textString = "To access this content, you must confirm you are at least **18** years old as required by UK law.\n\nThis is a one-time process using your phone's camera. Your selfie will not be stored by Telegram." let text = text.update( @@ -195,7 +196,7 @@ private final class SheetContent: CombinedComponent { ), content: AnyComponentWithIdentity( id: AnyHashable(0), - component: AnyComponent(MultilineTextComponent(text: .plain(NSMutableAttributedString(string: "Verify My Age", font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)))) + component: AnyComponent(MultilineTextComponent(text: .plain(NSMutableAttributedString(string: strings.AgeVerification_Verify, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)))) ), isEnabled: true, displaysProgress: false, @@ -410,11 +411,11 @@ public func presentAgeVerification(context: AccountContext, parentController: Vi let navigationController = parentController?.navigationController Queue.mainQueue().after(2.0) { - let controller = UndoOverlayController(presentationData: presentationData, content: .actionSucceeded(title: "Age check passed!", text: "You can now view this content.", cancel: nil, destructive: false), action: { _ in return true }) + let controller = UndoOverlayController(presentationData: presentationData, content: .actionSucceeded(title: presentationData.strings.AgeVerification_Success_Title, text: presentationData.strings.AgeVerification_Success_Text, cancel: nil, destructive: false), action: { _ in return true }) (navigationController?.viewControllers.last as? ViewController)?.present(controller, in: .window(.root)) } } else { - let controller = UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_banned", scale: 0.066, colors: [:], title: "Age check failed!", text: "Sorry, you can't view this content.", customUndoText: nil, timeout: nil), action: { _ in return true }) + let controller = UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_banned", scale: 0.066, colors: [:], title: presentationData.strings.AgeVerification_Fail_Title, text: presentationData.strings.AgeVerification_Fail_Text, customUndoText: nil, timeout: nil), action: { _ in return true }) parentController?.present(controller, in: .window(.root)) } }) diff --git a/submodules/TelegramUI/Components/FaceScanScreen/Sources/FaceScanScreen.swift b/submodules/TelegramUI/Components/FaceScanScreen/Sources/FaceScanScreen.swift index 7481d73260..936b807798 100644 --- a/submodules/TelegramUI/Components/FaceScanScreen/Sources/FaceScanScreen.swift +++ b/submodules/TelegramUI/Components/FaceScanScreen/Sources/FaceScanScreen.swift @@ -67,6 +67,7 @@ final class FaceScanScreenComponent: Component { case completed } private var processState: State = .waitingForFace + private var transitioningToViewFinder = false private var lastFaceYaw: NSNumber? private var lastFacePitch: NSNumber? @@ -108,7 +109,7 @@ final class FaceScanScreenComponent: Component { self.backgroundColor = .black - //self.previewLayer.backgroundColor = UIColor.red.cgColor + self.previewLayer.backgroundColor = UIColor.red.cgColor self.previewLayer.videoGravity = .resizeAspectFill self.layer.addSublayer(previewLayer) @@ -239,7 +240,7 @@ final class FaceScanScreenComponent: Component { let targetCenter = CGPoint(x: 0.5, y: 0.5) let distance = sqrt(pow(faceCenter.x - targetCenter.x, 2) + pow(faceCenter.y - targetCenter.y, 2)) - if distance < 0.2 { + if distance < 0.35 { switch processState { case .waitingForFace: self.processState = .positioning @@ -337,6 +338,9 @@ final class FaceScanScreenComponent: Component { self.faceDetectionTimer?.invalidate() self.segmentTimer?.invalidate() + if self.processState != .waitingForFace && self.processState != .positioning { + self.transitioningToViewFinder = true + } self.processState = .waitingForFace self.completedAngles.removeAll() self.currentSegment = nil @@ -433,7 +437,7 @@ final class FaceScanScreenComponent: Component { let center = CGPoint(x: availableSize.width / 2, y: environment.statusBarHeight + 10.0 + widthRadius * 1.3) var previewScale = 1.0 - if self.processState == .tracking || self.processState == .readyToStart || self.processState == .completed { + if self.processState == .tracking || self.processState == .readyToStart || self.processState == .completed || self.transitioningToViewFinder { let circlePath = CGPath(roundedRect: CGRect(x: center.x - radius, y: center.y - radius, width: radius * 2, height: radius * 2), cornerWidth: radius, cornerHeight: radius, transform: nil) path.addPath(circlePath) @@ -457,7 +461,12 @@ final class FaceScanScreenComponent: Component { var instructionString = "Position your face\nwithin the frame" switch self.processState { case .waitingForFace, .positioning: - self.frameView.update(state: .viewFinder, transition: .spring(duration: 0.3)) + self.frameView.update(state: .viewFinder, intermediateCompletion: { [weak self] in + if let self { + self.transitioningToViewFinder = false + self.state?.updated(transition: .spring(duration: 0.3)) + } + }, transition: .spring(duration: 0.3)) instructionString = "Position your face\nwithin the frame" case .readyToStart: self.frameView.update(state: .segments(Set()), transition: .spring(duration: 0.3)) diff --git a/submodules/TelegramUI/Components/FaceScanScreen/Sources/FrameView.swift b/submodules/TelegramUI/Components/FaceScanScreen/Sources/FrameView.swift index c3dc8805fa..d6bf89770b 100644 --- a/submodules/TelegramUI/Components/FaceScanScreen/Sources/FrameView.swift +++ b/submodules/TelegramUI/Components/FaceScanScreen/Sources/FrameView.swift @@ -3,31 +3,28 @@ import Display import ComponentFlow final class FrameView: UIView { - enum State { + enum State: Equatable { case viewFinder case segments(Set) case success case failure } - private let maskLayer = CALayer() - private let viewFinderLayer = ViewFinderLayer() private let transitionLayer = TransitionLayer() private let segmentsLayer = SegmentsLayer() private var currentState: State = .viewFinder private var scheduledState: State? - private var isTransitioning = false + private var currentLayout: CGSize? + override init(frame: CGRect) { super.init(frame: frame) self.backgroundColor = .clear - - //self.layer.mask = self.maskLayer - + self.transitionLayer.isHidden = true self.segmentsLayer.isHidden = true @@ -40,7 +37,7 @@ final class FrameView: UIView { preconditionFailure() } - func update(state: State, transition: ComponentTransition) { + func update(state: State, intermediateCompletion: (() -> Void)? = nil, transition: ComponentTransition) { guard !self.isTransitioning else { self.scheduledState = state return @@ -62,6 +59,7 @@ final class FrameView: UIView { self.transitionLayer.animateOut(transition: transition) { self.transitionLayer.isHidden = true self.viewFinderLayer.isHidden = false + intermediateCompletion?() self.viewFinderLayer.animateIn(transition: transition) { self.isTransitioning = false self.maybeApplyScheduledState() @@ -118,18 +116,21 @@ final class FrameView: UIView { self.update(state: state, transition: .spring(duration: 0.3)) } } - + func update(size: CGSize) { - let bounds = CGRect(origin: .zero, size: size) + guard self.currentLayout != size else { + return + } + self.currentLayout = size - self.maskLayer.frame = bounds + let bounds = CGRect(origin: .zero, size: size) //let center = CGPoint(x: size.width / 2.0, y: size.height / 2.0) //let viewFinderWidth = bounds.width - 34.0 //let viewFinderSize = CGSize(width: viewFinderWidth, height: floor(viewFinderWidth * 1.17778)) let viewFinderFrame = bounds.insetBy(dx: 29.0, dy: 29.0) //viewFinderSize.centered(around: center) - self.viewFinderLayer.update(size: viewFinderFrame.size, closed: false, transition: .immediate) + self.viewFinderLayer.update(size: viewFinderFrame.size, closed: self.currentState != .viewFinder, transition: .immediate) self.viewFinderLayer.frame = viewFinderFrame let transitionFrame = bounds.insetBy(dx: 29.0, dy: 29.0) //viewFinderSize.centered(around: center) @@ -373,7 +374,7 @@ final class SegmentsLayer: SimpleLayer { let stripeLayer = SimpleShapeLayer() stripeLayer.path = path.cgPath - stripeLayer.strokeColor = UIColor.white.cgColor + stripeLayer.strokeColor = UIColor(rgb: 0xaaaaaa).cgColor stripeLayer.lineWidth = lineWidth stripeLayer.fillColor = UIColor.clear.cgColor stripeLayer.lineCap = .round diff --git a/submodules/TelegramUI/Components/Gifts/GiftOptionsScreen/Sources/GiftOptionsScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftOptionsScreen/Sources/GiftOptionsScreen.swift index 998507837e..747e0ec836 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftOptionsScreen/Sources/GiftOptionsScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftOptionsScreen/Sources/GiftOptionsScreen.swift @@ -460,9 +460,9 @@ final class GiftOptionsScreenComponent: Component { } if case let .generic(gift) = gift { if let perUserLimit = gift.perUserLimit, perUserLimit.remains == 0 { - //TODO:localize + let text = environment.strings.Gift_Options_Gift_BuyLimitReached(perUserLimit.total) let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } - let controller = UndoOverlayController(presentationData: presentationData, content: .sticker(context: component.context, file: gift.file, loop: true, title: nil, text: "You've already sent \(perUserLimit.total) of these gifts, and it's the limit.", undoText: nil, customAction: nil), action: { _ in return false }) + let controller = UndoOverlayController(presentationData: presentationData, content: .sticker(context: component.context, file: gift.file, loop: true, title: nil, text: text, undoText: nil, customAction: nil), action: { _ in return false }) mainController.present(controller, in: .current) return } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index ae50927286..400e9140a8 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -11366,10 +11366,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro |> map { [weak self, weak pane, weak giftsContext] filter, sorting, canReorder -> ContextController.Items in var items: [ContextMenuItem] = [] - if canReorder && hasVisibility { - //TODO:localize + if hasVisibility { if let pane, case .all = pane.currentCollection { - items.append(.action(ContextMenuActionItem(text: "Add Collection", icon: { theme in + items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_AddCollection, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/AddCollection"), color: theme.contextMenu.primaryColor) }, action: { [weak pane] _, f in f(.default) @@ -11379,7 +11378,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } }))) } else { - items.append(.action(ContextMenuActionItem(text: "Add Gifts", icon: { theme in + items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_AddGifts, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/AddGift"), color: theme.contextMenu.primaryColor) }, action: { [weak pane] _, f in f(.default) @@ -11389,27 +11388,29 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } }))) - items.append(.action(ContextMenuActionItem(text: "Share", icon: { theme in + items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_ShareCollection, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in f(.default) - + //TODO:release self?.openShareLink(url: "https://t.me/") }))) } - items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Reorder, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.contextMenu.primaryColor) - }, action: { [weak pane] _, f in - f(.default) - - if let pane { - pane.beginReordering() - } - }))) + if canReorder { + items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Reorder, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.contextMenu.primaryColor) + }, action: { [weak pane] _, f in + f(.default) + + if let pane { + pane.beginReordering() + } + }))) + } if let pane, case let .collection(id) = pane.currentCollection { - items.append(.action(ContextMenuActionItem(text: "Delete Collection", textColor: .destructive, icon: { theme in + items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_DeleteCollection, textColor: .destructive, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak pane] _, f in f(.default) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/AddGiftsScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/AddGiftsScreen.swift index 200ddf2b3a..b1ec546109 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/AddGiftsScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/AddGiftsScreen.swift @@ -153,15 +153,7 @@ final class AddGiftsScreenComponent: Component { let bottomPanelOffset: CGFloat = giftsListView.selectedItems.count > 0 ? 0.0 : bottomPanelHeight - //TODO:localize - var buttonString = "" - - if giftsListView.selectedItems.count > 1 { - buttonString = "Add \(giftsListView.selectedItems.count) Gifts" - } else { - buttonString = "Add 1 Gift" - } - + let buttonString = environment.strings.AddGifts_AddGifts(Int32(giftsListView.selectedItems.count)) let bottomPanelSize = self.buttonBackground.update( transition: transition, component: AnyComponent(BlurredBackgroundComponent( @@ -276,8 +268,7 @@ public final class AddGiftsScreen: ViewControllerComponentContainer { ), navigationBarAppearance: .default, theme: .default, updatedPresentationData: nil) - //TODO:localize - self.title = "Add Gifts" + self.title = presentationData.strings.AddGifts_Title self.navigationPresentation = .modal self.scrollToTop = { [weak self] in diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftsListView.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftsListView.swift index 50eda36c1c..ef195fb43d 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftsListView.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftsListView.swift @@ -783,12 +783,11 @@ final class GiftsListView: UIView { panelTransition.setFrame(view: self.emptyResultsClippingView, frame: CGRect(origin: CGPoint(x: 0.0, y: 48.0), size: params.size)) panelTransition.setBounds(view: self.emptyResultsClippingView, bounds: CGRect(origin: CGPoint(x: 0.0, y: 48.0), size: params.size)) - //TODO:localize let emptyResultsTitleSize = self.emptyResultsTitle.update( transition: .immediate, component: AnyComponent( MultilineTextComponent( - text: .plain(NSAttributedString(string: "Organize Your Gifts", font: Font.semibold(17.0), textColor: presentationData.theme.list.itemPrimaryTextColor)), + text: .plain(NSAttributedString(string: presentationData.strings.PeerInfo_Gifts_EmptyCollection_Title, font: Font.semibold(17.0), textColor: presentationData.theme.list.itemPrimaryTextColor)), horizontalAlignment: .center ) ), @@ -799,14 +798,14 @@ final class GiftsListView: UIView { transition: .immediate, component: AnyComponent( MultilineTextComponent( - text: .plain(NSAttributedString(string: "Add some gifts to this collection.", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)), + text: .plain(NSAttributedString(string: presentationData.strings.PeerInfo_Gifts_EmptyCollection_Text, font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)), horizontalAlignment: .center ) ), environment: {}, containerSize: CGSize(width: params.size.width - sideInset * 2.0, height: params.size.height) ) - let buttonAttributedString = NSAttributedString(string: "Add to Collection", font: Font.semibold(17.0), textColor: .white, paragraphAlignment: .center) + let buttonAttributedString = NSAttributedString(string: presentationData.strings.PeerInfo_Gifts_EmptyCollection_Action, font: Font.semibold(17.0), textColor: .white, paragraphAlignment: .center) let emptyResultsActionSize = self.emptyResultsAction.update( transition: .immediate, component: AnyComponent( diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift index 080a735761..ab1595fa59 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift @@ -196,13 +196,12 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr return } if let collections = self.collections, collections.count >= self.collectionsMaxCount { - let alertController = textAlertController(context: self.context, title: "Limit Reached", text: "Please remove one of the existing collections to add a new one.", actions: [TextAlertAction(type: .defaultAction, title: params.presentationData.strings.Common_OK, action: {})]) + let alertController = textAlertController(context: self.context, title: params.presentationData.strings.PeerInfo_Gifts_CollectionLimitReached_Title, text: params.presentationData.strings.PeerInfo_Gifts_CollectionLimitReached_Text, actions: [TextAlertAction(type: .defaultAction, title: params.presentationData.strings.Common_OK, action: {})]) self.parentController?.present(alertController, in: .window(.root)) return } - //TODO:localize - let promptController = promptController(sharedContext: self.context.sharedContext, updatedPresentationData: nil, text: "Create a New Collection", titleFont: .bold, subtitle: "Choose a name for your collection and start adding your gifts there.", value: "", placeholder: "Title", characterLimit: 20, displayCharacterLimit: true, apply: { [weak self] value in + let promptController = promptController(sharedContext: self.context.sharedContext, updatedPresentationData: nil, text: params.presentationData.strings.PeerInfo_Gifts_CreateCollection_Title, titleFont: .bold, subtitle: params.presentationData.strings.PeerInfo_Gifts_CreateCollection_Text, value: "", placeholder: params.presentationData.strings.PeerInfo_Gifts_CreateCollection_Placeholder, characterLimit: 20, displayCharacterLimit: true, apply: { [weak self] value in guard let self, let value else { return } @@ -253,11 +252,11 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr } public func renameCollection(id: Int32) { - guard let collection = self.collections?.first(where: { $0.id == id }) else { + guard let params = self.currentParams, let collection = self.collections?.first(where: { $0.id == id }) else { return } - let promptController = promptController(sharedContext: self.context.sharedContext, updatedPresentationData: nil, text: "Rename Collection", titleFont: .bold, value: collection.title, placeholder: "Title", characterLimit: 20, displayCharacterLimit: true, apply: { [weak self] value in + let promptController = promptController(sharedContext: self.context.sharedContext, updatedPresentationData: nil, text: params.presentationData.strings.PeerInfo_Gifts_RenameCollection_Title, titleFont: .bold, value: collection.title, placeholder: params.presentationData.strings.PeerInfo_Gifts_CreateCollection_Placeholder, characterLimit: 20, displayCharacterLimit: true, apply: { [weak self] value in guard let self, let value else { return } @@ -440,8 +439,8 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr } var items: [ContextMenuItem] = [] - //TODO:localize - items.append(.action(ContextMenuActionItem(text: "Add Gifts", icon: { theme in + + items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_AddGifts, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/AddGift"), color: theme.actionSheet.primaryTextColor) }, action: { [weak self] _, f in guard let self else { @@ -453,7 +452,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr self.addGiftsToCollection(id: id) }))) - items.append(.action(ContextMenuActionItem(text: "Rename", icon: { theme in + items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_RenameCollection, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.actionSheet.primaryTextColor) }, action: { [weak self] _, f in guard let self else { @@ -464,7 +463,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr self.renameCollection(id: id) }))) - items.append(.action(ContextMenuActionItem(text: "Share", icon: { theme in + items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_ShareCollection, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.actionSheet.primaryTextColor) }, action: { [weak self] _, f in guard let self else { @@ -472,10 +471,11 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr } f(.default) + //TODO:release let _ = self }))) - items.append(.action(ContextMenuActionItem(text: "Reorder", icon: { theme in + items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_Reorder, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.actionSheet.primaryTextColor) }, action: { [weak self] c, f in c?.dismiss(completion: { [weak self] in @@ -486,7 +486,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr }) }))) - items.append(.action(ContextMenuActionItem(text: "Delete Collection", textColor: .destructive, icon: { theme in + items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_DeleteCollection, textColor: .destructive, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] _, f in guard let self else { @@ -684,13 +684,12 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr let buttonSideInset = sideInset + 16.0 - //TODO:localize let buttonTitle: String if self.peerId == self.context.account.peerId { if case .all = self.currentCollection { buttonTitle = params.presentationData.strings.PeerInfo_Gifts_Send } else { - buttonTitle = "Add Gifts" + buttonTitle = params.presentationData.strings.PeerInfo_Gifts_AddGiftsButton } } else { buttonTitle = params.presentationData.strings.PeerInfo_Gifts_SendGift @@ -891,7 +890,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr var items: [ContextMenuItem] = [] if canManage { - items.append(.action(ContextMenuActionItem(text: "Add to Collection", textLayout: .twoLinesMax, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/AddToCollection"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in + items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Context_AddToCollection, textLayout: .twoLinesMax, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/AddToCollection"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in var subItems: [ContextMenuItem] = [] subItems.append(.action(ContextMenuActionItem(text: strings.Common_Back, textColor: .primary, icon: { theme in @@ -902,7 +901,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr subItems.append(.separator) - subItems.append(.action(ContextMenuActionItem(text: "New Collection", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/AddCollection"), color: theme.contextMenu.primaryColor) }, iconPosition: .left, action: { [weak self] c, f in + subItems.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Context_NewCollection, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/AddCollection"), color: theme.contextMenu.primaryColor) }, iconPosition: .left, action: { [weak self] c, f in f(.default) self?.createCollection(gifts: [gift]) @@ -1215,7 +1214,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr } if case let .collection(id) = self.currentCollection { - items.append(.action(ContextMenuActionItem(text: "Remove From Collection", textColor: .destructive, textLayout: .twoLinesMax, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/RemoveFromCollection"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] c, f in + items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Context_RemoveFromCollection, textColor: .destructive, textLayout: .twoLinesMax, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/RemoveFromCollection"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] c, f in f(.default) if let reference = gift.reference { diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenTodoContextMenu.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenTodoContextMenu.swift index 5b16755848..36860380ad 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenTodoContextMenu.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenTodoContextMenu.swift @@ -129,7 +129,7 @@ extension ChatControllerImpl { } if "".isEmpty { - //TODO:localize + //TODO:release items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Todo_ReplyToItem, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Reply"), color: theme.actionSheet.primaryTextColor) }, action: { [weak self] c, _ in