Various improvements

This commit is contained in:
Ilya Laktyushin 2025-12-17 14:31:54 +04:00
parent 28d4e1e171
commit 1a1f08de64
55 changed files with 3401 additions and 2944 deletions

View file

@ -57,6 +57,7 @@ swift_library(
"//submodules/TelegramUI/Components/GlassBarButtonComponent",
"//submodules/Components/BundleIconComponent",
"//submodules/TelegramUI/Components/LottieComponent",
"//submodules/TelegramUI/Components/AlertComponent",
],
visibility = [
"//visibility:public",

View file

@ -43,6 +43,7 @@ import GlassBarButtonComponent
import BundleIconComponent
import LottieComponent
import CryptoKit
import AlertComponent
private let durgerKingBotIds: [Int64] = [5104055776, 2200339955]
@ -761,12 +762,19 @@ public final class WebAppController: ViewController, AttachmentContainable {
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
var completed = false
let alertController = textAlertController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, title: nil, text: message, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {
if !completed {
completed = true
completionHandler()
}
})])
let alertController = AlertScreen(
context: self.context,
title: nil,
text: message,
actions: [
.init(title: self.presentationData.strings.Common_OK, action: {
if !completed {
completed = true
completionHandler()
}
})
]
)
alertController.dismissed = { byOutsideTap in
if byOutsideTap {
if !completed {
@ -780,17 +788,25 @@ public final class WebAppController: ViewController, AttachmentContainable {
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
var completed = false
let alertController = textAlertController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, title: nil, text: message, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: {
if !completed {
completed = true
completionHandler(false)
}
}), TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {
if !completed {
completed = true
completionHandler(true)
}
})])
let alertController = AlertScreen(
context: self.context,
title: nil,
text: message,
actions: [
.init(title: self.presentationData.strings.Common_Cancel, action: {
if !completed {
completed = true
completionHandler(false)
}
}),
.init(title: self.presentationData.strings.Common_OK, type: .default, action: {
if !completed {
completed = true
completionHandler(true)
}
})
]
)
alertController.dismissed = { byOutsideTap in
if byOutsideTap {
if !completed {
@ -1385,7 +1401,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
let presentationData = self.presentationData
let title = json["title"] as? String
var alertButtons: [TextAlertAction] = []
var actions: [AlertScreen.Action] = []
for buttonJson in buttons.reversed() {
if let button = buttonJson as? [String: Any], let id = button["id"] as? String, let type = button["type"] as? String {
@ -1395,27 +1411,27 @@ public final class WebAppController: ViewController, AttachmentContainable {
let text = button["text"] as? String
switch type {
case "default":
if let text = text {
alertButtons.append(TextAlertAction(type: .genericAction, title: text, action: {
if let text {
actions.append(AlertScreen.Action(title: text, action: {
buttonAction()
}))
}
case "destructive":
if let text = text {
alertButtons.append(TextAlertAction(type: .destructiveAction, title: text, action: {
if let text {
actions.append(AlertScreen.Action(title: text, type: .destructive, action: {
buttonAction()
}))
}
case "ok":
alertButtons.append(TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
actions.append(AlertScreen.Action(title: presentationData.strings.Common_OK, type: .default, action: {
buttonAction()
}))
case "cancel":
alertButtons.append(TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
actions.append(AlertScreen.Action(title: presentationData.strings.Common_Cancel, action: {
buttonAction()
}))
case "close":
alertButtons.append(TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Close, action: {
actions.append(AlertScreen.Action(title: presentationData.strings.Common_Close, action: {
buttonAction()
}))
default:
@ -1424,12 +1440,18 @@ public final class WebAppController: ViewController, AttachmentContainable {
}
}
var actionLayout: TextAlertContentActionLayout = .horizontal
if alertButtons.count > 2 {
var actionLayout: AlertScreen.ActionAligmnent = .default
if actions.count > 2 {
actionLayout = .vertical
alertButtons = Array(alertButtons.reversed())
actions = Array(actions.reversed())
}
let alertController = textAlertController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, title: title, text: message, actions: alertButtons, actionLayout: actionLayout)
let alertController = AlertScreen(
context: self.context,
configuration: AlertScreen.Configuration(actionAlignment: actionLayout, dismissOnOutsideTap: true, allowInputInset: false),
title: title,
text: message,
actions: actions
)
alertController.dismissed = { byOutsideTap in
if byOutsideTap {
self.sendAlertButtonEvent(id: nil)
@ -2113,18 +2135,26 @@ public final class WebAppController: ViewController, AttachmentContainable {
if result {
sendEvent(true)
} else {
let alertController = textAlertController(context: self.context, updatedPresentationData: controller.updatedPresentationData, title: self.presentationData.strings.WebApp_AllowWriteTitle, text: self.presentationData.strings.WebApp_AllowWriteConfirmation(controller.botName).string, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: {
sendEvent(false)
}), TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: { [weak self] in
guard let self else {
return
}
let _ = (self.context.engine.messages.allowBotSendMessages(botId: controller.botId)
|> deliverOnMainQueue).start(completed: {
sendEvent(true)
})
})], parseMarkdown: true)
let alertController = AlertScreen(
context: self.context,
title: self.presentationData.strings.WebApp_AllowWriteTitle,
text: self.presentationData.strings.WebApp_AllowWriteConfirmation(controller.botName).string,
actions: [
.init(title: self.presentationData.strings.Common_Cancel, action: {
sendEvent(false)
}),
.init(title: self.presentationData.strings.Common_OK, type: .default, action: { [weak self] in
guard let self else {
return
}
let _ = (self.context.engine.messages.allowBotSendMessages(botId: controller.botId)
|> deliverOnMainQueue).start(completed: {
sendEvent(true)
})
})
]
)
alertController.dismissed = { byOutsideTap in
if byOutsideTap {
sendEvent(false)
@ -2166,48 +2196,56 @@ public final class WebAppController: ViewController, AttachmentContainable {
text = self.presentationData.strings.WebApp_SharePhoneConfirmation(botName).string
}
let alertController = textAlertController(context: self.context, updatedPresentationData: controller.updatedPresentationData, title: self.presentationData.strings.WebApp_SharePhoneTitle, text: text, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: {
sendEvent(false)
}), TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: { [weak self] in
guard let self, case let .user(user) = accountPeer, let phone = user.phone, !phone.isEmpty else {
return
}
let sendMessageSignal = enqueueMessages(account: self.context.account, peerId: botId, messages: [
.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: TelegramMediaContact(firstName: user.firstName ?? "", lastName: user.lastName ?? "", phoneNumber: phone, peerId: user.id, vCardData: nil)), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])
])
|> mapToSignal { messageIds in
if let maybeMessageId = messageIds.first, let messageId = maybeMessageId {
return context.account.pendingMessageManager.pendingMessageStatus(messageId)
|> mapToSignal { status, _ -> Signal<Bool, NoError> in
if status != nil {
return .never()
let alertController = AlertScreen(
context: self.context,
title: self.presentationData.strings.WebApp_SharePhoneTitle,
text: text,
actions: [
.init(title: self.presentationData.strings.Common_Cancel, action: {
sendEvent(false)
}),
.init(title: self.presentationData.strings.Common_OK, type: .default, action: { [weak self] in
guard let self, case let .user(user) = accountPeer, let phone = user.phone, !phone.isEmpty else {
return
}
let sendMessageSignal = enqueueMessages(account: self.context.account, peerId: botId, messages: [
.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: TelegramMediaContact(firstName: user.firstName ?? "", lastName: user.lastName ?? "", phoneNumber: phone, peerId: user.id, vCardData: nil)), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])
])
|> mapToSignal { messageIds in
if let maybeMessageId = messageIds.first, let messageId = maybeMessageId {
return context.account.pendingMessageManager.pendingMessageStatus(messageId)
|> mapToSignal { status, _ -> Signal<Bool, NoError> in
if status != nil {
return .never()
} else {
return .single(true)
}
}
|> take(1)
} else {
return .single(true)
return .complete()
}
}
|> take(1)
} else {
return .complete()
}
}
let sendMessage = {
let _ = (sendMessageSignal
|> deliverOnMainQueue).start(completed: {
sendEvent(true)
let sendMessage = {
let _ = (sendMessageSignal
|> deliverOnMainQueue).start(completed: {
sendEvent(true)
})
}
if requiresUnblock {
let _ = (context.engine.privacy.requestUpdatePeerIsBlocked(peerId: botId, isBlocked: false)
|> deliverOnMainQueue).start(completed: {
sendMessage()
})
} else {
sendMessage()
}
})
}
if requiresUnblock {
let _ = (context.engine.privacy.requestUpdatePeerIsBlocked(peerId: botId, isBlocked: false)
|> deliverOnMainQueue).start(completed: {
sendMessage()
})
} else {
sendMessage()
}
})], parseMarkdown: true)
]
)
alertController.dismissed = { byOutsideTap in
if byOutsideTap {
sendEvent(false)

View file

@ -23,6 +23,7 @@ import ListItemComponentAdaptor
import TelegramStringFormatting
import UndoUI
import ChatMessagePaymentAlertController
import GlassBarButtonComponent
private final class SheetContent: CombinedComponent {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
@ -55,7 +56,7 @@ private final class SheetContent: CombinedComponent {
}
static var body: Body {
let closeButton = Child(Button.self)
let closeButton = Child(GlassBarButtonComponent.self)
let title = Child(Text.self)
let amountSection = Child(ListSectionComponent.self)
let button = Child(ButtonComponent.self)
@ -71,22 +72,31 @@ private final class SheetContent: CombinedComponent {
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
let sideInset: CGFloat = 16.0
var contentSize = CGSize(width: context.availableSize.width, height: 18.0)
var contentSize = CGSize(width: context.availableSize.width, height: 36.0)
let constrainedTitleWidth = context.availableSize.width - 16.0 * 2.0
let closeButton = closeButton.update(
component: Button(
content: AnyComponent(Text(text: environment.strings.Common_Cancel, font: Font.regular(17.0), color: theme.actionSheet.controlAccentColor)),
action: {
component: GlassBarButtonComponent(
size: CGSize(width: 40.0, height: 40.0),
backgroundColor: theme.rootController.navigationBar.glassBarButtonBackgroundColor,
isDark: theme.overallDarkAppearance,
state: .generic,
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
BundleIconComponent(
name: "Navigation/Close",
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
)
)),
action: { _ in
component.dismiss()
}
),
availableSize: CGSize(width: 120.0, height: 30.0),
availableSize: CGSize(width: 40.0, height: 40.0),
transition: .immediate
)
context.add(closeButton
.position(CGPoint(x: closeButton.size.width / 2.0 + sideInset, y: 28.0))
.position(CGPoint(x: 16.0 + closeButton.size.width / 2.0, y: 16.0 + closeButton.size.height / 2.0))
)
let title = title.update(
@ -95,7 +105,7 @@ private final class SheetContent: CombinedComponent {
transition: .immediate
)
context.add(title
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + title.size.height / 2.0))
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height))
)
contentSize.height += title.size.height
contentSize.height += 40.0
@ -344,6 +354,7 @@ private final class WebAppMessagePreviewSheetComponent: CombinedComponent {
})
}
)),
style: .glass,
backgroundColor: .color(environment.theme.list.blocksBackgroundColor),
followContentSizeChanges: false,
clipsContent: true,