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