mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
[WIP] Stickers editor
This commit is contained in:
parent
ff5307a254
commit
70eef8ecac
@ -11904,3 +11904,5 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Conversation.ViewStickers" = "VIEW STICKERS";
|
||||
"Conversation.ViewEmojis" = "VIEW EMOJIS";
|
||||
|
||||
"MediaEditor.StickersTooMuch" = "Sorry, you've reached the maximum number of stickers in this set. Try a different one.";
|
||||
|
@ -314,7 +314,7 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
||||
if stickerItem.file.isAnimatedSticker || stickerItem.file.isVideoSticker {
|
||||
let dimensions = stickerItem.file.dimensions ?? PixelDimensions(width: 512, height: 512)
|
||||
if stickerItem.file.isVideoSticker {
|
||||
self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: stickerItem.file, small: true))
|
||||
self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: stickerItem.file, small: true, fetched: true))
|
||||
} else {
|
||||
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: context.account.postbox, userLocation: .other, file: stickerItem.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))))
|
||||
}
|
||||
|
@ -1250,6 +1250,7 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
let presentationData = self.presentationData
|
||||
let updatedPresentationData = self.controller?.updatedPresentationData
|
||||
let navigationController = self.controller?.parentNavigationController as? NavigationController
|
||||
let sendSticker = self.controller?.sendSticker
|
||||
|
||||
var dismissImpl: (() -> Void)?
|
||||
let mainController = context.sharedContext.makeStickerMediaPickerScreen(
|
||||
@ -1275,7 +1276,7 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
commit()
|
||||
|
||||
let packController = StickerPackScreen(context: context, updatedPresentationData: updatedPresentationData, mainStickerPack: packReference, stickerPacks: [packReference], loadedStickerPacks: [], expandIfNeeded: true, parentNavigationController: navigationController, sendSticker: nil, sendEmoji: nil, actionPerformed: nil, dismissed: nil, getSourceRect: nil)
|
||||
let packController = StickerPackScreen(context: context, updatedPresentationData: updatedPresentationData, mainStickerPack: packReference, stickerPacks: [packReference], loadedStickerPacks: [], expandIfNeeded: true, parentNavigationController: navigationController, sendSticker: sendSticker, sendEmoji: nil, actionPerformed: nil, dismissed: nil, getSourceRect: nil)
|
||||
(navigationController?.viewControllers.last as? ViewController)?.present(packController, in: .window(.root))
|
||||
|
||||
Queue.mainQueue().after(0.1) {
|
||||
@ -1301,6 +1302,7 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
let presentationData = self.presentationData
|
||||
let updatedPresentationData = self.controller?.updatedPresentationData
|
||||
let navigationController = self.controller?.parentNavigationController as? NavigationController
|
||||
let sendSticker = self.controller?.sendSticker
|
||||
|
||||
let context = self.context
|
||||
let controller = self.context.sharedContext.makeStickerPickerScreen(context: self.context, inputData: self.stickerPickerInputData, completion: { file in
|
||||
@ -1323,7 +1325,7 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
let packReference: StickerPackReference = .id(id: info.id.id, accessHash: info.accessHash)
|
||||
let _ = (context.engine.stickers.addStickerToStickerSet(packReference: packReference, sticker: sticker)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
let packController = StickerPackScreen(context: context, updatedPresentationData: updatedPresentationData, mainStickerPack: packReference, stickerPacks: [packReference], loadedStickerPacks: [], expandIfNeeded: true, parentNavigationController: navigationController, sendSticker: nil, sendEmoji: nil, actionPerformed: nil, dismissed: nil, getSourceRect: nil)
|
||||
let packController = StickerPackScreen(context: context, updatedPresentationData: updatedPresentationData, mainStickerPack: packReference, stickerPacks: [packReference], loadedStickerPacks: [], expandIfNeeded: true, parentNavigationController: navigationController, sendSticker: sendSticker, sendEmoji: nil, actionPerformed: nil, dismissed: nil, getSourceRect: nil)
|
||||
(navigationController?.viewControllers.last as? ViewController)?.present(packController, in: .window(.root))
|
||||
|
||||
Queue.mainQueue().after(0.1) {
|
||||
@ -1345,8 +1347,10 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
}
|
||||
|
||||
let context = self.context
|
||||
let presentationData = self.presentationData
|
||||
let updatedPresentationData = self.controller?.updatedPresentationData
|
||||
let navigationController = self.controller?.parentNavigationController as? NavigationController
|
||||
let sendSticker = self.controller?.sendSticker
|
||||
|
||||
self.controller?.dismiss()
|
||||
|
||||
@ -1369,8 +1373,12 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
commit()
|
||||
|
||||
let packController = StickerPackScreen(context: context, updatedPresentationData: updatedPresentationData, mainStickerPack: packReference, stickerPacks: [packReference], loadedStickerPacks: [], expandIfNeeded: true, parentNavigationController: navigationController, sendSticker: nil, sendEmoji: nil, actionPerformed: nil, dismissed: nil, getSourceRect: nil)
|
||||
let packController = StickerPackScreen(context: context, updatedPresentationData: updatedPresentationData, mainStickerPack: packReference, stickerPacks: [packReference], loadedStickerPacks: [], expandIfNeeded: true, parentNavigationController: navigationController, sendSticker: sendSticker, sendEmoji: nil, actionPerformed: nil, dismissed: nil, getSourceRect: nil)
|
||||
(navigationController?.viewControllers.last as? ViewController)?.present(packController, in: .window(.root))
|
||||
|
||||
Queue.mainQueue().after(0.1) {
|
||||
packController.present(UndoOverlayController(presentationData: presentationData, content: .sticker(context: context, file: file, loop: true, title: nil, text: "Sticker updated.", undoText: nil, customAction: nil), elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
@ -2645,7 +2653,7 @@ public final class StickerPackScreenImpl: ViewController, StickerPackScreen {
|
||||
|
||||
private let initialSelectedStickerPackIndex: Int
|
||||
fileprivate weak var parentNavigationController: NavigationController?
|
||||
private let sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?
|
||||
fileprivate let sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?
|
||||
private let sendEmoji: ((String, ChatTextInputTextCustomEmojiAttribute) -> Void)?
|
||||
|
||||
fileprivate var controllerNode: StickerPackScreenNode {
|
||||
|
@ -162,7 +162,7 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
|
||||
self.activateBadgeAction?()
|
||||
}
|
||||
|
||||
public typealias AsyncLayout = (_ presentationData: ChatPresentationData, _ automaticDownloadSettings: MediaAutoDownloadSettings, _ associatedData: ChatMessageItemAssociatedData, _ attributes: ChatMessageEntryAttributes, _ context: AccountContext, _ controllerInteraction: ChatControllerInteraction, _ message: Message, _ messageRead: Bool, _ chatLocation: ChatLocation, _ title: String?, _ titleBadge: String?, _ subtitle: NSAttributedString?, _ text: String?, _ entities: [MessageTextEntity]?, _ media: (Media, ChatMessageAttachedContentNodeMediaFlags)?, _ mediaBadge: String?, _ actionIcon: ChatMessageAttachedContentActionIcon?, _ actionTitle: String?, _ displayLine: Bool, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ constrainedSize: CGSize, _ animationCache: AnimationCache, _ animationRenderer: MultiAnimationRenderer) -> (CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void)))
|
||||
public typealias AsyncLayout = (_ presentationData: ChatPresentationData, _ automaticDownloadSettings: MediaAutoDownloadSettings, _ associatedData: ChatMessageItemAssociatedData, _ attributes: ChatMessageEntryAttributes, _ context: AccountContext, _ controllerInteraction: ChatControllerInteraction, _ message: Message, _ messageRead: Bool, _ chatLocation: ChatLocation, _ title: String?, _ titleBadge: String?, _ subtitle: NSAttributedString?, _ text: String?, _ entities: [MessageTextEntity]?, _ media: ([Media], ChatMessageAttachedContentNodeMediaFlags)?, _ mediaBadge: String?, _ actionIcon: ChatMessageAttachedContentActionIcon?, _ actionTitle: String?, _ displayLine: Bool, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ constrainedSize: CGSize, _ animationCache: AnimationCache, _ animationRenderer: MultiAnimationRenderer) -> (CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void)))
|
||||
|
||||
public func makeProgress() -> Promise<Bool> {
|
||||
let progress = Promise<Bool>()
|
||||
@ -302,7 +302,7 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
|
||||
|
||||
var mediaAndFlags = mediaAndFlags
|
||||
if let mediaAndFlagsValue = mediaAndFlags {
|
||||
if mediaAndFlagsValue.0 is TelegramMediaStory || mediaAndFlagsValue.0 is WallpaperPreviewMedia {
|
||||
if mediaAndFlagsValue.0.first is TelegramMediaStory || mediaAndFlagsValue.0.first is WallpaperPreviewMedia {
|
||||
var flags = mediaAndFlagsValue.1
|
||||
flags.remove(.preferMediaInline)
|
||||
mediaAndFlags = (mediaAndFlagsValue.0, flags)
|
||||
@ -315,50 +315,52 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
|
||||
}
|
||||
var contentMediaInline = false
|
||||
|
||||
if let (media, flags) = mediaAndFlags {
|
||||
if let (mediaArray, flags) = mediaAndFlags {
|
||||
contentMediaInline = flags.contains(.preferMediaInline)
|
||||
|
||||
if let file = media as? TelegramMediaFile {
|
||||
if file.mimeType == "application/x-tgtheme-ios", let size = file.size, size < 16 * 1024 {
|
||||
contentMediaValue = file
|
||||
} else if file.isInstantVideo {
|
||||
contentMediaValue = file
|
||||
} else if file.isVideo {
|
||||
contentMediaValue = file
|
||||
} else if file.isSticker || file.isAnimatedSticker {
|
||||
contentMediaValue = file
|
||||
} else {
|
||||
contentFileValue = file
|
||||
}
|
||||
|
||||
if shouldDownloadMediaAutomatically(settings: automaticDownloadSettings, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, authorPeerId: message.author?.id, contactsPeerIds: associatedData.contactsPeerIds, media: file) {
|
||||
contentMediaAutomaticDownload = .full
|
||||
} else if shouldPredownloadMedia(settings: automaticDownloadSettings, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, media: file) {
|
||||
contentMediaAutomaticDownload = .prefetch
|
||||
}
|
||||
|
||||
if file.isAnimated {
|
||||
contentMediaAutomaticPlayback = context.sharedContext.energyUsageSettings.autoplayGif
|
||||
} else if file.isVideo && context.sharedContext.energyUsageSettings.autoplayVideo {
|
||||
var willDownloadOrLocal = false
|
||||
if case .full = contentMediaAutomaticDownload {
|
||||
willDownloadOrLocal = true
|
||||
if let media = mediaArray.first {
|
||||
if let file = media as? TelegramMediaFile {
|
||||
if file.mimeType == "application/x-tgtheme-ios", let size = file.size, size < 16 * 1024 {
|
||||
contentMediaValue = file
|
||||
} else if file.isInstantVideo {
|
||||
contentMediaValue = file
|
||||
} else if file.isVideo {
|
||||
contentMediaValue = file
|
||||
} else if file.isSticker || file.isAnimatedSticker {
|
||||
contentMediaValue = file
|
||||
} else {
|
||||
willDownloadOrLocal = context.account.postbox.mediaBox.completedResourcePath(file.resource) != nil
|
||||
contentFileValue = file
|
||||
}
|
||||
if willDownloadOrLocal {
|
||||
contentMediaAutomaticPlayback = true
|
||||
contentMediaAspectFilled = true
|
||||
|
||||
if shouldDownloadMediaAutomatically(settings: automaticDownloadSettings, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, authorPeerId: message.author?.id, contactsPeerIds: associatedData.contactsPeerIds, media: file) {
|
||||
contentMediaAutomaticDownload = .full
|
||||
} else if shouldPredownloadMedia(settings: automaticDownloadSettings, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, media: file) {
|
||||
contentMediaAutomaticDownload = .prefetch
|
||||
}
|
||||
|
||||
if file.isAnimated {
|
||||
contentMediaAutomaticPlayback = context.sharedContext.energyUsageSettings.autoplayGif
|
||||
} else if file.isVideo && context.sharedContext.energyUsageSettings.autoplayVideo {
|
||||
var willDownloadOrLocal = false
|
||||
if case .full = contentMediaAutomaticDownload {
|
||||
willDownloadOrLocal = true
|
||||
} else {
|
||||
willDownloadOrLocal = context.account.postbox.mediaBox.completedResourcePath(file.resource) != nil
|
||||
}
|
||||
if willDownloadOrLocal {
|
||||
contentMediaAutomaticPlayback = true
|
||||
contentMediaAspectFilled = true
|
||||
}
|
||||
}
|
||||
} else if let _ = media as? TelegramMediaImage {
|
||||
contentMediaValue = media
|
||||
} else if let _ = media as? TelegramMediaWebFile {
|
||||
contentMediaValue = media
|
||||
} else if let _ = media as? WallpaperPreviewMedia {
|
||||
contentMediaValue = media
|
||||
} else if let _ = media as? TelegramMediaStory {
|
||||
contentMediaValue = media
|
||||
}
|
||||
} else if let _ = media as? TelegramMediaImage {
|
||||
contentMediaValue = media
|
||||
} else if let _ = media as? TelegramMediaWebFile {
|
||||
contentMediaValue = media
|
||||
} else if let _ = media as? WallpaperPreviewMedia {
|
||||
contentMediaValue = media
|
||||
} else if let _ = media as? TelegramMediaStory {
|
||||
contentMediaValue = media
|
||||
}
|
||||
}
|
||||
|
||||
@ -939,7 +941,7 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
|
||||
|
||||
self.context = context
|
||||
self.message = message
|
||||
self.media = mediaAndFlags?.0
|
||||
self.media = mediaAndFlags?.0.first
|
||||
self.theme = presentationData.theme
|
||||
self.mainColor = mainColor
|
||||
|
||||
|
@ -50,7 +50,7 @@ public final class ChatMessageEventLogPreviousDescriptionContentNode: ChatMessag
|
||||
} else {
|
||||
text = item.message.text
|
||||
}
|
||||
let mediaAndFlags: (Media, ChatMessageAttachedContentNodeMediaFlags)? = nil
|
||||
let mediaAndFlags: ([Media], ChatMessageAttachedContentNodeMediaFlags)? = nil
|
||||
|
||||
let (initialWidth, continueLayout) = contentNodeLayout(item.presentationData, item.controllerInteraction.automaticMediaDownloadSettings, item.associatedData, item.attributes, item.context, item.controllerInteraction, item.message, true, .peer(id: item.message.id.peerId), title, nil, nil, text, messageEntities, mediaAndFlags, nil, nil, nil, true, layoutConstants, preparePosition, constrainedSize, item.controllerInteraction.presentationContext.animationCache, item.controllerInteraction.presentationContext.animationRenderer)
|
||||
|
||||
|
@ -45,7 +45,7 @@ public final class ChatMessageEventLogPreviousLinkContentNode: ChatMessageBubble
|
||||
|
||||
let title: String = item.message.text.contains("\n") ? item.presentationData.strings.Channel_AdminLog_MessagePreviousLinks : item.presentationData.strings.Channel_AdminLog_MessagePreviousLink
|
||||
let text: String = item.message.text
|
||||
let mediaAndFlags: (Media, ChatMessageAttachedContentNodeMediaFlags)? = nil
|
||||
let mediaAndFlags: ([Media], ChatMessageAttachedContentNodeMediaFlags)? = nil
|
||||
|
||||
let (initialWidth, continueLayout) = contentNodeLayout(item.presentationData, item.controllerInteraction.automaticMediaDownloadSettings, item.associatedData, item.attributes, item.context, item.controllerInteraction, item.message, true, .peer(id: item.message.id.peerId), title, nil, nil, text, messageEntities, mediaAndFlags, nil, nil, nil, true, layoutConstants, preparePosition, constrainedSize, item.controllerInteraction.presentationContext.animationCache, item.controllerInteraction.presentationContext.animationRenderer)
|
||||
|
||||
|
@ -50,7 +50,7 @@ public final class ChatMessageEventLogPreviousMessageContentNode: ChatMessageBub
|
||||
} else {
|
||||
text = item.message.text
|
||||
}
|
||||
let mediaAndFlags: (Media, ChatMessageAttachedContentNodeMediaFlags)? = nil
|
||||
let mediaAndFlags: ([Media], ChatMessageAttachedContentNodeMediaFlags)? = nil
|
||||
|
||||
let (initialWidth, continueLayout) = contentNodeLayout(item.presentationData, item.controllerInteraction.automaticMediaDownloadSettings, item.associatedData, item.attributes, item.context, item.controllerInteraction, item.message, true, .peer(id: item.message.id.peerId), title, nil, nil, text, messageEntities, mediaAndFlags, nil, nil, nil, true, layoutConstants, preparePosition, constrainedSize, item.controllerInteraction.presentationContext.animationCache, item.controllerInteraction.presentationContext.animationRenderer)
|
||||
|
||||
|
@ -67,16 +67,16 @@ public final class ChatMessageGameBubbleContentNode: ChatMessageBubbleContentNod
|
||||
|
||||
var title: String?
|
||||
var text: String?
|
||||
var mediaAndFlags: (Media, ChatMessageAttachedContentNodeMediaFlags)?
|
||||
var mediaAndFlags: ([Media], ChatMessageAttachedContentNodeMediaFlags)?
|
||||
|
||||
if let game = game {
|
||||
title = game.title
|
||||
text = game.description
|
||||
|
||||
if let file = game.file {
|
||||
mediaAndFlags = (file, [.preferMediaBeforeText])
|
||||
mediaAndFlags = ([file], [.preferMediaBeforeText])
|
||||
} else if let image = game.image {
|
||||
mediaAndFlags = (image, [.preferMediaBeforeText])
|
||||
mediaAndFlags = ([image], [.preferMediaBeforeText])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ public final class ChatMessageInvoiceBubbleContentNode: ChatMessageBubbleContent
|
||||
var title: String?
|
||||
var subtitle: NSAttributedString? = nil
|
||||
var text: String?
|
||||
var mediaAndFlags: (Media, ChatMessageAttachedContentNodeMediaFlags)?
|
||||
var mediaAndFlags: ([Media], ChatMessageAttachedContentNodeMediaFlags)?
|
||||
|
||||
var automaticDownloadSettings = item.controllerInteraction.automaticMediaDownloadSettings
|
||||
if let invoice = invoice {
|
||||
@ -61,7 +61,7 @@ public final class ChatMessageInvoiceBubbleContentNode: ChatMessageBubbleContent
|
||||
|
||||
if let image = invoice.photo {
|
||||
automaticDownloadSettings = MediaAutoDownloadSettings.defaultSettings
|
||||
mediaAndFlags = (image, [.preferMediaBeforeText])
|
||||
mediaAndFlags = ([image], [.preferMediaBeforeText])
|
||||
} else {
|
||||
let invoiceLabel = item.presentationData.strings.Message_InvoiceLabel
|
||||
var invoiceText = "\(formatCurrencyAmount(invoice.totalAmount, currency: invoice.currency)) "
|
||||
|
@ -242,7 +242,7 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
|
||||
var text: String?
|
||||
var entities: [MessageTextEntity]?
|
||||
var titleBadge: String?
|
||||
var mediaAndFlags: (Media, ChatMessageAttachedContentNodeMediaFlags)?
|
||||
var mediaAndFlags: ([Media], ChatMessageAttachedContentNodeMediaFlags)?
|
||||
var badge: String?
|
||||
|
||||
var actionIcon: ChatMessageAttachedContentActionIcon?
|
||||
@ -307,9 +307,9 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
|
||||
if let file = mainMedia as? TelegramMediaFile, webpage.type != "telegram_theme" {
|
||||
if let embedUrl = webpage.embedUrl, !embedUrl.isEmpty {
|
||||
if automaticPlayback {
|
||||
mediaAndFlags = (file, [.preferMediaBeforeText])
|
||||
mediaAndFlags = ([file], [.preferMediaBeforeText])
|
||||
} else {
|
||||
mediaAndFlags = (webpage.image ?? file, [.preferMediaBeforeText])
|
||||
mediaAndFlags = ([webpage.image ?? file], [.preferMediaBeforeText])
|
||||
}
|
||||
} else if webpage.type == "telegram_background" {
|
||||
var colors: [UInt32] = []
|
||||
@ -321,12 +321,12 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
|
||||
intensity = intensityValue
|
||||
}
|
||||
let media = WallpaperPreviewMedia(content: .file(file: file, colors: colors, rotation: rotation, intensity: intensity, false, false))
|
||||
mediaAndFlags = (media, [.preferMediaAspectFilled])
|
||||
mediaAndFlags = ([media], [.preferMediaAspectFilled])
|
||||
if let fileSize = file.size {
|
||||
badge = dataSizeString(fileSize, formatting: DataSizeStringFormatting(chatPresentationData: item.presentationData))
|
||||
}
|
||||
} else {
|
||||
mediaAndFlags = (file, [])
|
||||
mediaAndFlags = ([file], [])
|
||||
}
|
||||
} else if let image = mainMedia as? TelegramMediaImage {
|
||||
if let type = webpage.type, ["photo", "video", "embed", "gif", "document", "telegram_album"].contains(type) {
|
||||
@ -338,13 +338,13 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
|
||||
} else if let embedUrl = webpage.embedUrl, !embedUrl.isEmpty {
|
||||
flags.insert(.preferMediaBeforeText)
|
||||
}
|
||||
mediaAndFlags = (image, flags)
|
||||
mediaAndFlags = ([image], flags)
|
||||
} else if let _ = largestImageRepresentation(image.representations)?.dimensions {
|
||||
let flags = ChatMessageAttachedContentNodeMediaFlags()
|
||||
mediaAndFlags = (image, flags)
|
||||
mediaAndFlags = ([image], flags)
|
||||
}
|
||||
} else if let story = mainMedia as? TelegramMediaStory {
|
||||
mediaAndFlags = (story, [.preferMediaBeforeText, .titleBeforeMedia])
|
||||
mediaAndFlags = ([story], [.preferMediaBeforeText, .titleBeforeMedia])
|
||||
if let storyItem = item.message.associatedStories[story.storyId]?.get(Stories.StoredItem.self), case let .item(itemValue) = storyItem {
|
||||
text = itemValue.text
|
||||
entities = itemValue.entities
|
||||
@ -372,7 +372,7 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
|
||||
}
|
||||
if let content = content {
|
||||
let media = WallpaperPreviewMedia(content: content)
|
||||
mediaAndFlags = (media, [])
|
||||
mediaAndFlags = ([media], [])
|
||||
}
|
||||
} else if type == "telegram_theme" {
|
||||
var file: TelegramMediaFile?
|
||||
@ -397,10 +397,10 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
|
||||
}
|
||||
if let file = file {
|
||||
let media = WallpaperPreviewMedia(content: .file(file: file, colors: [], rotation: nil, intensity: nil, true, isSupported))
|
||||
mediaAndFlags = (media, ChatMessageAttachedContentNodeMediaFlags())
|
||||
mediaAndFlags = ([media], ChatMessageAttachedContentNodeMediaFlags())
|
||||
} else if let settings = settings {
|
||||
let media = WallpaperPreviewMedia(content: .themeSettings(settings))
|
||||
mediaAndFlags = (media, ChatMessageAttachedContentNodeMediaFlags())
|
||||
mediaAndFlags = ([media], ChatMessageAttachedContentNodeMediaFlags())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -479,6 +479,12 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
|
||||
break
|
||||
}
|
||||
}
|
||||
for attribute in webpage.attributes {
|
||||
if case let .stickerPack(stickerPack) = attribute, !stickerPack.files.isEmpty {
|
||||
mediaAndFlags = (stickerPack.files, .preferMediaInline)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if defaultWebpageImageSizeIsSmall(webpage: webpage) {
|
||||
mediaAndFlags?.1.insert(.preferMediaInline)
|
||||
@ -514,7 +520,7 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
|
||||
for media in item.message.media {
|
||||
switch media {
|
||||
case _ as TelegramMediaImage, _ as TelegramMediaFile, _ as TelegramMediaStory:
|
||||
mediaAndFlags = (media, [.preferMediaInline])
|
||||
mediaAndFlags = ([media], [.preferMediaInline])
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -258,7 +258,7 @@ private final class MediaCutoutScreenComponent: Component {
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
let result = super.hitTest(point, with: event)
|
||||
if let controller = self.environment?.controller() as? MediaCutoutScreen, [.erase, .restore].contains(controller.mode), result == self.previewContainerView {
|
||||
return nil//controller.previewView.superview
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
@ -2418,7 +2418,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
}
|
||||
}
|
||||
|
||||
final class Node: ViewControllerTracingNode, ASGestureRecognizerDelegate {
|
||||
final class Node: ViewControllerTracingNode, ASGestureRecognizerDelegate, UIScrollViewDelegate {
|
||||
private weak var controller: MediaEditorScreen?
|
||||
private let context: AccountContext
|
||||
fileprivate var interaction: DrawingToolsInteraction?
|
||||
@ -2438,6 +2438,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
fileprivate let toolValue: ComponentView<Empty>
|
||||
|
||||
fileprivate let previewContainerView: UIView
|
||||
fileprivate let previewScrollView: UIScrollView
|
||||
fileprivate let previewContentContainerView: PortalSourceView
|
||||
private var transitionInView: UIImageView?
|
||||
|
||||
@ -2523,6 +2524,14 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
self.previewContainerView.layer.cornerCurve = .continuous
|
||||
}
|
||||
|
||||
self.previewScrollView = UIScrollView()
|
||||
self.previewScrollView.contentInsetAdjustmentBehavior = .never
|
||||
self.previewScrollView.contentInset = .zero
|
||||
self.previewScrollView.showsHorizontalScrollIndicator = false
|
||||
self.previewScrollView.showsVerticalScrollIndicator = false
|
||||
self.previewScrollView.panGestureRecognizer.minimumNumberOfTouches = 2
|
||||
self.previewScrollView.isScrollEnabled = false
|
||||
|
||||
self.previewContentContainerView = PortalSourceView()
|
||||
|
||||
self.gradientView = UIImageView()
|
||||
@ -2568,6 +2577,9 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
|
||||
self.view.addSubview(self.backgroundDimView)
|
||||
self.view.addSubview(self.containerView)
|
||||
|
||||
self.previewScrollView.delegate = self
|
||||
|
||||
self.containerView.addSubview(self.previewContainerView)
|
||||
|
||||
if case .stickerEditor = controller.mode {
|
||||
@ -2597,7 +2609,8 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
self.previewContainerView.addSubview(self.gradientView)
|
||||
}
|
||||
|
||||
self.previewContainerView.addSubview(self.previewContentContainerView)
|
||||
self.previewContainerView.addSubview(self.previewScrollView)
|
||||
self.previewScrollView.addSubview(self.previewContentContainerView)
|
||||
|
||||
self.previewContentContainerView.addSubview(self.previewView)
|
||||
self.previewContentContainerView.addSubview(self.entitiesContainerView)
|
||||
@ -3050,7 +3063,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
controller.stickerSelectedEmoji = emoji
|
||||
let stickerEntity = DrawingStickerEntity(content: .file(.standalone(media: sticker), .sticker))
|
||||
stickerEntity.referenceDrawingSize = storyDimensions
|
||||
stickerEntity.scale = 4.0
|
||||
stickerEntity.scale = 4.0 * 0.97
|
||||
stickerEntity.position = CGPoint(x: storyDimensions.width / 2.0, y: storyDimensions.height / 2.0)
|
||||
self.entitiesView.add(stickerEntity, announce: false)
|
||||
}
|
||||
@ -3262,6 +3275,10 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Queue.mainQueue().after(0.1) {
|
||||
self.previewScrollView.pinchGestureRecognizer?.isEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
@objc func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
@ -4436,6 +4453,53 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
}
|
||||
}
|
||||
|
||||
private func adjustPreviewZoom(updating: Bool = false) {
|
||||
let minScale: CGFloat = 0.05
|
||||
let maxScale: CGFloat = 3.0
|
||||
|
||||
if self.previewScrollView.minimumZoomScale != minScale {
|
||||
self.previewScrollView.minimumZoomScale = minScale
|
||||
}
|
||||
if self.previewScrollView.maximumZoomScale != maxScale {
|
||||
self.previewScrollView.maximumZoomScale = maxScale
|
||||
}
|
||||
|
||||
let boundsSize = self.previewScrollView.frame.size
|
||||
var contentFrame = self.previewContentContainerView.frame
|
||||
if boundsSize.width > contentFrame.size.width {
|
||||
contentFrame.origin.x = (boundsSize.width - contentFrame.size.width) / 2.0
|
||||
} else {
|
||||
contentFrame.origin.x = 0.0
|
||||
}
|
||||
|
||||
if boundsSize.height > contentFrame.size.height {
|
||||
contentFrame.origin.y = (boundsSize.height - contentFrame.size.height) / 2.0
|
||||
} else {
|
||||
contentFrame.origin.y = 0.0
|
||||
}
|
||||
self.previewContentContainerView.frame = contentFrame
|
||||
|
||||
if !updating {
|
||||
self.stickerMaskDrawingView?.updateZoomScale(self.previewScrollView.zoomScale)
|
||||
}
|
||||
}
|
||||
|
||||
func scrollViewDidZoom(_ scrollView: UIScrollView) {
|
||||
self.adjustPreviewZoom()
|
||||
}
|
||||
|
||||
func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
|
||||
self.adjustPreviewZoom()
|
||||
|
||||
if scrollView.zoomScale < 1.0 {
|
||||
scrollView.setZoomScale(1.0, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
|
||||
return self.previewContentContainerView
|
||||
}
|
||||
|
||||
fileprivate var drawingScreen: DrawingScreen?
|
||||
fileprivate var stickerScreen: StickerPickerScreen?
|
||||
fileprivate weak var cutoutScreen: MediaCutoutScreen?
|
||||
@ -4723,6 +4787,12 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
guard let mediaEditor = self.mediaEditor, let stickerMaskDrawingView = self.stickerMaskDrawingView, let stickerBackgroundView = self.stickerBackgroundView else {
|
||||
return
|
||||
}
|
||||
|
||||
if [.cutoutErase, .cutoutRestore].contains(mode) {
|
||||
self.previewScrollView.isScrollEnabled = true
|
||||
self.previewScrollView.pinchGestureRecognizer?.isEnabled = true
|
||||
}
|
||||
|
||||
let cutoutController = MediaCutoutScreen(
|
||||
context: self.context,
|
||||
mode: cutoutMode,
|
||||
@ -4746,6 +4816,9 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
}
|
||||
cutoutController.dismissed = { [weak self] in
|
||||
if let self {
|
||||
self.previewScrollView.setZoomScale(1.0, animated: true)
|
||||
self.previewScrollView.isScrollEnabled = false
|
||||
self.previewScrollView.pinchGestureRecognizer?.isEnabled = false
|
||||
self.animateInFromTool(inPlace: true)
|
||||
}
|
||||
}
|
||||
@ -4911,8 +4984,18 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
|
||||
let previewFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - previewSize.width) / 2.0), y: topInset - bottomInputOffset + self.dismissOffset), size: previewSize)
|
||||
transition.setFrame(view: self.previewContainerView, frame: previewFrame)
|
||||
transition.setFrame(view: self.previewScrollView, frame: CGRect(origin: .zero, size: previewSize))
|
||||
|
||||
transition.setFrame(view: self.previewContentContainerView, frame: CGRect(origin: .zero, size: previewSize))
|
||||
if self.previewScrollView.contentSize == .zero {
|
||||
self.previewScrollView.zoomScale = 1.0
|
||||
self.previewScrollView.contentSize = previewSize
|
||||
}
|
||||
|
||||
if abs(self.previewContentContainerView.bounds.width - previewSize.width) > 1.0 {
|
||||
transition.setFrame(view: self.previewContentContainerView, frame: CGRect(origin: .zero, size: previewSize))
|
||||
}
|
||||
|
||||
self.adjustPreviewZoom(updating: true)
|
||||
transition.setFrame(view: self.previewView, frame: CGRect(origin: .zero, size: previewSize))
|
||||
|
||||
let entitiesViewScale = previewSize.width / storyDimensions.width
|
||||
@ -5125,6 +5208,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
public var completion: (MediaEditorScreen.Result, @escaping (@escaping () -> Void) -> Void) -> Void = { _, _ in }
|
||||
public var dismissed: () -> Void = { }
|
||||
public var willDismiss: () -> Void = { }
|
||||
public var sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?
|
||||
|
||||
private var adminedChannels = Promise<[EnginePeer]>()
|
||||
private var closeFriends = Promise<[EnginePeer]>()
|
||||
@ -6367,9 +6451,25 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
|
||||
contextItems.append(.custom(StickerPackListContextItem(context: self.context, packs: self.myStickerPacks, packSelected: { [weak self] pack in
|
||||
guard let self else {
|
||||
return
|
||||
return true
|
||||
}
|
||||
if pack.count >= 120 {
|
||||
let controller = UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.MediaEditor_StickersTooMuch, timeout: nil, customUndoText: nil), elevatedLayout: false, position: .top, animateInAsReplacement: false, action: { [weak self] action in
|
||||
if case .info = action, let self {
|
||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .stories, forceDark: true, dismissed: {
|
||||
|
||||
})
|
||||
self.push(controller)
|
||||
}
|
||||
return false
|
||||
})
|
||||
self.hapticFeedback.error()
|
||||
self.present(controller, in: .window(.root))
|
||||
return false
|
||||
} else {
|
||||
self.uploadSticker(file, action: .addToStickerPack(pack: .id(id: pack.id.id, accessHash: pack.accessHash), title: pack.title))
|
||||
return true
|
||||
}
|
||||
self.uploadSticker(file, action: .addToStickerPack(pack: .id(id: pack.id.id, accessHash: pack.accessHash), title: pack.title))
|
||||
}), false))
|
||||
|
||||
let items = ContextController.Items(
|
||||
|
@ -13,9 +13,9 @@ import ContextUI
|
||||
final class StickerPackListContextItem: ContextMenuCustomItem {
|
||||
let context: AccountContext
|
||||
let packs: [(StickerPackCollectionInfo, StickerPackItem?)]
|
||||
let packSelected: (StickerPackCollectionInfo) -> Void
|
||||
let packSelected: (StickerPackCollectionInfo) -> Bool
|
||||
|
||||
init(context: AccountContext, packs: [(StickerPackCollectionInfo, StickerPackItem?)], packSelected: @escaping (StickerPackCollectionInfo) -> Void) {
|
||||
init(context: AccountContext, packs: [(StickerPackCollectionInfo, StickerPackItem?)], packSelected: @escaping (StickerPackCollectionInfo) -> Bool) {
|
||||
self.context = context
|
||||
self.packs = packs
|
||||
self.packSelected = packSelected
|
||||
@ -75,9 +75,9 @@ private final class StickerPackListContextItemNode: ASDisplayNode, ContextMenuCu
|
||||
}
|
||||
|
||||
let action = ContextMenuActionItem(text: pack.title, textLayout: .singleLine, icon: { _ in nil }, iconSource: thumbnailIconSource, iconPosition: .left, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
item.packSelected(pack)
|
||||
if item.packSelected(pack) {
|
||||
f(.dismissWithoutContent)
|
||||
}
|
||||
})
|
||||
let actionNode = ContextControllerActionsListActionItemNode(getController: getController, requestDismiss: actionSelected, requestUpdateAction: { _, _ in }, item: action)
|
||||
actionNodes.append(actionNode)
|
||||
|
@ -7642,6 +7642,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if let editMessage = interfaceState.editMessage, let message = combinedInitialData.initialData?.associatedMessages[editMessage.messageId] {
|
||||
let (updatedState, updatedPreviewQueryState) = updatedChatEditInterfaceMessageState(context: strongSelf.context, state: updated, message: message)
|
||||
updated = updatedState
|
||||
strongSelf.editingUrlPreviewQueryState?.1.dispose()
|
||||
strongSelf.editingUrlPreviewQueryState = updatedPreviewQueryState
|
||||
}
|
||||
updated = updated.updatedSlowmodeState(slowmodeState)
|
||||
@ -8979,6 +8980,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
let (updatedState, updatedPreviewQueryState) = updatedChatEditInterfaceMessageState(context: strongSelf.context, state: updated, message: message)
|
||||
updated = updatedState
|
||||
strongSelf.editingUrlPreviewQueryState?.1.dispose()
|
||||
strongSelf.editingUrlPreviewQueryState = updatedPreviewQueryState
|
||||
|
||||
updated = updated.updatedInputMode({ _ in
|
||||
|
@ -1772,6 +1772,9 @@ extension ChatControllerImpl {
|
||||
}
|
||||
} as (MediaEditorScreen.Result, @escaping (@escaping () -> Void) -> Void) -> Void
|
||||
)
|
||||
editorController.sendSticker = { [weak self] file, sourceView, sourceRect in
|
||||
return self?.interfaceInteraction?.sendSticker(file, true, sourceView, sourceRect, nil, []) ?? false
|
||||
}
|
||||
self.push(editorController)
|
||||
},
|
||||
dismissed: {}
|
||||
|
@ -761,7 +761,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
if file.isAnimatedSticker {
|
||||
thumbnailItem = .animated(EngineMediaResource(file.resource))
|
||||
resourceReference = MediaResourceReference.media(media: .standalone(media: file), resource: file.resource)
|
||||
} else if let dimensions = file.dimensions, let resource = chatMessageStickerResource(file: file, small: false) as? TelegramMediaResource {
|
||||
} else if let dimensions = file.dimensions, let resource = chatMessageStickerResource(file: file, small: true) as? TelegramMediaResource {
|
||||
thumbnailItem = .still(TelegramMediaImageRepresentation(dimensions: dimensions, resource: resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false))
|
||||
resourceReference = MediaResourceReference.media(media: .standalone(media: file), resource: resource)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user