mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Temp
This commit is contained in:
parent
675696da2b
commit
0aac8d47ac
11 changed files with 197 additions and 19 deletions
|
|
@ -1537,14 +1537,18 @@ public protocol SharedAccountContext: AnyObject {
|
|||
|
||||
func makeLoginEmailSetupController(context: AccountContext, blocking: Bool, emailPattern: String?, canAutoDismissIfNeeded: Bool, navigationController: NavigationController?, completion: @escaping () -> Void, dismiss: @escaping () -> Void) -> ViewController
|
||||
func makePasskeySetupController(context: AccountContext, displaySkip: Bool, navigationController: NavigationController?, completion: @escaping () -> Void, dismiss: @escaping () -> Void) -> ViewController
|
||||
|
||||
func makeChatCustomRankSetupScreen(context: AccountContext, peerId: EnginePeer.Id, participantId: EnginePeer.Id, rank: String?, role: ChatRankInfoScreenRole) -> ViewController
|
||||
|
||||
func makePeerCopyProtectionInfoScreen(context: AccountContext, completion: @escaping () -> Void) -> ViewController
|
||||
|
||||
func makeChatRankInfoScreen(context: AccountContext, chatPeer: EnginePeer, userPeer: EnginePeer, role: ChatRankInfoScreenRole, rank: String, canChange: Bool, completion: @escaping () -> Void) -> ViewController
|
||||
|
||||
func makeChatRankPreviewItem(context: AccountContext, peer: EnginePeer, rank: String, rankRole: ChatRankInfoScreenRole, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, sectionId: Int32) -> ListViewItem
|
||||
func makeCreateBotScreen(
|
||||
context: AccountContext,
|
||||
parentBot: EnginePeer.Id,
|
||||
initialUsername: String?,
|
||||
initialTitle: String?,
|
||||
openAutomatically: Bool,
|
||||
completion: @escaping (EnginePeer.Id?) -> Void
|
||||
) async -> ViewController?
|
||||
|
||||
func navigateToCurrentCall()
|
||||
var hasOngoingCall: ValuePromise<Bool> { get }
|
||||
|
|
|
|||
|
|
@ -1778,6 +1778,26 @@ public extension TelegramEngine {
|
|||
public func composeAIMessage(text: TextWithEntities, mode: TelegramComposeAIMessageMode) -> Signal<TelegramAIComposeMessageResult, TelegramAIComposeMessageError> {
|
||||
return _internal_composeAIMessage(account: self.account, text: text, mode: mode)
|
||||
}
|
||||
|
||||
public func requestMiniAppButton(peerId: EnginePeer.Id, requestId: String) -> Signal<ReplyMarkupButton?, NoError> {
|
||||
let account = self.account
|
||||
return self.account.postbox.transaction { transaction -> Api.InputUser? in
|
||||
return transaction.getPeer(peerId).flatMap(apiInputUser)
|
||||
}
|
||||
|> mapToSignal { inputUser -> Signal<ReplyMarkupButton?, NoError> in
|
||||
guard let inputUser else {
|
||||
return .single(nil)
|
||||
}
|
||||
return account.network.request(Api.functions.bots.getRequestedWebViewButton(bot: inputUser, webappReqId: requestId))
|
||||
|> map { result -> ReplyMarkupButton in
|
||||
return ReplyMarkupButton(apiButton: result)
|
||||
}
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<ReplyMarkupButton?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import Foundation
|
|||
import SwiftSignalKit
|
||||
import Postbox
|
||||
|
||||
public typealias EnginePreferencesEntry = PreferencesEntry
|
||||
|
||||
public extension TelegramEngine {
|
||||
final class Preferences {
|
||||
private let account: Account
|
||||
|
|
|
|||
|
|
@ -315,17 +315,23 @@ private final class CreateBotSheetComponent: Component {
|
|||
let parentPeer: EnginePeer
|
||||
let initialUsername: String?
|
||||
let initialTitle: String?
|
||||
let openAutomatically: Bool
|
||||
let completion: (EnginePeer.Id) -> Void
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
parentPeer: EnginePeer,
|
||||
initialUsername: String?,
|
||||
initialTitle: String?
|
||||
initialTitle: String?,
|
||||
openAutomatically: Bool,
|
||||
completion: @escaping (EnginePeer.Id) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.parentPeer = parentPeer
|
||||
self.initialUsername = initialUsername
|
||||
self.initialTitle = initialTitle
|
||||
self.openAutomatically = openAutomatically
|
||||
self.completion = completion
|
||||
}
|
||||
|
||||
static func ==(lhs: CreateBotSheetComponent, rhs: CreateBotSheetComponent) -> Bool {
|
||||
|
|
@ -410,14 +416,14 @@ private final class CreateBotSheetComponent: Component {
|
|||
self.animateOut.invoke(Action { [weak controller, weak navigationController] _ in
|
||||
if let controller, let navigationController {
|
||||
controller.dismiss(completion: { [weak navigationController] in
|
||||
guard let navigationController else {
|
||||
return
|
||||
if component.openAutomatically, let navigationController {
|
||||
component.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(
|
||||
navigationController: navigationController,
|
||||
context: context,
|
||||
chatLocation: .peer(botPeer)
|
||||
))
|
||||
}
|
||||
component.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(
|
||||
navigationController: navigationController,
|
||||
context: context,
|
||||
chatLocation: .peer(botPeer)
|
||||
))
|
||||
component.completion(botPeer.id)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
@ -573,7 +579,9 @@ public class CreateBotScreen: ViewControllerComponentContainer {
|
|||
context: AccountContext,
|
||||
parentBot: EnginePeer.Id,
|
||||
initialUsername: String?,
|
||||
initialTitle: String?
|
||||
initialTitle: String?,
|
||||
openAutomatically: Bool,
|
||||
completion: @escaping (EnginePeer.Id) -> Void
|
||||
) async {
|
||||
self.context = context
|
||||
|
||||
|
|
@ -589,7 +597,9 @@ public class CreateBotScreen: ViewControllerComponentContainer {
|
|||
context: context,
|
||||
parentPeer: parentPeer,
|
||||
initialUsername: initialUsername,
|
||||
initialTitle: initialTitle
|
||||
initialTitle: initialTitle,
|
||||
openAutomatically: openAutomatically,
|
||||
completion: completion
|
||||
),
|
||||
navigationBarAppearance: .none,
|
||||
statusBarStyle: .ignore,
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ swift_library(
|
|||
"//submodules/TelegramUI/Components/ToastComponent",
|
||||
"//submodules/TelegramNotices",
|
||||
"//submodules/Markdown",
|
||||
"//submodules/TelegramUIPreferences",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import ListActionItemComponent
|
|||
import ToastComponent
|
||||
import TelegramNotices
|
||||
import Markdown
|
||||
import TelegramUIPreferences
|
||||
|
||||
final class TextProcessingContentComponent: Component {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
|
@ -40,6 +41,7 @@ final class TextProcessingContentComponent: Component {
|
|||
let mode: TextProcessingScreen.Mode
|
||||
let styles: [TelegramComposeAIMessageMode.Style]
|
||||
let inputText: TextWithEntities
|
||||
let initialEditState: TextProcessingScreen.EditState?
|
||||
let shouldDisplayStyleNotice: Bool
|
||||
let copyCurrentResult: (() -> Void)?
|
||||
let translateChat: ((String) -> Void)?
|
||||
|
|
@ -51,6 +53,7 @@ final class TextProcessingContentComponent: Component {
|
|||
mode: TextProcessingScreen.Mode,
|
||||
styles: [TelegramComposeAIMessageMode.Style],
|
||||
inputText: TextWithEntities,
|
||||
initialEditState: TextProcessingScreen.EditState?,
|
||||
shouldDisplayStyleNotice: Bool,
|
||||
copyCurrentResult: (() -> Void)?,
|
||||
translateChat: ((String) -> Void)?,
|
||||
|
|
@ -61,6 +64,7 @@ final class TextProcessingContentComponent: Component {
|
|||
self.context = context
|
||||
self.mode = mode
|
||||
self.inputText = inputText
|
||||
self.initialEditState = initialEditState
|
||||
self.shouldDisplayStyleNotice = shouldDisplayStyleNotice
|
||||
self.copyCurrentResult = copyCurrentResult
|
||||
self.translateChat = translateChat
|
||||
|
|
@ -106,7 +110,6 @@ final class TextProcessingContentComponent: Component {
|
|||
self.addSubview(self.currentContentBackground)
|
||||
self.addSubview(self.currentContentContainer)
|
||||
|
||||
|
||||
self.translateState.resultUpdated = { [weak self] _ in
|
||||
self?.externalStatesUpdated()
|
||||
}
|
||||
|
|
@ -163,6 +166,30 @@ final class TextProcessingContentComponent: Component {
|
|||
component.externalState.nonPremiumFloodTriggered = true
|
||||
#endif*/
|
||||
}
|
||||
|
||||
private func saveState() {
|
||||
guard let component = self.component else {
|
||||
return
|
||||
}
|
||||
if case let .edit(saveRestoreStateId, _, _) = component.mode, let saveRestoreStateId {
|
||||
let mappedMode: Int32
|
||||
switch self.currentMode {
|
||||
case .translate:
|
||||
mappedMode = 0
|
||||
case .stylize:
|
||||
mappedMode = 1
|
||||
case .fix:
|
||||
mappedMode = 2
|
||||
}
|
||||
|
||||
let state = TextProcessingScreen.EditState(
|
||||
selectedMode: mappedMode
|
||||
)
|
||||
let _ = component.context.engine.preferences.update(id: ApplicationSpecificPreferencesKeys.textProcessingEditingState(peerId: saveRestoreStateId), { _ in
|
||||
return EnginePreferencesEntry(state)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func update(component: TextProcessingContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) -> CGSize {
|
||||
self.isUpdating = true
|
||||
|
|
@ -498,6 +525,7 @@ private final class TextProcessingSheetComponent: Component {
|
|||
let ignoredTranslationLanguages: [String]
|
||||
let styles: [TelegramComposeAIMessageMode.Style]
|
||||
let inputText: TextWithEntities
|
||||
let initialEditState: TextProcessingScreen.EditState?
|
||||
let shouldDisplayStyleNotice: Bool
|
||||
let copyCurrentResult: ((TextWithEntities) -> Void)?
|
||||
let translateChat: ((String) -> Void)?
|
||||
|
|
@ -508,6 +536,7 @@ private final class TextProcessingSheetComponent: Component {
|
|||
ignoredTranslationLanguages: [String],
|
||||
styles: [TelegramComposeAIMessageMode.Style],
|
||||
inputText: TextWithEntities,
|
||||
initialEditState: TextProcessingScreen.EditState?,
|
||||
shouldDisplayStyleNotice: Bool,
|
||||
copyCurrentResult: ((TextWithEntities) -> Void)?,
|
||||
translateChat: ((String) -> Void)?
|
||||
|
|
@ -517,6 +546,7 @@ private final class TextProcessingSheetComponent: Component {
|
|||
self.ignoredTranslationLanguages = ignoredTranslationLanguages
|
||||
self.styles = styles
|
||||
self.inputText = inputText
|
||||
self.initialEditState = initialEditState
|
||||
self.shouldDisplayStyleNotice = shouldDisplayStyleNotice
|
||||
self.copyCurrentResult = copyCurrentResult
|
||||
self.translateChat = translateChat
|
||||
|
|
@ -614,7 +644,7 @@ private final class TextProcessingSheetComponent: Component {
|
|||
}
|
||||
} else {
|
||||
switch component.mode {
|
||||
case let .edit(completion, send):
|
||||
case let .edit(_, completion, send):
|
||||
actionButtonTitle = "Apply"
|
||||
performSendAction = send
|
||||
isMainActionEnabled = !self.contentExternalState.isProcessing
|
||||
|
|
@ -663,6 +693,7 @@ private final class TextProcessingSheetComponent: Component {
|
|||
mode: component.mode,
|
||||
styles: component.styles,
|
||||
inputText: component.inputText,
|
||||
initialEditState: component.initialEditState,
|
||||
shouldDisplayStyleNotice: component.shouldDisplayStyleNotice,
|
||||
copyCurrentResult: component.copyCurrentResult != nil ? {
|
||||
copyCurrentResultImpl()
|
||||
|
|
@ -891,10 +922,18 @@ private final class TextProcessingSheetComponent: Component {
|
|||
|
||||
public class TextProcessingScreen: ViewControllerComponentContainer {
|
||||
public enum Mode {
|
||||
case edit(completion: (TextWithEntities) -> Void, send: ((TextWithEntities) -> Void)?)
|
||||
case edit(saveRestoreStateId: EnginePeer.Id?, completion: (TextWithEntities) -> Void, send: ((TextWithEntities) -> Void)?)
|
||||
case translate(fromLanguage: String?)
|
||||
}
|
||||
|
||||
struct EditState: Codable {
|
||||
var selectedMode: Int32
|
||||
|
||||
init(selectedMode: Int32) {
|
||||
self.selectedMode = selectedMode
|
||||
}
|
||||
}
|
||||
|
||||
private let context: AccountContext
|
||||
|
||||
public init(
|
||||
|
|
@ -908,8 +947,14 @@ public class TextProcessingScreen: ViewControllerComponentContainer {
|
|||
self.context = context
|
||||
|
||||
let styles = await context.engine.messages.composeAIMessageStyles().get()
|
||||
|
||||
let shouldDisplayStyleNotice = await ApplicationSpecificNotice.getAITextProcessingStyleSelection(accountManager: context.sharedContext.accountManager).get() < 3
|
||||
|
||||
var initialEditState: EditState?
|
||||
if case let .edit(saveRestoreStateId, _, _) = mode, let saveRestoreStateId {
|
||||
initialEditState = await context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Configuration.ApplicationSpecificPreference(key: ApplicationSpecificPreferencesKeys.textProcessingEditingState(peerId: saveRestoreStateId))
|
||||
).get()?.get(EditState.self)
|
||||
}
|
||||
|
||||
super.init(
|
||||
context: context,
|
||||
|
|
@ -919,6 +964,7 @@ public class TextProcessingScreen: ViewControllerComponentContainer {
|
|||
ignoredTranslationLanguages: ignoredTranslationLanguages,
|
||||
styles: styles,
|
||||
inputText: inputText,
|
||||
initialEditState: initialEditState,
|
||||
shouldDisplayStyleNotice: shouldDisplayStyleNotice,
|
||||
copyCurrentResult: copyResult,
|
||||
translateChat: translateChat
|
||||
|
|
|
|||
|
|
@ -4482,6 +4482,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
self.controller?.push(await TextProcessingScreen(
|
||||
context: self.context,
|
||||
mode: .edit(
|
||||
saveRestoreStateId: self.chatLocation.peerId,
|
||||
completion: { [weak self] text in
|
||||
guard let self, let controller = self.controller else {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1944,7 +1944,10 @@ func openResolvedUrlImpl(
|
|||
context: context,
|
||||
parentBot: parentBot,
|
||||
initialUsername: username,
|
||||
initialTitle: title
|
||||
initialTitle: title,
|
||||
openAutomatically: true,
|
||||
completion: { _ in
|
||||
}
|
||||
) else {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ import ChatParticipantRightsScreen
|
|||
import PeerCopyProtectionInfoScreen
|
||||
import ChatRankInfoScreen
|
||||
import RankChatPreviewItem
|
||||
import CreateBotScreen
|
||||
|
||||
private final class AccountUserInterfaceInUseContext {
|
||||
let subscribers = Bag<(Bool) -> Void>()
|
||||
|
|
@ -4363,6 +4364,24 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||
)
|
||||
return RankChatPreviewItem(context: context, systemStyle: .glass, theme: theme, componentTheme: theme, strings: strings, sectionId: sectionId, fontSize: fontSize, chatBubbleCorners: chatBubbleCorners, wallpaper: wallpaper, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameOrder, messageItems: [messageItem])
|
||||
}
|
||||
|
||||
public func makeCreateBotScreen(
|
||||
context: AccountContext,
|
||||
parentBot: EnginePeer.Id,
|
||||
initialUsername: String?,
|
||||
initialTitle: String?,
|
||||
openAutomatically: Bool,
|
||||
completion: @escaping (EnginePeer.Id?) -> Void
|
||||
) async -> ViewController? {
|
||||
return await CreateBotScreen(
|
||||
context: context,
|
||||
parentBot: parentBot,
|
||||
initialUsername: initialUsername,
|
||||
initialTitle: initialTitle,
|
||||
openAutomatically: openAutomatically,
|
||||
completion: completion
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private func peerInfoControllerImpl(context: AccountContext, updatedPresentationData: (PresentationData, Signal<PresentationData, NoError>)?, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, requestsContext: PeerInvitationImportersContext? = nil) -> ViewController? {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ private enum ApplicationSpecificPreferencesKeyValues: Int32 {
|
|||
case widgetSettings = 19
|
||||
case mediaAutoSaveSettings = 20
|
||||
case ageVerificationState = 21
|
||||
case textProcessingEditingState = 22
|
||||
}
|
||||
|
||||
public struct ApplicationSpecificPreferencesKeys {
|
||||
|
|
@ -18,6 +19,13 @@ public struct ApplicationSpecificPreferencesKeys {
|
|||
public static let widgetSettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.widgetSettings.rawValue)
|
||||
public static let mediaAutoSaveSettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.mediaAutoSaveSettings.rawValue)
|
||||
public static let ageVerificationState = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.ageVerificationState.rawValue)
|
||||
|
||||
public static func textProcessingEditingState(peerId: PeerId) -> ValueBoxKey {
|
||||
let key = ValueBoxKey(length: 4 + 8)
|
||||
key.setInt32(0, value: ApplicationSpecificPreferencesKeyValues.textProcessingEditingState.rawValue)
|
||||
key.setInt64(4, value: peerId.toInt64())
|
||||
return key
|
||||
}
|
||||
}
|
||||
|
||||
private enum ApplicationSpecificSharedDataKeyValues: Int32 {
|
||||
|
|
|
|||
|
|
@ -1930,6 +1930,10 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||
self.controller?.verifyAgeCompletion?(Int(ageValue))
|
||||
}
|
||||
}
|
||||
case "web_app_request_chat":
|
||||
if let json, let requestId = json["req_id"] as? String {
|
||||
self.requestChat(requestId: requestId)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
|
@ -2299,6 +2303,66 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||
})
|
||||
}
|
||||
|
||||
fileprivate func requestChat(requestId: String) {
|
||||
guard let controller = self.controller, !self.dismissed else {
|
||||
return
|
||||
}
|
||||
let _ = (self.context.engine.messages.requestMiniAppButton(peerId: controller.botId, requestId: requestId)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] button in
|
||||
guard let self, let button else {
|
||||
return
|
||||
}
|
||||
switch button.action {
|
||||
case let .requestPeer(peerType, buttonId, maxQuantity):
|
||||
let _ = maxQuantity
|
||||
|
||||
switch peerType {
|
||||
case let .createBot(createBot):
|
||||
Task { @MainActor [weak self] in
|
||||
guard let self, let controller = self.controller else {
|
||||
return
|
||||
}
|
||||
let createBotScreen = await self.context.sharedContext.makeCreateBotScreen(
|
||||
context: self.context,
|
||||
parentBot: controller.botId,
|
||||
initialUsername: createBot.suggestedUsername,
|
||||
initialTitle: createBot.suggestedName,
|
||||
openAutomatically: false,
|
||||
completion: { [weak self] resultId in
|
||||
guard let self, let controller = self.controller else {
|
||||
return
|
||||
}
|
||||
if let resultId {
|
||||
let _ = self.context.engine.peers.sendBotRequestedPeer(peerId: controller.botId, requestId: requestId, buttonId: buttonId, requestedPeerIds: [resultId]
|
||||
).startStandalone(error: { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.webView?.sendEvent(name: "requested_chat_failed", data: nil)
|
||||
}, completed: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.webView?.sendEvent(name: "requested_chat_sent", data: nil)
|
||||
})
|
||||
} else {
|
||||
self.webView?.sendEvent(name: "requested_chat_failed", data: nil)
|
||||
}
|
||||
}
|
||||
)
|
||||
if let createBotScreen {
|
||||
controller.push(createBotScreen)
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fileprivate func invokeCustomMethod(requestId: String, method: String, params: String) {
|
||||
guard let controller = self.controller, !self.dismissed else {
|
||||
return
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue