mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
eb406e4032
@ -5143,7 +5143,7 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"Settings.Devices" = "Devices";
|
||||
"Settings.AddDevice" = "Scan QR";
|
||||
"AuthSessions.DevicesTitle" = "Devices";
|
||||
"AuthSessions.AddDevice" = "Add Device";
|
||||
"AuthSessions.AddDevice" = "Scan QR";
|
||||
"AuthSessions.AddDevice.ScanInfo" = "Scan a QR code to log into\nthis account on another device.";
|
||||
"AuthSessions.AddDevice.ScanTitle" = "Scan QR Code";
|
||||
"AuthSessions.AddDevice.InvalidQRCode" = "Invalid QR Code";
|
||||
|
@ -19,7 +19,7 @@ private let colorKeyRegex = try? NSRegularExpression(pattern: "\"k\":\\[[\\d\\.]
|
||||
private func transformedWithTheme(data: Data, theme: PresentationTheme) -> Data {
|
||||
if var string = String(data: data, encoding: .utf8) {
|
||||
var colors: [UIColor] = [0x333333, 0xFFFFFF, 0x50A7EA, 0x212121].map { UIColor(rgb: $0) }
|
||||
let replacementColors: [UIColor] = [theme.list.itemPrimaryTextColor.mixedWith(.white, alpha: 0.2), theme.list.plainBackgroundColor, theme.list.itemAccentColor, theme.list.itemPrimaryTextColor.mixedWith(.white, alpha: 0.12)]
|
||||
let replacementColors: [UIColor] = [theme.list.itemPrimaryTextColor.mixedWith(.white, alpha: 0.2), theme.list.plainBackgroundColor, theme.list.itemAccentColor, theme.list.plainBackgroundColor]
|
||||
|
||||
func colorToString(_ color: UIColor) -> String {
|
||||
var r: CGFloat = 0.0
|
||||
@ -284,6 +284,8 @@ private final class AuthDataTransferSplashScreenNode: ViewControllerTracingNode
|
||||
updateInHierarchy = { [weak self] value in
|
||||
if value {
|
||||
self?.animationNode?.play()
|
||||
} else {
|
||||
self?.animationNode?.reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -354,6 +356,11 @@ private final class AuthDataTransferSplashScreenNode: ViewControllerTracingNode
|
||||
contentY += iconSize.height + iconSpacing
|
||||
if let animationNode = self.animationNode {
|
||||
transition.updateFrameAdditive(node: animationNode, frame: iconFrame)
|
||||
if iconFrame.minY < 0.0 {
|
||||
transition.updateAlpha(node: animationNode, alpha: 0.0)
|
||||
} else {
|
||||
transition.updateAlpha(node: animationNode, alpha: 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
let titleFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width) / 2.0), y: contentY), size: titleSize)
|
||||
|
@ -23,6 +23,9 @@ static_library(
|
||||
"//submodules/SwipeToDismissGesture:SwipeToDismissGesture",
|
||||
"//submodules/CheckNode:CheckNode",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/StickerPackPreviewUI:StickerPackPreviewUI",
|
||||
"//submodules/OverlayStatusController:OverlayStatusController",
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -10,6 +10,10 @@ import TelegramPresentationData
|
||||
import AccountContext
|
||||
import RadialStatusNode
|
||||
import PhotoResources
|
||||
import AppBundle
|
||||
import StickerPackPreviewUI
|
||||
import OverlayStatusController
|
||||
import PresentationDataUtils
|
||||
|
||||
enum ChatMediaGalleryThumbnail: Equatable {
|
||||
case image(ImageMediaReference)
|
||||
@ -156,6 +160,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
private let imageNode: TransformImageNode
|
||||
fileprivate let _ready = Promise<Void>()
|
||||
fileprivate let _title = Promise<String>()
|
||||
fileprivate let _rightBarButtonItem = Promise<UIBarButtonItem?>()
|
||||
private let statusNodeContainer: HighlightableButtonNode
|
||||
private let statusNode: RadialStatusNode
|
||||
private let footerContentNode: ChatItemGalleryFooterContentNode
|
||||
@ -230,10 +235,53 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
} else {
|
||||
self._ready.set(.single(Void()))
|
||||
}
|
||||
if imageReference.media.flags.contains(.hasStickers) {
|
||||
let rightBarButtonItem = UIBarButtonItem(image: UIImage(bundleImageName: "Media Gallery/Stickers"), style: .plain, target: self, action: #selector(self.openStickersButtonPressed))
|
||||
self._rightBarButtonItem.set(.single(rightBarButtonItem))
|
||||
}
|
||||
}
|
||||
self.contextAndMedia = (self.context, imageReference.abstract)
|
||||
}
|
||||
|
||||
@objc func openStickersButtonPressed() {
|
||||
guard let (context, media) = self.contextAndMedia else {
|
||||
return
|
||||
}
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let progressSignal = Signal<Never, NoError> { [weak self] subscriber in
|
||||
guard let strongSelf = self else {
|
||||
return EmptyDisposable
|
||||
}
|
||||
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
|
||||
(strongSelf.baseNavigationController()?.topViewController as? ViewController)?.present(controller, in: .window(.root), with: nil)
|
||||
return ActionDisposable { [weak controller] in
|
||||
Queue.mainQueue().async() {
|
||||
controller?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|> runOn(Queue.mainQueue())
|
||||
|> delay(0.15, queue: Queue.mainQueue())
|
||||
let progressDisposable = progressSignal.start()
|
||||
|
||||
let signal = stickerPacksAttachedToMedia(account: context.account, media: media)
|
||||
|> afterDisposed {
|
||||
Queue.mainQueue().async {
|
||||
progressDisposable.dispose()
|
||||
}
|
||||
}
|
||||
let _ = (signal
|
||||
|> deliverOnMainQueue).start(next: { [weak self] packs in
|
||||
guard let strongSelf = self, !packs.isEmpty else {
|
||||
return
|
||||
}
|
||||
let baseNavigationController = strongSelf.baseNavigationController()
|
||||
baseNavigationController?.view.endEditing(true)
|
||||
let controller = StickerPackScreen(context: context, stickerPacks: packs, sendSticker: nil)
|
||||
(baseNavigationController?.topViewController as? ViewController)?.present(controller, in: .window(.root), with: nil)
|
||||
})
|
||||
}
|
||||
|
||||
func setFile(context: AccountContext, fileReference: FileMediaReference) {
|
||||
if self.contextAndMedia == nil || !self.contextAndMedia!.1.media.isEqual(to: fileReference.media) {
|
||||
if var largestSize = fileReference.media.dimensions {
|
||||
@ -447,6 +495,10 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
return self._title.get()
|
||||
}
|
||||
|
||||
override func rightBarButtonItem() -> Signal<UIBarButtonItem?, NoError> {
|
||||
return self._rightBarButtonItem.get()
|
||||
}
|
||||
|
||||
override func footerContent() -> Signal<GalleryFooterContentNode?, NoError> {
|
||||
return .single(self.footerContentNode)
|
||||
}
|
||||
|
@ -872,12 +872,12 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private func longPressMedia(_ media: InstantPageMedia) {
|
||||
let controller = ContextMenuController(actions: [ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.strings.Conversation_ContextMenuCopy), action: { [weak self] in
|
||||
if let strongSelf = self, let image = media.media as? TelegramMediaImage {
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: image.representations, immediateThumbnailData: image.immediateThumbnailData, reference: nil, partialReference: nil)
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: image.representations, immediateThumbnailData: image.immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
||||
let _ = copyToPasteboard(context: strongSelf.context, postbox: strongSelf.context.account.postbox, mediaReference: .standalone(media: media)).start()
|
||||
}
|
||||
}), ContextMenuAction(content: .text(title: self.strings.Conversation_LinkDialogSave, accessibilityLabel: self.strings.Conversation_LinkDialogSave), action: { [weak self] in
|
||||
if let strongSelf = self, let image = media.media as? TelegramMediaImage {
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: image.representations, immediateThumbnailData: image.immediateThumbnailData, reference: nil, partialReference: nil)
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: image.representations, immediateThumbnailData: image.immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
||||
let _ = saveToCameraRoll(context: strongSelf.context, postbox: strongSelf.context.account.postbox, mediaReference: .standalone(media: media)).start()
|
||||
}
|
||||
}), ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuShare, accessibilityLabel: self.strings.Conversation_ContextMenuShare), action: { [weak self] in
|
||||
|
@ -120,7 +120,7 @@ public struct InstantPageGalleryEntry: Equatable {
|
||||
if let dimensions = file.dimensions {
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: dimensions, resource: file.resource))
|
||||
}
|
||||
let image = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations, immediateThumbnailData: file.immediateThumbnailData, reference: nil, partialReference: nil)
|
||||
let image = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations, immediateThumbnailData: file.immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
||||
return InstantImageGalleryItem(context: context, presentationData: presentationData, imageReference: .webPage(webPage: WebpageReference(webPage), media: image), caption: caption, credit: credit, location: self.location, openUrl: openUrl, openUrlOptions: openUrlOptions)
|
||||
}
|
||||
} else if let embedWebpage = self.media.media as? TelegramMediaWebpage, case let .Loaded(webpageContent) = embedWebpage.content {
|
||||
|
@ -47,7 +47,7 @@ final class InstantPagePlayableVideoNode: ASDisplayNode, InstantPageNode, Galler
|
||||
|
||||
var imageReference: ImageMediaReference?
|
||||
if let file = media.media as? TelegramMediaFile, let presentation = smallestImageRepresentation(file.previewRepresentations) {
|
||||
let image = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [presentation], immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
||||
let image = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [presentation], immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
||||
imageReference = ImageMediaReference.webPage(webPage: WebpageReference(webPage), media: image)
|
||||
}
|
||||
|
||||
|
@ -418,7 +418,7 @@ private func loadLegacyMessages(account: TemporaryAccount, basePath: String, acc
|
||||
}
|
||||
}
|
||||
|
||||
parsedMedia.append(TelegramMediaImage(imageId: mediaId, representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil))
|
||||
parsedMedia.append(TelegramMediaImage(imageId: mediaId, representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: []))
|
||||
} else if let item = item as? TGVideoMediaAttachment {
|
||||
let mediaId = MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64())
|
||||
var representations: [TelegramMediaImageRepresentation] = []
|
||||
|
@ -13,6 +13,7 @@ import AccountContext
|
||||
import ImageCompression
|
||||
import MimeTypes
|
||||
import LocalMediaResources
|
||||
import LegacyUI
|
||||
|
||||
public func guessMimeTypeByFileExtension(_ ext: String) -> String {
|
||||
return TGMimeTypeMap.mimeType(forExtension: ext) ?? "application/binary"
|
||||
@ -132,13 +133,15 @@ public func legacyAssetPickerItemGenerator() -> ((Any?, String?, [Any]?, String?
|
||||
|
||||
}
|
||||
|
||||
// let stickers = (dict["stickers"] as? [TGDocumentMediaAttachment]).map { document -> FileMediaReference in
|
||||
// if let sticker = stickerFromLegacyDocument(document) {
|
||||
// return FileMediaReference.standalone(media: sticker)
|
||||
// }
|
||||
// }
|
||||
let stickers = (dict["stickers"] as? [TGDocumentMediaAttachment])?.compactMap { document -> FileMediaReference? in
|
||||
if let sticker = stickerFromLegacyDocument(document) {
|
||||
return FileMediaReference.standalone(media: sticker)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
} ?? []
|
||||
var result: [AnyHashable : Any] = [:]
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .image(data: .image(image), thumbnail: thumbnail, caption: caption, stickers: []), timer: (dict["timer"] as? NSNumber)?.intValue, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value)
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .image(data: .image(image), thumbnail: thumbnail, caption: caption, stickers: stickers), timer: (dict["timer"] as? NSNumber)?.intValue, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value)
|
||||
return result
|
||||
} else if (dict["type"] as! NSString) == "cloudPhoto" {
|
||||
let asset = dict["asset"] as! TGMediaAsset
|
||||
@ -318,9 +321,24 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -
|
||||
|
||||
let resource = LocalFileReferenceMediaResource(localFilePath: tempFilePath, randomId: randomId)
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(scaledSize), resource: resource))
|
||||
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: randomId), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
||||
|
||||
var imageFlags: TelegramMediaImageFlags = []
|
||||
|
||||
var stickerFiles: [TelegramMediaFile] = []
|
||||
if !stickers.isEmpty {
|
||||
for fileReference in stickers {
|
||||
stickerFiles.append(fileReference.media)
|
||||
}
|
||||
}
|
||||
|
||||
var attributes: [MessageAttribute] = []
|
||||
|
||||
if !stickerFiles.isEmpty {
|
||||
attributes.append(EmbeddedMediaStickersMessageAttribute(files: stickerFiles))
|
||||
imageFlags.insert(.hasStickers)
|
||||
}
|
||||
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: randomId), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: imageFlags)
|
||||
if let timer = item.timer, timer > 0 && timer <= 60 {
|
||||
attributes.append(AutoremoveTimeoutMessageAttribute(timeout: Int32(timer), countdownBeginTime: nil))
|
||||
}
|
||||
@ -337,7 +355,7 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -
|
||||
let resource = PhotoLibraryMediaResource(localIdentifier: asset.localIdentifier, uniqueId: arc4random64())
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(scaledSize), resource: resource))
|
||||
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: randomId), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: randomId), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
||||
var attributes: [MessageAttribute] = []
|
||||
if let timer = item.timer, timer > 0 && timer <= 60 {
|
||||
attributes.append(AutoremoveTimeoutMessageAttribute(timeout: Int32(timer), countdownBeginTime: nil))
|
||||
|
@ -8,7 +8,7 @@ import SwiftSignalKit
|
||||
import Display
|
||||
import StickerResources
|
||||
|
||||
func stickerFromLegacyDocument(_ documentAttachment: TGDocumentMediaAttachment) -> TelegramMediaFile? {
|
||||
public func stickerFromLegacyDocument(_ documentAttachment: TGDocumentMediaAttachment) -> TelegramMediaFile? {
|
||||
if documentAttachment.isSticker() {
|
||||
for case let sticker as TGDocumentAttributeSticker in documentAttachment.attributes {
|
||||
var attributes: [TelegramMediaFileAttribute] = []
|
||||
|
@ -115,7 +115,7 @@ final class ThemeGridSearchItemNode: GridItemNode {
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(imageDimensions), resource: imageResource))
|
||||
}
|
||||
if !representations.isEmpty {
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations, immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil)
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations, immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
||||
updateImageSignal = mediaGridMessagePhoto(account: item.account, photoReference: .standalone(media: tmpImage), fullRepresentationSize: CGSize(width: 512, height: 512))
|
||||
} else {
|
||||
updateImageSignal = .complete()
|
||||
|
@ -418,7 +418,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(thumbnailDimensions), resource: thumbnailResource))
|
||||
}
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(imageDimensions), resource: imageResource))
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
||||
|
||||
signal = chatMessagePhoto(postbox: context.account.postbox, photoReference: .standalone(media: tmpImage))
|
||||
fetchSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .media(media: .standalone(media: tmpImage), resource: imageResource))
|
||||
|
@ -480,7 +480,7 @@ public final class ShareController: ViewController {
|
||||
if !text.isEmpty {
|
||||
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
|
||||
}
|
||||
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil)), replyToMessageId: nil, localGroupingKey: nil))
|
||||
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])), replyToMessageId: nil, localGroupingKey: nil))
|
||||
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
|
||||
}
|
||||
case let .media(mediaReference):
|
||||
@ -586,7 +586,7 @@ public final class ShareController: ViewController {
|
||||
case let .quote(text, url):
|
||||
collectableItems.append(CollectableExternalShareItem(url: "", text: "\"\(text)\"\n\n\(url)", author: nil, timestamp: nil, mediaReference: nil))
|
||||
case let .image(representations):
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
||||
collectableItems.append(CollectableExternalShareItem(url: "", text: "", author: nil, timestamp: nil, mediaReference: .standalone(media: media)))
|
||||
case let .media(mediaReference):
|
||||
collectableItems.append(CollectableExternalShareItem(url: "", text: "", author: nil, timestamp: nil, mediaReference: mediaReference))
|
||||
@ -770,7 +770,7 @@ public final class ShareController: ViewController {
|
||||
}
|
||||
|
||||
private func saveToCameraRoll(representations: [ImageRepresentationWithReference]) {
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
||||
let media = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
||||
let context: AccountContext
|
||||
if self.currentContext.account.id == self.currentAccount.id {
|
||||
context = self.currentContext
|
||||
|
19
submodules/SpotlightSupport/BUCK
Normal file
19
submodules/SpotlightSupport/BUCK
Normal file
@ -0,0 +1,19 @@
|
||||
load("//Config:buck_rule_macros.bzl", "framework")
|
||||
|
||||
framework(
|
||||
name = "SpotlightSupport",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared",
|
||||
"//submodules/Postbox:Postbox#shared",
|
||||
"//submodules/SyncCore:SyncCore#shared",
|
||||
"//submodules/TelegramCore:TelegramCore#shared",
|
||||
"//submodules/Display:Display#shared",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
"$SDKROOT/System/Library/Frameworks/CoreSpotlight.framework",
|
||||
],
|
||||
)
|
@ -349,7 +349,7 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
let titleAreaInset: CGFloat = 50.0
|
||||
|
||||
var actionAreaHeight: CGFloat = 0.0
|
||||
actionAreaHeight += insets.bottom
|
||||
actionAreaHeight += insets.bottom + 12.0
|
||||
|
||||
transition.updateFrame(node: self.buttonNode, frame: CGRect(origin: CGPoint(x: buttonSideInset, y: layout.size.height - actionAreaHeight - buttonHeight), size: CGSize(width: layout.size.width - buttonSideInset * 2.0, height: buttonHeight)))
|
||||
actionAreaHeight += buttonHeight
|
||||
@ -550,7 +550,9 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
|
||||
return
|
||||
}
|
||||
if index == strongSelf.selectedStickerPackIndex {
|
||||
strongSelf.containerLayoutUpdated(layout, transition: transition)
|
||||
let modalProgress = strongSelf.containers[strongSelf.selectedStickerPackIndex].modalProgress
|
||||
strongSelf.modalProgressUpdated(modalProgress, transition)
|
||||
strongSelf.containerLayoutUpdated(layout, transition: .immediate)
|
||||
}
|
||||
}, presentInGlobalOverlay: presentInGlobalOverlay,
|
||||
sendSticker: sendSticker)
|
||||
@ -610,15 +612,12 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
|
||||
var scaledOffset: CGFloat = 0.0
|
||||
scaledOffset = -CGFloat(indexOffset) * (1.0 - expandProgress) * (scaledInset * 2.0) + CGFloat(indexOffset) * scaledDistance
|
||||
|
||||
transition.updateFrame(node: container, frame: CGRect(origin: CGPoint(x: CGFloat(indexOffset) * layout.size.width + self.relativeToSelectedStickerPackTransition + scaledOffset, y: containerVerticalOffset), size: layout.size))
|
||||
transition.updateSublayerTransformScale(node: container, scale: containerScale)
|
||||
transition.updateFrame(node: container, frame: CGRect(origin: CGPoint(x: CGFloat(indexOffset) * layout.size.width + self.relativeToSelectedStickerPackTransition + scaledOffset, y: containerVerticalOffset), size: layout.size), beginWithCurrentState: true)
|
||||
transition.updateSublayerTransformScaleAndOffset(node: container, scale: containerScale, offset: CGPoint(), beginWithCurrentState: true)
|
||||
if container.validLayout?.0 != layout {
|
||||
container.updateLayout(layout: layout, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
let modalProgress = self.containers[self.selectedStickerPackIndex].modalProgress
|
||||
self.modalProgressUpdated(modalProgress, transition)
|
||||
}
|
||||
|
||||
@objc private func panGesture(_ recognizer: UIPanGestureRecognizer) {
|
||||
|
@ -0,0 +1,18 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
|
||||
public class EmbeddedMediaStickersMessageAttribute: MessageAttribute {
|
||||
public let files: [TelegramMediaFile]
|
||||
|
||||
public init(files: [TelegramMediaFile]) {
|
||||
self.files = files
|
||||
}
|
||||
|
||||
required public init(decoder: PostboxDecoder) {
|
||||
self.files = decoder.decodeObjectArrayWithDecoderForKey("files")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeObjectArray(self.files, forKey: "files")
|
||||
}
|
||||
}
|
@ -39,6 +39,16 @@ public enum TelegramMediaImageReference: PostboxCoding, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public struct TelegramMediaImageFlags: OptionSet {
|
||||
public var rawValue: Int32
|
||||
|
||||
public init(rawValue: Int32) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
public static let hasStickers = TelegramMediaImageFlags(rawValue: 1 << 0)
|
||||
}
|
||||
|
||||
public final class TelegramMediaImage: Media, Equatable {
|
||||
public let imageId: MediaId
|
||||
public let representations: [TelegramMediaImageRepresentation]
|
||||
@ -46,17 +56,19 @@ public final class TelegramMediaImage: Media, Equatable {
|
||||
public let reference: TelegramMediaImageReference?
|
||||
public let partialReference: PartialMediaReference?
|
||||
public let peerIds: [PeerId] = []
|
||||
public let flags: TelegramMediaImageFlags
|
||||
|
||||
public var id: MediaId? {
|
||||
return self.imageId
|
||||
}
|
||||
|
||||
public init(imageId: MediaId, representations: [TelegramMediaImageRepresentation], immediateThumbnailData: Data?, reference: TelegramMediaImageReference?, partialReference: PartialMediaReference?) {
|
||||
public init(imageId: MediaId, representations: [TelegramMediaImageRepresentation], immediateThumbnailData: Data?, reference: TelegramMediaImageReference?, partialReference: PartialMediaReference?, flags: TelegramMediaImageFlags) {
|
||||
self.imageId = imageId
|
||||
self.representations = representations
|
||||
self.immediateThumbnailData = immediateThumbnailData
|
||||
self.reference = reference
|
||||
self.partialReference = partialReference
|
||||
self.flags = flags
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
@ -65,6 +77,7 @@ public final class TelegramMediaImage: Media, Equatable {
|
||||
self.immediateThumbnailData = decoder.decodeDataForKey("itd")
|
||||
self.reference = decoder.decodeObjectForKey("rf", decoder: { TelegramMediaImageReference(decoder: $0) }) as? TelegramMediaImageReference
|
||||
self.partialReference = decoder.decodeAnyObjectForKey("prf", decoder: { PartialMediaReference(decoder: $0) }) as? PartialMediaReference
|
||||
self.flags = TelegramMediaImageFlags(rawValue: decoder.decodeInt32ForKey("fl", orElse: 0))
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
@ -87,6 +100,7 @@ public final class TelegramMediaImage: Media, Equatable {
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "prf")
|
||||
}
|
||||
encoder.encodeInt32(self.flags.rawValue, forKey: "fl")
|
||||
}
|
||||
|
||||
public func representationForDisplayAtSize(_ size: PixelDimensions) -> TelegramMediaImageRepresentation? {
|
||||
@ -130,6 +144,9 @@ public final class TelegramMediaImage: Media, Equatable {
|
||||
if self.partialReference != other.partialReference {
|
||||
return false
|
||||
}
|
||||
if self.flags != other.flags {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -152,6 +169,9 @@ public final class TelegramMediaImage: Media, Equatable {
|
||||
if self.partialReference != other.partialReference {
|
||||
return false
|
||||
}
|
||||
if self.flags != other.flags {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -162,7 +182,7 @@ public final class TelegramMediaImage: Media, Equatable {
|
||||
}
|
||||
|
||||
public func withUpdatedPartialReference(_ partialReference: PartialMediaReference?) -> TelegramMediaImage {
|
||||
return TelegramMediaImage(imageId: self.imageId, representations: self.representations, immediateThumbnailData: self.immediateThumbnailData, reference: self.reference, partialReference: partialReference)
|
||||
return TelegramMediaImage(imageId: self.imageId, representations: self.representations, immediateThumbnailData: self.immediateThumbnailData, reference: self.reference, partialReference: partialReference, flags: self.flags)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,6 +149,7 @@ private var declaredEncodables: Void = {
|
||||
declareEncodable(RestrictedContentMessageAttribute.self, f: { RestrictedContentMessageAttribute(decoder: $0) })
|
||||
declareEncodable(SendScheduledMessageImmediatelyAction.self, f: { SendScheduledMessageImmediatelyAction(decoder: $0) })
|
||||
declareEncodable(WalletCollection.self, f: { WalletCollection(decoder: $0) })
|
||||
declareEncodable(EmbeddedMediaStickersMessageAttribute.self, f: { EmbeddedMediaStickersMessageAttribute(decoder: $0) })
|
||||
|
||||
return
|
||||
}()
|
||||
|
@ -55,7 +55,7 @@ private func convertForwardedMediaForSecretChat(_ media: Media) -> Media {
|
||||
if let file = media as? TelegramMediaFile {
|
||||
return TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: arc4random64()), partialReference: file.partialReference, resource: file.resource, previewRepresentations: file.previewRepresentations, immediateThumbnailData: file.immediateThumbnailData, mimeType: file.mimeType, size: file.size, attributes: file.attributes)
|
||||
} else if let image = media as? TelegramMediaImage {
|
||||
return TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: image.representations, immediateThumbnailData: image.immediateThumbnailData, reference: image.reference, partialReference: image.partialReference)
|
||||
return TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: image.representations, immediateThumbnailData: image.immediateThumbnailData, reference: image.reference, partialReference: image.partialReference, flags: [])
|
||||
} else {
|
||||
return media
|
||||
}
|
||||
@ -82,6 +82,8 @@ private func filterMessageAttributesForOutgoingMessage(_ attributes: [MessageAtt
|
||||
return true
|
||||
case _ as OutgoingScheduleInfoMessageAttribute:
|
||||
return true
|
||||
case _ as EmbeddedMediaStickersMessageAttribute:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ public func outgoingMessageWithChatContextResult(to peerId: PeerId, results: Cha
|
||||
arc4random_buf(&randomId, 8)
|
||||
let thumbnailResource = thumbnail.resource
|
||||
let imageDimensions = thumbnail.dimensions ?? PixelDimensions(width: 128, height: 128)
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: randomId), representations: [TelegramMediaImageRepresentation(dimensions: imageDimensions, resource: thumbnailResource)], immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: randomId), representations: [TelegramMediaImageRepresentation(dimensions: imageDimensions, resource: thumbnailResource)], immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
||||
return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: tmpImage), replyToMessageId: nil, localGroupingKey: nil)
|
||||
} else {
|
||||
return .message(text: caption, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)
|
||||
|
@ -350,6 +350,22 @@ private func uploadedMediaImageContent(network: Network, postbox: Postbox, trans
|
||||
flags |= 1 << 1
|
||||
ttlSeconds = autoremoveAttribute.timeout
|
||||
}
|
||||
var stickers: [Api.InputDocument]?
|
||||
for attribute in attributes {
|
||||
if let attribute = attribute as? EmbeddedMediaStickersMessageAttribute {
|
||||
var stickersValue: [Api.InputDocument] = []
|
||||
for file in attribute.files {
|
||||
if let resource = file.resource as? CloudDocumentMediaResource, let fileReference = resource.fileReference {
|
||||
stickersValue.append(Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: fileReference)))
|
||||
}
|
||||
}
|
||||
if !stickersValue.isEmpty {
|
||||
stickers = stickersValue
|
||||
flags |= 1 << 0
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
@ -357,10 +373,10 @@ private func uploadedMediaImageContent(network: Network, postbox: Postbox, trans
|
||||
|> mapToSignal { inputPeer -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
|
||||
if let inputPeer = inputPeer {
|
||||
if autoremoveAttribute != nil {
|
||||
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaUploadedPhoto(flags: flags, file: file, stickers: nil, ttlSeconds: ttlSeconds), text), reuploadInfo: nil)))
|
||||
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaUploadedPhoto(flags: flags, file: file, stickers: stickers, ttlSeconds: ttlSeconds), text), reuploadInfo: nil)))
|
||||
}
|
||||
|
||||
return network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(flags: flags, file: file, stickers: nil, ttlSeconds: ttlSeconds)))
|
||||
return network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(flags: flags, file: file, stickers: stickers, ttlSeconds: ttlSeconds)))
|
||||
|> mapError { _ -> PendingMessageUploadError in return .generic }
|
||||
|> mapToSignal { result -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
|
||||
switch result {
|
||||
|
@ -712,7 +712,7 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32
|
||||
resources.append((resource, thumb.makeData()))
|
||||
}
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: file.resource(key: SecretFileEncryptionKey(aesKey: key.makeData(), aesIv: iv.makeData()), decryptedSize: size)))
|
||||
let image = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudSecretImage, id: file.id), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
||||
let image = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudSecretImage, id: file.id), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
||||
parsedMedia.append(image)
|
||||
}
|
||||
case let .decryptedMessageMediaAudio(duration, mimeType, size, key, iv):
|
||||
@ -910,7 +910,7 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32
|
||||
resources.append((resource, thumb.makeData()))
|
||||
}
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: file.resource(key: SecretFileEncryptionKey(aesKey: key.makeData(), aesIv: iv.makeData()), decryptedSize: size)))
|
||||
let image = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudSecretImage, id: file.id), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
||||
let image = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudSecretImage, id: file.id), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
||||
parsedMedia.append(image)
|
||||
}
|
||||
case let .decryptedMessageMediaAudio(duration, mimeType, size, key, iv):
|
||||
@ -1144,7 +1144,7 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32
|
||||
resources.append((resource, thumb.makeData()))
|
||||
}
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: file.resource(key: SecretFileEncryptionKey(aesKey: key.makeData(), aesIv: iv.makeData()), decryptedSize: size)))
|
||||
let image = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudSecretImage, id: file.id), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
||||
let image = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudSecretImage, id: file.id), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
||||
parsedMedia.append(image)
|
||||
}
|
||||
case let .decryptedMessageMediaAudio(duration, mimeType, size, key, iv):
|
||||
|
@ -102,7 +102,7 @@ public func standaloneUploadedImage(account: Account, peerId: PeerId, text: Stri
|
||||
|> mapToSignal { result -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
|
||||
switch result {
|
||||
case let .encryptedFile(id, accessHash, size, dcId, _):
|
||||
return .single(.result(.media(.standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: [TelegramMediaImageRepresentation(dimensions: dimensions, resource: SecretFileMediaResource(fileId: id, accessHash: accessHash, containerSize: size, decryptedSize: Int32(data.count), datacenterId: Int(dcId), key: key))], immediateThumbnailData: nil, reference: nil, partialReference: nil)))))
|
||||
return .single(.result(.media(.standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: [TelegramMediaImageRepresentation(dimensions: dimensions, resource: SecretFileMediaResource(fileId: id, accessHash: accessHash, containerSize: size, decryptedSize: Int32(data.count), datacenterId: Int(dcId), key: key))], immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])))))
|
||||
case .encryptedFileEmpty:
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
import TelegramApi
|
||||
|
||||
import SwiftSignalKit
|
||||
import SyncCore
|
||||
import MtProtoKit
|
||||
|
||||
func telegramStickerPachThumbnailRepresentationFromApiSize(datacenterId: Int32, size: Api.PhotoSize) -> TelegramMediaImageRepresentation? {
|
||||
switch size {
|
||||
@ -49,3 +50,54 @@ extension StickerPackCollectionInfo {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func stickerPacksAttachedToMedia(account: Account, media: AnyMediaReference) -> Signal<[StickerPackReference], NoError> {
|
||||
let inputMedia: Api.InputStickeredMedia
|
||||
let resourceReference: MediaResourceReference
|
||||
if let imageReference = media.concrete(TelegramMediaImage.self), let reference = imageReference.media.reference, case let .cloud(imageId, accessHash, fileReference) = reference, let representation = largestImageRepresentation(imageReference.media.representations) {
|
||||
inputMedia = .inputStickeredMediaPhoto(id: Api.InputPhoto.inputPhoto(id: imageId, accessHash: accessHash, fileReference: Buffer(data: fileReference ?? Data())))
|
||||
resourceReference = imageReference.resourceReference(representation.resource)
|
||||
} else if let fileReference = media.concrete(TelegramMediaFile.self), let resource = fileReference.media.resource as? CloudDocumentMediaResource {
|
||||
inputMedia = .inputStickeredMediaDocument(id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())))
|
||||
resourceReference = fileReference.resourceReference(fileReference.media.resource)
|
||||
} else {
|
||||
return .single([])
|
||||
}
|
||||
return account.network.request(Api.functions.messages.getAttachedStickers(media: inputMedia))
|
||||
|> `catch` { _ -> Signal<[Api.StickerSetCovered], MTRpcError> in
|
||||
return revalidateMediaResourceReference(postbox: account.postbox, network: account.network, revalidationContext: account.mediaReferenceRevalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: resourceReference, preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: resourceReference.resource)
|
||||
|> mapError { _ -> MTRpcError in
|
||||
return MTRpcError(errorCode: 500, errorDescription: "Internal")
|
||||
}
|
||||
|> mapToSignal { reference -> Signal<[Api.StickerSetCovered], MTRpcError> in
|
||||
let inputMedia: Api.InputStickeredMedia
|
||||
if let resource = reference.updatedResource as? TelegramCloudMediaResourceWithFileReference, let updatedReference = resource.fileReference {
|
||||
if let imageReference = media.concrete(TelegramMediaImage.self), let reference = imageReference.media.reference, case let .cloud(imageId, accessHash, fileReference) = reference, let representation = largestImageRepresentation(imageReference.media.representations) {
|
||||
inputMedia = .inputStickeredMediaPhoto(id: Api.InputPhoto.inputPhoto(id: imageId, accessHash: accessHash, fileReference: Buffer(data: updatedReference ?? Data())))
|
||||
} else if let fileReference = media.concrete(TelegramMediaFile.self), let resource = fileReference.media.resource as? CloudDocumentMediaResource {
|
||||
inputMedia = .inputStickeredMediaDocument(id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: updatedReference ?? Data())))
|
||||
} else {
|
||||
return .single([])
|
||||
}
|
||||
return account.network.request(Api.functions.messages.getAttachedStickers(media: inputMedia))
|
||||
} else {
|
||||
return .single([])
|
||||
}
|
||||
}
|
||||
|> `catch` { _ -> Signal<[Api.StickerSetCovered], MTRpcError> in
|
||||
return .single([])
|
||||
}
|
||||
}
|
||||
|> map { result -> [StickerPackReference] in
|
||||
return result.map { pack in
|
||||
switch pack {
|
||||
case let .stickerSetCovered(set, _), let .stickerSetMultiCovered(set, _):
|
||||
let info = StickerPackCollectionInfo(apiSet: set, namespace: Namespaces.ItemCollection.CloudStickerPacks)
|
||||
return .id(id: info.id.id, accessHash: info.accessHash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|> `catch` { _ -> Signal<[StickerPackReference], NoError> in
|
||||
return .single([])
|
||||
}
|
||||
}
|
||||
|
@ -32,9 +32,14 @@ func telegramMediaImageRepresentationsFromApiSizes(datacenterId: Int32, photoId:
|
||||
|
||||
func telegramMediaImageFromApiPhoto(_ photo: Api.Photo) -> TelegramMediaImage? {
|
||||
switch photo {
|
||||
case let .photo(_, id, accessHash, fileReference, _, sizes, dcId):
|
||||
case let .photo(flags, id, accessHash, fileReference, _, sizes, dcId):
|
||||
let (immediateThumbnailData, representations) = telegramMediaImageRepresentationsFromApiSizes(datacenterId: dcId, photoId: id, accessHash: accessHash, fileReference: fileReference.makeData(), sizes: sizes)
|
||||
return TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudImage, id: id), representations: representations, immediateThumbnailData: immediateThumbnailData, reference: .cloud(imageId: id, accessHash: accessHash, fileReference: fileReference.makeData()), partialReference: nil)
|
||||
var imageFlags: TelegramMediaImageFlags = []
|
||||
let hasStickers = (flags & (1 << 0)) != 0
|
||||
if hasStickers {
|
||||
imageFlags.insert(.hasStickers)
|
||||
}
|
||||
return TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudImage, id: id), representations: representations, immediateThumbnailData: immediateThumbnailData, reference: .cloud(imageId: id, accessHash: accessHash, fileReference: fileReference.makeData()), partialReference: nil, flags: imageFlags)
|
||||
case .photoEmpty:
|
||||
return nil
|
||||
}
|
||||
|
22
submodules/TelegramUI/Images.xcassets/Media Gallery/Stickers.imageset/Contents.json
vendored
Normal file
22
submodules/TelegramUI/Images.xcassets/Media Gallery/Stickers.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "GalleryEmbeddedStickersIcon@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "GalleryEmbeddedStickersIcon@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
@ -35,6 +35,7 @@ import AppLock
|
||||
import PresentationDataUtils
|
||||
import TelegramIntents
|
||||
import AccountUtils
|
||||
import CoreSpotlight
|
||||
|
||||
#if canImport(BackgroundTasks)
|
||||
import BackgroundTasks
|
||||
@ -1828,6 +1829,53 @@ final class SharedApplicationContext {
|
||||
self.openUrl(url: url)
|
||||
}
|
||||
|
||||
if userActivity.activityType == CSSearchableItemActionType {
|
||||
if let uniqueIdentifier = userActivity.userInfo?[CSSearchableItemActivityIdentifier] as? String, uniqueIdentifier.hasPrefix("contact-") {
|
||||
if let peerIdValue = Int64(String(uniqueIdentifier[uniqueIdentifier.index(uniqueIdentifier.startIndex, offsetBy: "contact-".count)...])) {
|
||||
let peerId = PeerId(peerIdValue)
|
||||
|
||||
let signal = self.sharedContextPromise.get()
|
||||
|> take(1)
|
||||
|> mapToSignal { sharedApplicationContext -> Signal<(AccountRecordId?, [Account?]), NoError> in
|
||||
return sharedApplicationContext.sharedContext.activeAccounts
|
||||
|> take(1)
|
||||
|> mapToSignal { primary, accounts, _ -> Signal<(AccountRecordId?, [Account?]), NoError> in
|
||||
return combineLatest(accounts.map { _, account, _ -> Signal<Account?, NoError> in
|
||||
return account.postbox.transaction { transaction -> Account? in
|
||||
if transaction.getPeer(peerId) != nil {
|
||||
return account
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
})
|
||||
|> map { accounts -> (AccountRecordId?, [Account?]) in
|
||||
return (primary?.id, accounts)
|
||||
}
|
||||
}
|
||||
}
|
||||
let _ = (signal
|
||||
|> deliverOnMainQueue).start(next: { primary, accounts in
|
||||
if let primary = primary {
|
||||
for account in accounts {
|
||||
if let account = account, account.id == primary {
|
||||
self.openChatWhenReady(accountId: nil, peerId: peerId)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for account in accounts {
|
||||
if let account = account {
|
||||
self.openChatWhenReady(accountId: account.id, peerId: peerId)
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -225,7 +225,7 @@ private final class ChatContextResultPeekNode: ASDisplayNode, PeekControllerCont
|
||||
if updatedImageResource {
|
||||
if let imageResource = imageResource {
|
||||
let tmpRepresentation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: Int32(fittedImageDimensions.width * 2.0), height: Int32(fittedImageDimensions.height * 2.0)), resource: imageResource)
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [tmpRepresentation], immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [tmpRepresentation], immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
||||
updateImageSignal = chatMessagePhoto(postbox: self.account.postbox, photoReference: .standalone(media: tmpImage))
|
||||
} else {
|
||||
updateImageSignal = .complete()
|
||||
|
@ -220,7 +220,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
var photo: TelegramMediaImage?
|
||||
if !new.isEmpty {
|
||||
photo = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: new, immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
||||
photo = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: new, immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
||||
}
|
||||
|
||||
let action = TelegramMediaActionType.photoUpdated(image: photo)
|
||||
|
@ -310,7 +310,7 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
|
||||
updateImageSignal = chatMessageSticker(account: item.account, file: stickerFile, small: false, fetched: true)
|
||||
} else {
|
||||
let tmpRepresentation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(CGSize(width: fittedImageDimensions.width * 2.0, height: fittedImageDimensions.height * 2.0)), resource: imageResource)
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [tmpRepresentation], immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [tmpRepresentation], immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
||||
updateImageSignal = chatMessagePhoto(postbox: item.account.postbox, photoReference: .standalone(media: tmpImage))
|
||||
}
|
||||
} else {
|
||||
|
@ -161,6 +161,20 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
}
|
||||
}
|
||||
|
||||
self.historyNode.endedInteractiveDragging = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
switch strongSelf.historyNode.visibleContentOffset() {
|
||||
case let .known(value):
|
||||
if value <= -10.0 {
|
||||
strongSelf.requestDismiss()
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
self.controlsNode.updateIsExpanded = { [weak self] in
|
||||
if let strongSelf = self, let validLayout = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(validLayout, transition: .animated(duration: 0.3, curve: .spring))
|
||||
@ -242,7 +256,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
panRecognizer.delegate = self
|
||||
panRecognizer.delaysTouchesBegan = false
|
||||
panRecognizer.cancelsTouchesInView = true
|
||||
self.view.addGestureRecognizer(panRecognizer)
|
||||
//self.view.addGestureRecognizer(panRecognizer)
|
||||
}
|
||||
|
||||
func updatePresentationData(_ presentationData: PresentationData) {
|
||||
@ -305,18 +319,19 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
let result = super.hitTest(point, with: event)
|
||||
if self.controlsNode.bounds.contains(self.view.convert(point, to: self.controlsNode.view)) {
|
||||
if result == nil {
|
||||
return self.historyNode.view
|
||||
}
|
||||
}
|
||||
|
||||
if !self.bounds.contains(point) {
|
||||
return nil
|
||||
}
|
||||
if point.y < self.controlsNode.frame.minY {
|
||||
return self.dimNode.view
|
||||
}
|
||||
let result = super.hitTest(point, with: event)
|
||||
if self.controlsNode.frame.contains(point) {
|
||||
// if result == self.historyNode.view {
|
||||
// return self.view
|
||||
// }
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@ -532,6 +547,20 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
}
|
||||
}
|
||||
|
||||
self.historyNode.endedInteractiveDragging = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
switch strongSelf.historyNode.visibleContentOffset() {
|
||||
case let .known(value):
|
||||
if value <= -10.0 {
|
||||
strongSelf.requestDismiss()
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
self.historyNode.beganInteractiveDragging = { [weak self] in
|
||||
self?.controlsNode.collapse()
|
||||
}
|
||||
|
@ -145,6 +145,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
|
||||
private let displayUpgradeProgress: (Float?) -> Void
|
||||
|
||||
private var spotlightDataContext: SpotlightDataContext?
|
||||
private var widgetDataContext: WidgetDataContext?
|
||||
|
||||
public init(mainWindow: Window1?, basePath: String, encryptionParameters: ValueBoxEncryptionParameters, accountManager: AccountManager, appLockContext: AppLockContext, applicationBindings: TelegramApplicationBindings, initialPresentationDataAndSettings: InitialPresentationDataAndSettings, networkArguments: NetworkInitializationArguments, rootPath: String, legacyBasePath: String?, legacyCache: LegacyCache?, apsNotificationToken: Signal<Data?, NoError>, voipNotificationToken: Signal<Data?, NoError>, setNotificationCall: @escaping (PresentationCall?) -> Void, navigateToChat: @escaping (AccountRecordId, PeerId, MessageId?) -> Void, displayUpgradeProgress: @escaping (Float?) -> Void = { _ in }) {
|
||||
@ -634,10 +635,17 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
|
||||
self.updateNotificationTokensRegistration()
|
||||
|
||||
self.widgetDataContext = WidgetDataContext(basePath: self.basePath, activeAccount: self.activeAccounts
|
||||
|> map { primary, _, _ in
|
||||
return primary
|
||||
}, presentationData: self.presentationData)
|
||||
if applicationBindings.isMainApp {
|
||||
self.widgetDataContext = WidgetDataContext(basePath: self.basePath, activeAccount: self.activeAccounts
|
||||
|> map { primary, _, _ in
|
||||
return primary
|
||||
}, presentationData: self.presentationData)
|
||||
self.spotlightDataContext = SpotlightDataContext(accounts: self.activeAccounts |> map { _, accounts, _ in
|
||||
return accounts.map { _, account, _ in
|
||||
return account
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
193
submodules/TelegramUI/TelegramUI/SpotlightContacts.swift
Normal file
193
submodules/TelegramUI/TelegramUI/SpotlightContacts.swift
Normal file
@ -0,0 +1,193 @@
|
||||
import Foundation
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import SyncCore
|
||||
import TelegramCore
|
||||
import Display
|
||||
|
||||
import CoreSpotlight
|
||||
import MobileCoreServices
|
||||
|
||||
private let roundCorners = { () -> UIImage in
|
||||
let diameter: CGFloat = 60.0
|
||||
UIGraphicsBeginImageContextWithOptions(CGSize(width: diameter, height: diameter), false, 0.0)
|
||||
let context = UIGraphicsGetCurrentContext()!
|
||||
context.setBlendMode(.copy)
|
||||
context.setFillColor(UIColor.black.cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(), size: CGSize(width: diameter, height: diameter)))
|
||||
context.setFillColor(UIColor.clear.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: CGSize(width: diameter, height: diameter)))
|
||||
let image = UIGraphicsGetImageFromCurrentImageContext()!.stretchableImage(withLeftCapWidth: Int(diameter / 2.0), topCapHeight: Int(diameter / 2.0))
|
||||
UIGraphicsEndImageContext()
|
||||
return image
|
||||
}()
|
||||
|
||||
private struct SpotlightAccountContact: Equatable, Codable {
|
||||
var id: Int64
|
||||
var title: String
|
||||
var avatarPath: String?
|
||||
}
|
||||
|
||||
private func manageableSpotlightContacts(accounts: Signal<[Account], NoError>) -> Signal<[Int64: SpotlightAccountContact], NoError> {
|
||||
let queue = Queue()
|
||||
return accounts
|
||||
|> mapToSignal { accounts -> Signal<[[SpotlightAccountContact]], NoError> in
|
||||
return combineLatest(queue: queue, accounts.map { account -> Signal<[SpotlightAccountContact], NoError> in
|
||||
return account.postbox.contactPeersView(accountPeerId: account.peerId, includePresences: false)
|
||||
|> map { view -> [SpotlightAccountContact] in
|
||||
var result: [SpotlightAccountContact] = []
|
||||
for peer in view.peers {
|
||||
if let user = peer as? TelegramUser {
|
||||
result.append(SpotlightAccountContact(id: user.id.toInt64(), title: user.debugDisplayTitle, avatarPath: smallestImageRepresentation(user.photo).flatMap { representation in
|
||||
return account.postbox.mediaBox.resourcePath(representation.resource)
|
||||
}))
|
||||
}
|
||||
}
|
||||
result.sort(by: { $0.id < $1.id })
|
||||
return result
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
})
|
||||
}
|
||||
|> map { accountContacts -> [Int64: SpotlightAccountContact] in
|
||||
var result: [Int64: SpotlightAccountContact] = [:]
|
||||
for singleAccountContacts in accountContacts {
|
||||
for contact in singleAccountContacts {
|
||||
if result[contact.id] == nil {
|
||||
result[contact.id] = contact
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
private final class SpotlightContactContext {
|
||||
private let indexQueue: Queue
|
||||
private let disposable = MetaDisposable()
|
||||
private var contact: SpotlightAccountContact?
|
||||
|
||||
init(indexQueue: Queue) {
|
||||
self.indexQueue = indexQueue
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
}
|
||||
|
||||
func update(contact: SpotlightAccountContact) {
|
||||
if self.contact == contact {
|
||||
return
|
||||
}
|
||||
let photoUpdated = self.contact?.avatarPath != contact.avatarPath
|
||||
self.contact = contact
|
||||
|
||||
let indexQueue = self.indexQueue
|
||||
let indexSignal: Signal<Never, NoError> = Signal { subscriber in
|
||||
indexQueue.async {
|
||||
let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeText as String)
|
||||
attributeSet.title = contact.title
|
||||
if let avatarPath = contact.avatarPath, let avatarData = try? Data(contentsOf: URL(fileURLWithPath: avatarPath)), let image = UIImage(data: avatarData) {
|
||||
let size = CGSize(width: 120.0, height: 120.0)
|
||||
let context = DrawingContext(size: size, scale: 1.0, clear: true)
|
||||
context.withFlippedContext { c in
|
||||
c.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: size))
|
||||
c.setBlendMode(.destinationOut)
|
||||
c.draw(roundCorners.cgImage!, in: CGRect(origin: CGPoint(), size: size))
|
||||
}
|
||||
if let resultImage = context.generateImage(), let resultData = resultImage.pngData() {
|
||||
attributeSet.thumbnailData = resultData
|
||||
}
|
||||
}
|
||||
let item = CSSearchableItem(uniqueIdentifier: "contact-\(contact.id)", domainIdentifier: "telegram-contacts", attributeSet: attributeSet)
|
||||
Logger.shared.log("SpotlightDataContext", "index \(contact.id) title: \(contact.title)")
|
||||
CSSearchableIndex.default().indexSearchableItems([item], completionHandler: { error in
|
||||
if let error = error {
|
||||
Logger.shared.log("CSSearchableIndex", "error: \(error)")
|
||||
}
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
}
|
||||
|
||||
return EmptyDisposable
|
||||
}
|
||||
|
||||
self.disposable.set(indexSignal.start())
|
||||
}
|
||||
}
|
||||
|
||||
private final class SpotlightDataContextImpl {
|
||||
private let queue: Queue
|
||||
private let indexQueue: Queue = Queue()
|
||||
private var contactContexts: [Int64: SpotlightContactContext] = [:]
|
||||
|
||||
private var listDisposable: Disposable?
|
||||
|
||||
init(queue: Queue, accounts: Signal<[Account], NoError>) {
|
||||
self.queue = queue
|
||||
|
||||
self.indexQueue.async {
|
||||
Logger.shared.log("SpotlightDataContext", "deleteSearchableItems")
|
||||
CSSearchableIndex.default().deleteSearchableItems(withDomainIdentifiers: ["telegram-contacts"], completionHandler: { _ in })
|
||||
}
|
||||
|
||||
self.listDisposable = (manageableSpotlightContacts(accounts: accounts
|
||||
|> map { accounts in
|
||||
return accounts.sorted(by: { $0.id < $1.id })
|
||||
}
|
||||
|> distinctUntilChanged(isEqual: { lhs, rhs in
|
||||
if lhs.count != rhs.count {
|
||||
return false
|
||||
}
|
||||
for i in 0 ..< lhs.count {
|
||||
if lhs[i] !== rhs[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}))
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] contacts in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.updateContacts(contacts: contacts)
|
||||
})
|
||||
}
|
||||
|
||||
private func updateContacts(contacts: [Int64: SpotlightAccountContact]) {
|
||||
var validIds = Set<Int64>()
|
||||
for (_, contact) in contacts {
|
||||
validIds.insert(contact.id)
|
||||
|
||||
let context: SpotlightContactContext
|
||||
if let current = self.contactContexts[contact.id] {
|
||||
context = current
|
||||
} else {
|
||||
context = SpotlightContactContext(indexQueue: self.indexQueue)
|
||||
self.contactContexts[contact.id] = context
|
||||
}
|
||||
context.update(contact: contact)
|
||||
}
|
||||
|
||||
var removeIds: [Int64] = []
|
||||
for id in self.contactContexts.keys {
|
||||
if !validIds.contains(id) {
|
||||
removeIds.append(id)
|
||||
}
|
||||
}
|
||||
for id in removeIds {
|
||||
self.contactContexts.removeValue(forKey: id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final class SpotlightDataContext {
|
||||
private let impl: QueueLocalObject<SpotlightDataContextImpl>
|
||||
|
||||
public init(accounts: Signal<[Account], NoError>) {
|
||||
let queue = Queue()
|
||||
self.impl = QueueLocalObject(queue: queue, generate: {
|
||||
return SpotlightDataContextImpl(queue: queue, accounts: accounts)
|
||||
})
|
||||
}
|
||||
}
|
@ -161,7 +161,7 @@ public func transformOutgoingMessageMedia(postbox: Postbox, network: Network, me
|
||||
let thumbnailResource = LocalFileMediaResource(fileId: arc4random64())
|
||||
postbox.mediaBox.storeResourceData(thumbnailResource.id, data: smallestData)
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(smallestSize), resource: thumbnailResource))
|
||||
let updatedImage = TelegramMediaImage(imageId: image.imageId, representations: representations, immediateThumbnailData: image.immediateThumbnailData, reference: image.reference, partialReference: image.partialReference)
|
||||
let updatedImage = TelegramMediaImage(imageId: image.imageId, representations: representations, immediateThumbnailData: image.immediateThumbnailData, reference: image.reference, partialReference: image.partialReference, flags: [])
|
||||
return .single(.standalone(media: updatedImage))
|
||||
}
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ final class VerticalListContextResultsChatInputPanelItemNode: ListViewItemNode {
|
||||
updateIconImageSignal = chatMessageSticker(account: item.account, file: stickerFile, small: false, fetched: true)
|
||||
} else {
|
||||
let tmpRepresentation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 55, height: 55), resource: imageResource)
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [tmpRepresentation], immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [tmpRepresentation], immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
||||
updateIconImageSignal = chatWebpageSnippetPhoto(account: item.account, photoReference: .standalone(media: tmpImage))
|
||||
}
|
||||
} else {
|
||||
|
@ -264,7 +264,7 @@ func legacyWebSearchItem(account: Account, result: ChatContextResult) -> LegacyW
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(thumbnailDimensions), resource: thumbnailResource))
|
||||
}
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(imageDimensions), resource: imageResource))
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations, immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil)
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations, immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
||||
thumbnailSignal = chatMessagePhotoDatas(postbox: account.postbox, photoReference: .standalone(media: tmpImage), autoFetchFullSize: false)
|
||||
|> mapToSignal { value -> Signal<UIImage, NoError> in
|
||||
let thumbnailData = value._0
|
||||
|
@ -138,7 +138,7 @@ final class WebSearchItemNode: GridItemNode {
|
||||
representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(imageDimensions), resource: imageResource))
|
||||
}
|
||||
if !representations.isEmpty {
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations, immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil)
|
||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations, immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
||||
updateImageSignal = mediaGridMessagePhoto(account: item.account, photoReference: .standalone(media: tmpImage))
|
||||
} else {
|
||||
updateImageSignal = .complete()
|
||||
|
Loading…
x
Reference in New Issue
Block a user