Various fixes

This commit is contained in:
Ilya Laktyushin 2022-12-18 16:30:59 +04:00
parent 8985192fa1
commit e380fdf6b7
14 changed files with 363 additions and 218 deletions

View File

@ -3,7 +3,7 @@ import UIKit
import Display
import AccountContext
final class DrawingBubbleEntity: DrawingEntity, Codable {
public final class DrawingBubbleEntity: DrawingEntity, Codable {
private enum CodingKeys: String, CodingKey {
case uuid
case drawType
@ -16,28 +16,30 @@ final class DrawingBubbleEntity: DrawingEntity, Codable {
case tailPosition
}
public enum DrawType: Codable {
enum DrawType: Codable {
case fill
case stroke
}
let uuid: UUID
let isAnimated: Bool
public let uuid: UUID
public let isAnimated: Bool
var drawType: DrawType
var color: DrawingColor
var lineWidth: CGFloat
public var color: DrawingColor
public var lineWidth: CGFloat
var referenceDrawingSize: CGSize
var position: CGPoint
var size: CGSize
var rotation: CGFloat
public var position: CGPoint
public var size: CGSize
public var rotation: CGFloat
var tailPosition: CGPoint
var center: CGPoint {
public var center: CGPoint {
return self.position
}
public var renderImage: UIImage?
init(drawType: DrawType, color: DrawingColor, lineWidth: CGFloat) {
self.uuid = UUID()
self.isAnimated = false
@ -53,7 +55,7 @@ final class DrawingBubbleEntity: DrawingEntity, Codable {
self.tailPosition = CGPoint(x: 0.16, y: 0.18)
}
init(from decoder: Decoder) throws {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.uuid = try container.decode(UUID.self, forKey: .uuid)
self.isAnimated = false
@ -67,7 +69,7 @@ final class DrawingBubbleEntity: DrawingEntity, Codable {
self.tailPosition = try container.decode(CGPoint.self, forKey: .tailPosition)
}
func encode(to encoder: Encoder) throws {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.uuid, forKey: .uuid)
try container.encode(self.drawType, forKey: .drawType)
@ -80,7 +82,7 @@ final class DrawingBubbleEntity: DrawingEntity, Codable {
try container.encode(self.tailPosition, forKey: .tailPosition)
}
func duplicate() -> DrawingEntity {
public func duplicate() -> DrawingEntity {
let newEntity = DrawingBubbleEntity(drawType: self.drawType, color: self.color, lineWidth: self.lineWidth)
newEntity.referenceDrawingSize = self.referenceDrawingSize
newEntity.position = self.position
@ -89,8 +91,8 @@ final class DrawingBubbleEntity: DrawingEntity, Codable {
return newEntity
}
weak var currentEntityView: DrawingEntityView?
func makeView(context: AccountContext) -> DrawingEntityView {
public weak var currentEntityView: DrawingEntityView?
public func makeView(context: AccountContext) -> DrawingEntityView {
let entityView = DrawingBubbleEntityView(context: context, entity: self)
self.currentEntityView = entityView
return entityView

View File

@ -3,7 +3,7 @@ import UIKit
import LegacyComponents
import AccountContext
protocol DrawingEntity: AnyObject {
public protocol DrawingEntity: AnyObject {
var uuid: UUID { get }
var isAnimated: Bool { get }
var center: CGPoint { get }
@ -56,6 +56,13 @@ enum CodableDrawingEntity {
}
}
public func decodeDrawingEntities(data: Data) -> [DrawingEntity] {
if let codableEntities = try? JSONDecoder().decode([CodableDrawingEntity].self, from: data) {
return codableEntities.map { $0.entity }
}
return []
}
extension CodableDrawingEntity: Codable {
private enum CodingKeys: String, CodingKey {
case type
@ -226,11 +233,7 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView {
sticker.position = center
if setup {
sticker.referenceDrawingSize = self.size
if !sticker.file.isVideoSticker && sticker.file.mimeType.hasSuffix("webm") {
sticker.scale = 4.0
} else {
sticker.scale = 1.0
}
sticker.scale = 1.0
}
} else if let bubble = entity as? DrawingBubbleEntity {
bubble.position = center

View File

@ -16,6 +16,7 @@ import LottieAnimationComponent
import ViewControllerComponent
import ContextUI
import ChatEntityKeyboardInputNode
import EntityKeyboard
enum DrawingToolState: Equatable {
enum Key: CaseIterable {
@ -463,6 +464,8 @@ private final class DrawingScreenComponent: CombinedComponent {
var selectedEntity: DrawingEntity?
var lastFontSize: CGFloat = 0.5
private let stickerPickerInputData = Promise<StickerPickerInputData>()
init(context: AccountContext, updateToolState: ActionSlot<DrawingToolState>, insertEntity: ActionSlot<DrawingEntity>, deselectEntity: ActionSlot<Void>, updatePlayback: ActionSlot<Bool>, present: @escaping (ViewController) -> Void) {
self.context = context
@ -478,6 +481,56 @@ private final class DrawingScreenComponent: CombinedComponent {
self.currentColor = self.drawingState.tools.first?.color ?? DrawingColor(rgb: 0xffffff)
self.updateToolState.invoke(self.drawingState.currentToolState)
let stickerPickerInputData = self.stickerPickerInputData
Queue.concurrentDefaultQueue().after(0.5, {
let emojiItems = EmojiPagerContentComponent.emojiInputData(
context: context,
animationCache: context.animationCache,
animationRenderer: context.animationRenderer,
isStandalone: false,
isStatusSelection: false,
isReactionSelection: false,
isEmojiSelection: true,
topReactionItems: [],
areUnicodeEmojiEnabled: true,
areCustomEmojiEnabled: true,
chatPeerId: context.account.peerId,
hasSearch: false
)
let stickerItems = EmojiPagerContentComponent.stickerInputData(
context: context,
animationCache: context.animationCache,
animationRenderer: context.animationRenderer,
stickerNamespaces: [Namespaces.ItemCollection.CloudStickerPacks],
stickerOrderedItemListCollectionIds: [Namespaces.OrderedItemList.CloudSavedStickers, Namespaces.OrderedItemList.CloudRecentStickers, Namespaces.OrderedItemList.CloudAllPremiumStickers],
chatPeerId: context.account.peerId,
hasSearch: false,
hasTrending: true
)
let maskItems = EmojiPagerContentComponent.stickerInputData(
context: context,
animationCache: context.animationCache,
animationRenderer: context.animationRenderer,
stickerNamespaces: [Namespaces.ItemCollection.CloudMaskPacks],
stickerOrderedItemListCollectionIds: [],
chatPeerId: context.account.peerId,
hasSearch: false,
hasTrending: false
)
let signal = combineLatest(queue: .mainQueue(),
emojiItems,
stickerItems,
maskItems
) |> map { emoji, stickers, masks -> StickerPickerInputData in
return StickerPickerInputData(emoji: emoji, stickers: stickers, masks: masks)
}
stickerPickerInputData.set(signal)
})
}
private var currentToolState: DrawingToolState {
@ -717,7 +770,7 @@ private final class DrawingScreenComponent: CombinedComponent {
self.currentMode = .sticker
self.updatePlayback.invoke(false)
let controller = StickerPickerScreen(context: self.context)
let controller = StickerPickerScreen(context: self.context, inputData: self.stickerPickerInputData.get())
controller.completion = { [weak self] file in
self?.updatePlayback.invoke(true)
@ -2363,13 +2416,6 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController {
}
strongSelf.toggleInputMode()
}
// inputView?.presentController = { [weak self] c in
// guard let strongSelf = self else {
// return
// }
// strongSelf.presentController(c)
// }
textView.inputView = inputView
} else {
textView.inputView = nil

View File

@ -3,7 +3,7 @@ import UIKit
import Display
import AccountContext
final class DrawingSimpleShapeEntity: DrawingEntity, Codable {
public final class DrawingSimpleShapeEntity: DrawingEntity, Codable {
private enum CodingKeys: String, CodingKey {
case uuid
case shapeType
@ -27,23 +27,25 @@ final class DrawingSimpleShapeEntity: DrawingEntity, Codable {
case stroke
}
let uuid: UUID
let isAnimated: Bool
public let uuid: UUID
public let isAnimated: Bool
var shapeType: ShapeType
var drawType: DrawType
var color: DrawingColor
var lineWidth: CGFloat
public var color: DrawingColor
public var lineWidth: CGFloat
var referenceDrawingSize: CGSize
var position: CGPoint
var size: CGSize
var rotation: CGFloat
public var position: CGPoint
public var size: CGSize
public var rotation: CGFloat
var center: CGPoint {
public var center: CGPoint {
return self.position
}
public var renderImage: UIImage?
init(shapeType: ShapeType, drawType: DrawType, color: DrawingColor, lineWidth: CGFloat) {
self.uuid = UUID()
self.isAnimated = false
@ -59,7 +61,7 @@ final class DrawingSimpleShapeEntity: DrawingEntity, Codable {
self.rotation = 0.0
}
init(from decoder: Decoder) throws {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.uuid = try container.decode(UUID.self, forKey: .uuid)
self.isAnimated = false
@ -73,7 +75,7 @@ final class DrawingSimpleShapeEntity: DrawingEntity, Codable {
self.rotation = try container.decode(CGFloat.self, forKey: .rotation)
}
func encode(to encoder: Encoder) throws {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.uuid, forKey: .uuid)
try container.encode(self.shapeType, forKey: .shapeType)
@ -86,7 +88,7 @@ final class DrawingSimpleShapeEntity: DrawingEntity, Codable {
try container.encode(self.rotation, forKey: .rotation)
}
func duplicate() -> DrawingEntity {
public func duplicate() -> DrawingEntity {
let newEntity = DrawingSimpleShapeEntity(shapeType: self.shapeType, drawType: self.drawType, color: self.color, lineWidth: self.lineWidth)
newEntity.referenceDrawingSize = self.referenceDrawingSize
newEntity.position = self.position
@ -95,8 +97,8 @@ final class DrawingSimpleShapeEntity: DrawingEntity, Codable {
return newEntity
}
weak var currentEntityView: DrawingEntityView?
func makeView(context: AccountContext) -> DrawingEntityView {
public weak var currentEntityView: DrawingEntityView?
public func makeView(context: AccountContext) -> DrawingEntityView {
let entityView = DrawingSimpleShapeEntityView(context: context, entity: self)
self.currentEntityView = entityView
return entityView

View File

@ -8,7 +8,7 @@ import TelegramAnimatedStickerNode
import StickerResources
import AccountContext
final class DrawingStickerEntity: DrawingEntity, Codable {
public final class DrawingStickerEntity: DrawingEntity, Codable {
private enum CodingKeys: String, CodingKey {
case uuid
case isAnimated
@ -20,23 +20,28 @@ final class DrawingStickerEntity: DrawingEntity, Codable {
case mirrored
}
let uuid: UUID
let isAnimated: Bool
let file: TelegramMediaFile
public let uuid: UUID
public let isAnimated: Bool
public let file: TelegramMediaFile
var referenceDrawingSize: CGSize
var position: CGPoint
var scale: CGFloat
var rotation: CGFloat
var mirrored: Bool
public var referenceDrawingSize: CGSize
public var position: CGPoint
public var scale: CGFloat
public var rotation: CGFloat
public var mirrored: Bool
var color: DrawingColor = DrawingColor.clear
var lineWidth: CGFloat = 0.0
public var color: DrawingColor = DrawingColor.clear
public var lineWidth: CGFloat = 0.0
var center: CGPoint {
public var center: CGPoint {
return self.position
}
public var baseSize: CGSize {
let size = max(10.0, min(self.referenceDrawingSize.width, self.referenceDrawingSize.height) * 0.4)
return CGSize(width: size, height: size)
}
init(file: TelegramMediaFile) {
self.uuid = UUID()
self.isAnimated = file.isAnimatedSticker
@ -50,7 +55,7 @@ final class DrawingStickerEntity: DrawingEntity, Codable {
self.mirrored = false
}
init(from decoder: Decoder) throws {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.uuid = try container.decode(UUID.self, forKey: .uuid)
self.isAnimated = try container.decode(Bool.self, forKey: .isAnimated)
@ -62,7 +67,7 @@ final class DrawingStickerEntity: DrawingEntity, Codable {
self.mirrored = try container.decode(Bool.self, forKey: .mirrored)
}
func encode(to encoder: Encoder) throws {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.uuid, forKey: .uuid)
try container.encode(self.isAnimated, forKey: .isAnimated)
@ -74,7 +79,7 @@ final class DrawingStickerEntity: DrawingEntity, Codable {
try container.encode(self.mirrored, forKey: .mirrored)
}
func duplicate() -> DrawingEntity {
public func duplicate() -> DrawingEntity {
let newEntity = DrawingStickerEntity(file: self.file)
newEntity.referenceDrawingSize = self.referenceDrawingSize
newEntity.position = self.position
@ -84,8 +89,8 @@ final class DrawingStickerEntity: DrawingEntity, Codable {
return newEntity
}
weak var currentEntityView: DrawingEntityView?
func makeView(context: AccountContext) -> DrawingEntityView {
public weak var currentEntityView: DrawingEntityView?
public func makeView(context: AccountContext) -> DrawingEntityView {
let entityView = DrawingStickerEntityView(context: context, entity: self)
self.currentEntityView = entityView
return entityView
@ -256,9 +261,9 @@ final class DrawingStickerEntityView: DrawingEntityView {
}
self.center = self.stickerEntity.position
let size = max(10.0, min(self.stickerEntity.referenceDrawingSize.width, self.stickerEntity.referenceDrawingSize.height) * 0.45)
let size = self.stickerEntity.baseSize
self.bounds = CGRect(origin: .zero, size: dimensions.fitted(CGSize(width: size, height: size)))
self.bounds = CGRect(origin: .zero, size: dimensions.aspectFitted(size))
self.transform = CGAffineTransformScale(CGAffineTransformMakeRotation(self.stickerEntity.rotation), self.stickerEntity.scale, self.stickerEntity.scale)
var transform = CATransform3DIdentity

View File

@ -6,7 +6,7 @@ import AccountContext
import TextFormat
import EmojiTextAttachmentView
final class DrawingTextEntity: DrawingEntity, Codable {
public final class DrawingTextEntity: DrawingEntity, Codable {
final class CustomEmojiAttribute: Codable {
private enum CodingKeys: String, CodingKey {
case attribute
@ -122,8 +122,8 @@ final class DrawingTextEntity: DrawingEntity, Codable {
}
}
var uuid: UUID
var isAnimated: Bool {
public var uuid: UUID
public var isAnimated: Bool {
var isAnimated = false
self.text.enumerateAttributes(in: NSMakeRange(0, self.text.length), options: [], using: { attributes, range, _ in
if let _ = attributes[ChatTextInputAttributes.customEmoji] as? ChatTextInputTextCustomEmojiAttribute {
@ -138,8 +138,8 @@ final class DrawingTextEntity: DrawingEntity, Codable {
var font: Font
var alignment: Alignment
var fontSize: CGFloat
var color: DrawingColor
var lineWidth: CGFloat = 0.0
public var color: DrawingColor
public var lineWidth: CGFloat = 0.0
var referenceDrawingSize: CGSize
var position: CGPoint
@ -147,10 +147,12 @@ final class DrawingTextEntity: DrawingEntity, Codable {
var scale: CGFloat
var rotation: CGFloat
var center: CGPoint {
public var center: CGPoint {
return self.position
}
public var renderImage: UIImage?
init(text: NSAttributedString, style: Style, font: Font, alignment: Alignment, fontSize: CGFloat, color: DrawingColor) {
self.uuid = UUID()
@ -168,7 +170,7 @@ final class DrawingTextEntity: DrawingEntity, Codable {
self.rotation = 0.0
}
init(from decoder: Decoder) throws {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.uuid = try container.decode(UUID.self, forKey: .uuid)
let text = try container.decode(String.self, forKey: .text)
@ -192,7 +194,7 @@ final class DrawingTextEntity: DrawingEntity, Codable {
self.rotation = try container.decode(CGFloat.self, forKey: .rotation)
}
func encode(to encoder: Encoder) throws {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.uuid, forKey: .uuid)
try container.encode(self.text.string, forKey: .text)
@ -217,7 +219,7 @@ final class DrawingTextEntity: DrawingEntity, Codable {
try container.encode(self.rotation, forKey: .rotation)
}
func duplicate() -> DrawingEntity {
public func duplicate() -> DrawingEntity {
let newEntity = DrawingTextEntity(text: self.text, style: self.style, font: self.font, alignment: self.alignment, fontSize: self.fontSize, color: self.color)
newEntity.referenceDrawingSize = self.referenceDrawingSize
newEntity.position = self.position
@ -227,8 +229,8 @@ final class DrawingTextEntity: DrawingEntity, Codable {
return newEntity
}
weak var currentEntityView: DrawingEntityView?
func makeView(context: AccountContext) -> DrawingEntityView {
public weak var currentEntityView: DrawingEntityView?
public func makeView(context: AccountContext) -> DrawingEntityView {
let entityView = DrawingTextEntityView(context: context, entity: self)
self.currentEntityView = entityView
return entityView
@ -718,6 +720,9 @@ final class DrawingTextEntititySelectionView: DrawingEntitySelectionView, UIGest
}
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if let entityView = self.entityView as? DrawingTextEntityView, entityView.isEditing {
return false
}
return true
}
@ -726,6 +731,7 @@ final class DrawingTextEntititySelectionView: DrawingEntitySelectionView, UIGest
guard let entityView = self.entityView, let entity = entityView.entity as? DrawingTextEntity else {
return
}
let location = gestureRecognizer.location(in: self)
switch gestureRecognizer.state {
@ -781,10 +787,10 @@ final class DrawingTextEntititySelectionView: DrawingEntitySelectionView, UIGest
}
override func handlePinch(_ gestureRecognizer: UIPinchGestureRecognizer) {
guard let entityView = self.entityView, let entity = entityView.entity as? DrawingTextEntity else {
guard let entityView = self.entityView as? DrawingTextEntityView, !entityView.isEditing, let entity = entityView.entity as? DrawingTextEntity else {
return
}
switch gestureRecognizer.state {
case .began, .changed:
let scale = gestureRecognizer.scale
@ -798,7 +804,7 @@ final class DrawingTextEntititySelectionView: DrawingEntitySelectionView, UIGest
}
override func handleRotate(_ gestureRecognizer: UIRotationGestureRecognizer) {
guard let entityView = self.entityView, let entity = entityView.entity as? DrawingTextEntity else {
guard let entityView = self.entityView as? DrawingTextEntityView, !entityView.isEditing, let entity = entityView.entity as? DrawingTextEntity else {
return
}

View File

@ -3,7 +3,7 @@ import UIKit
import QuartzCore
import simd
struct DrawingColor: Equatable, Codable {
public struct DrawingColor: Equatable, Codable {
private enum CodingKeys: String, CodingKey {
case red
case green
@ -57,7 +57,7 @@ struct DrawingColor: Equatable, Codable {
self.init(color: UIColor(rgb: rgb))
}
init(from decoder: Decoder) throws {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.red = try container.decode(CGFloat.self, forKey: .red)
self.green = try container.decode(CGFloat.self, forKey: .green)

View File

@ -3,7 +3,7 @@ import UIKit
import Display
import AccountContext
final class DrawingVectorEntity: DrawingEntity, Codable {
public final class DrawingVectorEntity: DrawingEntity, Codable {
private enum CodingKeys: String, CodingKey {
case uuid
case type
@ -22,14 +22,14 @@ final class DrawingVectorEntity: DrawingEntity, Codable {
case twoSidedArrow
}
let uuid: UUID
let isAnimated: Bool
public let uuid: UUID
public let isAnimated: Bool
var type: VectorType
var color: DrawingColor
var lineWidth: CGFloat
public var color: DrawingColor
public var lineWidth: CGFloat
var drawingSize: CGSize
public var drawingSize: CGSize
var referenceDrawingSize: CGSize
var start: CGPoint
var mid: (CGFloat, CGFloat)
@ -46,10 +46,12 @@ final class DrawingVectorEntity: DrawingEntity, Codable {
}
}
var center: CGPoint {
public var center: CGPoint {
return self.start
}
public var renderImage: UIImage?
init(type: VectorType, color: DrawingColor, lineWidth: CGFloat) {
self.uuid = UUID()
self.isAnimated = false
@ -65,7 +67,7 @@ final class DrawingVectorEntity: DrawingEntity, Codable {
self.end = CGPoint()
}
init(from decoder: Decoder) throws {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.uuid = try container.decode(UUID.self, forKey: .uuid)
self.isAnimated = false
@ -82,7 +84,7 @@ final class DrawingVectorEntity: DrawingEntity, Codable {
self.end = try container.decode(CGPoint.self, forKey: .end)
}
func encode(to encoder: Encoder) throws {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.uuid, forKey: .uuid)
try container.encode(self.type, forKey: .type)
@ -95,7 +97,7 @@ final class DrawingVectorEntity: DrawingEntity, Codable {
try container.encode(self.end, forKey: .end)
}
func duplicate() -> DrawingEntity {
public func duplicate() -> DrawingEntity {
let newEntity = DrawingVectorEntity(type: self.type, color: self.color, lineWidth: self.lineWidth)
newEntity.drawingSize = self.drawingSize
newEntity.referenceDrawingSize = self.referenceDrawingSize
@ -105,8 +107,8 @@ final class DrawingVectorEntity: DrawingEntity, Codable {
return newEntity
}
weak var currentEntityView: DrawingEntityView?
func makeView(context: AccountContext) -> DrawingEntityView {
public weak var currentEntityView: DrawingEntityView?
public func makeView(context: AccountContext) -> DrawingEntityView {
let entityView = DrawingVectorEntityView(context: context, entity: self)
self.currentEntityView = entityView
return entityView

View File

@ -14,7 +14,7 @@ import PagerComponent
import FeaturedStickersScreen
import TelegramNotices
struct InputData: Equatable {
struct StickerPickerInputData: Equatable {
var emoji: EmojiPagerContentComponent
var stickers: EmojiPagerContentComponent?
var masks: EmojiPagerContentComponent?
@ -37,7 +37,7 @@ private final class StickerSelectionComponent: Component {
let strings: PresentationStrings
let deviceMetrics: DeviceMetrics
let bottomInset: CGFloat
let content: InputData
let content: StickerPickerInputData
let backgroundColor: UIColor
let separatorColor: UIColor
@ -46,7 +46,7 @@ private final class StickerSelectionComponent: Component {
strings: PresentationStrings,
deviceMetrics: DeviceMetrics,
bottomInset: CGFloat,
content: InputData,
content: StickerPickerInputData,
backgroundColor: UIColor,
separatorColor: UIColor
) {
@ -197,7 +197,7 @@ private final class StickerSelectionComponent: Component {
}
}
public class StickerPickerScreen: ViewController {
class StickerPickerScreen: ViewController {
final class Node: ViewControllerTracingNode, UIScrollViewDelegate, UIGestureRecognizerDelegate {
private var presentationData: PresentationData
private weak var controller: StickerPickerScreen?
@ -209,7 +209,7 @@ public class StickerPickerScreen: ViewController {
let scrollView: UIScrollView
let hostView: ComponentHostView<Empty>
private var content: InputData?
private var content: StickerPickerInputData?
private let contentDisposable = MetaDisposable()
private var scheduledEmojiContentAnimationHint: EmojiPagerContentComponent.ContentAnimation?
@ -251,51 +251,9 @@ public class StickerPickerScreen: ViewController {
self.containerView.addSubview(self.scrollView)
self.scrollView.addSubview(self.hostView)
let emojiItems = EmojiPagerContentComponent.emojiInputData(
context: context,
animationCache: context.animationCache,
animationRenderer: context.animationRenderer,
isStandalone: false,
isStatusSelection: false,
isReactionSelection: false,
isEmojiSelection: true,
topReactionItems: [],
areUnicodeEmojiEnabled: true,
areCustomEmojiEnabled: true,
chatPeerId: context.account.peerId,
hasSearch: false
)
let stickerItems = EmojiPagerContentComponent.stickerInputData(
context: context,
animationCache: context.animationCache,
animationRenderer: context.animationRenderer,
stickerNamespaces: [Namespaces.ItemCollection.CloudStickerPacks],
stickerOrderedItemListCollectionIds: [Namespaces.OrderedItemList.CloudSavedStickers, Namespaces.OrderedItemList.CloudRecentStickers, Namespaces.OrderedItemList.CloudAllPremiumStickers],
chatPeerId: context.account.peerId,
hasSearch: false,
hasTrending: true
)
let maskItems = EmojiPagerContentComponent.stickerInputData(
context: context,
animationCache: context.animationCache,
animationRenderer: context.animationRenderer,
stickerNamespaces: [Namespaces.ItemCollection.CloudMaskPacks],
stickerOrderedItemListCollectionIds: [],
chatPeerId: context.account.peerId,
hasSearch: false,
hasTrending: false
)
let signal = combineLatest(queue: .mainQueue(),
emojiItems,
stickerItems,
maskItems
)
self.contentDisposable.set(signal.start(next: { [weak self] emoji, stickers, masks in
self.contentDisposable.set(controller.inputData.start(next: { [weak self] inputData in
if let strongSelf = self {
strongSelf.updateContent(InputData(emoji: emoji, stickers: stickers, masks: masks))
strongSelf.updateContent(inputData)
}
}))
}
@ -304,7 +262,7 @@ public class StickerPickerScreen: ViewController {
self.contentDisposable.dispose()
}
func updateContent(_ content: InputData) {
func updateContent(_ content: StickerPickerInputData) {
self.content = content
content.emoji.inputInteractionHolder.inputInteraction = EmojiPagerContentComponent.InputInteraction(
@ -999,6 +957,7 @@ public class StickerPickerScreen: ViewController {
private let context: AccountContext
private let theme: PresentationTheme
private let inputData: Signal<StickerPickerInputData, NoError>
private var currentLayout: ContainerViewLayout?
@ -1007,26 +966,28 @@ public class StickerPickerScreen: ViewController {
var completion: (TelegramMediaFile?) -> Void = { _ in }
public init(context: AccountContext) {
init(context: AccountContext, inputData: Signal<StickerPickerInputData, NoError>) {
self.context = context
self.theme = defaultDarkColorPresentationTheme
self.inputData = inputData
super.init(navigationBarPresentationData: nil)
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
self.statusBar.statusBarStyle = .Ignore
}
required public init(coder aDecoder: NSCoder) {
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override open func loadDisplayNode() {
override func loadDisplayNode() {
self.displayNode = Node(context: self.context, controller: self, theme: self.theme)
self.displayNodeDidLoad()
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
}
public override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
self.view.endEditing(true)
if flag {
self.node.animateOut(completion: {
@ -1039,19 +1000,19 @@ public class StickerPickerScreen: ViewController {
}
}
override open func viewDidAppear(_ animated: Bool) {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.node.updateIsVisible(isVisible: true)
}
override open func viewDidDisappear(_ animated: Bool) {
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.node.updateIsVisible(isVisible: false)
}
override open func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
self.currentLayout = layout
super.containerLayoutUpdated(layout, transition: transition)

View File

@ -21,7 +21,7 @@
+ (instancetype)dataWithDrawingData:(NSData *)data entitiesData:(NSData *)entitiesData image:(UIImage *)image stillImage:(UIImage *)stillImage hasAnimation:(bool)hasAnimation;
+ (instancetype)dataWithPaintingImagePath:(NSString *)imagePath entitiesData:(NSData *)entitiesData;
+ (instancetype)dataWithPaintingImagePath:(NSString *)imagePath entitiesData:(NSData *)entitiesData hasAnimation:(bool)hasAnimation;
+ (instancetype)dataWithPaintingImagePath:(NSString *)imagePath;

View File

@ -31,10 +31,11 @@
return paintingData;
}
+ (instancetype)dataWithPaintingImagePath:(NSString *)imagePath entitiesData:(NSData *)entitiesData {
+ (instancetype)dataWithPaintingImagePath:(NSString *)imagePath entitiesData:(NSData *)entitiesData hasAnimation:(bool)hasAnimation {
TGPaintingData *paintingData = [[TGPaintingData alloc] init];
paintingData->_imagePath = imagePath;
paintingData->_entitiesData = entitiesData;
paintingData->_hasAnimation = hasAnimation;
return paintingData;
}
@ -49,6 +50,7 @@
{
TGPaintingData *paintingData = [[TGPaintingData alloc] init];
paintingData->_entitiesData = _entitiesData;
paintingData->_hasAnimation = _hasAnimation;
return paintingData;
}

View File

@ -77,7 +77,7 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
if (dictionary[@"originalSize"])
adjustments->_originalSize = [dictionary[@"originalSize"] CGSizeValue];
if (dictionary[@"entitiesData"]) {
adjustments->_paintingData = [TGPaintingData dataWithPaintingImagePath:dictionary[@"paintingImagePath"] entitiesData:dictionary[@"entitiesData"]];
adjustments->_paintingData = [TGPaintingData dataWithPaintingImagePath:dictionary[@"paintingImagePath"] entitiesData:dictionary[@"entitiesData"] hasAnimation:[dictionary[@"hasAnimation"] boolValue]];
} else if (dictionary[@"paintingImagePath"]) {
adjustments->_paintingData = [TGPaintingData dataWithPaintingImagePath:dictionary[@"paintingImagePath"]];
}
@ -217,6 +217,7 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
}
if (self.paintingData.entitiesData != nil) {
dict[@"entitiesData"] = self.paintingData.entitiesData;
dict[@"hasAnimation"] = @(self.paintingData.hasAnimation);
}
}

View File

@ -63,7 +63,7 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
}
var angle: CGFloat {
return self.entity.angle
return self.entity.rotation
}
var baseSize: CGSize? {
@ -76,7 +76,7 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
let account: Account
let file: TelegramMediaFile
let entity: TGPhotoPaintStickerEntity
let entity: DrawingStickerEntity
let animated: Bool
let durationPromise = Promise<Double>()
@ -92,55 +92,50 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
let imagePromise = Promise<UIImage>()
init?(account: Account, entity: TGPhotoPaintStickerEntity) {
let decoder = PostboxDecoder(buffer: MemoryBuffer(data: entity.document))
if let file = decoder.decodeRootObject() as? TelegramMediaFile {
self.account = account
self.entity = entity
self.file = file
self.animated = file.isAnimatedSticker || file.isVideoSticker
if file.isAnimatedSticker || file.isVideoSticker {
self.source = AnimatedStickerResourceSource(account: account, resource: file.resource, isVideo: file.isVideoSticker)
if let source = self.source {
let dimensions = self.file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 384, height: 384))
self.disposables.add((source.cachedDataPath(width: Int(fittedDimensions.width), height: Int(fittedDimensions.height))
|> deliverOn(self.queue)).start(next: { [weak self] path, complete in
if let strongSelf = self, complete {
if let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: [.mappedRead]) {
let queue = strongSelf.queue
let frameSource = AnimatedStickerCachedFrameSource(queue: queue, data: data, complete: complete, notifyUpdated: {})!
strongSelf.frameCount = frameSource.frameCount
strongSelf.frameRate = frameSource.frameRate
let duration = Double(frameSource.frameCount) / Double(frameSource.frameRate)
strongSelf.totalDuration = duration
strongSelf.durationPromise.set(.single(duration))
let frameQueue = QueueLocalObject<AnimatedStickerFrameQueue>(queue: queue, generate: {
return AnimatedStickerFrameQueue(queue: queue, length: 1, source: frameSource)
})
strongSelf.frameQueue.set(.single(frameQueue))
}
}
}))
}
} else {
self.disposables.add((chatMessageSticker(account: self.account, userLocation: .other, file: self.file, small: false, fetched: true, onlyFullSize: true, thumbnail: false, synchronousLoad: false)
|> deliverOn(self.queue)).start(next: { [weak self] generator in
if let strongSelf = self {
let context = generator(TransformImageArguments(corners: ImageCorners(), imageSize: entity.baseSize, boundingSize: entity.baseSize, intrinsicInsets: UIEdgeInsets()))
let image = context?.generateImage()
if let image = image {
strongSelf.imagePromise.set(.single(image))
init(account: Account, entity: DrawingStickerEntity) {
self.account = account
self.entity = entity
self.file = entity.file
self.animated = file.isAnimatedSticker || file.isVideoSticker
if file.isAnimatedSticker || file.isVideoSticker {
self.source = AnimatedStickerResourceSource(account: account, resource: file.resource, isVideo: file.isVideoSticker)
if let source = self.source {
let dimensions = self.file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 384, height: 384))
self.disposables.add((source.cachedDataPath(width: Int(fittedDimensions.width), height: Int(fittedDimensions.height))
|> deliverOn(self.queue)).start(next: { [weak self] path, complete in
if let strongSelf = self, complete {
if let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: [.mappedRead]) {
let queue = strongSelf.queue
let frameSource = AnimatedStickerCachedFrameSource(queue: queue, data: data, complete: complete, notifyUpdated: {})!
strongSelf.frameCount = frameSource.frameCount
strongSelf.frameRate = frameSource.frameRate
let duration = Double(frameSource.frameCount) / Double(frameSource.frameRate)
strongSelf.totalDuration = duration
strongSelf.durationPromise.set(.single(duration))
let frameQueue = QueueLocalObject<AnimatedStickerFrameQueue>(queue: queue, generate: {
return AnimatedStickerFrameQueue(queue: queue, length: 1, source: frameSource)
})
strongSelf.frameQueue.set(.single(frameQueue))
}
}
}))
}
} else {
return nil
self.disposables.add((chatMessageSticker(account: self.account, userLocation: .other, file: self.file, small: false, fetched: true, onlyFullSize: true, thumbnail: false, synchronousLoad: false)
|> deliverOn(self.queue)).start(next: { [weak self] generator in
if let strongSelf = self {
let context = generator(TransformImageArguments(corners: ImageCorners(), imageSize: entity.baseSize, boundingSize: entity.baseSize, intrinsicInsets: UIEdgeInsets()))
let image = context?.generateImage()
if let image = image {
strongSelf.imagePromise.set(.single(image))
}
}
}))
}
}
@ -277,6 +272,126 @@ private class LegacyPaintTextEntity: LegacyPaintEntity {
}
}
private class LegacyPaintSimpleShapeEntity: LegacyPaintEntity {
var position: CGPoint {
return self.entity.position
}
var scale: CGFloat {
return 1.0
}
var angle: CGFloat {
return self.entity.rotation
}
var baseSize: CGSize? {
return self.entity.size
}
var mirrored: Bool {
return false
}
let entity: DrawingSimpleShapeEntity
init(entity: DrawingSimpleShapeEntity) {
self.entity = entity
}
var cachedCIImage: CIImage?
func image(for time: CMTime, fps: Int, completion: @escaping (CIImage?) -> Void) {
var image: CIImage?
if let cachedImage = self.cachedCIImage {
image = cachedImage
} else if let renderImage = entity.renderImage {
image = CIImage(image: renderImage)
self.cachedCIImage = image
}
completion(image)
}
}
private class LegacyPaintBubbleEntity: LegacyPaintEntity {
var position: CGPoint {
return self.entity.position
}
var scale: CGFloat {
return 1.0
}
var angle: CGFloat {
return self.entity.rotation
}
var baseSize: CGSize? {
return self.entity.size
}
var mirrored: Bool {
return false
}
let entity: DrawingBubbleEntity
init(entity: DrawingBubbleEntity) {
self.entity = entity
}
var cachedCIImage: CIImage?
func image(for time: CMTime, fps: Int, completion: @escaping (CIImage?) -> Void) {
var image: CIImage?
if let cachedImage = self.cachedCIImage {
image = cachedImage
} else if let renderImage = entity.renderImage {
image = CIImage(image: renderImage)
self.cachedCIImage = image
}
completion(image)
}
}
private class LegacyPaintVectorEntity: LegacyPaintEntity {
var position: CGPoint {
return CGPoint(x: self.entity.drawingSize.width * 0.5, y: self.entity.drawingSize.height * 0.5)
}
var scale: CGFloat {
return 1.0
}
var angle: CGFloat {
return 0.0
}
var baseSize: CGSize? {
return self.entity.drawingSize
}
var mirrored: Bool {
return false
}
let entity: DrawingVectorEntity
init(entity: DrawingVectorEntity) {
self.entity = entity
}
var cachedCIImage: CIImage?
func image(for time: CMTime, fps: Int, completion: @escaping (CIImage?) -> Void) {
var image: CIImage?
if let cachedImage = self.cachedCIImage {
image = cachedImage
} else if let renderImage = entity.renderImage {
image = CIImage(image: renderImage)
self.cachedCIImage = image
}
completion(image)
}
}
public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRenderer {
private let account: Account?
private let queue = Queue()
@ -290,19 +405,24 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender
self.originalSize = adjustments.originalSize
self.cropRect = adjustments.cropRect.isEmpty ? nil : adjustments.cropRect
let entities: [LegacyPaintEntity] = []
// if let paintingData = adjustments.paintingData, let paintingEntities = paintingData.entities {
// for paintingEntity in paintingEntities {
// if let sticker = paintingEntity as? TGPhotoPaintStickerEntity {
// if let account = account, let entity = LegacyPaintStickerEntity(account: account, entity: sticker) {
// entities.append(entity)
// }
// } else if let text = paintingEntity as? TGPhotoPaintTextEntity {
// entities.append(LegacyPaintTextEntity(entity: text))
// }
// }
// }
self.entities = entities
var renderEntities: [LegacyPaintEntity] = []
if let account = account, let paintingData = adjustments.paintingData, let entitiesData = paintingData.entitiesData {
let entities = decodeDrawingEntities(data: entitiesData)
for entity in entities {
if let sticker = entity as? DrawingStickerEntity {
renderEntities.append(LegacyPaintStickerEntity(account: account, entity: sticker))
} else if let _ = entity as? DrawingTextEntity {
// renderEntities.append(LegacyPaintStickerEntity(account: account, entity: sticker))
} else if let simpleShape = entity as? DrawingSimpleShapeEntity {
renderEntities.append(LegacyPaintSimpleShapeEntity(entity: simpleShape))
} else if let bubble = entity as? DrawingBubbleEntity {
renderEntities.append(LegacyPaintBubbleEntity(entity: bubble))
} else if let vector = entity as? DrawingVectorEntity {
renderEntities.append(LegacyPaintVectorEntity(entity: vector))
}
}
}
self.entities = renderEntities
super.init()
}
@ -360,7 +480,7 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender
public func entities(for time: CMTime, fps: Int, size: CGSize, completion: (([CIImage]?) -> Void)!) {
let entities = self.entities
let maxSide = max(size.width, size.height)
let paintingScale = maxSide / 1920.0
let paintingScale = maxSide / 2560.0
self.queue.async {
if entities.isEmpty {
@ -394,7 +514,7 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender
}
transform = CGAffineTransform(translationX: entity.position.x * paintingScale, y: size.height - entity.position.y * paintingScale)
transform = transform.rotated(by: CGFloat.pi * 2 - entity.angle)
transform = transform.rotated(by: CGFloat.pi * 2.0 - entity.angle)
transform = transform.scaledBy(x: scale, y: scale)
if entity.mirrored {
transform = transform.scaledBy(x: -1.0, y: 1.0)

View File

@ -30,7 +30,6 @@ class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode
private var videoStartTimestamp: Double?
private let buttonNode: HighlightTrackingButtonNode
private let buttonStarsNode: PremiumStarsNode
private let buttonTitleNode: TextNode
private var absoluteRect: (CGRect, CGSize)?
@ -51,9 +50,7 @@ class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode
self.buttonNode = HighlightTrackingButtonNode()
self.buttonNode.clipsToBounds = true
self.buttonNode.cornerRadius = 17.0
self.buttonStarsNode = PremiumStarsNode()
self.buttonTitleNode = TextNode()
self.buttonTitleNode.isUserInteractionEnabled = false
self.buttonTitleNode.displaysAsynchronously = false
@ -65,7 +62,6 @@ class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode
self.addSubnode(self.imageNode)
self.addSubnode(self.buttonNode)
self.buttonNode.addSubnode(self.buttonStarsNode)
self.addSubnode(self.buttonTitleNode)
self.buttonNode.highligthedChanged = { [weak self] highlighted in
@ -273,7 +269,6 @@ class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode
let buttonSize = CGSize(width: buttonTitleLayout.size.width + 38.0, height: 34.0)
strongSelf.buttonNode.frame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - buttonSize.width) / 2.0), y: subtitleFrame.maxY + 10.0), size: buttonSize)
strongSelf.buttonStarsNode.frame = CGRect(origin: .zero, size: buttonSize)
if item.controllerInteraction.presentationContext.backgroundNode?.hasExtraBubbleBackground() == true {
if strongSelf.mediaBackgroundContent == nil, let backgroundContent = item.controllerInteraction.presentationContext.backgroundNode?.makeBubbleBackground(for: .free) {