Various Fixes

This commit is contained in:
Ilya Laktyushin 2021-06-17 23:14:23 +03:00
parent 0e225c0226
commit d646ee3492
17 changed files with 338 additions and 97 deletions

View File

@ -527,19 +527,19 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
self.cancel?() self.cancel?()
} }
@objc func installActionButtonPressed() { private func createStickerSet(title: String, shortName: String) {
let controller = importStickerPackTitleController(sharedContext: self.context.sharedContext, account: self.context.account, title: self.presentationData.strings.ImportStickerPack_ChooseName, text: self.presentationData.strings.ImportStickerPack_ChooseNameDescription, placeholder: "", doneButtonTitle: nil, value: nil, maxLength: 128, apply: { [weak self] title in guard let stickerPack = self.stickerPack else {
if let strongSelf = self, let stickerPack = strongSelf.stickerPack, var title = title { return
title = title.trimmingTrailingSpaces() }
let shortName = title.replacingOccurrences(of: " ", with: "") + "_by_laktyushin"
var stickers: [ImportSticker] = [] var stickers: [ImportSticker] = []
for item in strongSelf.currentItems { for item in self.currentItems {
var dimensions = PixelDimensions(width: 512, height: 512) var dimensions = PixelDimensions(width: 512, height: 512)
if case let .image(data) = item.stickerItem.content, let image = UIImage(data: data) { if case let .image(data) = item.stickerItem.content, let image = UIImage(data: data) {
dimensions = PixelDimensions(image.size) dimensions = PixelDimensions(image.size)
} }
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max)) let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
strongSelf.context.account.postbox.mediaBox.storeResourceData(resource.id, data: item.stickerItem.data) self.context.account.postbox.mediaBox.storeResourceData(resource.id, data: item.stickerItem.data)
stickers.append(ImportSticker(resource: resource, emojis: item.stickerItem.emojis, dimensions: dimensions)) stickers.append(ImportSticker(resource: resource, emojis: item.stickerItem.emojis, dimensions: dimensions))
} }
var thumbnailSticker: ImportSticker? var thumbnailSticker: ImportSticker?
@ -549,17 +549,17 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
dimensions = PixelDimensions(image.size) dimensions = PixelDimensions(image.size)
} }
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max)) let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
strongSelf.context.account.postbox.mediaBox.storeResourceData(resource.id, data: thumbnail.data) self.context.account.postbox.mediaBox.storeResourceData(resource.id, data: thumbnail.data)
thumbnailSticker = ImportSticker(resource: resource, emojis: [], dimensions: dimensions) thumbnailSticker = ImportSticker(resource: resource, emojis: [], dimensions: dimensions)
} }
strongSelf.progress = (0.0, 0, Int32(stickers.count)) self.progress = (0.0, 0, Int32(stickers.count))
strongSelf.radialStatus.transitionToState(.progress(color: strongSelf.presentationData.theme.list.itemAccentColor, lineWidth: 6.0, value: max(0.01, 0.0), cancelEnabled: false, animateRotation: false), animated: false, synchronous: true, completion: {}) self.radialStatus.transitionToState(.progress(color: self.presentationData.theme.list.itemAccentColor, lineWidth: 6.0, value: max(0.01, 0.0), cancelEnabled: false, animateRotation: false), animated: false, synchronous: true, completion: {})
if let (layout, navigationBarHeight) = strongSelf.containerLayout { if let (layout, navigationBarHeight) = self.containerLayout {
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.2, curve: .easeInOut)) self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.2, curve: .easeInOut))
} }
strongSelf.disposable.set((createStickerSet(account: strongSelf.context.account, title: title, shortName: shortName, stickers: stickers, thumbnail: thumbnailSticker, isAnimated: stickerPack.isAnimated) self.disposable.set((self.context.engine.stickers.createStickerSet(title: title, shortName: shortName, stickers: stickers, thumbnail: thumbnailSticker, isAnimated: stickerPack.isAnimated)
|> deliverOnMainQueue).start(next: { [weak self] status in |> deliverOnMainQueue).start(next: { [weak self] status in
if let strongSelf = self { if let strongSelf = self {
if case let .complete(info, items) = status { if case let .complete(info, items) = status {
@ -608,12 +608,20 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
} }
} }
} }
}, error: { error in }, error: { [weak self] error in
if let strongSelf = self { if let strongSelf = self {
} }
})) }))
} }
@objc func installActionButtonPressed() {
let controller = importStickerPackTitleController(sharedContext: self.context.sharedContext, account: self.context.account, title: self.presentationData.strings.ImportStickerPack_ChooseName, text: self.presentationData.strings.ImportStickerPack_ChooseNameDescription, placeholder: "", doneButtonTitle: nil, value: nil, maxLength: 128, apply: { [weak self] title in
if let strongSelf = self, let stickerPack = strongSelf.stickerPack, var title = title {
title = title.trimmingTrailingSpaces()
}
}) })
self.present?(controller, nil) self.present?(controller, nil)
} }

View File

@ -15,6 +15,7 @@ private final class ImportStickerPackTitleInputFieldNode: ASDisplayNode, ASEdita
private let backgroundNode: ASImageNode private let backgroundNode: ASImageNode
private let textInputNode: EditableTextNode private let textInputNode: EditableTextNode
private let placeholderNode: ASTextNode private let placeholderNode: ASTextNode
private let prefixNode: ASTextNode
private let clearButton: HighlightableButtonNode private let clearButton: HighlightableButtonNode
var updateHeight: (() -> Void)? var updateHeight: (() -> Void)?
@ -45,6 +46,12 @@ private final class ImportStickerPackTitleInputFieldNode: ASDisplayNode, ASEdita
} }
} }
var prefix: String = "" {
didSet {
self.prefixNode.attributedText = NSAttributedString(string: self.prefix, font: Font.regular(17.0), textColor: self.theme.actionSheet.inputTextColor)
}
}
private let maxLength: Int private let maxLength: Int
init(theme: PresentationTheme, placeholder: String, maxLength: Int, returnKeyType: UIReturnKeyType = .done) { init(theme: PresentationTheme, placeholder: String, maxLength: Int, returnKeyType: UIReturnKeyType = .done) {
@ -74,6 +81,11 @@ private final class ImportStickerPackTitleInputFieldNode: ASDisplayNode, ASEdita
self.placeholderNode.displaysAsynchronously = false self.placeholderNode.displaysAsynchronously = false
self.placeholderNode.attributedText = NSAttributedString(string: placeholder, font: Font.regular(17.0), textColor: self.theme.actionSheet.inputPlaceholderColor) self.placeholderNode.attributedText = NSAttributedString(string: placeholder, font: Font.regular(17.0), textColor: self.theme.actionSheet.inputPlaceholderColor)
self.prefixNode = ASTextNode()
self.prefixNode.isUserInteractionEnabled = false
self.prefixNode.displaysAsynchronously = false
self.prefixNode.attributedText = NSAttributedString(string: placeholder, font: Font.regular(17.0), textColor: self.theme.actionSheet.inputPlaceholderColor)
self.clearButton = HighlightableButtonNode() self.clearButton = HighlightableButtonNode()
self.clearButton.imageNode.displaysAsynchronously = false self.clearButton.imageNode.displaysAsynchronously = false
self.clearButton.imageNode.displayWithoutProcessing = true self.clearButton.imageNode.displayWithoutProcessing = true
@ -88,6 +100,7 @@ private final class ImportStickerPackTitleInputFieldNode: ASDisplayNode, ASEdita
self.addSubnode(self.backgroundNode) self.addSubnode(self.backgroundNode)
self.addSubnode(self.textInputNode) self.addSubnode(self.textInputNode)
self.addSubnode(self.placeholderNode) self.addSubnode(self.placeholderNode)
self.addSubnode(self.prefixNode)
self.addSubnode(self.clearButton) self.addSubnode(self.clearButton)
self.clearButton.addTarget(self, action: #selector(self.clearPressed), forControlEvents: .touchUpInside) self.clearButton.addTarget(self, action: #selector(self.clearPressed), forControlEvents: .touchUpInside)
@ -466,3 +479,49 @@ func importStickerPackTitleController(sharedContext: SharedAccountContext, accou
} }
return controller return controller
} }
func importStickerPackShortNameController(sharedContext: SharedAccountContext, account: Account, title: String, text: String, placeholder: String, doneButtonTitle: String? = nil, value: String?, maxLength: Int, apply: @escaping (String?) -> Void) -> AlertController {
let presentationData = sharedContext.currentPresentationData.with { $0 }
var dismissImpl: ((Bool) -> Void)?
var applyImpl: (() -> Void)?
let actions: [TextAlertAction] = [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
dismissImpl?(true)
}), TextAlertAction(type: .defaultAction, title: doneButtonTitle ?? presentationData.strings.Common_Done, action: {
applyImpl?()
})]
let contentNode = ImportStickerPackTitleAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), ptheme: presentationData.theme, strings: presentationData.strings, actions: actions, title: title, text: text, placeholder: placeholder, value: value, maxLength: maxLength)
contentNode.complete = {
applyImpl?()
}
applyImpl = { [weak contentNode] in
guard let contentNode = contentNode else {
return
}
dismissImpl?(true)
let previousValue = value ?? ""
let newValue = contentNode.value.trimmingCharacters(in: .whitespacesAndNewlines)
apply(previousValue != newValue || value == nil ? newValue : nil)
}
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode)
let presentationDataDisposable = sharedContext.presentationData.start(next: { [weak controller, weak contentNode] presentationData in
controller?.theme = AlertControllerTheme(presentationData: presentationData)
contentNode?.inputFieldNode.updateTheme(presentationData.theme)
})
controller.dismissed = {
presentationDataDisposable.dispose()
}
dismissImpl = { [weak controller, weak contentNode] animated in
contentNode?.inputFieldNode.deactivateInput()
if animated {
controller?.dismissAnimated()
} else {
controller?.dismiss()
}
}
return controller
}

View File

@ -445,7 +445,7 @@ static CGRect viewFrame(UIView *view)
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState | animationCurveOption animations:^ [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState | animationCurveOption animations:^
{ {
CGAffineTransform transform = CGAffineTransformScale(transform, 0.25f, 0.25f); CGAffineTransform transform = CGAffineTransformMakeScale(0.25, 0.25);
_cancelButton.transform = transform; _cancelButton.transform = transform;
_cancelButton.alpha = 0.0f; _cancelButton.alpha = 0.0f;
} completion:nil]; } completion:nil];

View File

@ -653,6 +653,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-427863538] = { return Api.InputStickerSet.parse_inputStickerSetDice($0) } dict[-427863538] = { return Api.InputStickerSet.parse_inputStickerSetDice($0) }
dict[-1231326505] = { return Api.messages.ChatAdminsWithInvites.parse_chatAdminsWithInvites($0) } dict[-1231326505] = { return Api.messages.ChatAdminsWithInvites.parse_chatAdminsWithInvites($0) }
dict[-1729618630] = { return Api.BotInfo.parse_botInfo($0) } dict[-1729618630] = { return Api.BotInfo.parse_botInfo($0) }
dict[-2046910401] = { return Api.stickers.SuggestedShortName.parse_suggestedShortName($0) }
dict[-1519637954] = { return Api.updates.State.parse_state($0) } dict[-1519637954] = { return Api.updates.State.parse_state($0) }
dict[537022650] = { return Api.User.parse_userEmpty($0) } dict[537022650] = { return Api.User.parse_userEmpty($0) }
dict[-1820043071] = { return Api.User.parse_user($0) } dict[-1820043071] = { return Api.User.parse_user($0) }
@ -1405,6 +1406,8 @@ public struct Api {
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.BotInfo: case let _1 as Api.BotInfo:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.stickers.SuggestedShortName:
_1.serialize(buffer, boxed)
case let _1 as Api.updates.State: case let _1 as Api.updates.State:
_1.serialize(buffer, boxed) _1.serialize(buffer, boxed)
case let _1 as Api.User: case let _1 as Api.User:

View File

@ -621,6 +621,44 @@ public struct upload {
} }
} }
public extension Api { public extension Api {
public struct stickers {
public enum SuggestedShortName: TypeConstructorDescription {
case suggestedShortName(shortName: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .suggestedShortName(let shortName):
if boxed {
buffer.appendInt32(-2046910401)
}
serializeString(shortName, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .suggestedShortName(let shortName):
return ("suggestedShortName", [("shortName", shortName)])
}
}
public static func parse_suggestedShortName(_ reader: BufferReader) -> SuggestedShortName? {
var _1: String?
_1 = parseString(reader)
let _c1 = _1 != nil
if _c1 {
return Api.stickers.SuggestedShortName.suggestedShortName(shortName: _1!)
}
else {
return nil
}
}
}
}
}
public extension Api {
public struct storage { public struct storage {
public enum FileType: TypeConstructorDescription { public enum FileType: TypeConstructorDescription {
case fileUnknown case fileUnknown
@ -6373,6 +6411,20 @@ public extension Api {
return result return result
}) })
} }
public static func suggestShortName(title: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.stickers.SuggestedShortName>) {
let buffer = Buffer()
buffer.appendInt32(1303364867)
serializeString(title, buffer: buffer, boxed: false)
return (FunctionDescription(name: "stickers.suggestShortName", parameters: [("title", title)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stickers.SuggestedShortName? in
let reader = BufferReader(buffer)
var result: Api.stickers.SuggestedShortName?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.stickers.SuggestedShortName
}
return result
})
}
} }
public struct account { public struct account {
public static func registerDevice(flags: Int32, tokenType: Int32, token: String, appSandbox: Api.Bool, secret: Buffer, otherUids: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) { public static func registerDevice(flags: Int32, tokenType: Int32, token: String, appSandbox: Api.Bool, secret: Buffer, otherUids: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {

View File

@ -78,7 +78,6 @@ public enum CreateStickerSetError {
case generic case generic
} }
public struct ImportSticker { public struct ImportSticker {
let resource: MediaResource let resource: MediaResource
let emojis: [String] let emojis: [String]
@ -96,7 +95,7 @@ public enum CreateStickerSetStatus {
case complete(StickerPackCollectionInfo, [ItemCollectionItem]) case complete(StickerPackCollectionInfo, [ItemCollectionItem])
} }
public func createStickerSet(account: Account, title: String, shortName: String, stickers: [ImportSticker], thumbnail: ImportSticker?, isAnimated: Bool) -> Signal<CreateStickerSetStatus, CreateStickerSetError> { func _internal_createStickerSet(account: Account, title: String, shortName: String, stickers: [ImportSticker], thumbnail: ImportSticker?, isAnimated: Bool) -> Signal<CreateStickerSetStatus, CreateStickerSetError> {
return account.postbox.loadedPeerWithId(account.peerId) return account.postbox.loadedPeerWithId(account.peerId)
|> castError(CreateStickerSetError.self) |> castError(CreateStickerSetError.self)
|> mapToSignal { peer -> Signal<CreateStickerSetStatus, CreateStickerSetError> in |> mapToSignal { peer -> Signal<CreateStickerSetStatus, CreateStickerSetError> in
@ -209,3 +208,35 @@ public func createStickerSet(account: Account, title: String, shortName: String,
} }
} }
} }
func _internal_getStickerSetShortNameSuggestion(account: Account, title: String) -> Signal<String?, NoError> {
return account.network.request(Api.functions.stickers.suggestShortName(title: title))
|> map (Optional.init)
|> `catch` { _ in
return .single(nil)
}
|> map { result in
guard let result = result else {
return nil
}
switch result {
case let .suggestedShortName(shortName):
return shortName
}
}
}
func _internal_stickerSetShortNameAvailability(account: Account, shortName: String) -> Signal<AddressNameAvailability, NoError> {
return account.network.request(Api.functions.stickers.checkShortName(shortName: shortName))
|> map { result -> AddressNameAvailability in
switch result {
case .boolTrue:
return .available
case .boolFalse:
return .taken
}
}
|> `catch` { error -> Signal<AddressNameAvailability, NoError> in
return .single(.invalid)
}
}

View File

@ -69,5 +69,28 @@ public extension TelegramEngine {
public func stickerPacksAttachedToMedia(media: AnyMediaReference) -> Signal<[StickerPackReference], NoError> { public func stickerPacksAttachedToMedia(media: AnyMediaReference) -> Signal<[StickerPackReference], NoError> {
return _internal_stickerPacksAttachedToMedia(account: self.account, media: media) return _internal_stickerPacksAttachedToMedia(account: self.account, media: media)
} }
public func createStickerSet(title: String, shortName: String, stickers: [ImportSticker], thumbnail: ImportSticker?, isAnimated: Bool) -> Signal<CreateStickerSetStatus, CreateStickerSetError> {
return _internal_createStickerSet(account: self.account, title: title, shortName: shortName, stickers: stickers, thumbnail: thumbnail, isAnimated: isAnimated)
}
public func getStickerSetShortNameSuggestion(title: String) -> Signal<String?, NoError> {
return _internal_getStickerSetShortNameSuggestion(account: self.account, title: title)
}
public func validateStickerSetShortNameInteractive(shortName: String) -> Signal<AddressNameValidationStatus, NoError> {
if let error = _internal_checkAddressNameFormat(shortName) {
return .single(.invalidFormat(error))
} else {
return .single(.checking)
|> then(
_internal_stickerSetShortNameAvailability(account: self.account, shortName: shortName)
|> delay(0.3, queue: Queue.concurrentDefaultQueue())
|> map { result -> AddressNameValidationStatus in
.availability(result)
}
)
}
}
} }
} }

View File

@ -4927,7 +4927,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if canSendMessagesToChat(strongSelf.presentationInterfaceState) { if canSendMessagesToChat(strongSelf.presentationInterfaceState) {
let _ = strongSelf.presentVoiceMessageDiscardAlert(action: { let _ = strongSelf.presentVoiceMessageDiscardAlert(action: {
if let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId) { if let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId) {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState({ $0.withUpdatedReplyMessageId(message.id) }).updatedSearch(nil) }, completion: completion) strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState({ $0.withUpdatedReplyMessageId(message.id) }).updatedSearch(nil).updatedShowCommands(false) }, completion: completion)
strongSelf.updateItemNodesSearchTextHighlightStates() strongSelf.updateItemNodesSearchTextHighlightStates()
strongSelf.chatDisplayNode.ensureInputViewFocused() strongSelf.chatDisplayNode.ensureInputViewFocused()
} else { } else {
@ -4988,6 +4988,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
updated = updated.updatedInputMode({ _ in updated = updated.updatedInputMode({ _ in
return .text return .text
}) })
updated = updated.updatedShowCommands(false)
return updated return updated
}, completion: completion) }, completion: completion)
@ -4999,7 +5000,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}, beginMessageSelection: { [weak self] messageIds, completion in }, beginMessageSelection: { [weak self] messageIds, completion in
if let strongSelf = self, strongSelf.isNodeLoaded { if let strongSelf = self, strongSelf.isNodeLoaded {
let _ = strongSelf.presentVoiceMessageDiscardAlert(action: { let _ = strongSelf.presentVoiceMessageDiscardAlert(action: {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState { $0.withUpdatedSelectedMessages(messageIds) } }, completion: completion) strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState { $0.withUpdatedSelectedMessages(messageIds) }.updatedShowCommands(false) }, completion: completion)
if let selectionState = strongSelf.presentationInterfaceState.interfaceState.selectionState { if let selectionState = strongSelf.presentationInterfaceState.interfaceState.selectionState {
let count = selectionState.selectedIds.count let count = selectionState.selectedIds.count

View File

@ -1889,7 +1889,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
} }
func frameForVisibleArea() -> CGRect { func frameForVisibleArea() -> CGRect {
let rect = CGRect(origin: CGPoint(x: self.visibleAreaInset.left, y: self.visibleAreaInset.top), size: CGSize(width: self.bounds.size.width - self.visibleAreaInset.left - self.visibleAreaInset.right, height: self.bounds.size.height - self.visibleAreaInset.top - self.visibleAreaInset.bottom)) var rect = CGRect(origin: CGPoint(x: self.visibleAreaInset.left, y: self.visibleAreaInset.top), size: CGSize(width: self.bounds.size.width - self.visibleAreaInset.left - self.visibleAreaInset.right, height: self.bounds.size.height - self.visibleAreaInset.top - self.visibleAreaInset.bottom))
if let inputContextPanelNode = self.inputContextPanelNode, let topItemFrame = inputContextPanelNode.topItemFrame {
rect.size.height = topItemFrame.minY
}
if let containerNode = self.containerNode { if let containerNode = self.containerNode {
return containerNode.view.convert(rect, to: self.view) return containerNode.view.convert(rect, to: self.view)
} else { } else {

View File

@ -34,4 +34,8 @@ class ChatInputContextPanelNode: ASDisplayNode {
func animateOut(completion: @escaping () -> Void) { func animateOut(completion: @escaping () -> Void) {
completion() completion()
} }
var topItemFrame: CGRect? {
return nil
}
} }

View File

@ -257,6 +257,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
private var searchActivityIndicator: ActivityIndicator? private var searchActivityIndicator: ActivityIndicator?
var audioRecordingInfoContainerNode: ASDisplayNode? var audioRecordingInfoContainerNode: ASDisplayNode?
var audioRecordingDotNode: AnimationNode? var audioRecordingDotNode: AnimationNode?
var audioRecordingDotNodeDismissed = false
var audioRecordingTimeNode: ChatTextInputAudioRecordingTimeNode? var audioRecordingTimeNode: ChatTextInputAudioRecordingTimeNode?
var audioRecordingCancelIndicator: ChatTextInputAudioRecordingCancelIndicator? var audioRecordingCancelIndicator: ChatTextInputAudioRecordingCancelIndicator?
var animatingBinNode: AnimationNode? var animatingBinNode: AnimationNode?
@ -479,11 +480,11 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
if let strongSelf = self { if let strongSelf = self {
if let strongSelf = self { if let strongSelf = self {
if highlighted { if highlighted {
strongSelf.menuButton.layer.removeAnimation(forKey: "opacity") let transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .spring)
strongSelf.menuButton.alpha = 0.4 transition.updateTransformScale(node: strongSelf.menuButton, scale: 0.85)
} else { } else {
strongSelf.menuButton.alpha = 1.0 let transition: ContainedViewLayoutTransition = .animated(duration: 0.5, curve: .spring)
strongSelf.menuButton.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) transition.updateTransformScale(node: strongSelf.menuButton, scale: 1.0)
} }
} }
} }
@ -1033,7 +1034,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
var hasMenuButton = false var hasMenuButton = false
var menuButtonExpanded = false var menuButtonExpanded = false
if let peer = interfaceState.renderedPeer?.peer as? TelegramUser, let _ = peer.botInfo, interfaceState.hasBotCommands { if let peer = interfaceState.renderedPeer?.peer as? TelegramUser, let _ = peer.botInfo, interfaceState.hasBotCommands && interfaceState.editMessageState == nil {
hasMenuButton = true hasMenuButton = true
var inputHasText = false var inputHasText = false
@ -1231,6 +1232,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self.audioRecordingDotNode?.removeFromSupernode() self.audioRecordingDotNode?.removeFromSupernode()
audioRecordingDotNode = AnimationNode(animation: "BinRed") audioRecordingDotNode = AnimationNode(animation: "BinRed")
self.audioRecordingDotNode = audioRecordingDotNode self.audioRecordingDotNode = audioRecordingDotNode
self.audioRecordingDotNodeDismissed = false
self.insertSubnode(audioRecordingDotNode, belowSubnode: self.menuButton) self.insertSubnode(audioRecordingDotNode, belowSubnode: self.menuButton)
self.animatingBinNode?.removeFromSupernode() self.animatingBinNode?.removeFromSupernode()
self.animatingBinNode = nil self.animatingBinNode = nil
@ -1269,7 +1271,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
audioRecordingCancelIndicator.layer.animateAlpha(from: CGFloat(audioRecordingCancelIndicator.layer.presentation()?.opacity ?? 1), to: 0, duration: 0.15, delay: 0, removeOnCompletion: false) audioRecordingCancelIndicator.layer.animateAlpha(from: CGFloat(audioRecordingCancelIndicator.layer.presentation()?.opacity ?? 1), to: 0, duration: 0.15, delay: 0, removeOnCompletion: false)
} }
} else { } else {
let update = self.actionButtons.micButton.audioRecorder != nil var update = self.actionButtons.micButton.audioRecorder != nil || self.actionButtons.micButton.videoRecordingStatus != nil
self.actionButtons.micButton.audioRecorder = nil self.actionButtons.micButton.audioRecorder = nil
self.actionButtons.micButton.videoRecordingStatus = nil self.actionButtons.micButton.videoRecordingStatus = nil
transition.updateAlpha(layer: self.textInputBackgroundNode.layer, alpha: 1.0) transition.updateAlpha(layer: self.textInputBackgroundNode.layer, alpha: 1.0)
@ -1302,7 +1304,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self?.attachmentButton.layer.animateScale(from: 0.3, to: 1.0, duration: 0.15, delay: 0, removeOnCompletion: false) self?.attachmentButton.layer.animateScale(from: 0.3, to: 1.0, duration: 0.15, delay: 0, removeOnCompletion: false)
} }
if update { if update && !self.audioRecordingDotNodeDismissed {
audioRecordingDotNode.layer.removeAllAnimations() audioRecordingDotNode.layer.removeAllAnimations()
} }
@ -1311,15 +1313,20 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self.audioRecordingDotNode?.removeFromSupernode() self.audioRecordingDotNode?.removeFromSupernode()
self.audioRecordingDotNode = nil self.audioRecordingDotNode = nil
} else { } else {
if !self.audioRecordingDotNodeDismissed {
audioRecordingDotNode.layer.removeAllAnimations()
}
audioRecordingDotNode.completion = dismissDotNode audioRecordingDotNode.completion = dismissDotNode
audioRecordingDotNode.play() audioRecordingDotNode.play()
update = true
} }
} else { } else {
dismissDotNode() dismissDotNode()
} }
if update { if update && !self.audioRecordingDotNodeDismissed {
self.audioRecordingDotNode?.layer.animatePosition(from: CGPoint(), to: CGPoint(x: leftMenuInset, y: 0.0), duration: 0.15, removeOnCompletion: false, additive: true) self.audioRecordingDotNode?.layer.animatePosition(from: CGPoint(), to: CGPoint(x: leftMenuInset, y: 0.0), duration: 0.15, removeOnCompletion: false, additive: true)
self.audioRecordingDotNodeDismissed = true
} }
} }
@ -2174,6 +2181,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
} }
@objc func menuButtonPressed() { @objc func menuButtonPressed() {
self.hapticFeedback.impact(.light)
self.interfaceInteraction?.updateShowCommands { value in self.interfaceInteraction?.updateShowCommands { value in
return !value return !value
} }

View File

@ -242,4 +242,14 @@ final class CommandChatInputContextPanelNode: ChatInputContextPanelNode {
let listViewFrame = self.listView.frame let listViewFrame = self.listView.frame
return self.listView.hitTest(CGPoint(x: point.x - listViewFrame.minX, y: point.y - listViewFrame.minY), with: event) return self.listView.hitTest(CGPoint(x: point.x - listViewFrame.minX, y: point.y - listViewFrame.minY), with: event)
} }
override var topItemFrame: CGRect? {
var topItemFrame: CGRect?
self.listView.forEachItemNode { itemNode in
if topItemFrame == nil {
topItemFrame = itemNode.frame
}
}
return topItemFrame
}
} }

View File

@ -260,4 +260,14 @@ final class CommandMenuChatInputContextPanelNode: ChatInputContextPanelNode {
let listViewFrame = self.listView.frame let listViewFrame = self.listView.frame
return self.listView.hitTest(CGPoint(x: point.x - listViewFrame.minX, y: point.y - listViewFrame.minY), with: event) return self.listView.hitTest(CGPoint(x: point.x - listViewFrame.minX, y: point.y - listViewFrame.minY), with: event)
} }
override var topItemFrame: CGRect? {
var topItemFrame: CGRect?
self.listView.forEachItemNode { itemNode in
if topItemFrame == nil {
topItemFrame = itemNode.frame
}
}
return topItemFrame
}
} }

View File

@ -259,5 +259,14 @@ final class HashtagChatInputContextPanelNode: ChatInputContextPanelNode {
let listViewFrame = self.listView.frame let listViewFrame = self.listView.frame
return self.listView.hitTest(CGPoint(x: point.x - listViewFrame.minX, y: point.y - listViewFrame.minY), with: event) return self.listView.hitTest(CGPoint(x: point.x - listViewFrame.minX, y: point.y - listViewFrame.minY), with: event)
} }
}
override var topItemFrame: CGRect? {
var topItemFrame: CGRect?
self.listView.forEachItemNode { itemNode in
if topItemFrame == nil {
topItemFrame = itemNode.frame
}
}
return topItemFrame
}
}

View File

@ -287,4 +287,14 @@ final class MentionChatInputContextPanelNode: ChatInputContextPanelNode {
let listViewFrame = self.listView.frame let listViewFrame = self.listView.frame
return self.listView.hitTest(CGPoint(x: point.x - listViewFrame.minX, y: point.y - listViewFrame.minY), with: event) return self.listView.hitTest(CGPoint(x: point.x - listViewFrame.minX, y: point.y - listViewFrame.minY), with: event)
} }
override var topItemFrame: CGRect? {
var topItemFrame: CGRect?
self.listView.forEachItemNode { itemNode in
if topItemFrame == nil {
topItemFrame = itemNode.frame
}
}
return topItemFrame
}
} }

View File

@ -358,7 +358,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition) let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition)
let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: listNodeSize, insets: insets, duration: duration, curve: curve) let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: listNodeSize, insets: insets, duration: duration, curve: curve)
self.historyNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets) self.historyNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets)
if let replacementHistoryNode = replacementHistoryNode { if let replacementHistoryNode = self.replacementHistoryNode {
let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: listNodeSize, insets: insets, duration: 0.0, curve: .Default(duration: nil)) let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: listNodeSize, insets: insets, duration: 0.0, curve: .Default(duration: nil))
replacementHistoryNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets) replacementHistoryNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets)
} }

View File

@ -366,4 +366,14 @@ final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContex
strongSelf.updateInternalResults(mergedResults) strongSelf.updateInternalResults(mergedResults)
})) }))
} }
override var topItemFrame: CGRect? {
var topItemFrame: CGRect?
self.listView.forEachItemNode { itemNode in
if topItemFrame == nil {
topItemFrame = itemNode.frame
}
}
return topItemFrame
}
} }