mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various Fixes
This commit is contained in:
parent
f8890b9734
commit
80426cdf8f
@ -361,7 +361,7 @@ public final class DeviceAccess {
|
|||||||
switch status {
|
switch status {
|
||||||
case .restricted, .denied, .notDetermined:
|
case .restricted, .denied, .notDetermined:
|
||||||
value = false
|
value = false
|
||||||
case .authorized:
|
case .authorized, .limited:
|
||||||
value = true
|
value = true
|
||||||
@unknown default:
|
@unknown default:
|
||||||
fatalError()
|
fatalError()
|
||||||
@ -416,8 +416,6 @@ public final class DeviceAccess {
|
|||||||
locationManager?.requestAlwaysAuthorization(completion: { status in
|
locationManager?.requestAlwaysAuthorization(completion: { status in
|
||||||
completion(status == .authorizedAlways)
|
completion(status == .authorizedAlways)
|
||||||
})
|
})
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
@unknown default:
|
@unknown default:
|
||||||
fatalError()
|
fatalError()
|
||||||
|
@ -2,6 +2,12 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import Postbox
|
import Postbox
|
||||||
|
|
||||||
|
enum StickerVerificationStatus {
|
||||||
|
case loading
|
||||||
|
case verified
|
||||||
|
case declined
|
||||||
|
}
|
||||||
|
|
||||||
public class ImportStickerPack {
|
public class ImportStickerPack {
|
||||||
public class Sticker: Equatable {
|
public class Sticker: Equatable {
|
||||||
public enum Content {
|
public enum Content {
|
||||||
@ -32,6 +38,14 @@ public class ImportStickerPack {
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isAnimated: Bool {
|
||||||
|
if case .animation = self.content {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public let software: String
|
public let software: String
|
||||||
|
@ -29,7 +29,7 @@ public final class ImportStickerPackController: ViewController, StandalonePresen
|
|||||||
|
|
||||||
private let stickerPack: ImportStickerPack
|
private let stickerPack: ImportStickerPack
|
||||||
private var presentationDataDisposable: Disposable?
|
private var presentationDataDisposable: Disposable?
|
||||||
|
private var verificationDisposable: Disposable?
|
||||||
|
|
||||||
public init(context: AccountContext, stickerPack: ImportStickerPack, parentNavigationController: NavigationController?) {
|
public init(context: AccountContext, stickerPack: ImportStickerPack, parentNavigationController: NavigationController?) {
|
||||||
self.context = context
|
self.context = context
|
||||||
@ -57,6 +57,7 @@ public final class ImportStickerPackController: ViewController, StandalonePresen
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
self.presentationDataDisposable?.dispose()
|
self.presentationDataDisposable?.dispose()
|
||||||
|
self.verificationDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func loadDisplayNode() {
|
override public func loadDisplayNode() {
|
||||||
@ -77,8 +78,65 @@ public final class ImportStickerPackController: ViewController, StandalonePresen
|
|||||||
self.controllerNode.navigationController = self.parentNavigationController
|
self.controllerNode.navigationController = self.parentNavigationController
|
||||||
|
|
||||||
Queue.mainQueue().after(0.1) {
|
Queue.mainQueue().after(0.1) {
|
||||||
self.controllerNode.updateStickerPack(self.stickerPack)
|
self.controllerNode.updateStickerPack(self.stickerPack, verifiedStickers: Set(), declinedStickers: Set(), uploadedStickerResources: [:])
|
||||||
|
|
||||||
|
if self.stickerPack.isAnimated {
|
||||||
|
let _ = (self.context.account.postbox.loadedPeerWithId(self.context.account.peerId)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var signals: [Signal<(UUID, StickerVerificationStatus, MediaResource?), NoError>] = []
|
||||||
|
for sticker in strongSelf.stickerPack.stickers {
|
||||||
|
if let resource = strongSelf.controllerNode.stickerResources[sticker.uuid] {
|
||||||
|
signals.append(strongSelf.context.engine.stickers.uploadSticker(peer: peer, resource: resource, alt: sticker.emojis.first ?? "", dimensions: PixelDimensions(width: 512, height: 512), isAnimated: true)
|
||||||
|
|> map { result -> (UUID, StickerVerificationStatus, MediaResource?) in
|
||||||
|
switch result {
|
||||||
|
case .progress:
|
||||||
|
return (sticker.uuid, .loading, nil)
|
||||||
|
case let .complete(resource, mimeType):
|
||||||
|
if mimeType == "application/x-tgsticker" {
|
||||||
|
return (sticker.uuid, .verified, resource)
|
||||||
|
} else {
|
||||||
|
return (sticker.uuid, .declined, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> `catch` { _ -> Signal<(UUID, StickerVerificationStatus, MediaResource?), NoError> in
|
||||||
|
return .single((sticker.uuid, .declined, nil))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strongSelf.verificationDisposable = (combineLatest(signals)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] results in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var verifiedStickers = Set<UUID>()
|
||||||
|
var declinedStickers = Set<UUID>()
|
||||||
|
var uploadedStickerResources: [UUID: MediaResource] = [:]
|
||||||
|
for (uuid, result, resource) in results {
|
||||||
|
switch result {
|
||||||
|
case .verified:
|
||||||
|
if let resource = resource {
|
||||||
|
verifiedStickers.insert(uuid)
|
||||||
|
uploadedStickerResources[uuid] = resource
|
||||||
|
} else {
|
||||||
|
declinedStickers.insert(uuid)
|
||||||
|
}
|
||||||
|
case .declined:
|
||||||
|
declinedStickers.insert(uuid)
|
||||||
|
case .loading:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strongSelf.controllerNode.updateStickerPack(strongSelf.stickerPack, verifiedStickers: verifiedStickers, declinedStickers: declinedStickers, uploadedStickerResources: uploadedStickerResources)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.ready.set(self.controllerNode.ready.get())
|
self.ready.set(self.controllerNode.ready.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,13 +17,13 @@ import RadialStatusNode
|
|||||||
import UndoUI
|
import UndoUI
|
||||||
import StickerPackPreviewUI
|
import StickerPackPreviewUI
|
||||||
|
|
||||||
private struct StickerPackPreviewGridEntry: Comparable, Identifiable {
|
private struct StickerPackPreviewGridEntry: Comparable, Equatable, Identifiable {
|
||||||
let index: Int
|
let index: Int
|
||||||
let stickerItem: ImportStickerPack.Sticker
|
let stickerItem: ImportStickerPack.Sticker
|
||||||
|
let isVerified: Bool
|
||||||
|
|
||||||
var stableId: Int {
|
var stableId: Int {
|
||||||
return self.index
|
return self.index
|
||||||
// return self.stickerItem.file.fileId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static func <(lhs: StickerPackPreviewGridEntry, rhs: StickerPackPreviewGridEntry) -> Bool {
|
static func <(lhs: StickerPackPreviewGridEntry, rhs: StickerPackPreviewGridEntry) -> Bool {
|
||||||
@ -31,8 +31,10 @@ private struct StickerPackPreviewGridEntry: Comparable, Identifiable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func item(account: Account, interaction: StickerPackPreviewInteraction, theme: PresentationTheme) -> StickerPackPreviewGridItem {
|
func item(account: Account, interaction: StickerPackPreviewInteraction, theme: PresentationTheme) -> StickerPackPreviewGridItem {
|
||||||
return StickerPackPreviewGridItem(account: account, stickerItem: self.stickerItem, interaction: interaction, theme: theme, isEmpty: false)
|
return StickerPackPreviewGridItem(account: account, stickerItem: self.stickerItem, interaction: interaction, theme: theme, isVerified: self.isVerified)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct StickerPackPreviewGridTransaction {
|
private struct StickerPackPreviewGridTransaction {
|
||||||
@ -53,6 +55,9 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
|||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
private var stickerPack: ImportStickerPack?
|
private var stickerPack: ImportStickerPack?
|
||||||
|
var stickerResources: [UUID: MediaResource] = [:]
|
||||||
|
private var uploadedStickerResources: [UUID: MediaResource] = [:]
|
||||||
|
private var stickerPackReady = true
|
||||||
|
|
||||||
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
||||||
|
|
||||||
@ -130,6 +135,7 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
|||||||
self.contentTitleNode = ImmediateTextNode()
|
self.contentTitleNode = ImmediateTextNode()
|
||||||
self.contentTitleNode.displaysAsynchronously = false
|
self.contentTitleNode.displaysAsynchronously = false
|
||||||
self.contentTitleNode.maximumNumberOfLines = 1
|
self.contentTitleNode.maximumNumberOfLines = 1
|
||||||
|
self.contentTitleNode.alpha = 0.0
|
||||||
|
|
||||||
self.contentSeparatorNode = ASDisplayNode()
|
self.contentSeparatorNode = ASDisplayNode()
|
||||||
self.contentSeparatorNode.isLayerBacked = true
|
self.contentSeparatorNode.isLayerBacked = true
|
||||||
@ -205,6 +211,8 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
|||||||
self.wrappingScrollNode.addSubnode(self.progressText)
|
self.wrappingScrollNode.addSubnode(self.progressText)
|
||||||
self.wrappingScrollNode.addSubnode(self.infoText)
|
self.wrappingScrollNode.addSubnode(self.infoText)
|
||||||
|
|
||||||
|
self.installActionButtonNode.setTitle(self.presentationData.strings.ImportStickerPack_CreateStickerSet, with: Font.regular(20.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
|
||||||
|
|
||||||
self.contentGridNode.presentationLayoutUpdated = { [weak self] presentationLayout, transition in
|
self.contentGridNode.presentationLayoutUpdated = { [weak self] presentationLayout, transition in
|
||||||
self?.gridPresentationLayoutUpdated(presentationLayout, transition: transition)
|
self?.gridPresentationLayoutUpdated(presentationLayout, transition: transition)
|
||||||
}
|
}
|
||||||
@ -346,15 +354,13 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
|||||||
|
|
||||||
var transaction: StickerPackPreviewGridTransaction?
|
var transaction: StickerPackPreviewGridTransaction?
|
||||||
|
|
||||||
var animateIn = false
|
|
||||||
|
|
||||||
var forceTitleUpdate = false
|
var forceTitleUpdate = false
|
||||||
if self.progress != nil && !self.hadProgress {
|
if self.progress != nil && !self.hadProgress {
|
||||||
self.hadProgress = true
|
self.hadProgress = true
|
||||||
forceTitleUpdate = true
|
forceTitleUpdate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if let _ = self.stickerPack, self.currentItems.isEmpty || self.currentItems.count != self.pendingItems.count || forceTitleUpdate {
|
if let _ = self.stickerPack, self.currentItems.isEmpty || self.currentItems.count != self.pendingItems.count || self.pendingItems != self.currentItems || forceTitleUpdate {
|
||||||
let previousItems = self.currentItems
|
let previousItems = self.currentItems
|
||||||
self.currentItems = self.pendingItems
|
self.currentItems = self.pendingItems
|
||||||
|
|
||||||
@ -366,7 +372,6 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
|||||||
title = self.presentationData.strings.ImportStickerPack_StickerCount(Int32(self.currentItems.count))
|
title = self.presentationData.strings.ImportStickerPack_StickerCount(Int32(self.currentItems.count))
|
||||||
}
|
}
|
||||||
self.contentTitleNode.attributedText = stringWithAppliedEntities(title, entities: [], baseColor: self.presentationData.theme.actionSheet.primaryTextColor, linkColor: self.presentationData.theme.actionSheet.controlAccentColor, baseFont: titleFont, linkFont: titleFont, boldFont: titleFont, italicFont: titleFont, boldItalicFont: titleFont, fixedFont: titleFont, blockQuoteFont: titleFont)
|
self.contentTitleNode.attributedText = stringWithAppliedEntities(title, entities: [], baseColor: self.presentationData.theme.actionSheet.primaryTextColor, linkColor: self.presentationData.theme.actionSheet.controlAccentColor, baseFont: titleFont, linkFont: titleFont, boldFont: titleFont, italicFont: titleFont, boldItalicFont: titleFont, fixedFont: titleFont, blockQuoteFont: titleFont)
|
||||||
animateIn = true
|
|
||||||
|
|
||||||
if !forceTitleUpdate {
|
if !forceTitleUpdate {
|
||||||
transaction = StickerPackPreviewGridTransaction(previousList: previousItems, list: self.currentItems, account: self.context.account, interaction: self.interaction, theme: self.presentationData.theme)
|
transaction = StickerPackPreviewGridTransaction(previousList: previousItems, list: self.currentItems, account: self.context.account, interaction: self.interaction, theme: self.presentationData.theme)
|
||||||
@ -406,12 +411,6 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
|||||||
self.contentGridNode.transaction(GridNodeTransaction(deleteItems: transaction?.deletions ?? [], insertItems: transaction?.insertions ?? [], updateItems: transaction?.updates ?? [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: gridSize, insets: UIEdgeInsets(top: topInset, left: 0.0, bottom: bottomGridInset, right: 0.0), preloadSize: 80.0, type: .fixed(itemSize: CGSize(width: itemWidth, height: itemWidth), fillWidth: nil, lineSpacing: 0.0, itemSpacing: nil)), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in })
|
self.contentGridNode.transaction(GridNodeTransaction(deleteItems: transaction?.deletions ?? [], insertItems: transaction?.insertions ?? [], updateItems: transaction?.updates ?? [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: gridSize, insets: UIEdgeInsets(top: topInset, left: 0.0, bottom: bottomGridInset, right: 0.0), preloadSize: 80.0, type: .fixed(itemSize: CGSize(width: itemWidth, height: itemWidth), fillWidth: nil, lineSpacing: 0.0, itemSpacing: nil)), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in })
|
||||||
transition.updateFrame(node: self.contentGridNode, frame: CGRect(origin: CGPoint(x: floor((contentContainerFrame.size.width - contentFrame.size.width) / 2.0), y: titleAreaHeight), size: gridSize))
|
transition.updateFrame(node: self.contentGridNode, frame: CGRect(origin: CGPoint(x: floor((contentContainerFrame.size.width - contentFrame.size.width) / 2.0), y: titleAreaHeight), size: gridSize))
|
||||||
|
|
||||||
if animateIn {
|
|
||||||
self.contentGridNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
|
||||||
self.installActionButtonNode.titleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
|
||||||
self.installActionSeparatorNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
|
||||||
}
|
|
||||||
|
|
||||||
transition.updateAlpha(node: self.contentGridNode, alpha: self.progress == nil ? 1.0 : 0.0)
|
transition.updateAlpha(node: self.contentGridNode, alpha: self.progress == nil ? 1.0 : 0.0)
|
||||||
|
|
||||||
var effectiveProgress: CGFloat = 0.0
|
var effectiveProgress: CGFloat = 0.0
|
||||||
@ -563,7 +562,12 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
|||||||
if case let .image(data) = item.stickerItem.content, let image = UIImage(data: data) {
|
if case let .image(data) = item.stickerItem.content, let image = UIImage(data: data) {
|
||||||
dimensions = PixelDimensions(image.size)
|
dimensions = PixelDimensions(image.size)
|
||||||
}
|
}
|
||||||
if let resource = item.stickerItem.resource {
|
if let resource = self.uploadedStickerResources[item.stickerItem.uuid] {
|
||||||
|
if let localResource = item.stickerItem.resource {
|
||||||
|
self.context.account.postbox.mediaBox.copyResourceData(from: localResource.id, to: resource.id)
|
||||||
|
}
|
||||||
|
stickers.append(ImportSticker(resource: resource, emojis: item.stickerItem.emojis, dimensions: dimensions))
|
||||||
|
} else if let resource = item.stickerItem.resource {
|
||||||
stickers.append(ImportSticker(resource: resource, emojis: item.stickerItem.emojis, dimensions: dimensions))
|
stickers.append(ImportSticker(resource: resource, emojis: item.stickerItem.emojis, dimensions: dimensions))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -592,6 +596,7 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
|||||||
if case let .complete(info, items) = status {
|
if case let .complete(info, items) = status {
|
||||||
if let (_, _, count) = strongSelf.progress {
|
if let (_, _, count) = strongSelf.progress {
|
||||||
strongSelf.progress = (1.0, count, count)
|
strongSelf.progress = (1.0, count, count)
|
||||||
|
strongSelf.radialStatus.transitionToState(.progress(color: strongSelf.presentationData.theme.list.itemAccentColor, lineWidth: 6.0, value: 1.0, cancelEnabled: false, animateRotation: false), animated: !stickerPack.isAnimated, synchronous: true, completion: {})
|
||||||
if let (layout, navigationBarHeight) = strongSelf.containerLayout {
|
if let (layout, navigationBarHeight) = strongSelf.containerLayout {
|
||||||
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||||
}
|
}
|
||||||
@ -631,9 +636,11 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
|||||||
if let firstStickerItem = firstStickerItem, let resource = firstStickerItem.resource as? TelegramMediaResource {
|
if let firstStickerItem = firstStickerItem, let resource = firstStickerItem.resource as? TelegramMediaResource {
|
||||||
firstItem = StickerPackItem(index: ItemCollectionItemIndex(index: 0, id: 0), file: TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: stickerPack.isAnimated ? "application/x-tgsticker": "image/png", size: nil, attributes: [.FileName(fileName: stickerPack.isAnimated ? "sticker.tgs" : "sticker.png"), .ImageSize(size: firstStickerItem.dimensions)]), indexKeys: [])
|
firstItem = StickerPackItem(index: ItemCollectionItemIndex(index: 0, id: 0), file: TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: stickerPack.isAnimated ? "application/x-tgsticker": "image/png", size: nil, attributes: [.FileName(fileName: stickerPack.isAnimated ? "sticker.tgs" : "sticker.png"), .ImageSize(size: firstStickerItem.dimensions)]), indexKeys: [])
|
||||||
}
|
}
|
||||||
strongSelf.presentInGlobalOverlay?(UndoOverlayController(presentationData: strongSelf.presentationData, content: .stickersModified(title: strongSelf.presentationData.strings.StickerPackActionInfo_AddedTitle, text: strongSelf.presentationData.strings.StickerPackActionInfo_AddedText(info.title).0, undo: false, info: info, topItem: firstItem ?? items.first, context: strongSelf.context), elevatedLayout: false, action: { _ in
|
strongSelf.presentInGlobalOverlay?(UndoOverlayController(presentationData: strongSelf.presentationData, content: .stickersModified(title: strongSelf.presentationData.strings.StickerPackActionInfo_AddedTitle, text: strongSelf.presentationData.strings.StickerPackActionInfo_AddedText(info.title).0, undo: false, info: info, topItem: firstItem ?? items.first, context: strongSelf.context), elevatedLayout: false, action: { action in
|
||||||
// (navigationController?.viewControllers.last as? ViewController)?.present(StickerPackScreen(context: context, mode: .settings, mainStickerPack: .id(id: info.id.id, accessHash: info.accessHash), stickerPacks: [], parentNavigationController: navigationController, actionPerformed: { _, _, _ in
|
if case .info = action {
|
||||||
// }), in: .window(.root))
|
(navigationController?.viewControllers.last as? ViewController)?.present(StickerPackScreen(context: context, mode: .settings, mainStickerPack: .id(id: info.id.id, accessHash: info.accessHash), stickerPacks: [], parentNavigationController: navigationController, actionPerformed: { _, _, _ in
|
||||||
|
}), in: .window(.root))
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}), nil)
|
}), nil)
|
||||||
strongSelf.cancel?()
|
strongSelf.cancel?()
|
||||||
@ -716,23 +723,35 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateStickerPack(_ stickerPack: ImportStickerPack) {
|
func updateStickerPack(_ stickerPack: ImportStickerPack, verifiedStickers: Set<UUID>, declinedStickers: Set<UUID>, uploadedStickerResources: [UUID: MediaResource]) {
|
||||||
self.stickerPack = stickerPack
|
self.stickerPack = stickerPack
|
||||||
|
self.uploadedStickerResources = uploadedStickerResources
|
||||||
var updatedItems: [StickerPackPreviewGridEntry] = []
|
var updatedItems: [StickerPackPreviewGridEntry] = []
|
||||||
for item in stickerPack.stickers {
|
for item in stickerPack.stickers {
|
||||||
|
if declinedStickers.contains(item.uuid) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if let resource = self.stickerResources[item.uuid] {
|
||||||
|
item.resource = resource
|
||||||
|
} else {
|
||||||
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
|
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
|
||||||
self.context.account.postbox.mediaBox.storeResourceData(resource.id, data: item.data)
|
self.context.account.postbox.mediaBox.storeResourceData(resource.id, data: item.data)
|
||||||
item.resource = resource
|
item.resource = resource
|
||||||
updatedItems.append(StickerPackPreviewGridEntry(index: updatedItems.count, stickerItem: item))
|
self.stickerResources[item.uuid] = resource
|
||||||
|
}
|
||||||
|
updatedItems.append(StickerPackPreviewGridEntry(index: updatedItems.count, stickerItem: item, isVerified: !item.isAnimated || verifiedStickers.contains(item.uuid)))
|
||||||
}
|
}
|
||||||
self.pendingItems = updatedItems
|
self.pendingItems = updatedItems
|
||||||
|
|
||||||
|
if stickerPack.isAnimated {
|
||||||
|
self.stickerPackReady = stickerPack.stickers.count == (verifiedStickers.count + declinedStickers.count) && updatedItems.count > 0
|
||||||
|
}
|
||||||
|
|
||||||
self.interaction.playAnimatedStickers = true
|
self.interaction.playAnimatedStickers = true
|
||||||
|
|
||||||
if let _ = self.containerLayout {
|
if let _ = self.containerLayout {
|
||||||
self.dequeueUpdateStickerPack()
|
self.dequeueUpdateStickerPack()
|
||||||
}
|
}
|
||||||
self.installActionButtonNode.setTitle(self.presentationData.strings.ImportStickerPack_CreateStickerSet, with: Font.regular(20.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func dequeueUpdateStickerPack() {
|
func dequeueUpdateStickerPack() {
|
||||||
@ -742,11 +761,17 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
|||||||
transition = .animated(duration: 0.4, curve: .spring)
|
transition = .animated(duration: 0.4, curve: .spring)
|
||||||
} else {
|
} else {
|
||||||
transition = .immediate
|
transition = .immediate
|
||||||
|
|
||||||
self.contentTitleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
|
||||||
self.contentGridNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
|
||||||
self.installActionButtonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.contentTitleNode.alpha = 1.0
|
||||||
|
self.contentTitleNode.layer.animateAlpha(from: self.contentTitleNode.alpha, to: 1.0, duration: 0.2)
|
||||||
|
|
||||||
|
self.contentGridNode.alpha = 1.0
|
||||||
|
self.contentGridNode.layer.animateAlpha(from: self.contentGridNode.alpha, to: 1.0, duration: 0.2)
|
||||||
|
|
||||||
|
let buttonTransition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .easeInOut)
|
||||||
|
buttonTransition.updateAlpha(node: self.installActionButtonNode, alpha: self.stickerPackReady ? 1.0 : 0.3)
|
||||||
|
|
||||||
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
||||||
|
|
||||||
if !self.didSetReady {
|
if !self.didSetReady {
|
||||||
|
@ -27,21 +27,21 @@ final class StickerPackPreviewGridItem: GridItem {
|
|||||||
let stickerItem: ImportStickerPack.Sticker
|
let stickerItem: ImportStickerPack.Sticker
|
||||||
let interaction: StickerPackPreviewInteraction
|
let interaction: StickerPackPreviewInteraction
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let isEmpty: Bool
|
let isVerified: Bool
|
||||||
|
|
||||||
let section: GridSection? = nil
|
let section: GridSection? = nil
|
||||||
|
|
||||||
init(account: Account, stickerItem: ImportStickerPack.Sticker, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isEmpty: Bool) {
|
init(account: Account, stickerItem: ImportStickerPack.Sticker, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isVerified: Bool) {
|
||||||
self.account = account
|
self.account = account
|
||||||
self.stickerItem = stickerItem
|
self.stickerItem = stickerItem
|
||||||
self.interaction = interaction
|
self.interaction = interaction
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.isEmpty = isEmpty
|
self.isVerified = isVerified
|
||||||
}
|
}
|
||||||
|
|
||||||
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
|
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
|
||||||
let node = StickerPackPreviewGridItemNode()
|
let node = StickerPackPreviewGridItemNode()
|
||||||
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isEmpty: self.isEmpty)
|
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isVerified: self.isVerified)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ final class StickerPackPreviewGridItem: GridItem {
|
|||||||
assertionFailure()
|
assertionFailure()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isEmpty: self.isEmpty)
|
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isVerified: self.isVerified)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,9 +58,10 @@ private let textFont = Font.regular(20.0)
|
|||||||
|
|
||||||
final class StickerPackPreviewGridItemNode: GridItemNode {
|
final class StickerPackPreviewGridItemNode: GridItemNode {
|
||||||
private var currentState: (Account, ImportStickerPack.Sticker?, CGSize)?
|
private var currentState: (Account, ImportStickerPack.Sticker?, CGSize)?
|
||||||
private var isEmpty: Bool?
|
private var isVerified: Bool?
|
||||||
private let imageNode: ASImageNode
|
private let imageNode: ASImageNode
|
||||||
private var animationNode: AnimatedStickerNode?
|
private var animationNode: AnimatedStickerNode?
|
||||||
|
private var placeholderNode: ShimmerEffectNode?
|
||||||
|
|
||||||
private var theme: PresentationTheme?
|
private var theme: PresentationTheme?
|
||||||
|
|
||||||
@ -100,11 +101,11 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
|||||||
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))
|
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup(account: Account, stickerItem: ImportStickerPack.Sticker?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isEmpty: Bool) {
|
func setup(account: Account, stickerItem: ImportStickerPack.Sticker?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isVerified: Bool) {
|
||||||
self.interaction = interaction
|
self.interaction = interaction
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
|
|
||||||
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 !== stickerItem || self.isEmpty != isEmpty {
|
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 !== stickerItem || self.isVerified != isVerified {
|
||||||
var dimensions = CGSize(width: 512.0, height: 512.0)
|
var dimensions = CGSize(width: 512.0, height: 512.0)
|
||||||
if let stickerItem = stickerItem {
|
if let stickerItem = stickerItem {
|
||||||
switch stickerItem.content {
|
switch stickerItem.content {
|
||||||
@ -121,15 +122,35 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
|||||||
}
|
}
|
||||||
case .animation:
|
case .animation:
|
||||||
self.imageNode.isHidden = true
|
self.imageNode.isHidden = true
|
||||||
|
|
||||||
|
if isVerified {
|
||||||
let animationNode = AnimatedStickerNode()
|
let animationNode = AnimatedStickerNode()
|
||||||
self.animationNode = animationNode
|
self.animationNode = animationNode
|
||||||
|
|
||||||
|
if let placeholderNode = self.placeholderNode {
|
||||||
|
self.placeholderNode = nil
|
||||||
|
placeholderNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak placeholderNode] _ in
|
||||||
|
placeholderNode?.removeFromSupernode()
|
||||||
|
})
|
||||||
|
self.insertSubnode(animationNode, belowSubnode: placeholderNode)
|
||||||
|
} else {
|
||||||
self.addSubnode(animationNode)
|
self.addSubnode(animationNode)
|
||||||
|
}
|
||||||
|
|
||||||
let fittedDimensions = dimensions.aspectFitted(CGSize(width: 160.0, height: 160.0))
|
let fittedDimensions = dimensions.aspectFitted(CGSize(width: 160.0, height: 160.0))
|
||||||
if let resource = stickerItem.resource {
|
if let resource = stickerItem.resource {
|
||||||
animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .direct(cachePathPrefix: nil))
|
animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .direct(cachePathPrefix: nil))
|
||||||
}
|
}
|
||||||
animationNode.visibility = self.isVisibleInGrid && self.interaction?.playAnimatedStickers ?? true
|
animationNode.visibility = self.isVisibleInGrid && self.interaction?.playAnimatedStickers ?? true
|
||||||
|
} else {
|
||||||
|
let placeholderNode = ShimmerEffectNode()
|
||||||
|
self.placeholderNode = placeholderNode
|
||||||
|
|
||||||
|
self.addSubnode(placeholderNode)
|
||||||
|
if let (absoluteRect, containerSize) = self.absoluteLocation {
|
||||||
|
placeholderNode.updateAbsoluteRect(absoluteRect, within: containerSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dimensions = CGSize()
|
dimensions = CGSize()
|
||||||
@ -137,7 +158,7 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
|||||||
self.currentState = (account, stickerItem, dimensions)
|
self.currentState = (account, stickerItem, dimensions)
|
||||||
self.setNeedsLayout()
|
self.setNeedsLayout()
|
||||||
}
|
}
|
||||||
self.isEmpty = isEmpty
|
self.isVerified = isVerified
|
||||||
}
|
}
|
||||||
|
|
||||||
override func layout() {
|
override func layout() {
|
||||||
@ -154,6 +175,11 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
|||||||
animationNode.frame = CGRect(origin: CGPoint(x: floor((bounds.size.width - imageSize.width) / 2.0), y: (bounds.size.height - imageSize.height) / 2.0), size: imageSize)
|
animationNode.frame = CGRect(origin: CGPoint(x: floor((bounds.size.width - imageSize.width) / 2.0), y: (bounds.size.height - imageSize.height) / 2.0), size: imageSize)
|
||||||
animationNode.updateLayout(size: imageSize)
|
animationNode.updateLayout(size: imageSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let placeholderNode = self.placeholderNode, let theme = self.theme {
|
||||||
|
placeholderNode.update(backgroundColor: theme.list.itemBlocksBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor, shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: [.roundedRect(rect: CGRect(origin: CGPoint(), size: imageSize), cornerRadius: 11.0)], horizontal: true, size: imageSize)
|
||||||
|
placeholderNode.frame = self.imageNode.frame
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,5 +211,13 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var absoluteLocation: (CGRect, CGSize)?
|
||||||
|
override func updateAbsoluteRect(_ absoluteRect: CGRect, within containerSize: CGSize) {
|
||||||
|
self.absoluteLocation = (absoluteRect, containerSize)
|
||||||
|
if let placeholderNode = self.placeholderNode {
|
||||||
|
placeholderNode.updateAbsoluteRect(absoluteRect, within: containerSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,14 +26,10 @@ typedef enum {
|
|||||||
|
|
||||||
@protocol LegacyComponentsAccessChecker <NSObject>
|
@protocol LegacyComponentsAccessChecker <NSObject>
|
||||||
|
|
||||||
- (bool)checkAddressBookAuthorizationStatusWithAlertDismissComlpetion:(void (^)(void))alertDismissCompletion;
|
|
||||||
|
|
||||||
- (bool)checkPhotoAuthorizationStatusForIntent:(TGPhotoAccessIntent)intent alertDismissCompletion:(void (^)(void))alertDismissCompletion;
|
- (bool)checkPhotoAuthorizationStatusForIntent:(TGPhotoAccessIntent)intent alertDismissCompletion:(void (^)(void))alertDismissCompletion;
|
||||||
|
|
||||||
- (bool)checkMicrophoneAuthorizationStatusForIntent:(TGMicrophoneAccessIntent)intent alertDismissCompletion:(void (^)(void))alertDismissCompletion;
|
- (bool)checkMicrophoneAuthorizationStatusForIntent:(TGMicrophoneAccessIntent)intent alertDismissCompletion:(void (^)(void))alertDismissCompletion;
|
||||||
|
|
||||||
- (bool)checkCameraAuthorizationStatusForIntent:(TGCameraAccessIntent)intent alertDismissCompletion:(void (^)(void))alertDismissCompletion;
|
- (bool)checkCameraAuthorizationStatusForIntent:(TGCameraAccessIntent)intent completion:(void (^)(BOOL))completion alertDismissCompletion:(void (^)(void))alertDismissCompletion;
|
||||||
|
|
||||||
- (bool)checkLocationAuthorizationStatusForIntent:(TGLocationAccessIntent)intent alertDismissComlpetion:(void (^)(void))alertDismissCompletion;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -270,9 +270,9 @@
|
|||||||
|
|
||||||
- (void)_displayCameraWithView:(TGAttachmentCameraView *)cameraView menuController:(TGMenuSheetController *)menuController
|
- (void)_displayCameraWithView:(TGAttachmentCameraView *)cameraView menuController:(TGMenuSheetController *)menuController
|
||||||
{
|
{
|
||||||
if (![[[LegacyComponentsGlobals provider] accessChecker] checkCameraAuthorizationStatusForIntent:TGCameraAccessIntentDefault alertDismissCompletion:nil])
|
[[[LegacyComponentsGlobals provider] accessChecker] checkCameraAuthorizationStatusForIntent:TGCameraAccessIntentDefault completion:^(BOOL allowed) {
|
||||||
|
if (!allowed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ([_context currentlyInSplitView])
|
if ([_context currentlyInSplitView])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -365,6 +365,7 @@
|
|||||||
|
|
||||||
[menuController dismissAnimated:false];
|
[menuController dismissAnimated:false];
|
||||||
};
|
};
|
||||||
|
} alertDismissCompletion:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_displayMediaPicker
|
- (void)_displayMediaPicker
|
||||||
|
@ -271,7 +271,7 @@
|
|||||||
|
|
||||||
+ (void)_displayCameraWithView:(TGAttachmentCameraView *)cameraView menuController:(TGMenuSheetController *)menuController parentController:(TGViewController *)parentController context:(id<LegacyComponentsContext>)context intent:(TGPassportAttachIntent)intent uploadAction:(void (^)(SSignal *, void (^)(void)))uploadAction
|
+ (void)_displayCameraWithView:(TGAttachmentCameraView *)cameraView menuController:(TGMenuSheetController *)menuController parentController:(TGViewController *)parentController context:(id<LegacyComponentsContext>)context intent:(TGPassportAttachIntent)intent uploadAction:(void (^)(SSignal *, void (^)(void)))uploadAction
|
||||||
{
|
{
|
||||||
if (![[[LegacyComponentsGlobals provider] accessChecker] checkCameraAuthorizationStatusForIntent:TGCameraAccessIntentDefault alertDismissCompletion:nil])
|
if (![[[LegacyComponentsGlobals provider] accessChecker] checkCameraAuthorizationStatusForIntent:TGCameraAccessIntentDefault completion:^(BOOL allowed) { } alertDismissCompletion:nil])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ([context currentlyInSplitView])
|
if ([context currentlyInSplitView])
|
||||||
|
@ -39,10 +39,6 @@ private final class LegacyComponentsAccessCheckerImpl: NSObject, LegacyComponent
|
|||||||
self.context = context
|
self.context = context
|
||||||
}
|
}
|
||||||
|
|
||||||
public func checkAddressBookAuthorizationStatus(alertDismissComlpetion alertDismissCompletion: (() -> Void)!) -> Bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
public func checkPhotoAuthorizationStatus(for intent: TGPhotoAccessIntent, alertDismissCompletion: (() -> Void)!) -> Bool {
|
public func checkPhotoAuthorizationStatus(for intent: TGPhotoAccessIntent, alertDismissCompletion: (() -> Void)!) -> Bool {
|
||||||
if let context = self.context {
|
if let context = self.context {
|
||||||
DeviceAccess.authorizeAccess(to: .mediaLibrary(.send), presentationData: context.sharedContext.currentPresentationData.with { $0 }, present: context.sharedContext.presentGlobalController, openSettings: context.sharedContext.applicationBindings.openSettings, { value in
|
DeviceAccess.authorizeAccess(to: .mediaLibrary(.send), presentationData: context.sharedContext.currentPresentationData.with { $0 }, present: context.sharedContext.presentGlobalController, openSettings: context.sharedContext.applicationBindings.openSettings, { value in
|
||||||
@ -58,24 +54,10 @@ private final class LegacyComponentsAccessCheckerImpl: NSObject, LegacyComponent
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
public func checkCameraAuthorizationStatus(for intent: TGCameraAccessIntent, alertDismissCompletion: (() -> Void)!) -> Bool {
|
public func checkCameraAuthorizationStatus(for intent: TGCameraAccessIntent, completion: ((Bool) -> Void)!, alertDismissCompletion: (() -> Void)!) -> Bool {
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
public func checkLocationAuthorizationStatus(for intent: TGLocationAccessIntent, alertDismissComlpetion alertDismissCompletion: (() -> Void)!) -> Bool {
|
|
||||||
let subject: DeviceAccessLocationSubject
|
|
||||||
if intent == TGLocationAccessIntentSend {
|
|
||||||
subject = .send
|
|
||||||
} else if intent == TGLocationAccessIntentLiveLocation {
|
|
||||||
subject = .live
|
|
||||||
} else if intent == TGLocationAccessIntentTracking {
|
|
||||||
subject = .tracking
|
|
||||||
} else {
|
|
||||||
assertionFailure()
|
|
||||||
subject = .send
|
|
||||||
}
|
|
||||||
if let context = self.context {
|
if let context = self.context {
|
||||||
DeviceAccess.authorizeAccess(to: .location(subject), presentationData: context.sharedContext.currentPresentationData.with { $0 }, present: context.sharedContext.presentGlobalController, openSettings: context.sharedContext.applicationBindings.openSettings, { value in
|
DeviceAccess.authorizeAccess(to: .camera(.video), presentationData: context.sharedContext.currentPresentationData.with { $0 }, present: context.sharedContext.presentGlobalController, openSettings: context.sharedContext.applicationBindings.openSettings, { value in
|
||||||
|
completion(value)
|
||||||
if !value {
|
if !value {
|
||||||
alertDismissCompletion?()
|
alertDismissCompletion?()
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,10 @@ import UIKit
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import Display
|
import Display
|
||||||
|
|
||||||
private final class ShimmerEffectForegroundNode: ASDisplayNode {
|
final class ShimmerEffectForegroundNode: ASDisplayNode {
|
||||||
private var currentBackgroundColor: UIColor?
|
private var currentBackgroundColor: UIColor?
|
||||||
private var currentForegroundColor: UIColor?
|
private var currentForegroundColor: UIColor?
|
||||||
|
private var currentHorizontal: Bool?
|
||||||
private let imageNodeContainer: ASDisplayNode
|
private let imageNodeContainer: ASDisplayNode
|
||||||
private let imageNode: ASImageNode
|
private let imageNode: ASImageNode
|
||||||
|
|
||||||
@ -45,14 +46,36 @@ private final class ShimmerEffectForegroundNode: ASDisplayNode {
|
|||||||
self.updateAnimation()
|
self.updateAnimation()
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(backgroundColor: UIColor, foregroundColor: UIColor) {
|
func update(backgroundColor: UIColor, foregroundColor: UIColor, horizontal: Bool = false) {
|
||||||
if let currentBackgroundColor = self.currentBackgroundColor, currentBackgroundColor.isEqual(backgroundColor), let currentForegroundColor = self.currentForegroundColor, currentForegroundColor.isEqual(foregroundColor) {
|
if let currentBackgroundColor = self.currentBackgroundColor, currentBackgroundColor.isEqual(backgroundColor), let currentForegroundColor = self.currentForegroundColor, currentForegroundColor.isEqual(foregroundColor), self.currentHorizontal == horizontal {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.currentBackgroundColor = backgroundColor
|
self.currentBackgroundColor = backgroundColor
|
||||||
self.currentForegroundColor = foregroundColor
|
self.currentForegroundColor = foregroundColor
|
||||||
|
self.currentHorizontal = horizontal
|
||||||
|
|
||||||
self.imageNode.image = generateImage(CGSize(width: 16.0, height: 320.0), opaque: false, scale: 1.0, rotatedContext: { size, context in
|
let image: UIImage?
|
||||||
|
if horizontal {
|
||||||
|
image = generateImage(CGSize(width: 320.0, height: 16.0), opaque: false, scale: 1.0, rotatedContext: { size, context in
|
||||||
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
context.setFillColor(backgroundColor.cgColor)
|
||||||
|
context.fill(CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
context.clip(to: CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
let transparentColor = foregroundColor.withAlphaComponent(0.0).cgColor
|
||||||
|
let peakColor = foregroundColor.cgColor
|
||||||
|
|
||||||
|
var locations: [CGFloat] = [0.0, 0.5, 1.0]
|
||||||
|
let colors: [CGColor] = [transparentColor, peakColor, transparentColor]
|
||||||
|
|
||||||
|
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||||
|
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
|
||||||
|
|
||||||
|
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: 0.0), options: CGGradientDrawingOptions())
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
image = generateImage(CGSize(width: 16.0, height: 320.0), opaque: false, scale: 1.0, rotatedContext: { size, context in
|
||||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
context.setFillColor(backgroundColor.cgColor)
|
context.setFillColor(backgroundColor.cgColor)
|
||||||
context.fill(CGRect(origin: CGPoint(), size: size))
|
context.fill(CGRect(origin: CGPoint(), size: size))
|
||||||
@ -71,6 +94,9 @@ private final class ShimmerEffectForegroundNode: ASDisplayNode {
|
|||||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
|
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
self.imageNode.image = image
|
||||||
|
self.updateAnimation()
|
||||||
|
}
|
||||||
|
|
||||||
func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
|
func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
|
||||||
if let absoluteLocation = self.absoluteLocation, absoluteLocation.0 == rect && absoluteLocation.1 == containerSize {
|
if let absoluteLocation = self.absoluteLocation, absoluteLocation.0 == rect && absoluteLocation.1 == containerSize {
|
||||||
@ -95,7 +121,7 @@ private final class ShimmerEffectForegroundNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateAnimation() {
|
private func updateAnimation() {
|
||||||
let shouldBeAnimating = self.isCurrentlyInHierarchy && self.absoluteLocation != nil
|
let shouldBeAnimating = self.isCurrentlyInHierarchy && self.absoluteLocation != nil && self.currentHorizontal != nil
|
||||||
if shouldBeAnimating != self.shouldBeAnimating {
|
if shouldBeAnimating != self.shouldBeAnimating {
|
||||||
self.shouldBeAnimating = shouldBeAnimating
|
self.shouldBeAnimating = shouldBeAnimating
|
||||||
if shouldBeAnimating {
|
if shouldBeAnimating {
|
||||||
@ -107,9 +133,18 @@ private final class ShimmerEffectForegroundNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func addImageAnimation() {
|
private func addImageAnimation() {
|
||||||
guard let containerSize = self.absoluteLocation?.1 else {
|
guard let containerSize = self.absoluteLocation?.1, let horizontal = self.currentHorizontal else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if horizontal {
|
||||||
|
let gradientHeight: CGFloat = 320.0
|
||||||
|
self.imageNode.frame = CGRect(origin: CGPoint(x: -gradientHeight, y: 0.0), size: CGSize(width: gradientHeight, height: containerSize.height))
|
||||||
|
let animation = self.imageNode.layer.makeAnimation(from: 0.0 as NSNumber, to: (containerSize.width + gradientHeight) as NSNumber, keyPath: "position.x", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 1.3 * 1.0, delay: 0.0, mediaTimingFunction: nil, removeOnCompletion: true, additive: true)
|
||||||
|
animation.repeatCount = Float.infinity
|
||||||
|
animation.beginTime = 1.0
|
||||||
|
self.imageNode.layer.add(animation, forKey: "shimmer")
|
||||||
|
} else {
|
||||||
let gradientHeight: CGFloat = 250.0
|
let gradientHeight: CGFloat = 250.0
|
||||||
self.imageNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -gradientHeight), size: CGSize(width: containerSize.width, height: gradientHeight))
|
self.imageNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -gradientHeight), size: CGSize(width: containerSize.width, height: gradientHeight))
|
||||||
let animation = self.imageNode.layer.makeAnimation(from: 0.0 as NSNumber, to: (containerSize.height + gradientHeight) as NSNumber, keyPath: "position.y", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 1.3 * 1.0, delay: 0.0, mediaTimingFunction: nil, removeOnCompletion: true, additive: true)
|
let animation = self.imageNode.layer.makeAnimation(from: 0.0 as NSNumber, to: (containerSize.height + gradientHeight) as NSNumber, keyPath: "position.y", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 1.3 * 1.0, delay: 0.0, mediaTimingFunction: nil, removeOnCompletion: true, additive: true)
|
||||||
@ -117,6 +152,7 @@ private final class ShimmerEffectForegroundNode: ASDisplayNode {
|
|||||||
animation.beginTime = 1.0
|
animation.beginTime = 1.0
|
||||||
self.imageNode.layer.add(animation, forKey: "shimmer")
|
self.imageNode.layer.add(animation, forKey: "shimmer")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class ShimmerEffectNode: ASDisplayNode {
|
public final class ShimmerEffectNode: ASDisplayNode {
|
||||||
@ -135,6 +171,7 @@ public final class ShimmerEffectNode: ASDisplayNode {
|
|||||||
private var currentBackgroundColor: UIColor?
|
private var currentBackgroundColor: UIColor?
|
||||||
private var currentForegroundColor: UIColor?
|
private var currentForegroundColor: UIColor?
|
||||||
private var currentShimmeringColor: UIColor?
|
private var currentShimmeringColor: UIColor?
|
||||||
|
private var currentHorizontal: Bool?
|
||||||
private var currentSize = CGSize()
|
private var currentSize = CGSize()
|
||||||
|
|
||||||
override public init() {
|
override public init() {
|
||||||
@ -157,8 +194,8 @@ public final class ShimmerEffectNode: ASDisplayNode {
|
|||||||
self.effectNode.updateAbsoluteRect(rect, within: containerSize)
|
self.effectNode.updateAbsoluteRect(rect, within: containerSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func update(backgroundColor: UIColor, foregroundColor: UIColor, shimmeringColor: UIColor, shapes: [Shape], size: CGSize) {
|
public func update(backgroundColor: UIColor, foregroundColor: UIColor, shimmeringColor: UIColor, shapes: [Shape], horizontal: Bool = false, size: CGSize) {
|
||||||
if self.currentShapes == shapes, let currentBackgroundColor = self.currentBackgroundColor, currentBackgroundColor.isEqual(backgroundColor), let currentForegroundColor = self.currentForegroundColor, currentForegroundColor.isEqual(foregroundColor), let currentShimmeringColor = self.currentShimmeringColor, currentShimmeringColor.isEqual(shimmeringColor), self.currentSize == size {
|
if self.currentShapes == shapes, let currentBackgroundColor = self.currentBackgroundColor, currentBackgroundColor.isEqual(backgroundColor), let currentForegroundColor = self.currentForegroundColor, currentForegroundColor.isEqual(foregroundColor), let currentShimmeringColor = self.currentShimmeringColor, currentShimmeringColor.isEqual(shimmeringColor), horizontal == self.currentHorizontal, self.currentSize == size {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,11 +203,12 @@ public final class ShimmerEffectNode: ASDisplayNode {
|
|||||||
self.currentForegroundColor = foregroundColor
|
self.currentForegroundColor = foregroundColor
|
||||||
self.currentShimmeringColor = shimmeringColor
|
self.currentShimmeringColor = shimmeringColor
|
||||||
self.currentShapes = shapes
|
self.currentShapes = shapes
|
||||||
|
self.currentHorizontal = horizontal
|
||||||
self.currentSize = size
|
self.currentSize = size
|
||||||
|
|
||||||
self.backgroundNode.backgroundColor = foregroundColor
|
self.backgroundNode.backgroundColor = foregroundColor
|
||||||
|
|
||||||
self.effectNode.update(backgroundColor: foregroundColor, foregroundColor: shimmeringColor)
|
self.effectNode.update(backgroundColor: foregroundColor, foregroundColor: shimmeringColor, horizontal: horizontal)
|
||||||
|
|
||||||
self.foregroundNode.image = generateImage(size, rotatedContext: { size, context in
|
self.foregroundNode.image = generateImage(size, rotatedContext: { size, context in
|
||||||
context.setFillColor(backgroundColor.cgColor)
|
context.setFillColor(backgroundColor.cgColor)
|
||||||
|
@ -2,124 +2,6 @@ import Foundation
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import Display
|
import Display
|
||||||
|
|
||||||
private final class ShimmerEffectForegroundNode: ASDisplayNode {
|
|
||||||
private var currentBackgroundColor: UIColor?
|
|
||||||
private var currentForegroundColor: UIColor?
|
|
||||||
private let imageNodeContainer: ASDisplayNode
|
|
||||||
private let imageNode: ASImageNode
|
|
||||||
|
|
||||||
private var absoluteLocation: (CGRect, CGSize)?
|
|
||||||
private var isCurrentlyInHierarchy = false
|
|
||||||
private var shouldBeAnimating = false
|
|
||||||
|
|
||||||
override init() {
|
|
||||||
self.imageNodeContainer = ASDisplayNode()
|
|
||||||
self.imageNodeContainer.isLayerBacked = true
|
|
||||||
|
|
||||||
self.imageNode = ASImageNode()
|
|
||||||
self.imageNode.isLayerBacked = true
|
|
||||||
self.imageNode.displaysAsynchronously = false
|
|
||||||
self.imageNode.displayWithoutProcessing = true
|
|
||||||
self.imageNode.contentMode = .scaleToFill
|
|
||||||
|
|
||||||
super.init()
|
|
||||||
|
|
||||||
self.isLayerBacked = true
|
|
||||||
self.clipsToBounds = true
|
|
||||||
|
|
||||||
self.imageNodeContainer.addSubnode(self.imageNode)
|
|
||||||
self.addSubnode(self.imageNodeContainer)
|
|
||||||
}
|
|
||||||
|
|
||||||
override func didEnterHierarchy() {
|
|
||||||
super.didEnterHierarchy()
|
|
||||||
|
|
||||||
self.isCurrentlyInHierarchy = true
|
|
||||||
self.updateAnimation()
|
|
||||||
}
|
|
||||||
|
|
||||||
override func didExitHierarchy() {
|
|
||||||
super.didExitHierarchy()
|
|
||||||
|
|
||||||
self.isCurrentlyInHierarchy = false
|
|
||||||
self.updateAnimation()
|
|
||||||
}
|
|
||||||
|
|
||||||
func update(backgroundColor: UIColor, foregroundColor: UIColor) {
|
|
||||||
if let currentBackgroundColor = self.currentBackgroundColor, currentBackgroundColor.isEqual(backgroundColor), let currentForegroundColor = self.currentForegroundColor, currentForegroundColor.isEqual(foregroundColor) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.currentBackgroundColor = backgroundColor
|
|
||||||
self.currentForegroundColor = foregroundColor
|
|
||||||
|
|
||||||
let image = generateImage(CGSize(width: 320.0, height: 16.0), opaque: false, scale: 1.0, rotatedContext: { size, context in
|
|
||||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
|
||||||
context.setFillColor(backgroundColor.cgColor)
|
|
||||||
context.fill(CGRect(origin: CGPoint(), size: size))
|
|
||||||
|
|
||||||
context.clip(to: CGRect(origin: CGPoint(), size: size))
|
|
||||||
|
|
||||||
let transparentColor = foregroundColor.withAlphaComponent(0.0).cgColor
|
|
||||||
let peakColor = foregroundColor.cgColor
|
|
||||||
|
|
||||||
var locations: [CGFloat] = [0.0, 0.5, 1.0]
|
|
||||||
let colors: [CGColor] = [transparentColor, peakColor, transparentColor]
|
|
||||||
|
|
||||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
|
||||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
|
|
||||||
|
|
||||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: 0.0), options: CGGradientDrawingOptions())
|
|
||||||
})
|
|
||||||
self.imageNode.image = image
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
|
|
||||||
if let absoluteLocation = self.absoluteLocation, absoluteLocation.0 == rect && absoluteLocation.1 == containerSize {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let sizeUpdated = self.absoluteLocation?.1 != containerSize
|
|
||||||
let frameUpdated = self.absoluteLocation?.0 != rect
|
|
||||||
self.absoluteLocation = (rect, containerSize)
|
|
||||||
|
|
||||||
if sizeUpdated {
|
|
||||||
if self.shouldBeAnimating {
|
|
||||||
self.imageNode.layer.removeAnimation(forKey: "shimmer")
|
|
||||||
self.addImageAnimation()
|
|
||||||
} else {
|
|
||||||
self.updateAnimation()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if frameUpdated {
|
|
||||||
self.imageNodeContainer.frame = CGRect(origin: CGPoint(x: -rect.minX, y: -rect.minY), size: containerSize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func updateAnimation() {
|
|
||||||
let shouldBeAnimating = self.isCurrentlyInHierarchy && self.absoluteLocation != nil
|
|
||||||
if shouldBeAnimating != self.shouldBeAnimating {
|
|
||||||
self.shouldBeAnimating = shouldBeAnimating
|
|
||||||
if shouldBeAnimating {
|
|
||||||
self.addImageAnimation()
|
|
||||||
} else {
|
|
||||||
self.imageNode.layer.removeAnimation(forKey: "shimmer")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func addImageAnimation() {
|
|
||||||
guard let containerSize = self.absoluteLocation?.1 else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let gradientHeight: CGFloat = 320.0
|
|
||||||
self.imageNode.frame = CGRect(origin: CGPoint(x: -gradientHeight, y: 0.0), size: CGSize(width: gradientHeight, height: containerSize.height))
|
|
||||||
let animation = self.imageNode.layer.makeAnimation(from: 0.0 as NSNumber, to: (containerSize.width + gradientHeight) as NSNumber, keyPath: "position.x", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 1.3 * 1.0, delay: 0.0, mediaTimingFunction: nil, removeOnCompletion: true, additive: true)
|
|
||||||
animation.repeatCount = Float.infinity
|
|
||||||
animation.beginTime = 1.0
|
|
||||||
self.imageNode.layer.add(animation, forKey: "shimmer")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private let decodingMap: [String] = ["A", "A", "C", "A", "A", "A", "A", "H", "A", "A", "A", "L", "M", "A", "A", "A", "Q", "A", "S", "T", "A", "V", "A", "A", "A", "Z", "a", "a", "c", "a", "a", "a", "a", "h", "a", "a", "a", "l", "m", "a", "a", "a", "q", "a", "s", "t", "a", "v", "a", ".", "a", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "-", ","]
|
private let decodingMap: [String] = ["A", "A", "C", "A", "A", "A", "A", "H", "A", "A", "A", "L", "M", "A", "A", "A", "Q", "A", "S", "T", "A", "V", "A", "A", "A", "Z", "a", "a", "c", "a", "a", "a", "a", "h", "a", "a", "a", "l", "m", "a", "a", "a", "q", "a", "s", "t", "a", "v", "a", ".", "a", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "-", ","]
|
||||||
private func decodeStickerThumbnailData(_ data: Data) -> String {
|
private func decodeStickerThumbnailData(_ data: Data) -> String {
|
||||||
var string = "M"
|
var string = "M"
|
||||||
@ -199,7 +81,7 @@ public class StickerShimmerEffectNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.backgroundNode.backgroundColor = foregroundColor
|
self.backgroundNode.backgroundColor = foregroundColor
|
||||||
|
|
||||||
self.effectNode.update(backgroundColor: backgroundColor == nil ? .clear : foregroundColor, foregroundColor: shimmeringColor)
|
self.effectNode.update(backgroundColor: backgroundColor == nil ? .clear : foregroundColor, foregroundColor: shimmeringColor, horizontal: true)
|
||||||
|
|
||||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||||
let image = generateImage(size, rotatedContext: { size, context in
|
let image = generateImage(size, rotatedContext: { size, context in
|
||||||
|
@ -4370,8 +4370,8 @@ public final class VoiceChatController: ViewController {
|
|||||||
self.actionButton.update(size: centralButtonSize, buttonSize: CGSize(width: 112.0, height: 112.0), state: actionButtonState, title: actionButtonTitle, subtitle: actionButtonSubtitle, dark: self.isFullscreen, small: smallButtons, animated: true)
|
self.actionButton.update(size: centralButtonSize, buttonSize: CGSize(width: 112.0, height: 112.0), state: actionButtonState, title: actionButtonTitle, subtitle: actionButtonSubtitle, dark: self.isFullscreen, small: smallButtons, animated: true)
|
||||||
|
|
||||||
var hasCameraButton = self.callState?.isVideoEnabled ?? false
|
var hasCameraButton = self.callState?.isVideoEnabled ?? false
|
||||||
if let joinedVideo = self.joinedVideo, !joinedVideo {
|
if let joinedVideo = self.joinedVideo {
|
||||||
hasCameraButton = false
|
hasCameraButton = joinedVideo
|
||||||
}
|
}
|
||||||
switch actionButtonState {
|
switch actionButtonState {
|
||||||
case let .active(state):
|
case let .active(state):
|
||||||
@ -4790,7 +4790,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
displayPanelVideos = self.displayPanelVideos
|
displayPanelVideos = self.displayPanelVideos
|
||||||
}
|
}
|
||||||
|
|
||||||
var joinedVideo = true
|
var joinedVideo = self.joinedVideo ?? true
|
||||||
|
|
||||||
var myEntry: VoiceChatPeerEntry?
|
var myEntry: VoiceChatPeerEntry?
|
||||||
var mainEntry: VoiceChatPeerEntry?
|
var mainEntry: VoiceChatPeerEntry?
|
||||||
@ -4929,7 +4929,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isTile || (isTablet) {
|
if !isTile || isTablet || !joinedVideo {
|
||||||
entries.append(.peer(peerEntry, index))
|
entries.append(.peer(peerEntry, index))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,12 +5,12 @@ import TelegramApi
|
|||||||
|
|
||||||
import SyncCore
|
import SyncCore
|
||||||
|
|
||||||
private enum UploadStickerStatus {
|
public enum UploadStickerStatus {
|
||||||
case progress(Float)
|
case progress(Float)
|
||||||
case complete(TelegramMediaFile)
|
case complete(CloudDocumentMediaResource, String)
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum UploadStickerError {
|
public enum UploadStickerError {
|
||||||
case generic
|
case generic
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ private func uploadedSticker(postbox: Postbox, network: Network, resource: Media
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func uploadSticker(account: Account, peer: Peer, resource: MediaResource, alt: String, dimensions: PixelDimensions, isAnimated: Bool) -> Signal<UploadStickerStatus, UploadStickerError> {
|
func _internal_uploadSticker(account: Account, peer: Peer, resource: MediaResource, alt: String, dimensions: PixelDimensions, isAnimated: Bool) -> Signal<UploadStickerStatus, UploadStickerError> {
|
||||||
guard let inputPeer = apiInputPeer(peer) else {
|
guard let inputPeer = apiInputPeer(peer) else {
|
||||||
return .fail(.generic)
|
return .fail(.generic)
|
||||||
}
|
}
|
||||||
@ -59,8 +59,8 @@ private func uploadSticker(account: Account, peer: Peer, resource: MediaResource
|
|||||||
|> mapToSignal { media -> Signal<UploadStickerStatus, UploadStickerError> in
|
|> mapToSignal { media -> Signal<UploadStickerStatus, UploadStickerError> in
|
||||||
switch media {
|
switch media {
|
||||||
case let .messageMediaDocument(_, document, _):
|
case let .messageMediaDocument(_, document, _):
|
||||||
if let document = document, let file = telegramMediaFileFromApiDocument(document) {
|
if let document = document, let file = telegramMediaFileFromApiDocument(document), let resource = file.resource as? CloudDocumentMediaResource {
|
||||||
return .single(.complete(file))
|
return .single(.complete(resource, file.mimeType))
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
@ -108,35 +108,37 @@ func _internal_createStickerSet(account: Account, title: String, shortName: Stri
|
|||||||
stickers.append(thumbnail)
|
stickers.append(thumbnail)
|
||||||
}
|
}
|
||||||
for sticker in stickers {
|
for sticker in stickers {
|
||||||
uploadStickers.append(uploadSticker(account: account, peer: peer, resource: sticker.resource, alt: sticker.emojis.first ?? "", dimensions: sticker.dimensions, isAnimated: isAnimated)
|
if let resource = sticker.resource as? CloudDocumentMediaResource {
|
||||||
|
uploadStickers.append(.single(.complete(resource, isAnimated ? "application/x-tgsticker": "image/png")))
|
||||||
|
} else {
|
||||||
|
uploadStickers.append(_internal_uploadSticker(account: account, peer: peer, resource: sticker.resource, alt: sticker.emojis.first ?? "", dimensions: sticker.dimensions, isAnimated: isAnimated)
|
||||||
|> mapError { _ -> CreateStickerSetError in
|
|> mapError { _ -> CreateStickerSetError in
|
||||||
return .generic
|
return .generic
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return combineLatest(uploadStickers)
|
return combineLatest(uploadStickers)
|
||||||
|> mapToSignal { uploadedStickers -> Signal<CreateStickerSetStatus, CreateStickerSetError> in
|
|> mapToSignal { uploadedStickers -> Signal<CreateStickerSetStatus, CreateStickerSetError> in
|
||||||
var documents: [TelegramMediaFile] = []
|
var resources: [CloudDocumentMediaResource] = []
|
||||||
for sticker in uploadedStickers {
|
for sticker in uploadedStickers {
|
||||||
if case let .complete(document) = sticker {
|
if case let .complete(resource, _) = sticker {
|
||||||
documents.append(document)
|
resources.append(resource)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if documents.count == stickers.count {
|
if resources.count == stickers.count {
|
||||||
var flags: Int32 = 0
|
var flags: Int32 = 0
|
||||||
if isAnimated {
|
if isAnimated {
|
||||||
flags |= (1 << 1)
|
flags |= (1 << 1)
|
||||||
}
|
}
|
||||||
var inputStickers: [Api.InputStickerSetItem] = []
|
var inputStickers: [Api.InputStickerSetItem] = []
|
||||||
let stickerDocuments = thumbnail != nil ? documents.dropLast() : documents
|
let stickerDocuments = thumbnail != nil ? resources.dropLast() : resources
|
||||||
for i in 0 ..< stickerDocuments.count {
|
for i in 0 ..< stickerDocuments.count {
|
||||||
let sticker = stickers[i]
|
let sticker = stickers[i]
|
||||||
let document = documents[i]
|
let resource = resources[i]
|
||||||
if let resource = document.resource as? CloudDocumentMediaResource {
|
|
||||||
inputStickers.append(.inputStickerSetItem(flags: 0, document: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), emoji: sticker.emojis.first ?? "", maskCoords: nil))
|
inputStickers.append(.inputStickerSetItem(flags: 0, document: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data())), emoji: sticker.emojis.first ?? "", maskCoords: nil))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
var thumbnailDocument: Api.InputDocument?
|
var thumbnailDocument: Api.InputDocument?
|
||||||
if thumbnail != nil, let document = documents.last, let resource = document.resource as? CloudDocumentMediaResource {
|
if thumbnail != nil, let resource = resources.last {
|
||||||
flags |= (1 << 2)
|
flags |= (1 << 2)
|
||||||
thumbnailDocument = .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data()))
|
thumbnailDocument = .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data()))
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,10 @@ public extension TelegramEngine {
|
|||||||
return _internal_stickerPacksAttachedToMedia(account: self.account, media: media)
|
return _internal_stickerPacksAttachedToMedia(account: self.account, media: media)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func uploadSticker(peer: Peer, resource: MediaResource, alt: String, dimensions: PixelDimensions, isAnimated: Bool) -> Signal<UploadStickerStatus, UploadStickerError> {
|
||||||
|
return _internal_uploadSticker(account: self.account, peer: peer, resource: resource, alt: alt, dimensions: dimensions, isAnimated: isAnimated)
|
||||||
|
}
|
||||||
|
|
||||||
public func createStickerSet(title: String, shortName: String, stickers: [ImportSticker], thumbnail: ImportSticker?, isAnimated: Bool, software: String?) -> Signal<CreateStickerSetStatus, CreateStickerSetError> {
|
public func createStickerSet(title: String, shortName: String, stickers: [ImportSticker], thumbnail: ImportSticker?, isAnimated: Bool, software: String?) -> Signal<CreateStickerSetStatus, CreateStickerSetError> {
|
||||||
return _internal_createStickerSet(account: self.account, title: title, shortName: shortName, stickers: stickers, thumbnail: thumbnail, isAnimated: isAnimated, software: software)
|
return _internal_createStickerSet(account: self.account, title: title, shortName: shortName, stickers: stickers, thumbnail: thumbnail, isAnimated: isAnimated, software: software)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user