mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
[Temp] New input pane
This commit is contained in:
217
submodules/TelegramUI/Sources/ChatEntityKeyboardInputNode.swift
Normal file
217
submodules/TelegramUI/Sources/ChatEntityKeyboardInputNode.swift
Normal file
@@ -0,0 +1,217 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import AccountContext
|
||||
import ChatPresentationInterfaceState
|
||||
import ComponentFlow
|
||||
import EntityKeyboard
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import ComponentDisplayAdapters
|
||||
|
||||
final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
struct InputData: Equatable {
|
||||
let emoji: EmojiPagerContentComponent
|
||||
let stickers: EmojiPagerContentComponent
|
||||
|
||||
init(
|
||||
emoji: EmojiPagerContentComponent,
|
||||
stickers: EmojiPagerContentComponent
|
||||
) {
|
||||
self.emoji = emoji
|
||||
self.stickers = stickers
|
||||
}
|
||||
}
|
||||
|
||||
static func inputData(context: AccountContext, interfaceInteraction: ChatPanelInterfaceInteraction) -> Signal<InputData, NoError> {
|
||||
let emojiInputInteraction = EmojiPagerContentComponent.InputInteraction(
|
||||
performItemAction: { [weak interfaceInteraction] item, _, _ in
|
||||
guard let interfaceInteraction = interfaceInteraction else {
|
||||
return
|
||||
}
|
||||
interfaceInteraction.insertText(item.emoji)
|
||||
},
|
||||
deleteBackwards: { [weak interfaceInteraction] in
|
||||
guard let interfaceInteraction = interfaceInteraction else {
|
||||
return
|
||||
}
|
||||
interfaceInteraction.backwardsDeleteText()
|
||||
}
|
||||
)
|
||||
let stickerInputInteraction = EmojiPagerContentComponent.InputInteraction(
|
||||
performItemAction: { [weak interfaceInteraction] item, view, rect in
|
||||
guard let interfaceInteraction = interfaceInteraction else {
|
||||
return
|
||||
}
|
||||
let _ = interfaceInteraction.sendSticker(.standalone(media: item.file), false, view, rect)
|
||||
},
|
||||
deleteBackwards: { [weak interfaceInteraction] in
|
||||
guard let interfaceInteraction = interfaceInteraction else {
|
||||
return
|
||||
}
|
||||
interfaceInteraction.backwardsDeleteText()
|
||||
}
|
||||
)
|
||||
|
||||
let animationCache = AnimationCacheImpl(basePath: context.account.postbox.mediaBox.basePath + "/animation-cache", allocateTempFile: {
|
||||
return TempBox.shared.tempFile(fileName: "file").path
|
||||
})
|
||||
let animationRenderer = MultiAnimationRendererImpl()
|
||||
|
||||
let emojiItems: Signal<EmojiPagerContentComponent, NoError> = context.engine.stickers.loadedStickerPack(reference: .animatedEmoji, forceActualized: false)
|
||||
|> map { animatedEmoji -> EmojiPagerContentComponent in
|
||||
var emojiItems: [EmojiPagerContentComponent.Item] = []
|
||||
|
||||
switch animatedEmoji {
|
||||
case let .result(_, items, _):
|
||||
for item in items {
|
||||
if let emoji = item.getStringRepresentationsOfIndexKeys().first {
|
||||
let strippedEmoji = emoji.basicEmoji.0.strippedEmoji
|
||||
emojiItems.append(EmojiPagerContentComponent.Item(
|
||||
emoji: strippedEmoji,
|
||||
file: item.file
|
||||
))
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
var itemGroups: [EmojiPagerContentComponent.ItemGroup] = []
|
||||
itemGroups.append(EmojiPagerContentComponent.ItemGroup(
|
||||
id: "all",
|
||||
title: nil,
|
||||
items: emojiItems
|
||||
))
|
||||
return EmojiPagerContentComponent(
|
||||
context: context,
|
||||
animationCache: animationCache,
|
||||
animationRenderer: animationRenderer,
|
||||
inputInteraction: emojiInputInteraction,
|
||||
itemGroups: itemGroups,
|
||||
itemLayoutType: .compact
|
||||
)
|
||||
}
|
||||
|
||||
let orderedItemListCollectionIds: [Int32] = [Namespaces.OrderedItemList.CloudSavedStickers]
|
||||
let namespaces: [ItemCollectionId.Namespace] = [Namespaces.ItemCollection.CloudStickerPacks]
|
||||
let stickerItems: Signal<EmojiPagerContentComponent, NoError> = context.account.postbox.itemCollectionsView(orderedItemListCollectionIds: orderedItemListCollectionIds, namespaces: namespaces, aroundIndex: nil, count: 10000000)
|
||||
|> map { view -> EmojiPagerContentComponent in
|
||||
struct ItemGroup {
|
||||
var id: ItemCollectionId
|
||||
var items: [EmojiPagerContentComponent.Item]
|
||||
}
|
||||
var itemGroups: [ItemGroup] = []
|
||||
var itemGroupIndexById: [AnyHashable: Int] = [:]
|
||||
|
||||
for entry in view.entries {
|
||||
guard let item = entry.item as? StickerPackItem else {
|
||||
continue
|
||||
}
|
||||
if !item.file.isAnimatedSticker {
|
||||
continue
|
||||
}
|
||||
let resultItem = EmojiPagerContentComponent.Item(
|
||||
emoji: "",
|
||||
file: item.file
|
||||
)
|
||||
let groupId = entry.index.collectionId
|
||||
if let groupIndex = itemGroupIndexById[groupId] {
|
||||
itemGroups[groupIndex].items.append(resultItem)
|
||||
} else {
|
||||
itemGroupIndexById[groupId] = itemGroups.count
|
||||
itemGroups.append(ItemGroup(id: groupId, items: [resultItem]))
|
||||
}
|
||||
}
|
||||
|
||||
return EmojiPagerContentComponent(
|
||||
context: context,
|
||||
animationCache: animationCache,
|
||||
animationRenderer: animationRenderer,
|
||||
inputInteraction: stickerInputInteraction,
|
||||
itemGroups: itemGroups.map { group -> EmojiPagerContentComponent.ItemGroup in
|
||||
var title: String?
|
||||
for (id, info, _) in view.collectionInfos {
|
||||
if id == group.id, let info = info as? StickerPackCollectionInfo {
|
||||
title = info.title.uppercased()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return EmojiPagerContentComponent.ItemGroup(id: group.id, title: title, items: group.items)
|
||||
},
|
||||
itemLayoutType: .detailed
|
||||
)
|
||||
}
|
||||
|
||||
return combineLatest(queue: .mainQueue(),
|
||||
emojiItems,
|
||||
stickerItems
|
||||
)
|
||||
|> map { emoji, stickers -> InputData in
|
||||
return InputData(
|
||||
emoji: emoji,
|
||||
stickers: stickers
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private let entityKeyboardView: ComponentHostView<Empty>
|
||||
|
||||
private var currentInputData: InputData
|
||||
private var inputDataDisposable: Disposable?
|
||||
|
||||
init(context: AccountContext, currentInputData: InputData, updatedInputData: Signal<InputData, NoError>) {
|
||||
self.currentInputData = currentInputData
|
||||
self.entityKeyboardView = ComponentHostView<Empty>()
|
||||
|
||||
super.init()
|
||||
|
||||
self.view.addSubview(self.entityKeyboardView)
|
||||
|
||||
self.externalTopPanelContainer = SparseContainerView()
|
||||
|
||||
self.inputDataDisposable = (updatedInputData
|
||||
|> deliverOnMainQueue).start(next: { [weak self] inputData in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.currentInputData = inputData
|
||||
})
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.inputDataDisposable?.dispose()
|
||||
}
|
||||
|
||||
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, standardInputHeight: CGFloat, inputHeight: CGFloat, maximumHeight: CGFloat, inputPanelHeight: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, deviceMetrics: DeviceMetrics, isVisible: Bool) -> (CGFloat, CGFloat) {
|
||||
let entityKeyboardSize = self.entityKeyboardView.update(
|
||||
transition: Transition(transition),
|
||||
component: AnyComponent(EntityKeyboardComponent(
|
||||
theme: interfaceState.theme,
|
||||
bottomInset: bottomInset,
|
||||
emojiContent: self.currentInputData.emoji,
|
||||
stickerContent: self.currentInputData.stickers,
|
||||
externalTopPanelContainer: self.externalTopPanelContainer,
|
||||
topPanelExtensionUpdated: { [weak self] topPanelExtension, transition in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if strongSelf.topBackgroundExtension != topPanelExtension {
|
||||
strongSelf.topBackgroundExtension = topPanelExtension
|
||||
strongSelf.topBackgroundExtensionUpdated?(transition.containedViewLayoutTransition)
|
||||
}
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: width, height: standardInputHeight)
|
||||
)
|
||||
transition.updateFrame(view: self.entityKeyboardView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: entityKeyboardSize))
|
||||
|
||||
return (standardInputHeight, 0.0)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user