Various improvements

This commit is contained in:
Ilya Laktyushin 2026-02-04 16:36:09 +04:00
parent b3aef93435
commit c5a0ad267c
10 changed files with 84 additions and 29 deletions

View file

@ -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$@**.";

View file

@ -135,6 +135,7 @@ extension ChatListControllerImpl {
updatedPresentationData: nil,
peer: chatPeer,
member: user,
onLeave: true,
initialError: error,
present: { c, a in
presentController(c)

View file

@ -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<CGRect>
public let boundsUpdated: ActionSlot<BoundsUpdate>
public init(
theme: PresentationTheme,
@ -32,7 +37,7 @@ public final class ResizableSheetComponentEnvironment: Equatable {
screenSize: CGSize,
regularMetricsSize: CGSize?,
dismiss: @escaping (Bool) -> Void,
boundsUpdated: ActionSlot<CGRect> = ActionSlot<CGRect>()
boundsUpdated: ActionSlot<BoundsUpdate> = ActionSlot<BoundsUpdate>()
) {
self.theme = theme
self.statusBarHeight = statusBarHeight
@ -479,7 +484,7 @@ public final class ResizableSheetComponent<ChildEnvironmentType: Sendable & Equa
var bounds = self.scrollView.bounds
bounds.size.width = itemLayout.fillingSize
self.environment?.boundsUpdated.invoke(bounds)
self.environment?.boundsUpdated.invoke(ResizableSheetComponentEnvironment.BoundsUpdate(bounds: bounds, isInteractive: self.scrollView.isTracking))
}
private var didPlayAppearanceAnimation = false

View file

@ -1109,6 +1109,7 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
updatedPresentationData: updatedPresentationData,
peer: peer,
member: member,
onLeave: false,
initialError: error,
present: { c, a in
presentControllerImpl?(c, a)

View file

@ -263,7 +263,7 @@ private final class CraftGiftPageContent: Component {
self.craftStateDisposable = (component.craftContext.state
|> 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(

View file

@ -35,7 +35,7 @@ final class SelectGiftPageContent: Component {
let starsTopUpOptions: Signal<[StarsTopUpOption]?, NoError>
let selectGift: (GiftItem) -> Void
let dismiss: () -> Void
let boundsUpdated: ActionSlot<CGRect>
let boundsUpdated: ActionSlot<ResizableSheetComponentEnvironment.BoundsUpdate>
init(
context: AccountContext,
@ -47,7 +47,7 @@ final class SelectGiftPageContent: Component {
starsTopUpOptions: Signal<[StarsTopUpOption]?, NoError>,
selectGift: @escaping (GiftItem) -> Void,
dismiss: @escaping () -> Void,
boundsUpdated: ActionSlot<CGRect>
boundsUpdated: ActionSlot<ResizableSheetComponentEnvironment.BoundsUpdate>
) {
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<EnvironmentType>.self)
let animateOut = StoredActionSlot(Action<Void>.self)
let boundsUpdated = ActionSlot<CGRect>()
let boundsUpdated = ActionSlot<ResizableSheetComponentEnvironment.BoundsUpdate>()
return { context in
let component = context.component

View file

@ -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
}

View file

@ -169,6 +169,7 @@ private func confirmChannelOwnershipTransferController(
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = 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<PresentationData, NoError>)? = 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:

View file

@ -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
}
}

View file

@ -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)