Merge commit '7621e2f8dec938cf48181c8b10afc9b01f444e68' into beta

This commit is contained in:
Ilya Laktyushin
2025-12-06 02:17:48 +04:00
commit 8344b97e03
28070 changed files with 7995182 additions and 0 deletions
@@ -0,0 +1,25 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "BotSettingsScreen",
module_name = "BotSettingsScreen",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/Display",
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/TelegramCore",
"//submodules/TelegramPresentationData",
"//submodules/ItemListUI",
"//submodules/ItemListPeerItem",
"//submodules/AccountContext",
],
visibility = [
"//visibility:public",
],
)
@@ -0,0 +1,172 @@
import UIKit
import Display
import SwiftSignalKit
import TelegramCore
import TelegramPresentationData
import ItemListUI
import ItemListPeerItem
import AccountContext
private final class BotListSettingsArguments {
let context: AccountContext
let openBot: (EnginePeer.Id) -> Void
init(
context: AccountContext,
openBot: @escaping (EnginePeer.Id) -> Void
) {
self.context = context
self.openBot = openBot
}
}
private enum BotListSettingsSection: Int32 {
case botItems
}
private enum BotListSettingsEntry: ItemListNodeEntry {
case botItem(peer: EnginePeer)
var section: ItemListSectionId {
switch self {
case .botItem:
return BotListSettingsSection.botItems.rawValue
}
}
var stableId: EnginePeer.Id {
switch self {
case let .botItem(peer):
return peer.id
}
}
static func ==(lhs: BotListSettingsEntry, rhs: BotListSettingsEntry) -> Bool {
switch lhs {
case let .botItem(peer):
if case .botItem(peer) = rhs {
return true
} else {
return false
}
}
}
static func <(lhs: BotListSettingsEntry, rhs: BotListSettingsEntry) -> Bool {
switch lhs {
case let .botItem(lhsPeer):
switch rhs {
case let .botItem(rhsPeer):
if lhsPeer.compactDisplayTitle != rhsPeer.compactDisplayTitle {
return lhsPeer.compactDisplayTitle < rhsPeer.compactDisplayTitle
}
return lhsPeer.id < rhsPeer.id
}
}
}
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
let arguments = arguments as! BotListSettingsArguments
switch self {
case let .botItem(peer):
return ItemListPeerItem(
presentationData: presentationData,
systemStyle: .glass,
dateTimeFormat: presentationData.dateTimeFormat,
nameDisplayOrder: presentationData.nameDisplayOrder,
context: arguments.context,
peer: peer,
presence: nil,
text: .none,
label: .disclosure(""),
editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false),
enabled: true,
selectable: true,
sectionId: self.section,
action: {
arguments.openBot(peer.id)
},
setPeerIdWithRevealedOptions: { _, _ in
},
removePeer: { _ in
},
style: .blocks
)
}
}
}
private struct BotListSettingsState: Equatable {
init() {
}
}
private func botListSettingsEntries(
presentationData: PresentationData,
peers: [EnginePeer]
) -> [BotListSettingsEntry] {
var entries: [BotListSettingsEntry] = []
for peer in peers {
entries.append(.botItem(peer: peer))
}
entries.sort(by: { $0 < $1 })
return entries
}
public func botListSettingsScreen(context: AccountContext) -> ViewController {
let initialState = BotListSettingsState()
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
let stateValue = Atomic(value: initialState)
let updateState: ((BotListSettingsState) -> BotListSettingsState) -> Void = { f in
statePromise.set(stateValue.modify { f($0) })
}
let _ = updateState
var pushControllerImpl: ((ViewController) -> Void)?
let actionsDisposable = DisposableSet()
let arguments = BotListSettingsArguments(
context: context,
openBot: { peerId in
pushControllerImpl?(botSettingsScreen(context: context, peerId: peerId))
}
)
let botPeerList: Signal<[EnginePeer], NoError> = context.engine.peers.botsWithBiometricState()
|> distinctUntilChanged
|> mapToSignal { peerIds -> Signal<[EnginePeer], NoError> in
return context.engine.data.subscribe(
EngineDataList(peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:)))
)
|> map { peers -> [EnginePeer] in
return peers.compactMap { $0 }
}
}
let signal = combineLatest(
context.sharedContext.presentationData,
statePromise.get(),
botPeerList
)
|> deliverOnMainQueue
|> map { presentationData, state, botPeerList -> (ItemListControllerState, (ItemListNodeState, Any)) in
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.Settings_BotListSettings), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: botListSettingsEntries(presentationData: presentationData, peers: botPeerList), style: .blocks, animateChanges: true)
return (controllerState, (listState, arguments))
} |> afterDisposed {
actionsDisposable.dispose()
}
let controller = ItemListController(context: context, state: signal)
pushControllerImpl = { [weak controller] c in
(controller?.navigationController as? NavigationController)?.pushViewController(c, animated: true)
}
return controller
}
@@ -0,0 +1,151 @@
import UIKit
import Display
import SwiftSignalKit
import TelegramCore
import TelegramPresentationData
import ItemListUI
import AccountContext
private final class BotSettingsArguments {
let context: AccountContext
let updateBiometryAccess: (Bool) -> Void
init(
context: AccountContext,
updateBiometryAccess: @escaping (Bool) -> Void
) {
self.context = context
self.updateBiometryAccess = updateBiometryAccess
}
}
private enum BotSettingsSection: Int32 {
case settings
}
private enum BotSettingsEntry: ItemListNodeEntry {
case biometryAccess(value: Bool)
var section: ItemListSectionId {
switch self {
case .biometryAccess:
return BotSettingsSection.settings.rawValue
}
}
var stableId: Int {
switch self {
case .biometryAccess:
return 0
}
}
static func ==(lhs: BotSettingsEntry, rhs: BotSettingsEntry) -> Bool {
switch lhs {
case let .biometryAccess(value):
if case .biometryAccess(value) = rhs {
return true
} else {
return false
}
}
}
static func <(lhs: BotSettingsEntry, rhs: BotSettingsEntry) -> Bool {
return lhs.stableId < rhs.stableId
}
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
let arguments = arguments as! BotSettingsArguments
switch self {
case let .biometryAccess(value):
return ItemListSwitchItem(
presentationData: presentationData,
systemStyle: .glass,
title: presentationData.strings.Settings_BotSettings_Biometry,
value: value,
sectionId: self.section,
style: .blocks,
updated: { value in
arguments.updateBiometryAccess(value)
}
)
}
}
}
private struct BotSettingsState: Equatable {
init() {
}
}
private func botSettingsEntries(
presentationData: PresentationData,
peer: EnginePeer?,
biometricsState: TelegramBotBiometricsState?
) -> [BotSettingsEntry] {
var entries: [BotSettingsEntry] = []
if let biometricsState {
entries.append(.biometryAccess(value: biometricsState.accessGranted))
}
return entries
}
public func botSettingsScreen(context: AccountContext, peerId: EnginePeer.Id) -> ViewController {
let initialState = BotSettingsState()
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
let stateValue = Atomic(value: initialState)
let updateState: ((BotSettingsState) -> BotSettingsState) -> Void = { f in
statePromise.set(stateValue.modify { f($0) })
}
var pushControllerImpl: ((ViewController) -> Void)?
let _ = pushControllerImpl
let _ = updateState
let actionsDisposable = DisposableSet()
let arguments = BotSettingsArguments(
context: context,
updateBiometryAccess: { value in
context.engine.peers.updateBotBiometricsState(peerId: peerId, update: { state in
var state = state ?? TelegramBotBiometricsState.create()
state.accessGranted = value
return state
})
}
)
let data = context.engine.data.subscribe(
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId),
TelegramEngine.EngineData.Item.Peer.BotBiometricsState(id: peerId)
)
let signal = combineLatest(
context.sharedContext.presentationData,
statePromise.get(),
data
)
|> deliverOnMainQueue
|> map { presentationData, state, data -> (ItemListControllerState, (ItemListNodeState, Any)) in
let (peer, biometricsState) = data
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(peer?.compactDisplayTitle ?? ""), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: botSettingsEntries(presentationData: presentationData, peer: peer, biometricsState: biometricsState), style: .blocks, animateChanges: true)
return (controllerState, (listState, arguments))
} |> afterDisposed {
actionsDisposable.dispose()
}
let controller = ItemListController(context: context, state: signal)
pushControllerImpl = { [weak controller] c in
(controller?.navigationController as? NavigationController)?.pushViewController(c)
}
return controller
}