Skip to content

Commit

Permalink
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
Browse files Browse the repository at this point in the history
  • Loading branch information
laktyushin committed Aug 3, 2022
2 parents d6b6faf + 8336310 commit 348acd4
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 74 deletions.
3 changes: 3 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ build --spawn_strategy=standalone

build --strategy=SwiftCompile=standalone
build --define RULES_SWIFT_BUILD_DUMMY_WORKER=1

#build --linkopt=-fuse-ld=/Users/ali/build/zld/build/Build/Products/Release/zld
#build --linkopt=-Wl,-zld_original_ld_path,__BAZEL_XCODE_DEVELOPER_DIR__/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public class ExternalMusicAlbumArtResource: Equatable {
}

public func fetchExternalMusicAlbumArtResource(engine: TelegramEngine, file: FileMediaReference?, resource: ExternalMusicAlbumArtResource) -> Signal<EngineMediaResource.Fetch.Result, EngineMediaResource.Fetch.Error> {
return engine.resources.fetchAlbumCover(file: file, title: resource.title, performer: resource.performer)
return engine.resources.fetchAlbumCover(file: file, title: resource.title, performer: resource.performer, isThumbnail: resource.isThumbnail)

/*return Signal { subscriber in
if resource.performer.isEmpty || resource.performer.lowercased().trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) == "unknown artist" || resource.title.isEmpty {
Expand Down
14 changes: 14 additions & 0 deletions submodules/SSignalKit/SwiftSignalKit/Source/Atomic.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import Foundation

public enum AtomicLockError: Error {
case isLocked
}

public final class Atomic<T> {
private var lock: pthread_mutex_t
private var value: T
Expand All @@ -23,6 +27,16 @@ public final class Atomic<T> {
return result
}

public func tryWith<R>(_ f: (T) -> R) throws -> R {
if pthread_mutex_trylock(&self.lock) == 0 {
let result = f(self.value)
pthread_mutex_unlock(&self.lock)
return result
} else {
throw AtomicLockError.isLocked
}
}

public func modify(_ f: (T) -> T) -> T {
pthread_mutex_lock(&self.lock)
let result = f(self.value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ final class StickerPackEmojisItemNode: GridItemNode {
context: context,
dimensions: item.file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0),
immediateThumbnailData: item.file.immediateThumbnailData,
shimmerView: strongSelf.shimmerHostView,
shimmerView: nil,//strongSelf.shimmerHostView,
color: theme.chat.inputPanel.primaryTextColor.withMultipliedAlpha(0.08),
size: itemNativeFitSize
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ final class StickerPackPreviewGridItem: GridItem {

func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
let node = StickerPackPreviewGridItemNode()
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isLocked: self.isLocked, isEmpty: self.isEmpty)
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isLocked: self.isLocked, isPremium: self.isPremium, isEmpty: self.isEmpty)
return node
}

Expand All @@ -59,7 +59,7 @@ final class StickerPackPreviewGridItem: GridItem {
assertionFailure()
return
}
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isLocked: self.isLocked, isEmpty: self.isEmpty)
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isLocked: self.isLocked, isPremium: self.isPremium, isEmpty: self.isEmpty)
}
}

Expand All @@ -68,6 +68,7 @@ private let textFont = Font.regular(20.0)
final class StickerPackPreviewGridItemNode: GridItemNode {
private var currentState: (Account, StickerPackItem?)?
private var isLocked: Bool?
private var isPremium: Bool?
private var isEmpty: Bool?
private let imageNode: TransformImageNode
private var animationNode: AnimatedStickerNode?
Expand Down Expand Up @@ -167,11 +168,11 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
}

private var setupTimestamp: Double?
func setup(account: Account, stickerItem: StickerPackItem?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isLocked: Bool, isEmpty: Bool) {
func setup(account: Account, stickerItem: StickerPackItem?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isLocked: Bool, isPremium: Bool, isEmpty: Bool) {
self.interaction = interaction
self.theme = theme

if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 != stickerItem || self.isLocked != isLocked || self.isEmpty != isEmpty {
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 != stickerItem || self.isLocked != isLocked || self.isPremium != isPremium || self.isEmpty != isEmpty {
self.isLocked = isLocked

if isLocked {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -739,12 +739,14 @@ final class AlbumCoverResource: TelegramMediaResource, MediaResourceWithWebFileR
let file: FileMediaReference?
let title: String
let performer: String
let isThumbnail: Bool

init(datacenterId: Int, file: FileMediaReference?, title: String, performer: String) {
init(datacenterId: Int, file: FileMediaReference?, title: String, performer: String, isThumbnail: Bool) {
self.datacenterId = datacenterId
self.file = file
self.title = title
self.performer = performer
self.isThumbnail = isThumbnail
}

init(decoder: PostboxDecoder) {
Expand All @@ -761,17 +763,21 @@ final class AlbumCoverResource: TelegramMediaResource, MediaResourceWithWebFileR
document = .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data()))
flags |= 1 << 0
}
if !self.title.isEmpty {
var requestTitle: String?
var requestPerformer: String?
if !self.title.isEmpty || !self.performer.isEmpty {
requestTitle = self.title
requestPerformer = self.performer
flags |= 1 << 1
}
if !self.performer.isEmpty {
flags |= 1 << 1
if self.isThumbnail {
flags |= 1 << 2
}
return .inputWebFileAudioAlbumThumbLocation(
flags: flags,
document: document,
title: self.title.isEmpty ? nil : self.title,
performer: self.performer.isEmpty ? nil : self.performer
title: requestTitle,
performer: requestPerformer
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,12 @@ public extension TelegramEngine {
}
}

public func fetchAlbumCover(file: FileMediaReference?, title: String, performer: String) -> Signal<EngineMediaResource.Fetch.Result, EngineMediaResource.Fetch.Error> {
public func fetchAlbumCover(file: FileMediaReference?, title: String, performer: String, isThumbnail: Bool) -> Signal<EngineMediaResource.Fetch.Result, EngineMediaResource.Fetch.Error> {
let signal = currentWebDocumentsHostDatacenterId(postbox: self.account.postbox, isTestingEnvironment: self.account.testingEnvironment)
|> castError(EngineMediaResource.Fetch.Error.self)
|> take(1)
|> mapToSignal { datacenterId -> Signal<EngineMediaResource.Fetch.Result, EngineMediaResource.Fetch.Error> in
let resource = AlbumCoverResource(datacenterId: Int(datacenterId), file: file, title: title, performer: performer)
let resource = AlbumCoverResource(datacenterId: Int(datacenterId), file: file, title: title, performer: performer, isThumbnail: isThumbnail)

return multipartFetch(postbox: self.account.postbox, network: self.account.network, mediaReferenceRevalidationContext: self.account.mediaReferenceRevalidationContext, resource: resource, datacenterId: Int(datacenterId), size: nil, intervals: .single([(0 ..< Int64.max, .default)]), parameters: MediaResourceFetchParameters(
tag: nil,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,14 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
} else {
let pointSize = self.pointSize
let placeholderColor = self.placeholderColor
let isThumbnailCancelled = Atomic<Bool>(value: false)
self.loadDisposable = self.renderer.loadFirstFrame(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, size: self.pixelSize, fetch: animationCacheFetchFile(context: self.context, resource: .media(media: .standalone(media: file), resource: file.resource), type: AnimationCacheAnimationType(file: file), keyframeOnly: true), completion: { [weak self] result, isFinal in
if !result {
MultiAnimationRendererImpl.firstFrameQueue.async {
let image = generateStickerPlaceholderImage(data: file.immediateThumbnailData, size: pointSize, scale: min(2.0, UIScreenScale), imageSize: file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0), backgroundColor: nil, foregroundColor: placeholderColor)

DispatchQueue.main.async {
guard let strongSelf = self else {
guard let strongSelf = self, !isThumbnailCancelled.with({ $0 }) else {
return
}
if let image = image {
Expand All @@ -207,6 +208,7 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
guard let strongSelf = self else {
return
}
let _ = isThumbnailCancelled.swap(true)
strongSelf.loadAnimation()
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,11 @@ open class MultiAnimationRenderTarget: SimpleLayer {

private final class LoadFrameGroupTask {
let task: () -> () -> Void
let queueAffinity: Int

init(task: @escaping () -> () -> Void) {
init(task: @escaping () -> () -> Void, queueAffinity: Int) {
self.task = task
self.queueAffinity = queueAffinity
}
}

Expand Down Expand Up @@ -222,11 +224,12 @@ private final class ItemAnimationContext {
static let queue1 = Queue(name: "ItemAnimationContext-1", qos: .default)

private let cache: AnimationCache
let queueAffinity: Int
private let stateUpdated: () -> Void

private var disposable: Disposable?
private var displayLink: ConstantDisplayLinkAnimator?
private var item: AnimationCacheItem?
private var item: Atomic<AnimationCacheItem>?

private var currentFrame: Frame?
private var isLoadingFrame: Bool = false
Expand All @@ -241,16 +244,19 @@ private final class ItemAnimationContext {

let targets = Bag<Weak<MultiAnimationRenderTarget>>()

init(cache: AnimationCache, itemId: String, size: CGSize, fetch: @escaping (AnimationCacheFetchOptions) -> Disposable, stateUpdated: @escaping () -> Void) {
init(cache: AnimationCache, queueAffinity: Int, itemId: String, size: CGSize, fetch: @escaping (AnimationCacheFetchOptions) -> Disposable, stateUpdated: @escaping () -> Void) {
self.cache = cache
self.queueAffinity = queueAffinity
self.stateUpdated = stateUpdated

self.disposable = cache.get(sourceId: itemId, size: size, fetch: fetch).start(next: { [weak self] result in
Queue.mainQueue().async {
guard let strongSelf = self else {
return
}
strongSelf.item = result.item
if let item = result.item {
strongSelf.item = Atomic(value: item)
}
strongSelf.updateIsPlaying()
}
})
Expand Down Expand Up @@ -330,9 +336,14 @@ private final class ItemAnimationContext {

return LoadFrameGroupTask(task: { [weak self] in
let currentFrame: Frame?
if let frame = item.advance(advance: frameAdvance, requestedFormat: .rgba) {
currentFrame = Frame(frame: frame)
} else {
do {
if let frame = try item.tryWith({ $0.advance(advance: frameAdvance, requestedFormat: .rgba) }) {
currentFrame = Frame(frame: frame)
} else {
currentFrame = nil
}
} catch {
assertionFailure()
currentFrame = nil
}

Expand All @@ -356,7 +367,7 @@ private final class ItemAnimationContext {
}
}
}
})
}, queueAffinity: self.queueAffinity)
}

if let _ = self.currentFrame {
Expand All @@ -383,6 +394,7 @@ public final class MultiAnimationRendererImpl: MultiAnimationRenderer {
}

private var itemContexts: [ItemKey: ItemAnimationContext] = [:]
private var nextQueueAffinity: Int = 0

private(set) var isPlaying: Bool = false {
didSet {
Expand All @@ -403,7 +415,9 @@ public final class MultiAnimationRendererImpl: MultiAnimationRenderer {
if let current = self.itemContexts[itemKey] {
itemContext = current
} else {
itemContext = ItemAnimationContext(cache: cache, itemId: itemId, size: size, fetch: fetch, stateUpdated: { [weak self] in
let queueAffinity = self.nextQueueAffinity
self.nextQueueAffinity += 1
itemContext = ItemAnimationContext(cache: cache, queueAffinity: queueAffinity, itemId: itemId, size: size, fetch: fetch, stateUpdated: { [weak self] in
guard let strongSelf = self else {
return
}
Expand Down Expand Up @@ -668,59 +682,40 @@ public final class MultiAnimationRendererImpl: MultiAnimationRenderer {
}

if !tasks.isEmpty {
if tasks.count > 2 {
let tasks0 = Array(tasks.prefix(tasks.count / 2))
let tasks1 = Array(tasks.suffix(tasks.count - tasks0.count))

var tasks0Completions: [() -> Void]?
var tasks1Completions: [() -> Void]?

let complete: (Int, [() -> Void]) -> Void = { index, completions in
Queue.mainQueue().async {
if index == 0 {
tasks0Completions = completions
} else if index == 1 {
tasks1Completions = completions
}
if let tasks0Completions = tasks0Completions, let tasks1Completions = tasks1Completions {
for completion in tasks0Completions {
completion()
}
for completion in tasks1Completions {
completion()
}
}
}
}

ItemAnimationContext.queue0.async {
var completions: [() -> Void] = []
for task in tasks0 {
let complete = task.task()
completions.append(complete)
}
complete(0, completions)
}
ItemAnimationContext.queue1.async {
let tasks0 = tasks.filter { $0.queueAffinity % 2 == 0 }
let tasks1 = tasks.filter { $0.queueAffinity % 2 == 1 }
let allTasks = [tasks0, tasks1]

let taskCompletions = Atomic<[Int: [() -> Void]]>(value: [:])
let queues: [Queue] = [ItemAnimationContext.queue0, ItemAnimationContext.queue1]

for i in 0 ..< 2 {
let partTasks = allTasks[i]
let id = i
queues[i].async {
var completions: [() -> Void] = []
for task in tasks1 {
for task in partTasks {
let complete = task.task()
completions.append(complete)
}
complete(1, completions)
}
} else {
ItemAnimationContext.queue0.async {
var completions: [() -> Void] = []
for task in tasks {
let complete = task.task()
completions.append(complete)

var complete = false
let _ = taskCompletions.modify { current in
var current = current
current[id] = completions
if current.count == 2 {
complete = true
}
return current
}

if !completions.isEmpty {
if complete {
Queue.mainQueue().async {
for completion in completions {
completion()
let allCompletions = taskCompletions.with { $0 }
for (_, fs) in allCompletions {
for f in fs {
f()
}
}
}
}
Expand Down
Loading

0 comments on commit 348acd4

Please sign in to comment.