mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Stickers Import Improvements
This commit is contained in:
parent
4136c049f6
commit
1c1e44833e
@ -274,6 +274,9 @@ final class PeekControllerNode: ViewControllerTracingNode {
|
||||
}
|
||||
|
||||
func activateMenu() {
|
||||
if self.content.menuItems().isEmpty {
|
||||
return
|
||||
}
|
||||
if case .press = self.content.menuActivation() {
|
||||
self.hapticFeedback.impact()
|
||||
}
|
||||
|
@ -3,44 +3,81 @@ import UIKit
|
||||
|
||||
public class ImportStickerPack {
|
||||
public class Sticker: Equatable {
|
||||
public enum Content {
|
||||
case image(Data)
|
||||
case animation(Data)
|
||||
}
|
||||
|
||||
public static func == (lhs: ImportStickerPack.Sticker, rhs: ImportStickerPack.Sticker) -> Bool {
|
||||
return lhs.uuid == rhs.uuid
|
||||
}
|
||||
|
||||
let image: UIImage
|
||||
let content: Content
|
||||
let emojis: [String]
|
||||
let uuid: UUID
|
||||
|
||||
init(image: UIImage, emojis: [String], uuid: UUID = UUID()) {
|
||||
self.image = image
|
||||
init(content: Content, emojis: [String], uuid: UUID = UUID()) {
|
||||
self.content = content
|
||||
self.emojis = emojis
|
||||
self.uuid = uuid
|
||||
}
|
||||
|
||||
var data: Data {
|
||||
switch self.content {
|
||||
case let .image(data):
|
||||
return data
|
||||
case let .animation(data):
|
||||
return data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var identifier: String
|
||||
public var name: String
|
||||
public let software: String
|
||||
public var thumbnail: String?
|
||||
public let isAnimated: Bool
|
||||
|
||||
public var stickers: [Sticker]
|
||||
public let thumbnail: Sticker?
|
||||
public let stickers: [Sticker]
|
||||
|
||||
public init?(data: Data) {
|
||||
guard let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
|
||||
return nil
|
||||
}
|
||||
|
||||
self.name = json["name"] as? String ?? ""
|
||||
self.identifier = json["identifier"] as? String ?? ""
|
||||
self.software = json["software"] as? String ?? ""
|
||||
self.isAnimated = json["isAnimated"] as? Bool ?? false
|
||||
let isAnimated = json["isAnimated"] as? Bool ?? false
|
||||
self.isAnimated = isAnimated
|
||||
|
||||
func parseSticker(_ sticker: [String: Any]) -> Sticker? {
|
||||
if let dataString = sticker["data"] as? String, let mimeType = sticker["mimeType"] as? String, let data = Data(base64Encoded: dataString) {
|
||||
var content: Sticker.Content?
|
||||
switch mimeType.lowercased() {
|
||||
case "image/png":
|
||||
if !isAnimated {
|
||||
content = .image(data)
|
||||
}
|
||||
case "application/x-tgsticker":
|
||||
if isAnimated {
|
||||
content = .animation(data)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
if let content = content {
|
||||
return Sticker(content: content, emojis: sticker["emojis"] as? [String] ?? [])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if let thumbnail = json["thumbnail"] as? [String: Any], let parsedSticker = parseSticker(thumbnail) {
|
||||
self.thumbnail = parsedSticker
|
||||
} else {
|
||||
self.thumbnail = nil
|
||||
}
|
||||
|
||||
var stickers: [Sticker] = []
|
||||
if let stickersArray = json["stickers"] as? [[String: Any]] {
|
||||
for sticker in stickersArray {
|
||||
if let dataString = sticker["data"] as? String, let data = Data(base64Encoded: dataString), let image = UIImage(data: data) {
|
||||
stickers.append(Sticker(image: image, emojis: sticker["emojis"] as? [String] ?? []))
|
||||
if let parsedSticker = parseSticker(sticker) {
|
||||
stickers.append(parsedSticker)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,9 @@ public final class ImportStickerPackController: ViewController, StandalonePresen
|
||||
self.controllerNode.cancel = { [weak self] in
|
||||
self?.dismiss()
|
||||
}
|
||||
self.controllerNode.present = { [weak self] controller, arguments in
|
||||
self?.present(controller, in: .window(.root), with: arguments)
|
||||
}
|
||||
self.controllerNode.presentInGlobalOverlay = { [weak self] controller, arguments in
|
||||
self?.presentInGlobalOverlay(controller, with: arguments)
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
||||
|
||||
private var interaction: StickerPackPreviewInteraction!
|
||||
|
||||
var present: ((ViewController, Any?) -> Void)?
|
||||
var presentInGlobalOverlay: ((ViewController, Any?) -> Void)?
|
||||
var dismiss: (() -> Void)?
|
||||
var cancel: (() -> Void)?
|
||||
@ -75,10 +76,13 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
||||
let ready = Promise<Bool>()
|
||||
private var didSetReady = false
|
||||
|
||||
private var pendingItems: [StickerPackPreviewGridEntry] = []
|
||||
private var currentItems: [StickerPackPreviewGridEntry] = []
|
||||
|
||||
private var hapticFeedback: HapticFeedback?
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
|
||||
init(context: AccountContext) {
|
||||
self.context = context
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
@ -151,6 +155,10 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
@ -160,31 +168,23 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
||||
self.contentGridNode.view.addGestureRecognizer(PeekControllerGestureRecognizer(contentAtPoint: { [weak self] point -> Signal<(ASDisplayNode, PeekControllerContent)?, NoError>? in
|
||||
if let strongSelf = self {
|
||||
if let itemNode = strongSelf.contentGridNode.itemNodeAtPoint(point) as? StickerPackPreviewGridItemNode, let item = itemNode.stickerPackItem {
|
||||
// var menuItems: [PeekControllerMenuItem] = []
|
||||
// if let stickerPack = strongSelf.stickerPack, case let .result(info, _, _) = stickerPack, info.id.namespace == Namespaces.ItemCollection.CloudStickerPacks {
|
||||
// if strongSelf.sendSticker != nil {
|
||||
// menuItems.append(PeekControllerMenuItem(title: strongSelf.presentationData.strings.ShareMenu_Send, color: .accent, font: .bold, action: { node, rect in
|
||||
// if let strongSelf = self {
|
||||
// return strongSelf.sendSticker?(.standalone(media: item.file), node, rect) ?? false
|
||||
// } else {
|
||||
// return false
|
||||
// }
|
||||
// }))
|
||||
// }
|
||||
// menuItems.append(PeekControllerMenuItem(title: isStarred ? strongSelf.presentationData.strings.Stickers_RemoveFromFavorites : strongSelf.presentationData.strings.Stickers_AddToFavorites, color: isStarred ? .destructive : .accent, action: { _, _ in
|
||||
// if let strongSelf = self {
|
||||
// if isStarred {
|
||||
// let _ = removeSavedSticker(postbox: strongSelf.context.account.postbox, mediaId: item.file.fileId).start()
|
||||
// } else {
|
||||
// let _ = addSavedSticker(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, file: item.file).start()
|
||||
// }
|
||||
// }
|
||||
// return true
|
||||
// }))
|
||||
// menuItems.append(PeekControllerMenuItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { _, _ in return true }))
|
||||
// }
|
||||
// return (itemNode, StickerPreviewPeekContent(account: strongSelf.context.account, item: .pack(item), menu: menuItems))
|
||||
return .single((itemNode, StickerPreviewPeekContent(account: strongSelf.context.account, item: item, menu: [])))
|
||||
var menuItems: [ContextMenuItem] = []
|
||||
if strongSelf.currentItems.count > 1 {
|
||||
menuItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ImportStickerPack_RemoveFromImport, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] c, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
if let strongSelf = self {
|
||||
var updatedItems = strongSelf.currentItems
|
||||
updatedItems.removeAll(where: { $0.stickerItem.uuid == item.uuid })
|
||||
strongSelf.pendingItems = updatedItems
|
||||
|
||||
if let (layout, navigationHeight) = strongSelf.containerLayout {
|
||||
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||
}
|
||||
}
|
||||
})))
|
||||
}
|
||||
return .single((itemNode, StickerPreviewPeekContent(account: strongSelf.context.account, item: item, menu: menuItems)))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -304,21 +304,16 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
||||
var itemCount = 0
|
||||
var animateIn = false
|
||||
|
||||
if let stickerPack = self.stickerPack {
|
||||
var updatedItems: [StickerPackPreviewGridEntry] = []
|
||||
for item in stickerPack.stickers {
|
||||
updatedItems.append(StickerPackPreviewGridEntry(index: updatedItems.count, stickerItem: item))
|
||||
}
|
||||
if let _ = self.stickerPack, self.currentItems.isEmpty || self.currentItems.count != self.pendingItems.count {
|
||||
let previousItems = self.currentItems
|
||||
self.currentItems = self.pendingItems
|
||||
|
||||
if self.currentItems.isEmpty && !updatedItems.isEmpty {
|
||||
let entities = generateTextEntities(stickerPack.name, enabledTypes: [.mention])
|
||||
let font = Font.medium(20.0)
|
||||
self.contentTitleNode.attributedText = stringWithAppliedEntities(stickerPack.name, entities: entities, baseColor: self.presentationData.theme.actionSheet.primaryTextColor, linkColor: self.presentationData.theme.actionSheet.controlAccentColor, baseFont: font, linkFont: font, boldFont: font, italicFont: font, boldItalicFont: font, fixedFont: font, blockQuoteFont: font)
|
||||
animateIn = true
|
||||
itemCount = updatedItems.count
|
||||
}
|
||||
transaction = StickerPackPreviewGridTransaction(previousList: self.currentItems, list: updatedItems, account: self.context.account, interaction: self.interaction, theme: self.presentationData.theme)
|
||||
self.currentItems = updatedItems
|
||||
let titleFont = Font.medium(20.0)
|
||||
self.contentTitleNode.attributedText = stringWithAppliedEntities(self.presentationData.strings.ImportStickerPack_StickerCount(Int32(self.currentItems.count)), entities: [], baseColor: self.presentationData.theme.actionSheet.primaryTextColor, linkColor: self.presentationData.theme.actionSheet.controlAccentColor, baseFont: titleFont, linkFont: titleFont, boldFont: titleFont, italicFont: titleFont, boldItalicFont: titleFont, fixedFont: titleFont, blockQuoteFont: titleFont)
|
||||
animateIn = true
|
||||
itemCount = self.currentItems.count
|
||||
|
||||
transaction = StickerPackPreviewGridTransaction(previousList: previousItems, list: self.currentItems, account: self.context.account, interaction: self.interaction, theme: self.presentationData.theme)
|
||||
}
|
||||
|
||||
let titleSize = self.contentTitleNode.updateLayout(CGSize(width: contentContainerFrame.size.width - 24.0, height: CGFloat.greatestFiniteMagnitude))
|
||||
@ -421,7 +416,45 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
||||
}
|
||||
|
||||
@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.disposable.set(createStickerSet(account: strongSelf.context.account, title: title, shortName: shortName, stickers: stickers, thumbnail: thumbnailSticker, isAnimated: stickerPack.isAnimated).start(next: { [weak self] status in
|
||||
if let strongSelf = self {
|
||||
if case let .complete(pack, items) = status {
|
||||
print("done!")
|
||||
}
|
||||
}
|
||||
}, error: { error in
|
||||
if let strongSelf = self {
|
||||
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
self.present?(controller, nil)
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
@ -461,13 +494,18 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
||||
|
||||
func updateStickerPack(_ stickerPack: ImportStickerPack) {
|
||||
self.stickerPack = stickerPack
|
||||
var updatedItems: [StickerPackPreviewGridEntry] = []
|
||||
for item in stickerPack.stickers {
|
||||
updatedItems.append(StickerPackPreviewGridEntry(index: updatedItems.count, stickerItem: item))
|
||||
}
|
||||
self.pendingItems = updatedItems
|
||||
|
||||
// self.interaction.playAnimatedStickers = stickerSettings.loopAnimatedStickers
|
||||
|
||||
if let _ = self.containerLayout {
|
||||
self.dequeueUpdateStickerPack()
|
||||
}
|
||||
self.installActionButtonNode.setTitle("Create Sticker Set", with: Font.regular(20.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
|
||||
self.installActionButtonNode.setTitle(self.presentationData.strings.ImportStickerPack_CreateStickerSet, with: Font.regular(20.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
|
||||
// switch stickerPack {
|
||||
// case .none, .fetching:
|
||||
// self.installActionSeparatorNode.alpha = 0.0
|
||||
|
@ -0,0 +1,468 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
import UrlEscaping
|
||||
|
||||
private final class ImportStickerPackTitleInputFieldNode: ASDisplayNode, ASEditableTextNodeDelegate {
|
||||
private var theme: PresentationTheme
|
||||
private let backgroundNode: ASImageNode
|
||||
private let textInputNode: EditableTextNode
|
||||
private let placeholderNode: ASTextNode
|
||||
private let clearButton: HighlightableButtonNode
|
||||
|
||||
var updateHeight: (() -> Void)?
|
||||
var complete: (() -> Void)?
|
||||
var textChanged: ((String) -> Void)?
|
||||
|
||||
private let backgroundInsets = UIEdgeInsets(top: 8.0, left: 16.0, bottom: 15.0, right: 16.0)
|
||||
private let inputInsets = UIEdgeInsets(top: 5.0, left: 12.0, bottom: 5.0, right: 12.0)
|
||||
|
||||
var text: String {
|
||||
get {
|
||||
return self.textInputNode.attributedText?.string ?? ""
|
||||
}
|
||||
set {
|
||||
self.textInputNode.attributedText = NSAttributedString(string: newValue, font: Font.regular(17.0), textColor: self.theme.actionSheet.inputTextColor)
|
||||
self.placeholderNode.isHidden = !newValue.isEmpty
|
||||
if self.textInputNode.isFirstResponder() {
|
||||
self.clearButton.isHidden = newValue.isEmpty
|
||||
} else {
|
||||
self.clearButton.isHidden = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var placeholder: String = "" {
|
||||
didSet {
|
||||
self.placeholderNode.attributedText = NSAttributedString(string: self.placeholder, font: Font.regular(17.0), textColor: self.theme.actionSheet.inputPlaceholderColor)
|
||||
}
|
||||
}
|
||||
|
||||
private let maxLength: Int
|
||||
|
||||
init(theme: PresentationTheme, placeholder: String, maxLength: Int, returnKeyType: UIReturnKeyType = .done) {
|
||||
self.theme = theme
|
||||
self.maxLength = maxLength
|
||||
|
||||
self.backgroundNode = ASImageNode()
|
||||
self.backgroundNode.isLayerBacked = true
|
||||
self.backgroundNode.displaysAsynchronously = false
|
||||
self.backgroundNode.displayWithoutProcessing = true
|
||||
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 12.0, color: theme.actionSheet.inputHollowBackgroundColor, strokeColor: theme.actionSheet.inputBorderColor, strokeWidth: 1.0)
|
||||
|
||||
self.textInputNode = EditableTextNode()
|
||||
self.textInputNode.typingAttributes = [NSAttributedString.Key.font.rawValue: Font.regular(17.0), NSAttributedString.Key.foregroundColor.rawValue: theme.actionSheet.inputTextColor]
|
||||
self.textInputNode.clipsToBounds = true
|
||||
self.textInputNode.hitTestSlop = UIEdgeInsets(top: -5.0, left: -5.0, bottom: -5.0, right: -5.0)
|
||||
self.textInputNode.textContainerInset = UIEdgeInsets(top: self.inputInsets.top, left: 0.0, bottom: self.inputInsets.bottom, right: 0.0)
|
||||
self.textInputNode.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
|
||||
self.textInputNode.keyboardType = .default
|
||||
self.textInputNode.autocapitalizationType = .sentences
|
||||
self.textInputNode.returnKeyType = returnKeyType
|
||||
self.textInputNode.autocorrectionType = .default
|
||||
self.textInputNode.tintColor = theme.actionSheet.controlAccentColor
|
||||
|
||||
self.placeholderNode = ASTextNode()
|
||||
self.placeholderNode.isUserInteractionEnabled = false
|
||||
self.placeholderNode.displaysAsynchronously = false
|
||||
self.placeholderNode.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
|
||||
self.clearButton.displaysAsynchronously = false
|
||||
self.clearButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Clear"), color: theme.actionSheet.inputClearButtonColor), for: [])
|
||||
self.clearButton.isHidden = true
|
||||
|
||||
super.init()
|
||||
|
||||
self.textInputNode.delegate = self
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.textInputNode)
|
||||
self.addSubnode(self.placeholderNode)
|
||||
self.addSubnode(self.clearButton)
|
||||
|
||||
self.clearButton.addTarget(self, action: #selector(self.clearPressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
||||
func updateTheme(_ theme: PresentationTheme) {
|
||||
self.theme = theme
|
||||
|
||||
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 12.0, color: self.theme.actionSheet.inputHollowBackgroundColor, strokeColor: self.theme.actionSheet.inputBorderColor, strokeWidth: 1.0)
|
||||
self.textInputNode.keyboardAppearance = self.theme.rootController.keyboardColor.keyboardAppearance
|
||||
self.placeholderNode.attributedText = NSAttributedString(string: self.placeholderNode.attributedText?.string ?? "", font: Font.regular(17.0), textColor: self.theme.actionSheet.inputPlaceholderColor)
|
||||
self.textInputNode.tintColor = self.theme.actionSheet.controlAccentColor
|
||||
self.clearButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Clear"), color: theme.actionSheet.inputClearButtonColor), for: [])
|
||||
}
|
||||
|
||||
func updateLayout(width: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
let backgroundInsets = self.backgroundInsets
|
||||
let inputInsets = self.inputInsets
|
||||
|
||||
let textFieldHeight = self.calculateTextFieldMetrics(width: width)
|
||||
let panelHeight = textFieldHeight + backgroundInsets.top + backgroundInsets.bottom
|
||||
|
||||
let backgroundFrame = CGRect(origin: CGPoint(x: backgroundInsets.left, y: backgroundInsets.top), size: CGSize(width: width - backgroundInsets.left - backgroundInsets.right, height: panelHeight - backgroundInsets.top - backgroundInsets.bottom))
|
||||
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
|
||||
|
||||
let placeholderSize = self.placeholderNode.measure(backgroundFrame.size)
|
||||
transition.updateFrame(node: self.placeholderNode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + inputInsets.left, y: backgroundFrame.minY + floor((backgroundFrame.size.height - placeholderSize.height) / 2.0)), size: placeholderSize))
|
||||
|
||||
transition.updateFrame(node: self.textInputNode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + inputInsets.left, y: backgroundFrame.minY), size: CGSize(width: backgroundFrame.size.width - inputInsets.left - inputInsets.right - 20.0, height: backgroundFrame.size.height)))
|
||||
|
||||
if let image = self.clearButton.image(for: []) {
|
||||
transition.updateFrame(node: self.clearButton, frame: CGRect(origin: CGPoint(x: backgroundFrame.maxX - 8.0 - image.size.width, y: backgroundFrame.minY + floor((backgroundFrame.size.height - image.size.height) / 2.0)), size: image.size))
|
||||
}
|
||||
|
||||
return panelHeight
|
||||
}
|
||||
|
||||
func activateInput() {
|
||||
self.textInputNode.becomeFirstResponder()
|
||||
}
|
||||
|
||||
func deactivateInput() {
|
||||
self.textInputNode.resignFirstResponder()
|
||||
}
|
||||
|
||||
@objc func editableTextNodeDidUpdateText(_ editableTextNode: ASEditableTextNode) {
|
||||
self.updateTextNodeText(animated: true)
|
||||
self.textChanged?(editableTextNode.textView.text)
|
||||
self.placeholderNode.isHidden = !(editableTextNode.textView.text ?? "").isEmpty
|
||||
self.clearButton.isHidden = !self.placeholderNode.isHidden
|
||||
}
|
||||
|
||||
func editableTextNodeDidBeginEditing(_ editableTextNode: ASEditableTextNode) {
|
||||
self.clearButton.isHidden = (editableTextNode.textView.text ?? "").isEmpty
|
||||
}
|
||||
|
||||
func editableTextNodeDidFinishEditing(_ editableTextNode: ASEditableTextNode) {
|
||||
self.clearButton.isHidden = true
|
||||
}
|
||||
|
||||
func editableTextNode(_ editableTextNode: ASEditableTextNode, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
|
||||
let updatedText = (editableTextNode.textView.text as NSString).replacingCharacters(in: range, with: text)
|
||||
if updatedText.count > maxLength {
|
||||
self.textInputNode.layer.addShakeAnimation()
|
||||
return false
|
||||
}
|
||||
if text == "\n" {
|
||||
self.complete?()
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private func calculateTextFieldMetrics(width: CGFloat) -> CGFloat {
|
||||
let backgroundInsets = self.backgroundInsets
|
||||
let inputInsets = self.inputInsets
|
||||
|
||||
let unboundTextFieldHeight = max(33.0, ceil(self.textInputNode.measure(CGSize(width: width - backgroundInsets.left - backgroundInsets.right - inputInsets.left - inputInsets.right - 20.0, height: CGFloat.greatestFiniteMagnitude)).height))
|
||||
|
||||
return min(61.0, max(33.0, unboundTextFieldHeight))
|
||||
}
|
||||
|
||||
private func updateTextNodeText(animated: Bool) {
|
||||
let backgroundInsets = self.backgroundInsets
|
||||
|
||||
let textFieldHeight = self.calculateTextFieldMetrics(width: self.bounds.size.width)
|
||||
|
||||
let panelHeight = textFieldHeight + backgroundInsets.top + backgroundInsets.bottom
|
||||
if !self.bounds.size.height.isEqual(to: panelHeight) {
|
||||
self.updateHeight?()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func clearPressed() {
|
||||
self.placeholderNode.isHidden = false
|
||||
self.clearButton.isHidden = true
|
||||
|
||||
self.textInputNode.attributedText = nil
|
||||
self.updateHeight?()
|
||||
}
|
||||
}
|
||||
|
||||
private final class ImportStickerPackTitleAlertContentNode: AlertContentNode {
|
||||
private let strings: PresentationStrings
|
||||
private let title: String
|
||||
private let text: String
|
||||
|
||||
private let titleNode: ASTextNode
|
||||
private let textNode: ASTextNode
|
||||
let inputFieldNode: ImportStickerPackTitleInputFieldNode
|
||||
|
||||
private let actionNodesSeparator: ASDisplayNode
|
||||
private let actionNodes: [TextAlertContentActionNode]
|
||||
private let actionVerticalSeparators: [ASDisplayNode]
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
|
||||
private var validLayout: CGSize?
|
||||
|
||||
private let hapticFeedback = HapticFeedback()
|
||||
|
||||
var complete: (() -> Void)? {
|
||||
didSet {
|
||||
self.inputFieldNode.complete = self.complete
|
||||
}
|
||||
}
|
||||
|
||||
override var dismissOnOutsideTap: Bool {
|
||||
return self.isUserInteractionEnabled
|
||||
}
|
||||
|
||||
init(theme: AlertControllerTheme, ptheme: PresentationTheme, strings: PresentationStrings, actions: [TextAlertAction], title: String, text: String, placeholder: String, value: String?, maxLength: Int) {
|
||||
self.strings = strings
|
||||
self.title = title
|
||||
self.text = text
|
||||
|
||||
self.titleNode = ASTextNode()
|
||||
self.titleNode.maximumNumberOfLines = 2
|
||||
self.textNode = ASTextNode()
|
||||
self.textNode.maximumNumberOfLines = 8
|
||||
|
||||
self.inputFieldNode = ImportStickerPackTitleInputFieldNode(theme: ptheme, placeholder: placeholder, maxLength: maxLength)
|
||||
self.inputFieldNode.text = value ?? ""
|
||||
|
||||
self.actionNodesSeparator = ASDisplayNode()
|
||||
self.actionNodesSeparator.isLayerBacked = true
|
||||
|
||||
self.actionNodes = actions.map { action -> TextAlertContentActionNode in
|
||||
return TextAlertContentActionNode(theme: theme, action: action)
|
||||
}
|
||||
|
||||
var actionVerticalSeparators: [ASDisplayNode] = []
|
||||
if actions.count > 1 {
|
||||
for _ in 0 ..< actions.count - 1 {
|
||||
let separatorNode = ASDisplayNode()
|
||||
separatorNode.isLayerBacked = true
|
||||
actionVerticalSeparators.append(separatorNode)
|
||||
}
|
||||
}
|
||||
self.actionVerticalSeparators = actionVerticalSeparators
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.titleNode)
|
||||
self.addSubnode(self.textNode)
|
||||
|
||||
self.addSubnode(self.inputFieldNode)
|
||||
|
||||
self.addSubnode(self.actionNodesSeparator)
|
||||
|
||||
for actionNode in self.actionNodes {
|
||||
self.addSubnode(actionNode)
|
||||
}
|
||||
|
||||
for separatorNode in self.actionVerticalSeparators {
|
||||
self.addSubnode(separatorNode)
|
||||
}
|
||||
|
||||
self.inputFieldNode.updateHeight = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let _ = strongSelf.validLayout {
|
||||
strongSelf.requestLayout?(.animated(duration: 0.15, curve: .spring))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.updateTheme(theme)
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
}
|
||||
|
||||
var value: String {
|
||||
return self.inputFieldNode.text
|
||||
}
|
||||
|
||||
override func updateTheme(_ theme: AlertControllerTheme) {
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.title, font: Font.bold(17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
self.textNode.attributedText = NSAttributedString(string: self.text, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
|
||||
self.actionNodesSeparator.backgroundColor = theme.separatorColor
|
||||
for actionNode in self.actionNodes {
|
||||
actionNode.updateTheme(theme)
|
||||
}
|
||||
for separatorNode in self.actionVerticalSeparators {
|
||||
separatorNode.backgroundColor = theme.separatorColor
|
||||
}
|
||||
|
||||
if let size = self.validLayout {
|
||||
_ = self.updateLayout(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
override func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||
var size = size
|
||||
size.width = min(size.width, 270.0)
|
||||
let measureSize = CGSize(width: size.width - 16.0 * 2.0, height: CGFloat.greatestFiniteMagnitude)
|
||||
|
||||
let hadValidLayout = self.validLayout != nil
|
||||
|
||||
self.validLayout = size
|
||||
|
||||
var origin: CGPoint = CGPoint(x: 0.0, y: 20.0)
|
||||
let spacing: CGFloat = 5.0
|
||||
|
||||
let titleSize = self.titleNode.measure(measureSize)
|
||||
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - titleSize.width) / 2.0), y: origin.y), size: titleSize))
|
||||
origin.y += titleSize.height + 4.0
|
||||
|
||||
let textSize = self.textNode.measure(measureSize)
|
||||
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: origin.y), size: textSize))
|
||||
origin.y += textSize.height + 6.0 + spacing
|
||||
|
||||
let actionButtonHeight: CGFloat = 44.0
|
||||
var minActionsWidth: CGFloat = 0.0
|
||||
let maxActionWidth: CGFloat = floor(size.width / CGFloat(self.actionNodes.count))
|
||||
let actionTitleInsets: CGFloat = 8.0
|
||||
|
||||
var effectiveActionLayout = TextAlertContentActionLayout.horizontal
|
||||
for actionNode in self.actionNodes {
|
||||
let actionTitleSize = actionNode.titleNode.updateLayout(CGSize(width: maxActionWidth, height: actionButtonHeight))
|
||||
if case .horizontal = effectiveActionLayout, actionTitleSize.height > actionButtonHeight * 0.6667 {
|
||||
effectiveActionLayout = .vertical
|
||||
}
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
minActionsWidth += actionTitleSize.width + actionTitleInsets
|
||||
case .vertical:
|
||||
minActionsWidth = max(minActionsWidth, actionTitleSize.width + actionTitleInsets)
|
||||
}
|
||||
}
|
||||
|
||||
let insets = UIEdgeInsets(top: 18.0, left: 18.0, bottom: 9.0, right: 18.0)
|
||||
|
||||
var contentWidth = max(titleSize.width, minActionsWidth)
|
||||
contentWidth = max(contentWidth, 234.0)
|
||||
|
||||
var actionsHeight: CGFloat = 0.0
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
actionsHeight = actionButtonHeight
|
||||
case .vertical:
|
||||
actionsHeight = actionButtonHeight * CGFloat(self.actionNodes.count)
|
||||
}
|
||||
|
||||
let resultWidth = contentWidth + insets.left + insets.right
|
||||
|
||||
let inputFieldWidth = resultWidth
|
||||
let inputFieldHeight = self.inputFieldNode.updateLayout(width: inputFieldWidth, transition: transition)
|
||||
let inputHeight = inputFieldHeight
|
||||
transition.updateFrame(node: self.inputFieldNode, frame: CGRect(x: 0.0, y: origin.y, width: resultWidth, height: inputFieldHeight))
|
||||
transition.updateAlpha(node: self.inputFieldNode, alpha: inputHeight > 0.0 ? 1.0 : 0.0)
|
||||
|
||||
let resultSize = CGSize(width: resultWidth, height: titleSize.height + textSize.height + spacing + inputHeight + actionsHeight + insets.top + insets.bottom)
|
||||
|
||||
transition.updateFrame(node: self.actionNodesSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
|
||||
|
||||
var actionOffset: CGFloat = 0.0
|
||||
let actionWidth: CGFloat = floor(resultSize.width / CGFloat(self.actionNodes.count))
|
||||
var separatorIndex = -1
|
||||
var nodeIndex = 0
|
||||
for actionNode in self.actionNodes {
|
||||
if separatorIndex >= 0 {
|
||||
let separatorNode = self.actionVerticalSeparators[separatorIndex]
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: actionOffset - UIScreenPixel, y: resultSize.height - actionsHeight), size: CGSize(width: UIScreenPixel, height: actionsHeight - UIScreenPixel)))
|
||||
case .vertical:
|
||||
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
|
||||
}
|
||||
}
|
||||
separatorIndex += 1
|
||||
|
||||
let currentActionWidth: CGFloat
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
if nodeIndex == self.actionNodes.count - 1 {
|
||||
currentActionWidth = resultSize.width - actionOffset
|
||||
} else {
|
||||
currentActionWidth = actionWidth
|
||||
}
|
||||
case .vertical:
|
||||
currentActionWidth = resultSize.width
|
||||
}
|
||||
|
||||
let actionNodeFrame: CGRect
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
actionNodeFrame = CGRect(origin: CGPoint(x: actionOffset, y: resultSize.height - actionsHeight), size: CGSize(width: currentActionWidth, height: actionButtonHeight))
|
||||
actionOffset += currentActionWidth
|
||||
case .vertical:
|
||||
actionNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset), size: CGSize(width: currentActionWidth, height: actionButtonHeight))
|
||||
actionOffset += actionButtonHeight
|
||||
}
|
||||
|
||||
transition.updateFrame(node: actionNode, frame: actionNodeFrame)
|
||||
|
||||
nodeIndex += 1
|
||||
}
|
||||
|
||||
if !hadValidLayout {
|
||||
self.inputFieldNode.activateInput()
|
||||
}
|
||||
|
||||
return resultSize
|
||||
}
|
||||
|
||||
func animateError() {
|
||||
self.inputFieldNode.layer.addShakeAnimation()
|
||||
self.hapticFeedback.error()
|
||||
}
|
||||
}
|
||||
|
||||
func importStickerPackTitleController(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
|
||||
}
|
@ -57,12 +57,10 @@ final class StickerPackPreviewGridItem: GridItem {
|
||||
private let textFont = Font.regular(20.0)
|
||||
|
||||
final class StickerPackPreviewGridItemNode: GridItemNode {
|
||||
private var currentState: (Account, ImportStickerPack.Sticker?)?
|
||||
private var currentState: (Account, ImportStickerPack.Sticker?, CGSize)?
|
||||
private var isEmpty: Bool?
|
||||
// private let imageNode: TransformImageNode
|
||||
private let imageNode: ASImageNode
|
||||
private var animationNode: AnimatedStickerNode?
|
||||
private var placeholderNode: StickerShimmerEffectNode?
|
||||
|
||||
private var theme: PresentationTheme?
|
||||
|
||||
@ -86,50 +84,16 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
||||
|
||||
override init() {
|
||||
self.imageNode = ASImageNode()
|
||||
// self.imageNode = TransformImageNode()
|
||||
// self.imageNode.isLayerBacked = !smartInvertColorsEnabled()
|
||||
self.placeholderNode = StickerShimmerEffectNode()
|
||||
self.placeholderNode?.isUserInteractionEnabled = false
|
||||
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.imageNode)
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
// self.addSubnode(placeholderNode)
|
||||
}
|
||||
|
||||
var firstTime = true
|
||||
// self.imageNode.imageUpdated = { [weak self] image in
|
||||
// guard let strongSelf = self else {
|
||||
// return
|
||||
// }
|
||||
// if image != nil {
|
||||
// strongSelf.removePlaceholder(animated: !firstTime)
|
||||
// }
|
||||
// firstTime = false
|
||||
// }
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.stickerFetchedDisposable.dispose()
|
||||
}
|
||||
|
||||
private func removePlaceholder(animated: Bool) {
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
self.placeholderNode = nil
|
||||
if !animated {
|
||||
placeholderNode.removeFromSupernode()
|
||||
} else {
|
||||
placeholderNode.allowsGroupOpacity = true
|
||||
placeholderNode.alpha = 0.0
|
||||
placeholderNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak placeholderNode] _ in
|
||||
placeholderNode?.removeFromSupernode()
|
||||
placeholderNode?.allowsGroupOpacity = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
@ -141,47 +105,34 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
||||
self.theme = theme
|
||||
|
||||
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 !== stickerItem || self.isEmpty != isEmpty {
|
||||
var dimensions = CGSize(width: 512.0, height: 512.0)
|
||||
if let stickerItem = stickerItem {
|
||||
self.imageNode.image = stickerItem.image
|
||||
// if stickerItem.file.isAnimatedSticker {
|
||||
// let dimensions = stickerItem.file.dimensions ?? PixelDimensions(width: 512, height: 512)
|
||||
// self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, file: stickerItem.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))))
|
||||
//
|
||||
// if self.animationNode == nil {
|
||||
// let animationNode = AnimatedStickerNode()
|
||||
// self.animationNode = animationNode
|
||||
// self.addSubnode(animationNode)
|
||||
// animationNode.started = { [weak self] in
|
||||
// self?.imageNode.isHidden = true
|
||||
// self?.removePlaceholder(animated: false)
|
||||
// }
|
||||
// }
|
||||
// let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
|
||||
// self.animationNode?.setup(source: AnimatedStickerResourceSource(account: account, resource: stickerItem.file.resource), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .cached)
|
||||
// self.animationNode?.visibility = self.isVisibleInGrid && self.interaction?.playAnimatedStickers ?? true
|
||||
// self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, fileReference: stickerPackFileReference(stickerItem.file), resource: stickerItem.file.resource).start())
|
||||
// } else {
|
||||
// if let animationNode = self.animationNode {
|
||||
// animationNode.visibility = false
|
||||
// self.animationNode = nil
|
||||
// animationNode.removeFromSupernode()
|
||||
// }
|
||||
// self.imageNode.setSignal(chatMessageSticker(account: account, file: stickerItem.file, small: true))
|
||||
// self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, fileReference: stickerPackFileReference(stickerItem.file), resource: chatMessageStickerResource(file: stickerItem.file, small: true)).start())
|
||||
// }
|
||||
} else {
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
if isEmpty {
|
||||
if !placeholderNode.alpha.isZero {
|
||||
placeholderNode.alpha = 0.0
|
||||
placeholderNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
|
||||
switch stickerItem.content {
|
||||
case let .image(data):
|
||||
if let animationNode = self.animationNode {
|
||||
animationNode.visibility = false
|
||||
self.animationNode = nil
|
||||
animationNode.removeFromSupernode()
|
||||
}
|
||||
} else {
|
||||
placeholderNode.alpha = 1.0
|
||||
}
|
||||
self.imageNode.isHidden = false
|
||||
if let image = UIImage(data: data) {
|
||||
self.imageNode.image = image
|
||||
dimensions = image.size
|
||||
}
|
||||
case let .animation(data):
|
||||
self.imageNode.isHidden = true
|
||||
let animationNode = AnimatedStickerNode()
|
||||
self.animationNode = animationNode
|
||||
self.addSubnode(animationNode)
|
||||
|
||||
let fittedDimensions = dimensions.aspectFitted(CGSize(width: 160.0, height: 160.0))
|
||||
// animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: stickerItem.file.resource), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .cached)
|
||||
animationNode.visibility = self.isVisibleInGrid && self.interaction?.playAnimatedStickers ?? true
|
||||
}
|
||||
} else {
|
||||
dimensions = CGSize()
|
||||
}
|
||||
self.currentState = (account, stickerItem)
|
||||
self.currentState = (account, stickerItem, dimensions)
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
self.isEmpty = isEmpty
|
||||
@ -194,32 +145,13 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
||||
let boundsSide = min(bounds.size.width - 14.0, bounds.size.height - 14.0)
|
||||
let boundingSize = CGSize(width: boundsSide, height: boundsSide)
|
||||
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
let placeholderFrame = CGRect(origin: CGPoint(x: floor((bounds.width - boundingSize.width) / 2.0), y: floor((bounds.height - boundingSize.height) / 2.0)), size: boundingSize)
|
||||
placeholderNode.frame = bounds
|
||||
|
||||
// if let theme = self.theme, let (_, stickerItem) = self.currentState, let item = stickerItem {
|
||||
// placeholderNode.update(backgroundColor: theme.list.itemBlocksBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor, shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), data: item.file.immediateThumbnailData, size: placeholderFrame.size)
|
||||
// }
|
||||
}
|
||||
|
||||
self.imageNode.frame = bounds
|
||||
// if let (_, item) = self.currentState {
|
||||
// if let item = item, let dimensions = item.file.dimensions?.cgSize {
|
||||
// let imageSize = dimensions.aspectFitted(boundingSize)
|
||||
// self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))()
|
||||
// self.imageNode.frame = CGRect(origin: CGPoint(x: floor((bounds.size.width - imageSize.width) / 2.0), y: (bounds.size.height - imageSize.height) / 2.0), size: imageSize)
|
||||
// if let animationNode = self.animationNode {
|
||||
// animationNode.frame = CGRect(origin: CGPoint(x: floor((bounds.size.width - imageSize.width) / 2.0), y: (bounds.size.height - imageSize.height) / 2.0), size: imageSize)
|
||||
// animationNode.updateLayout(size: imageSize)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
override func updateAbsoluteRect(_ absoluteRect: CGRect, within containerSize: CGSize) {
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
placeholderNode.updateAbsoluteRect(absoluteRect, within: containerSize)
|
||||
if let (_, _, dimensions) = self.currentState {
|
||||
let imageSize = dimensions.aspectFitted(boundingSize)
|
||||
self.imageNode.frame = CGRect(origin: CGPoint(x: floor((bounds.size.width - imageSize.width) / 2.0), y: (bounds.size.height - imageSize.height) / 2.0), size: imageSize)
|
||||
if let animationNode = self.animationNode {
|
||||
animationNode.frame = CGRect(origin: CGPoint(x: floor((bounds.size.width - imageSize.width) / 2.0), y: (bounds.size.height - imageSize.height) / 2.0), size: imageSize)
|
||||
animationNode.updateLayout(size: imageSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,7 +164,7 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
||||
|
||||
func updatePreviewing(animated: Bool) {
|
||||
var isPreviewing = false
|
||||
if let (_, maybeItem) = self.currentState, let interaction = self.interaction, let item = maybeItem {
|
||||
if let (_, maybeItem, _) = self.currentState, let interaction = self.interaction, let item = maybeItem {
|
||||
isPreviewing = interaction.previewedItem === item
|
||||
}
|
||||
if self.currentIsPreviewing != isPreviewing {
|
||||
|
@ -68,15 +68,11 @@ private final class StickerPreviewPeekContentNode: ASDisplayNode, PeekController
|
||||
self.textNode = ASTextNode()
|
||||
self.imageNode = ASImageNode()
|
||||
self.imageNode.displaysAsynchronously = false
|
||||
self.imageNode.image = item.image
|
||||
|
||||
if case let .image(data) = item.content, let image = UIImage(data: data) {
|
||||
self.imageNode.image = image
|
||||
}
|
||||
self.textNode.attributedText = NSAttributedString(string: item.emojis.joined(separator: " "), font: Font.regular(32.0), textColor: .black)
|
||||
|
||||
// for case let .Sticker(text, _, _) in item.file.attributes {
|
||||
// self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(32.0), textColor: .black)
|
||||
// break
|
||||
// }
|
||||
|
||||
|
||||
// if item.file.isAnimatedSticker {
|
||||
// let animationNode = AnimatedStickerNode()
|
||||
// self.animationNode = animationNode
|
||||
@ -92,10 +88,6 @@ private final class StickerPreviewPeekContentNode: ASDisplayNode, PeekController
|
||||
// self.animationNode = nil
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// self.imageNode.setSignal(chatMessageSticker(account: account, file: item.file, small: false, fetched: true))
|
||||
|
||||
super.init()
|
||||
|
||||
self.isUserInteractionEnabled = false
|
||||
|
@ -330,8 +330,13 @@
|
||||
- (void)updateWithFetchResult:(TGMediaAssetFetchResult *)fetchResult
|
||||
{
|
||||
TGMediaAsset *currentAsset = ((TGMediaPickerGalleryItem *)_galleryController.currentItem).asset;
|
||||
bool exists = ([fetchResult indexOfAsset:currentAsset] != NSNotFound);
|
||||
|
||||
bool exists;
|
||||
if ([currentAsset isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||
exists = [fetchResult indexOfAsset:((TGCameraCapturedVideo *)currentAsset).originalAsset] != NSNotFound;
|
||||
} else {
|
||||
exists = ([fetchResult indexOfAsset:currentAsset] != NSNotFound);
|
||||
}
|
||||
if (!exists)
|
||||
{
|
||||
_galleryModel.dismiss(true, false);
|
||||
|
Loading…
x
Reference in New Issue
Block a user