mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various Fixes
This commit is contained in:
parent
0e225c0226
commit
d646ee3492
@ -527,92 +527,100 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
||||
self.cancel?()
|
||||
}
|
||||
|
||||
private func createStickerSet(title: String, shortName: String) {
|
||||
guard let stickerPack = self.stickerPack else {
|
||||
return
|
||||
}
|
||||
|
||||
var stickers: [ImportSticker] = []
|
||||
for item in self.currentItems {
|
||||
var dimensions = PixelDimensions(width: 512, height: 512)
|
||||
if case let .image(data) = item.stickerItem.content, let image = UIImage(data: data) {
|
||||
dimensions = PixelDimensions(image.size)
|
||||
}
|
||||
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
|
||||
self.context.account.postbox.mediaBox.storeResourceData(resource.id, data: item.stickerItem.data)
|
||||
stickers.append(ImportSticker(resource: resource, emojis: item.stickerItem.emojis, dimensions: dimensions))
|
||||
}
|
||||
var thumbnailSticker: ImportSticker?
|
||||
if let thumbnail = stickerPack.thumbnail {
|
||||
var dimensions = PixelDimensions(width: 512, height: 512)
|
||||
if case let .image(data) = thumbnail.content, let image = UIImage(data: data) {
|
||||
dimensions = PixelDimensions(image.size)
|
||||
}
|
||||
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
|
||||
self.context.account.postbox.mediaBox.storeResourceData(resource.id, data: thumbnail.data)
|
||||
thumbnailSticker = ImportSticker(resource: resource, emojis: [], dimensions: dimensions)
|
||||
}
|
||||
|
||||
self.progress = (0.0, 0, Int32(stickers.count))
|
||||
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) = self.containerLayout {
|
||||
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
}
|
||||
|
||||
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
|
||||
if let strongSelf = self {
|
||||
if case let .complete(info, items) = status {
|
||||
if let (_, _, count) = strongSelf.progress {
|
||||
strongSelf.progress = (1.0, count, count)
|
||||
if let (layout, navigationBarHeight) = strongSelf.containerLayout {
|
||||
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
}
|
||||
}
|
||||
let _ = strongSelf.context.engine.stickers.addStickerPackInteractively(info: info, items: items).start()
|
||||
|
||||
strongSelf.radialCheck.transitionToState(.progress(color: .clear, lineWidth: 6.0, value: 1.0, cancelEnabled: false, animateRotation: false), animated: false, synchronous: true, completion: {})
|
||||
strongSelf.radialCheck.transitionToState(.check(strongSelf.presentationData.theme.list.itemAccentColor), animated: true, synchronous: true, completion: {})
|
||||
strongSelf.radialStatus.layer.animateScale(from: 1.0, to: 1.05, duration: 0.07, delay: 0.0, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, additive: false, completion: { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.radialStatus.layer.animateScale(from: 1.05, to: 1.0, duration: 0.07, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false, additive: false)
|
||||
})
|
||||
strongSelf.radialStatusBackground.layer.animateScale(from: 1.0, to: 1.05, duration: 0.07, delay: 0.0, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, additive: false, completion: { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.radialStatusBackground.layer.animateScale(from: 1.05, to: 1.0, duration: 0.07, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false, additive: false)
|
||||
})
|
||||
strongSelf.radialCheck.layer.animateScale(from: 1.0, to: 1.05, duration: 0.07, delay: 0.0, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, additive: false, completion: { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.radialCheck.layer.animateScale(from: 1.05, to: 1.0, duration: 0.07, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false, additive: false)
|
||||
})
|
||||
strongSelf.radialStatusText.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
strongSelf.radialStatusText.layer.animateScale(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
|
||||
strongSelf.cancelButtonNode.isUserInteractionEnabled = false
|
||||
|
||||
Queue.mainQueue().after(1.0) {
|
||||
strongSelf.presentInGlobalOverlay?(UndoOverlayController(presentationData: strongSelf.presentationData, content: .stickersModified(title: strongSelf.presentationData.strings.StickerPackActionInfo_AddedTitle, text: strongSelf.presentationData.strings.StickerPackActionInfo_AddedText(info.title).0, undo: false, info: info, topItem: items.first, context: strongSelf.context), elevatedLayout: false, action: { _ in return true}), nil)
|
||||
strongSelf.dismiss?()
|
||||
}
|
||||
} else if case let .progress(progress, count, total) = status {
|
||||
strongSelf.progress = (CGFloat(progress), count, total)
|
||||
strongSelf.radialStatus.transitionToState(.progress(color: strongSelf.presentationData.theme.list.itemAccentColor, lineWidth: 6.0, value: max(0.01, CGFloat(progress)), cancelEnabled: false, animateRotation: false), animated: true, synchronous: true, completion: {})
|
||||
if let (layout, navigationBarHeight) = strongSelf.containerLayout {
|
||||
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, error: { [weak self] error in
|
||||
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()
|
||||
let shortName = title.replacingOccurrences(of: " ", with: "") + "_by_laktyushin"
|
||||
var stickers: [ImportSticker] = []
|
||||
for item in strongSelf.currentItems {
|
||||
var dimensions = PixelDimensions(width: 512, height: 512)
|
||||
if case let .image(data) = item.stickerItem.content, let image = UIImage(data: data) {
|
||||
dimensions = PixelDimensions(image.size)
|
||||
}
|
||||
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
|
||||
strongSelf.context.account.postbox.mediaBox.storeResourceData(resource.id, data: item.stickerItem.data)
|
||||
stickers.append(ImportSticker(resource: resource, emojis: item.stickerItem.emojis, dimensions: dimensions))
|
||||
}
|
||||
var thumbnailSticker: ImportSticker?
|
||||
if let thumbnail = stickerPack.thumbnail {
|
||||
var dimensions = PixelDimensions(width: 512, height: 512)
|
||||
if case let .image(data) = thumbnail.content, let image = UIImage(data: data) {
|
||||
dimensions = PixelDimensions(image.size)
|
||||
}
|
||||
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
|
||||
strongSelf.context.account.postbox.mediaBox.storeResourceData(resource.id, data: thumbnail.data)
|
||||
thumbnailSticker = ImportSticker(resource: resource, emojis: [], dimensions: dimensions)
|
||||
}
|
||||
|
||||
|
||||
strongSelf.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: {})
|
||||
if let (layout, navigationBarHeight) = strongSelf.containerLayout {
|
||||
strongSelf.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)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||
if let strongSelf = self {
|
||||
if case let .complete(info, items) = status {
|
||||
if let (_, _, count) = strongSelf.progress {
|
||||
strongSelf.progress = (1.0, count, count)
|
||||
if let (layout, navigationBarHeight) = strongSelf.containerLayout {
|
||||
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
}
|
||||
}
|
||||
let _ = strongSelf.context.engine.stickers.addStickerPackInteractively(info: info, items: items).start()
|
||||
|
||||
strongSelf.radialCheck.transitionToState(.progress(color: .clear, lineWidth: 6.0, value: 1.0, cancelEnabled: false, animateRotation: false), animated: false, synchronous: true, completion: {})
|
||||
strongSelf.radialCheck.transitionToState(.check(strongSelf.presentationData.theme.list.itemAccentColor), animated: true, synchronous: true, completion: {})
|
||||
strongSelf.radialStatus.layer.animateScale(from: 1.0, to: 1.05, duration: 0.07, delay: 0.0, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, additive: false, completion: { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.radialStatus.layer.animateScale(from: 1.05, to: 1.0, duration: 0.07, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false, additive: false)
|
||||
})
|
||||
strongSelf.radialStatusBackground.layer.animateScale(from: 1.0, to: 1.05, duration: 0.07, delay: 0.0, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, additive: false, completion: { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.radialStatusBackground.layer.animateScale(from: 1.05, to: 1.0, duration: 0.07, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false, additive: false)
|
||||
})
|
||||
strongSelf.radialCheck.layer.animateScale(from: 1.0, to: 1.05, duration: 0.07, delay: 0.0, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, additive: false, completion: { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.radialCheck.layer.animateScale(from: 1.05, to: 1.0, duration: 0.07, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false, additive: false)
|
||||
})
|
||||
strongSelf.radialStatusText.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
strongSelf.radialStatusText.layer.animateScale(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
|
||||
strongSelf.cancelButtonNode.isUserInteractionEnabled = false
|
||||
|
||||
Queue.mainQueue().after(1.0) {
|
||||
strongSelf.presentInGlobalOverlay?(UndoOverlayController(presentationData: strongSelf.presentationData, content: .stickersModified(title: strongSelf.presentationData.strings.StickerPackActionInfo_AddedTitle, text: strongSelf.presentationData.strings.StickerPackActionInfo_AddedText(info.title).0, undo: false, info: info, topItem: items.first, context: strongSelf.context), elevatedLayout: false, action: { _ in return true}), nil)
|
||||
strongSelf.dismiss?()
|
||||
}
|
||||
} else if case let .progress(progress, count, total) = status {
|
||||
strongSelf.progress = (CGFloat(progress), count, total)
|
||||
strongSelf.radialStatus.transitionToState(.progress(color: strongSelf.presentationData.theme.list.itemAccentColor, lineWidth: 6.0, value: max(0.01, CGFloat(progress)), cancelEnabled: false, animateRotation: false), animated: true, synchronous: true, completion: {})
|
||||
if let (layout, navigationBarHeight) = strongSelf.containerLayout {
|
||||
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, error: { error in
|
||||
if let strongSelf = self {
|
||||
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
self.present?(controller, nil)
|
||||
|
@ -15,6 +15,7 @@ private final class ImportStickerPackTitleInputFieldNode: ASDisplayNode, ASEdita
|
||||
private let backgroundNode: ASImageNode
|
||||
private let textInputNode: EditableTextNode
|
||||
private let placeholderNode: ASTextNode
|
||||
private let prefixNode: ASTextNode
|
||||
private let clearButton: HighlightableButtonNode
|
||||
|
||||
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
|
||||
|
||||
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.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.imageNode.displaysAsynchronously = false
|
||||
self.clearButton.imageNode.displayWithoutProcessing = true
|
||||
@ -88,6 +100,7 @@ private final class ImportStickerPackTitleInputFieldNode: ASDisplayNode, ASEdita
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.textInputNode)
|
||||
self.addSubnode(self.placeholderNode)
|
||||
self.addSubnode(self.prefixNode)
|
||||
self.addSubnode(self.clearButton)
|
||||
|
||||
self.clearButton.addTarget(self, action: #selector(self.clearPressed), forControlEvents: .touchUpInside)
|
||||
@ -466,3 +479,49 @@ func importStickerPackTitleController(sharedContext: SharedAccountContext, accou
|
||||
}
|
||||
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
|
||||
}
|
||||
|
@ -445,7 +445,7 @@ static CGRect viewFrame(UIView *view)
|
||||
|
||||
[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.alpha = 0.0f;
|
||||
} completion:nil];
|
||||
|
@ -653,6 +653,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-427863538] = { return Api.InputStickerSet.parse_inputStickerSetDice($0) }
|
||||
dict[-1231326505] = { return Api.messages.ChatAdminsWithInvites.parse_chatAdminsWithInvites($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[537022650] = { return Api.User.parse_userEmpty($0) }
|
||||
dict[-1820043071] = { return Api.User.parse_user($0) }
|
||||
@ -1405,6 +1406,8 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.BotInfo:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.stickers.SuggestedShortName:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.updates.State:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.User:
|
||||
|
@ -621,6 +621,44 @@ public struct upload {
|
||||
}
|
||||
}
|
||||
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 enum FileType: TypeConstructorDescription {
|
||||
case fileUnknown
|
||||
@ -6373,6 +6411,20 @@ public extension Api {
|
||||
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 static func registerDevice(flags: Int32, tokenType: Int32, token: String, appSandbox: Api.Bool, secret: Buffer, otherUids: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
|
@ -78,7 +78,6 @@ public enum CreateStickerSetError {
|
||||
case generic
|
||||
}
|
||||
|
||||
|
||||
public struct ImportSticker {
|
||||
let resource: MediaResource
|
||||
let emojis: [String]
|
||||
@ -96,7 +95,7 @@ public enum CreateStickerSetStatus {
|
||||
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)
|
||||
|> castError(CreateStickerSetError.self)
|
||||
|> 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)
|
||||
}
|
||||
}
|
@ -69,5 +69,28 @@ public extension TelegramEngine {
|
||||
public func stickerPacksAttachedToMedia(media: AnyMediaReference) -> Signal<[StickerPackReference], NoError> {
|
||||
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)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4927,7 +4927,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if canSendMessagesToChat(strongSelf.presentationInterfaceState) {
|
||||
let _ = strongSelf.presentVoiceMessageDiscardAlert(action: {
|
||||
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.chatDisplayNode.ensureInputViewFocused()
|
||||
} else {
|
||||
@ -4988,6 +4988,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
updated = updated.updatedInputMode({ _ in
|
||||
return .text
|
||||
})
|
||||
updated = updated.updatedShowCommands(false)
|
||||
|
||||
return updated
|
||||
}, completion: completion)
|
||||
@ -4999,7 +5000,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}, beginMessageSelection: { [weak self] messageIds, completion in
|
||||
if let strongSelf = self, strongSelf.isNodeLoaded {
|
||||
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 {
|
||||
let count = selectionState.selectedIds.count
|
||||
|
@ -1889,7 +1889,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
|
||||
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 {
|
||||
return containerNode.view.convert(rect, to: self.view)
|
||||
} else {
|
||||
|
@ -34,4 +34,8 @@ class ChatInputContextPanelNode: ASDisplayNode {
|
||||
func animateOut(completion: @escaping () -> Void) {
|
||||
completion()
|
||||
}
|
||||
|
||||
var topItemFrame: CGRect? {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -257,6 +257,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
private var searchActivityIndicator: ActivityIndicator?
|
||||
var audioRecordingInfoContainerNode: ASDisplayNode?
|
||||
var audioRecordingDotNode: AnimationNode?
|
||||
var audioRecordingDotNodeDismissed = false
|
||||
var audioRecordingTimeNode: ChatTextInputAudioRecordingTimeNode?
|
||||
var audioRecordingCancelIndicator: ChatTextInputAudioRecordingCancelIndicator?
|
||||
var animatingBinNode: AnimationNode?
|
||||
@ -479,11 +480,11 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
if let strongSelf = self {
|
||||
if let strongSelf = self {
|
||||
if highlighted {
|
||||
strongSelf.menuButton.layer.removeAnimation(forKey: "opacity")
|
||||
strongSelf.menuButton.alpha = 0.4
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .spring)
|
||||
transition.updateTransformScale(node: strongSelf.menuButton, scale: 0.85)
|
||||
} else {
|
||||
strongSelf.menuButton.alpha = 1.0
|
||||
strongSelf.menuButton.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.5, curve: .spring)
|
||||
transition.updateTransformScale(node: strongSelf.menuButton, scale: 1.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1033,7 +1034,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
|
||||
var hasMenuButton = 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
|
||||
|
||||
var inputHasText = false
|
||||
@ -1231,6 +1232,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
self.audioRecordingDotNode?.removeFromSupernode()
|
||||
audioRecordingDotNode = AnimationNode(animation: "BinRed")
|
||||
self.audioRecordingDotNode = audioRecordingDotNode
|
||||
self.audioRecordingDotNodeDismissed = false
|
||||
self.insertSubnode(audioRecordingDotNode, belowSubnode: self.menuButton)
|
||||
self.animatingBinNode?.removeFromSupernode()
|
||||
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)
|
||||
}
|
||||
} 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.videoRecordingStatus = nil
|
||||
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)
|
||||
}
|
||||
|
||||
if update {
|
||||
if update && !self.audioRecordingDotNodeDismissed {
|
||||
audioRecordingDotNode.layer.removeAllAnimations()
|
||||
}
|
||||
|
||||
@ -1311,15 +1313,20 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
self.audioRecordingDotNode?.removeFromSupernode()
|
||||
self.audioRecordingDotNode = nil
|
||||
} else {
|
||||
if !self.audioRecordingDotNodeDismissed {
|
||||
audioRecordingDotNode.layer.removeAllAnimations()
|
||||
}
|
||||
audioRecordingDotNode.completion = dismissDotNode
|
||||
audioRecordingDotNode.play()
|
||||
update = true
|
||||
}
|
||||
} else {
|
||||
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.audioRecordingDotNodeDismissed = true
|
||||
}
|
||||
}
|
||||
|
||||
@ -2174,6 +2181,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
}
|
||||
|
||||
@objc func menuButtonPressed() {
|
||||
self.hapticFeedback.impact(.light)
|
||||
self.interfaceInteraction?.updateShowCommands { value in
|
||||
return !value
|
||||
}
|
||||
|
@ -242,4 +242,14 @@ final class CommandChatInputContextPanelNode: ChatInputContextPanelNode {
|
||||
let listViewFrame = self.listView.frame
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -260,4 +260,14 @@ final class CommandMenuChatInputContextPanelNode: ChatInputContextPanelNode {
|
||||
let listViewFrame = self.listView.frame
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -259,5 +259,14 @@ final class HashtagChatInputContextPanelNode: ChatInputContextPanelNode {
|
||||
let listViewFrame = self.listView.frame
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -287,4 +287,14 @@ final class MentionChatInputContextPanelNode: ChatInputContextPanelNode {
|
||||
let listViewFrame = self.listView.frame
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -358,7 +358,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition)
|
||||
let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: listNodeSize, insets: insets, duration: duration, curve: curve)
|
||||
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))
|
||||
replacementHistoryNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets)
|
||||
}
|
||||
|
@ -366,4 +366,14 @@ final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContex
|
||||
strongSelf.updateInternalResults(mergedResults)
|
||||
}))
|
||||
}
|
||||
|
||||
override var topItemFrame: CGRect? {
|
||||
var topItemFrame: CGRect?
|
||||
self.listView.forEachItemNode { itemNode in
|
||||
if topItemFrame == nil {
|
||||
topItemFrame = itemNode.frame
|
||||
}
|
||||
}
|
||||
return topItemFrame
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user