diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 152b4e3ed4..4f58aff1d9 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -15679,7 +15679,6 @@ Error: %8$@"; "Gift.Craft.ViewVariants" = "View all craftable models"; "Gift.Craft.BackdropTooltip" = "**%1$@%** chance the crafted gift will have **%2$@** backdrop."; "Gift.Craft.SymbolTooltip" = "**%1$@%** chance the crafted gift will have **%2$@** symbol."; -"Gift.Craft.SuccessChanceSuffix" = "% Success Chance"; "Gift.Craft.Craft" = "Craft %@"; "Gift.Craft.Crafting.Title" = "Crafting"; "Gift.Craft.Crafting.Description" = "If crafting fails, all used gifts\nwill be lost."; @@ -15768,3 +15767,5 @@ Error: %8$@"; "AppointAnotherOwner.Title" = "Choose New Owner"; "Gift.View.Context.Craft" = "Craft"; + +"Group.OwnershipTransfer.DescriptionShortInfo" = "This will transfer the full **owner rights** for **%1$@** to **%2$@**."; diff --git a/submodules/ChatListUI/Sources/ChatListControllerLeaveChannelConfirmation.swift b/submodules/ChatListUI/Sources/ChatListControllerLeaveChannelConfirmation.swift index 6023992b39..e7218f17bd 100644 --- a/submodules/ChatListUI/Sources/ChatListControllerLeaveChannelConfirmation.swift +++ b/submodules/ChatListUI/Sources/ChatListControllerLeaveChannelConfirmation.swift @@ -135,6 +135,7 @@ extension ChatListControllerImpl { updatedPresentationData: nil, peer: chatPeer, member: user, + onLeave: true, initialError: error, present: { c, a in presentController(c) diff --git a/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift b/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift index 1e6f247d47..8ff5b544d2 100644 --- a/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift +++ b/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift @@ -9,6 +9,11 @@ import TelegramPresentationData import EdgeEffect public final class ResizableSheetComponentEnvironment: Equatable { + public struct BoundsUpdate { + public let bounds: CGRect + public let isInteractive: Bool + } + public let theme: PresentationTheme public let statusBarHeight: CGFloat public let safeInsets: UIEdgeInsets @@ -19,7 +24,7 @@ public final class ResizableSheetComponentEnvironment: Equatable { public let screenSize: CGSize public let regularMetricsSize: CGSize? public let dismiss: (Bool) -> Void - public let boundsUpdated: ActionSlot + public let boundsUpdated: ActionSlot public init( theme: PresentationTheme, @@ -32,7 +37,7 @@ public final class ResizableSheetComponentEnvironment: Equatable { screenSize: CGSize, regularMetricsSize: CGSize?, dismiss: @escaping (Bool) -> Void, - boundsUpdated: ActionSlot = ActionSlot() + boundsUpdated: ActionSlot = ActionSlot() ) { self.theme = theme self.statusBarHeight = statusBarHeight @@ -479,7 +484,7 @@ public final class ResizableSheetComponent deliverOnMainQueue).start(next: { [weak self] state in - guard let self else { + guard let self, let component = self.component else { return } self.craftState = state @@ -297,6 +297,10 @@ private final class CraftGiftPageContent: Component { self.component?.externalState.giftsMap = self.giftMap self.state?.updated(transition: .spring(duration: 0.4)) + + if state.gifts.count < 18, case .ready(true, _) = state.dataState { + component.craftContext.loadMore() + } }) self.upgradePreviewDisposable.add((component.context.engine.payments.getStarGiftUpgradeAttributes(giftId: initialGiftItem.gift.giftId) @@ -1622,9 +1626,31 @@ private final class SheetContainerComponent: CombinedComponent { )) } else { var buttonAnimatedItems: [AnimatedTextComponent.Item] = [] - buttonAnimatedItems.append(AnimatedTextComponent.Item(id: "percent", content: .number(Int(permilleValue / 10), minDigits: 1))) - buttonAnimatedItems.append(AnimatedTextComponent.Item(id: "suffix", content: .text(environment.strings.Gift_Craft_SuccessChanceSuffix))) + let rawString = environment.strings.Gift_Craft_Crafting_SuccessChance("{p}").string + var startIndex = rawString.startIndex + while true { + if let range = rawString.range(of: "{", range: startIndex ..< rawString.endIndex) { + if range.lowerBound != startIndex { + buttonAnimatedItems.append(AnimatedTextComponent.Item(id: AnyHashable(buttonAnimatedItems.count), content: .text(String(rawString[startIndex ..< range.lowerBound])))) + } + + startIndex = range.upperBound + if let endRange = rawString.range(of: "}", range: startIndex ..< rawString.endIndex) { + let controlString = rawString[range.upperBound ..< endRange.lowerBound] + if controlString == "p" { + buttonAnimatedItems.append(AnimatedTextComponent.Item(id: AnyHashable(buttonAnimatedItems.count), content: .number(Int(permilleValue / 10), minDigits: 1))) + } + startIndex = endRange.upperBound + } + } else { + break + } + } + if startIndex != rawString.endIndex { + buttonAnimatedItems.append(AnimatedTextComponent.Item(id: AnyHashable(buttonAnimatedItems.count), content: .text(String(rawString[startIndex ..< rawString.endIndex])))) + } + buttonContent = AnyComponentWithIdentity(id: "craft", component: AnyComponent( VStack([ AnyComponentWithIdentity( diff --git a/submodules/TelegramUI/Components/Gifts/GiftCraftScreen/Sources/SelectCraftGiftScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftCraftScreen/Sources/SelectCraftGiftScreen.swift index 8b64a139ff..456486acd9 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftCraftScreen/Sources/SelectCraftGiftScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftCraftScreen/Sources/SelectCraftGiftScreen.swift @@ -35,7 +35,7 @@ final class SelectGiftPageContent: Component { let starsTopUpOptions: Signal<[StarsTopUpOption]?, NoError> let selectGift: (GiftItem) -> Void let dismiss: () -> Void - let boundsUpdated: ActionSlot + let boundsUpdated: ActionSlot init( context: AccountContext, @@ -47,7 +47,7 @@ final class SelectGiftPageContent: Component { starsTopUpOptions: Signal<[StarsTopUpOption]?, NoError>, selectGift: @escaping (GiftItem) -> Void, dismiss: @escaping () -> Void, - boundsUpdated: ActionSlot + boundsUpdated: ActionSlot ) { self.context = context self.craftContext = craftContext @@ -310,6 +310,13 @@ final class SelectGiftPageContent: Component { storeGiftsView.updateScrolling(bounds: bounds.offsetBy(dx: 0.0, dy: -contentHeight), interactive: interactive, transition: .immediate) } + let bottomContentOffset = max(0.0, contentHeight - bounds.origin.y - bounds.height) + if interactive, bottomContentOffset < 800.0 { + Queue.mainQueue().justDispatch { + component.craftContext.loadMore() + } + } + return contentHeight } @@ -323,12 +330,12 @@ final class SelectGiftPageContent: Component { if self.component == nil { self.currentBounds = CGRect(origin: .zero, size: availableSize) - component.boundsUpdated.connect { [weak self] bounds in + component.boundsUpdated.connect { [weak self] update in guard let self else { return } - self.currentBounds = bounds - let _ = self.updateScrolling(interactive: true, transition: .immediate) + self.currentBounds = update.bounds + let _ = self.updateScrolling(interactive: update.isInteractive, transition: .immediate) } let initialGiftItem = GiftItem( @@ -370,7 +377,9 @@ final class SelectGiftPageContent: Component { self.availableGifts = items self.giftMap = giftMap - self.state?.updated(transition: .spring(duration: 0.4)) + if !self.isUpdating { + self.state?.updated(transition: .spring(duration: 0.4)) + } }) } @@ -545,7 +554,7 @@ private final class SheetContainerComponent: CombinedComponent { let sheet = Child(ResizableSheetComponent.self) let animateOut = StoredActionSlot(Action.self) - let boundsUpdated = ActionSlot() + let boundsUpdated = ActionSlot() return { context in let component = context.component diff --git a/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftStoreScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftStoreScreen.swift index 6d84a9c814..e711deca73 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftStoreScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftStoreScreen.swift @@ -103,6 +103,15 @@ public final class GiftStoreContentComponent: Component { if lhs.gift != rhs.gift { return false } + if lhs.safeInsets != rhs.safeInsets { + return false + } + if lhs.statusBarHeight != rhs.statusBarHeight { + return false + } + if lhs.navigationHeight != rhs.navigationHeight { + return false + } return true } diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift index 7162c75975..7e082fd710 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift @@ -1543,17 +1543,8 @@ private final class GiftViewSheetContent: CombinedComponent { self?.shareGift() }))) - - var canCraft = false - if let data = self.context.currentAppConfiguration.with({ $0 }).data { - if let _ = data["ios_enable_crafting"] { - canCraft = true - } else if let isDev = data["dev"] as? Double, isDev == 1.0 { - canCraft = true - } - } - - if let _ = arguments.canCraftDate, canCraft { + + if let _ = arguments.canCraftDate { items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_Craft, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Premium/Craft/Craft"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in @@ -5279,27 +5270,16 @@ private final class GiftViewSheetContent: CombinedComponent { var rightControlItems: [GlassControlGroupComponent.Item] = [] if uniqueGift != nil && !showWearPreview && !isDismantled { if let _ = component.subject.arguments?.canCraftDate { - var canCraft = false - if let data = component.context.currentAppConfiguration.with({ $0 }).data { - if let _ = data["ios_enable_crafting"] { - canCraft = true - } else if let isDev = data["dev"] as? Double, isDev == 1.0 { - canCraft = true - } - } - - if canCraft { - rightControlItems.append(GlassControlGroupComponent.Item( - id: AnyHashable("craft"), - content: .icon("Premium/Craft"), - action: { [weak state] in - guard let state else { - return - } - state.craftGift() + rightControlItems.append(GlassControlGroupComponent.Item( + id: AnyHashable("craft"), + content: .icon("Premium/Craft"), + action: { [weak state] in + guard let state else { + return } - )) - } + state.craftGift() + } + )) } rightControlItems.append(GlassControlGroupComponent.Item( diff --git a/submodules/TelegramUI/Components/PeerManagement/OwnershipTransferController/Sources/ChannelOwnershipTransferController.swift b/submodules/TelegramUI/Components/PeerManagement/OwnershipTransferController/Sources/ChannelOwnershipTransferController.swift index 4ed82f9463..5a27b12e51 100644 --- a/submodules/TelegramUI/Components/PeerManagement/OwnershipTransferController/Sources/ChannelOwnershipTransferController.swift +++ b/submodules/TelegramUI/Components/PeerManagement/OwnershipTransferController/Sources/ChannelOwnershipTransferController.swift @@ -169,6 +169,7 @@ private func confirmChannelOwnershipTransferController( updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peer: EnginePeer, member: TelegramUser, + onLeave: Bool, present: @escaping (ViewController, Any?) -> Void, push: @escaping (ViewController) -> Void, completion: @escaping (EnginePeer.Id?) -> Void @@ -184,7 +185,7 @@ private func confirmChannelOwnershipTransferController( var text: String if isGroup { title = presentationData.strings.Group_OwnershipTransfer_Title - text = presentationData.strings.Group_OwnershipTransfer_DescriptionInfo(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), EnginePeer.user(member).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string + text = onLeave ? presentationData.strings.Group_OwnershipTransfer_DescriptionShortInfo(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), EnginePeer.user(member).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string : presentationData.strings.Group_OwnershipTransfer_DescriptionInfo(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), EnginePeer.user(member).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string } else { title = presentationData.strings.Channel_OwnershipTransfer_Title text = presentationData.strings.Channel_OwnershipTransfer_DescriptionInfo(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), EnginePeer.user(member).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string @@ -211,6 +212,7 @@ public func channelOwnershipTransferController( updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peer: EnginePeer, member: TelegramUser, + onLeave: Bool, initialError: ChannelOwnershipTransferError, present: @escaping (ViewController, Any?) -> Void, push: @escaping (ViewController) -> Void, @@ -232,7 +234,7 @@ public func channelOwnershipTransferController( ] switch initialError { case .requestPassword: - return confirmChannelOwnershipTransferController(context: context, updatedPresentationData: updatedPresentationData, peer: peer, member: member, present: present, push: push, completion: completion) + return confirmChannelOwnershipTransferController(context: context, updatedPresentationData: updatedPresentationData, peer: peer, member: member, onLeave: onLeave, present: present, push: push, completion: completion) case .twoStepAuthTooFresh, .authSessionTooFresh: text = text + strings.OwnershipTransfer_ComeBackLater case .twoStepAuthMissing: diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index f2bfddf4a5..b3d5bb7486 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -290,13 +290,13 @@ public final class WebAppController: ViewController, AttachmentContainable { } } } - if #available(iOS 13.0, *) { - if self.presentationData.theme.overallDarkAppearance { - webView.overrideUserInterfaceStyle = .dark - } else { - webView.overrideUserInterfaceStyle = .unspecified - } + + if self.presentationData.theme.overallDarkAppearance { + webView.overrideUserInterfaceStyle = .dark + } else { + webView.overrideUserInterfaceStyle = .unspecified } + self.webView = webView self.addSubnode(self.backgroundNode) @@ -1093,6 +1093,9 @@ public final class WebAppController: ViewController, AttachmentContainable { guard let controller = self.controller else { return } + guard message.frameInfo.isMainFrame else { + return + } guard let body = message.body as? [String: Any] else { return } @@ -2028,12 +2031,10 @@ public final class WebAppController: ViewController, AttachmentContainable { self.updateHeaderBackgroundColor(transition: .immediate) self.sendThemeChangedEvent() - if #available(iOS 13.0, *) { - if self.presentationData.theme.overallDarkAppearance { - self.webView?.overrideUserInterfaceStyle = .dark - } else { - self.webView?.overrideUserInterfaceStyle = .unspecified - } + if self.presentationData.theme.overallDarkAppearance { + self.webView?.overrideUserInterfaceStyle = .dark + } else { + self.webView?.overrideUserInterfaceStyle = .unspecified } } diff --git a/submodules/WebUI/Sources/WebAppWebView.swift b/submodules/WebUI/Sources/WebAppWebView.swift index 29ef625b2b..436d8c36db 100644 --- a/submodules/WebUI/Sources/WebAppWebView.swift +++ b/submodules/WebUI/Sources/WebAppWebView.swift @@ -134,7 +134,7 @@ final class WebAppWebView: WKWebView { let contentController = WKUserContentController() var handleScriptMessageImpl: ((WKScriptMessage) -> Void)? - let eventProxyScript = WKUserScript(source: eventProxySource, injectionTime: .atDocumentStart, forMainFrameOnly: false) + let eventProxyScript = WKUserScript(source: eventProxySource, injectionTime: .atDocumentStart, forMainFrameOnly: true) contentController.addUserScript(eventProxyScript) contentController.add(WeakGameScriptMessageHandler { message in handleScriptMessageImpl?(message) diff --git a/versions.json b/versions.json index 12fb6fc717..44a6538fb3 100644 --- a/versions.json +++ b/versions.json @@ -1,5 +1,5 @@ { - "app": "12.3.3", + "app": "12.4", "xcode": "26.2", "bazel": "8.4.2:45e9388abf21d1107e146ea366ad080eb93cb6a5f3a4a3b048f78de0bc3faffa", "macos": "26"