diff --git a/Telegram/BUILD b/Telegram/BUILD
index 2aa652fad6..ce29f30dd0 100644
--- a/Telegram/BUILD
+++ b/Telegram/BUILD
@@ -1793,6 +1793,7 @@ plist_fragment(
BGTaskSchedulerPermittedIdentifiers
{telegram_bundle_id}.refresh
+ {telegram_bundle_id}.cleanup
CFBundleAllowMixedLocalizations
@@ -1893,6 +1894,7 @@ plist_fragment(
location
remote-notification
voip
+ processing
UIDeviceFamily
diff --git a/Telegram/NotificationService/Sources/NotificationService.swift b/Telegram/NotificationService/Sources/NotificationService.swift
index ee0c4185ac..f697af4b28 100644
--- a/Telegram/NotificationService/Sources/NotificationService.swift
+++ b/Telegram/NotificationService/Sources/NotificationService.swift
@@ -1169,6 +1169,12 @@ private final class NotificationServiceHandler {
parameters: MediaResourceFetchParameters(
tag: nil,
info: resourceFetchInfo(resource: resource),
+ location: messageId.flatMap { messageId in
+ return MediaResourceStorageLocation(
+ peerId: peerId,
+ messageId: messageId
+ )
+ },
isRandomAccessAllowed: true
),
encryptionKey: nil,
@@ -1220,6 +1226,7 @@ private final class NotificationServiceHandler {
parameters: MediaResourceFetchParameters(
tag: nil,
info: resourceFetchInfo(resource: resource),
+ location: nil,
isRandomAccessAllowed: true
),
encryptionKey: nil,
diff --git a/submodules/Components/ReactionImageComponent/Sources/ReactionImageComponent.swift b/submodules/Components/ReactionImageComponent/Sources/ReactionImageComponent.swift
index 413f41ec20..21e6f265ef 100644
--- a/submodules/Components/ReactionImageComponent/Sources/ReactionImageComponent.swift
+++ b/submodules/Components/ReactionImageComponent/Sources/ReactionImageComponent.swift
@@ -29,7 +29,17 @@ public func reactionStaticImage(context: AccountContext, animation: TelegramMedi
} else {
type = .still
}
- let fetchFrame = animationCacheFetchFile(context: context, resource: MediaResourceReference.standalone(resource: animation.resource), type: type, keyframeOnly: true)
+
+ var customColor: UIColor?
+ for attribute in animation.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ if isSingleColor {
+ customColor = nil
+ }
+ }
+ }
+
+ let fetchFrame = animationCacheFetchFile(context: context, resource: MediaResourceReference.standalone(resource: animation.resource), type: type, keyframeOnly: true, customColor: customColor)
class AnimationCacheItemWriterImpl: AnimationCacheItemWriter {
let queue: Queue
diff --git a/submodules/ContextUI/Sources/ContextActionsContainerNode.swift b/submodules/ContextUI/Sources/ContextActionsContainerNode.swift
index 14365a7fb8..b002bf3e07 100644
--- a/submodules/ContextUI/Sources/ContextActionsContainerNode.swift
+++ b/submodules/ContextUI/Sources/ContextActionsContainerNode.swift
@@ -586,7 +586,7 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
let textRightInset: CGFloat
if let _ = self.iconNode.image {
- textRightInset = iconSize.width - 8.0
+ textRightInset = iconSize.width - 2.0
} else {
textRightInset = 0.0
}
diff --git a/submodules/Display/Source/TextNode.swift b/submodules/Display/Source/TextNode.swift
index f514c9866c..b9621e5798 100644
--- a/submodules/Display/Source/TextNode.swift
+++ b/submodules/Display/Source/TextNode.swift
@@ -212,11 +212,13 @@ public final class TextNodeLayout: NSObject {
public let range: NSRange
public let rect: CGRect
public let value: AnyHashable
+ public let textColor: UIColor
- public init(range: NSRange, rect: CGRect, value: AnyHashable) {
+ public init(range: NSRange, rect: CGRect, value: AnyHashable, textColor: UIColor) {
self.range = range
self.rect = rect
self.value = value
+ self.textColor = textColor
}
public static func ==(lhs: EmbeddedItem, rhs: EmbeddedItem) -> Bool {
@@ -229,6 +231,9 @@ public final class TextNodeLayout: NSObject {
if lhs.value != rhs.value {
return false
}
+ if lhs.textColor != rhs.textColor {
+ return false
+ }
return true
}
}
@@ -301,7 +306,18 @@ public final class TextNodeLayout: NSObject {
spoilers.append(contentsOf: line.spoilers.map { ( $0.range, $0.frame.offsetBy(dx: lineFrame.minX, dy: lineFrame.minY)) })
spoilerWords.append(contentsOf: line.spoilerWords.map { ( $0.range, $0.frame.offsetBy(dx: lineFrame.minX, dy: lineFrame.minY)) })
for embeddedItem in line.embeddedItems {
- embeddedItems.append(TextNodeLayout.EmbeddedItem(range: embeddedItem.range, rect: embeddedItem.frame.offsetBy(dx: lineFrame.minX, dy: lineFrame.minY), value: embeddedItem.item))
+ var textColor: UIColor?
+ if let attributedString = attributedString, embeddedItem.range.location < attributedString.length {
+ if let color = attributedString.attribute(.foregroundColor, at: embeddedItem.range.location, effectiveRange: nil) as? UIColor {
+ textColor = color
+ }
+ if textColor == nil {
+ if let color = attributedString.attribute(.foregroundColor, at: 0, effectiveRange: nil) as? UIColor {
+ textColor = color
+ }
+ }
+ }
+ embeddedItems.append(TextNodeLayout.EmbeddedItem(range: embeddedItem.range, rect: embeddedItem.frame.offsetBy(dx: lineFrame.minX, dy: lineFrame.minY), value: embeddedItem.item, textColor: textColor ?? .black))
}
}
self.hasRTL = hasRTL
diff --git a/submodules/GalleryData/Sources/GalleryData.swift b/submodules/GalleryData/Sources/GalleryData.swift
index ab8410856b..448bc0dbe8 100644
--- a/submodules/GalleryData/Sources/GalleryData.swift
+++ b/submodules/GalleryData/Sources/GalleryData.swift
@@ -100,7 +100,7 @@ public func chatMessageGalleryControllerData(context: AccountContext, chatLocati
var instantPageMedia: (TelegramMediaWebpage, [InstantPageGalleryEntry])?
if message.media.isEmpty, let entities = message.textEntitiesAttribute?.entities, entities.count == 1, let firstEntity = entities.first, case let .CustomEmoji(_, fileId) = firstEntity.type, let file = message.associatedMedia[MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)] as? TelegramMediaFile {
for attribute in file.attributes {
- if case let .CustomEmoji(_, _, reference) = attribute {
+ if case let .CustomEmoji(_, _, _, reference) = attribute {
if let reference = reference {
return .stickerPack(reference)
}
diff --git a/submodules/Postbox/BUILD b/submodules/Postbox/BUILD
index b975adf50e..d9ce7c24b3 100644
--- a/submodules/Postbox/BUILD
+++ b/submodules/Postbox/BUILD
@@ -17,6 +17,7 @@ swift_library(
"//submodules/StringTransliteration:StringTransliteration",
"//submodules/ManagedFile:ManagedFile",
"//submodules/Utils/RangeSet:RangeSet",
+ "//submodules/CryptoUtils",
],
visibility = [
"//visibility:public",
diff --git a/submodules/Postbox/Sources/MediaBox.swift b/submodules/Postbox/Sources/MediaBox.swift
index 633603c788..f06225fce9 100644
--- a/submodules/Postbox/Sources/MediaBox.swift
+++ b/submodules/Postbox/Sources/MediaBox.swift
@@ -144,6 +144,8 @@ public final class MediaBox {
private let cacheQueue = Queue()
private let timeBasedCleanup: TimeBasedCleanup
+ public let storageBox: StorageBox
+
private let didRemoveResourcesPipe = ValuePipe()
public var didRemoveResources: Signal {
return .single(Void()) |> then(self.didRemoveResourcesPipe.signal())
@@ -187,6 +189,10 @@ public final class MediaBox {
public init(basePath: String) {
self.basePath = basePath
+ self.storageBox = StorageBox(logger: StorageBox.Logger(impl: { string in
+ postboxLog(string)
+ }), basePath: basePath + "/storage")
+
self.timeBasedCleanup = TimeBasedCleanup(generalPaths: [
self.basePath,
self.basePath + "/cache",
@@ -204,6 +210,14 @@ public final class MediaBox {
self.timeBasedCleanup.setMaxStoreTimes(general: general, shortLived: shortLived, gigabytesLimit: gigabytesLimit)
}
+ private func idForFileName(name: String) -> String {
+ if name.hasSuffix("_partial") {
+ return String(name[name.startIndex ..< name.index(name.endIndex, offsetBy: -8)])
+ } else {
+ return name
+ }
+ }
+
private func fileNameForId(_ id: MediaResourceId) -> String {
return "\(id.stringRepresentation)"
}
@@ -580,6 +594,10 @@ public final class MediaBox {
return
}
+ if let location = parameters?.location {
+ self.storageBox.add(reference: StorageBox.Reference(peerId: location.peerId, messageNamespace: UInt8(clamping: location.messageId.namespace), messageId: location.messageId.id), to: resource.id.stringRepresentation.data(using: .utf8)!)
+ }
+
guard let (fileContext, releaseContext) = self.fileContext(for: resource.id) else {
subscriber.putCompletion()
return
@@ -742,6 +760,10 @@ public final class MediaBox {
self.dataQueue.async {
let paths = self.storePathsForId(resource.id)
+ if let location = parameters?.location {
+ self.storageBox.add(reference: StorageBox.Reference(peerId: location.peerId, messageNamespace: UInt8(clamping: location.messageId.namespace), messageId: location.messageId.id), to: resource.id.stringRepresentation.data(using: .utf8)!)
+ }
+
if let _ = fileSize(paths.complete) {
if implNext {
subscriber.putNext(.local)
@@ -1174,6 +1196,17 @@ public final class MediaBox {
}
}
+ public func resourceUsage(id: MediaResourceId) -> Int64 {
+ let paths = self.storePathsForId(id)
+ if let size = fileSize(paths.complete) {
+ return Int64(size)
+ } else if let size = fileSize(paths.partial, useTotalFileAllocatedSize: true) {
+ return Int64(size)
+ } else {
+ return 0
+ }
+ }
+
public func collectResourceCacheUsage(_ ids: [MediaResourceId]) -> Signal<[MediaResourceId: Int64], NoError> {
return Signal { subscriber in
self.dataQueue.async {
@@ -1194,6 +1227,99 @@ public final class MediaBox {
}
}
+ public func collectAllResourceUsage() -> Signal<[(id: String?, path: String, size: Int64)], NoError> {
+ return Signal { subscriber in
+ self.dataQueue.async {
+ var result: [(id: String?, path: String, size: Int64)] = []
+
+ var fileIds = Set()
+
+ if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: self.basePath), includingPropertiesForKeys: [.fileSizeKey, .fileResourceIdentifierKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) {
+ loop: for url in enumerator {
+ if let url = url as? URL {
+ if let fileId = (try? url.resourceValues(forKeys: Set([.fileResourceIdentifierKey])))?.fileResourceIdentifier as? Data {
+ if fileIds.contains(fileId) {
+ //paths.append(url.lastPathComponent)
+ continue loop
+ }
+
+ if let value = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize, value != 0 {
+ fileIds.insert(fileId)
+ result.append((id: self.idForFileName(name: url.lastPathComponent), path: url.lastPathComponent, size: Int64(value)))
+ //paths.append(url.lastPathComponent)
+ }
+ }
+ }
+ }
+ }
+
+ /*var cacheResult: Int64 = 0
+
+ var excludePrefixes = Set()
+ for id in excludeIds {
+ let cachedRepresentationPrefix = self.fileNameForId(id)
+
+ excludePrefixes.insert(cachedRepresentationPrefix)
+ }
+
+ if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: self.basePath + "/cache"), includingPropertiesForKeys: [.fileSizeKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) {
+ loop: for url in enumerator {
+ if let url = url as? URL {
+ if let prefix = url.lastPathComponent.components(separatedBy: ":").first, excludePrefixes.contains(prefix) {
+ continue loop
+ }
+
+ if let value = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize, value != 0 {
+ paths.append("cache/" + url.lastPathComponent)
+ cacheResult += Int64(value)
+ }
+ }
+ }
+ }
+
+ func processRecursive(directoryPath: String, subdirectoryPath: String) {
+ if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: directoryPath), includingPropertiesForKeys: [.fileSizeKey, .isDirectoryKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) {
+ loop: for url in enumerator {
+ if let url = url as? URL {
+ if let prefix = url.lastPathComponent.components(separatedBy: ":").first, excludePrefixes.contains(prefix) {
+ continue loop
+ }
+
+ if let isDirectory = (try? url.resourceValues(forKeys: Set([.isDirectoryKey])))?.isDirectory, isDirectory {
+ processRecursive(directoryPath: url.path, subdirectoryPath: subdirectoryPath + "/\(url.lastPathComponent)")
+ } else if let value = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize, value != 0 {
+ paths.append("\(subdirectoryPath)/" + url.lastPathComponent)
+ cacheResult += Int64(value)
+ }
+ }
+ }
+ }
+ }
+
+ processRecursive(directoryPath: self.basePath + "/animation-cache", subdirectoryPath: "animation-cache")
+
+ if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: self.basePath + "/short-cache"), includingPropertiesForKeys: [.fileSizeKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) {
+ loop: for url in enumerator {
+ if let url = url as? URL {
+ if let prefix = url.lastPathComponent.components(separatedBy: ":").first, excludePrefixes.contains(prefix) {
+ continue loop
+ }
+
+ if let value = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize, value != 0 {
+ paths.append("short-cache/" + url.lastPathComponent)
+ cacheResult += Int64(value)
+ }
+ }
+ }
+ }*/
+
+ subscriber.putNext(result)
+ subscriber.putCompletion()
+ }
+ return EmptyDisposable
+ }
+ }
+
public func collectOtherResourceUsage(excludeIds: Set, combinedExcludeIds: Set) -> Signal<(Int64, [String], Int64), NoError> {
return Signal { subscriber in
self.dataQueue.async {
diff --git a/submodules/Postbox/Sources/MediaResource.swift b/submodules/Postbox/Sources/MediaResource.swift
index e4d4f2d773..e72385f7a2 100644
--- a/submodules/Postbox/Sources/MediaResource.swift
+++ b/submodules/Postbox/Sources/MediaResource.swift
@@ -39,14 +39,26 @@ public protocol MediaResourceFetchTag {
public protocol MediaResourceFetchInfo {
}
+public final class MediaResourceStorageLocation {
+ public let peerId: PeerId
+ public let messageId: MessageId
+
+ public init(peerId: PeerId, messageId: MessageId) {
+ self.peerId = peerId
+ self.messageId = messageId
+ }
+}
+
public struct MediaResourceFetchParameters {
public let tag: MediaResourceFetchTag?
public let info: MediaResourceFetchInfo?
+ public let location: MediaResourceStorageLocation?
public let isRandomAccessAllowed: Bool
- public init(tag: MediaResourceFetchTag?, info: MediaResourceFetchInfo?, isRandomAccessAllowed: Bool) {
+ public init(tag: MediaResourceFetchTag?, info: MediaResourceFetchInfo?, location: MediaResourceStorageLocation?, isRandomAccessAllowed: Bool) {
self.tag = tag
self.info = info
+ self.location = location
self.isRandomAccessAllowed = isRandomAccessAllowed
}
}
diff --git a/submodules/Postbox/Sources/SqliteValueBox.swift b/submodules/Postbox/Sources/SqliteValueBox.swift
index 088f89623d..2c8f462a53 100644
--- a/submodules/Postbox/Sources/SqliteValueBox.swift
+++ b/submodules/Postbox/Sources/SqliteValueBox.swift
@@ -188,6 +188,8 @@ public final class SqliteValueBox: ValueBox {
private var updateStatements: [Int32 : SqlitePreparedStatement] = [:]
private var insertOrReplacePrimaryKeyStatements: [Int32 : SqlitePreparedStatement] = [:]
private var insertOrReplaceIndexKeyStatements: [Int32 : SqlitePreparedStatement] = [:]
+ private var insertOrIgnorePrimaryKeyStatements: [Int32 : SqlitePreparedStatement] = [:]
+ private var insertOrIgnoreIndexKeyStatements: [Int32 : SqlitePreparedStatement] = [:]
private var deleteStatements: [Int32 : SqlitePreparedStatement] = [:]
private var moveStatements: [Int32 : SqlitePreparedStatement] = [:]
private var copyStatements: [TablePairKey : SqlitePreparedStatement] = [:]
@@ -1220,6 +1222,59 @@ public final class SqliteValueBox: ValueBox {
return resultStatement
}
+ private func insertOrIgnoreStatement(_ table: SqliteValueBoxTable, key: ValueBoxKey, value: MemoryBuffer) -> SqlitePreparedStatement {
+ precondition(self.queue.isCurrent())
+ checkTableKey(table.table, key)
+
+ let resultStatement: SqlitePreparedStatement
+
+ if table.table.keyType == .int64 || table.hasPrimaryKey {
+ if let statement = self.insertOrIgnorePrimaryKeyStatements[table.table.id] {
+ resultStatement = statement
+ } else {
+ var statement: OpaquePointer? = nil
+ let status = sqlite3_prepare_v2(self.database.handle, "INSERT INTO t\(table.table.id) (key, value) VALUES(?, ?) ON CONFLICT(key) DO NOTHING", -1, &statement, nil)
+ if status != SQLITE_OK {
+ let errorText = self.database.currentError() ?? "Unknown error"
+ preconditionFailure(errorText)
+ }
+ let preparedStatement = SqlitePreparedStatement(statement: statement)
+ self.insertOrIgnorePrimaryKeyStatements[table.table.id] = preparedStatement
+ resultStatement = preparedStatement
+ }
+ } else {
+ if let statement = self.insertOrIgnoreIndexKeyStatements[table.table.id] {
+ resultStatement = statement
+ } else {
+ var statement: OpaquePointer? = nil
+ let status = sqlite3_prepare_v2(self.database.handle, "INSERT INTO t\(table.table.id) (key, value) VALUES(?, ?)", -1, &statement, nil)
+ if status != SQLITE_OK {
+ let errorText = self.database.currentError() ?? "Unknown error"
+ preconditionFailure(errorText)
+ }
+ let preparedStatement = SqlitePreparedStatement(statement: statement)
+ self.insertOrIgnorePrimaryKeyStatements[table.table.id] = preparedStatement
+ resultStatement = preparedStatement
+ }
+ }
+
+ resultStatement.reset()
+
+ switch table.table.keyType {
+ case .binary:
+ resultStatement.bind(1, data: key.memory, length: key.length)
+ case .int64:
+ resultStatement.bind(1, number: key.getInt64(0))
+ }
+ if value.length == 0 {
+ resultStatement.bindNull(2)
+ } else {
+ resultStatement.bind(2, data: value.memory, length: value.length)
+ }
+
+ return resultStatement
+ }
+
private func deleteStatement(_ table: ValueBoxTable, key: ValueBoxKey) -> SqlitePreparedStatement {
precondition(self.queue.isCurrent())
checkTableKey(table, key)
@@ -1847,6 +1902,30 @@ public final class SqliteValueBox: ValueBox {
}
}
+ public func setOrIgnore(_ table: ValueBoxTable, key: ValueBoxKey, value: MemoryBuffer) {
+ precondition(self.queue.isCurrent())
+ let sqliteTable = self.checkTable(table)
+
+ if sqliteTable.hasPrimaryKey {
+ let statement = self.insertOrIgnoreStatement(sqliteTable, key: key, value: value)
+ while statement.step(handle: self.database.handle, pathToRemoveOnError: self.removeDatabaseOnError ? self.databasePath : nil) {
+ }
+ statement.reset()
+ } else {
+ if self.exists(table, key: key) {
+ let statement = self.updateStatement(table, key: key, value: value)
+ while statement.step(handle: self.database.handle, pathToRemoveOnError: self.removeDatabaseOnError ? self.databasePath : nil) {
+ }
+ statement.reset()
+ } else {
+ let statement = self.insertOrReplaceStatement(sqliteTable, key: key, value: value)
+ while statement.step(handle: self.database.handle, pathToRemoveOnError: self.removeDatabaseOnError ? self.databasePath : nil) {
+ }
+ statement.reset()
+ }
+ }
+ }
+
public func remove(_ table: ValueBoxTable, key: ValueBoxKey, secure: Bool) {
precondition(self.queue.isCurrent())
if let _ = self.tables[table.id] {
@@ -2108,6 +2187,16 @@ public final class SqliteValueBox: ValueBox {
}
self.insertOrReplacePrimaryKeyStatements.removeAll()
+ for (_, statement) in self.insertOrIgnoreIndexKeyStatements {
+ statement.destroy()
+ }
+ self.insertOrIgnoreIndexKeyStatements.removeAll()
+
+ for (_, statement) in self.insertOrIgnorePrimaryKeyStatements {
+ statement.destroy()
+ }
+ self.insertOrIgnorePrimaryKeyStatements.removeAll()
+
for (_, statement) in self.deleteStatements {
statement.destroy()
}
diff --git a/submodules/Postbox/Sources/StorageBox/StorageBox.swift b/submodules/Postbox/Sources/StorageBox/StorageBox.swift
new file mode 100644
index 0000000000..e3a2a51988
--- /dev/null
+++ b/submodules/Postbox/Sources/StorageBox/StorageBox.swift
@@ -0,0 +1,205 @@
+import Foundation
+import SwiftSignalKit
+import CryptoUtils
+
+public struct HashId: Hashable {
+ public let data: Data
+
+ public init(data: Data) {
+ precondition(data.count == 16)
+ self.data = data
+ }
+}
+
+private func md5Hash(_ data: Data) -> HashId {
+ let hashData = data.withUnsafeBytes { bytes -> Data in
+ return CryptoMD5(bytes.baseAddress!, Int32(bytes.count))
+ }
+ return HashId(data: hashData)
+}
+
+public final class StorageBox {
+ public struct Reference {
+ public var peerId: PeerId
+ public var messageNamespace: UInt8
+ public var messageId: Int32
+
+ public init(peerId: PeerId, messageNamespace: UInt8, messageId: Int32) {
+ self.peerId = peerId
+ self.messageNamespace = messageNamespace
+ self.messageId = messageId
+ }
+ }
+
+ public final class Entry {
+ public let id: Data
+ public let references: [Reference]
+
+ init(id: Data, references: [Reference]) {
+ self.id = id
+ self.references = references
+ }
+ }
+
+ public final class Logger {
+ private let impl: (String) -> Void
+
+ public init(impl: @escaping (String) -> Void) {
+ self.impl = impl
+ }
+
+ func log(_ string: @autoclosure () -> String) {
+ self.impl(string())
+ }
+ }
+
+ private final class Impl {
+ let queue: Queue
+ let logger: StorageBox.Logger
+ let basePath: String
+ let valueBox: SqliteValueBox
+ let hashIdToIdTable: ValueBoxTable
+ let idToReferenceTable: ValueBoxTable
+
+ init(queue: Queue, logger: StorageBox.Logger, basePath: String) {
+ self.queue = queue
+ self.logger = logger
+ self.basePath = basePath
+
+ let databasePath = self.basePath + "/db"
+ let _ = try? FileManager.default.createDirectory(atPath: databasePath, withIntermediateDirectories: true)
+ var valueBox = SqliteValueBox(basePath: databasePath, queue: queue, isTemporary: false, isReadOnly: false, useCaches: true, removeDatabaseOnError: true, encryptionParameters: nil, upgradeProgress: { _ in })
+ if valueBox == nil {
+ let _ = try? FileManager.default.removeItem(atPath: databasePath)
+ valueBox = SqliteValueBox(basePath: databasePath, queue: queue, isTemporary: false, isReadOnly: false, useCaches: true, removeDatabaseOnError: true, encryptionParameters: nil, upgradeProgress: { _ in })
+ }
+ guard let valueBox else {
+ preconditionFailure("Could not open database")
+ }
+ self.valueBox = valueBox
+
+ self.hashIdToIdTable = ValueBoxTable(id: 5, keyType: .binary, compactValuesOnCreation: true)
+ self.idToReferenceTable = ValueBoxTable(id: 6, keyType: .binary, compactValuesOnCreation: true)
+ }
+
+ func add(reference: Reference, to id: Data) {
+ self.valueBox.begin()
+
+ let hashId = md5Hash(id)
+
+ let mainKey = ValueBoxKey(length: hashId.data.count)
+ self.valueBox.setOrIgnore(self.hashIdToIdTable, key: mainKey, value: MemoryBuffer(data: id))
+
+ let idKey = ValueBoxKey(length: hashId.data.count + 8 + 1 + 4)
+ idKey.setData(0, value: hashId.data)
+ idKey.setInt64(hashId.data.count, value: reference.peerId.toInt64())
+ idKey.setUInt8(hashId.data.count + 8, value: reference.messageNamespace)
+ idKey.setInt32(hashId.data.count + 8 + 1, value: reference.messageId)
+ self.valueBox.setOrIgnore(self.idToReferenceTable, key: idKey, value: MemoryBuffer())
+
+ self.valueBox.commit()
+ }
+
+ func all() -> [Entry] {
+ var result: [Entry] = []
+
+ self.valueBox.begin()
+
+ var currentId: Data?
+ var currentReferences: [Reference] = []
+
+ self.valueBox.scan(self.idToReferenceTable, keys: { key in
+ let id = key.getData(0, length: 16)
+
+ let peerId = PeerId(key.getInt64(16))
+ let messageNamespace: UInt8 = key.getUInt8(16 + 8)
+ let messageId = key.getInt32(16 + 8 + 1)
+
+ let reference = Reference(peerId: peerId, messageNamespace: messageNamespace, messageId: messageId)
+
+ if currentId == id {
+ currentReferences.append(reference)
+ } else {
+ if let currentId = currentId, !currentReferences.isEmpty {
+ result.append(StorageBox.Entry(id: currentId, references: currentReferences))
+ currentReferences.removeAll(keepingCapacity: true)
+ }
+ currentId = id
+ currentReferences.append(reference)
+ }
+
+ return true
+ })
+
+ self.valueBox.commit()
+
+ return result
+ }
+
+ func get(ids: [Data]) -> [Entry] {
+ var result: [Entry] = []
+
+ self.valueBox.begin()
+
+ let idKey = ValueBoxKey(length: 16)
+
+ for id in ids {
+ let hashId = md5Hash(id)
+ idKey.setData(0, value: hashId.data)
+ var currentReferences: [Reference] = []
+ self.valueBox.range(self.idToReferenceTable, start: idKey, end: idKey.successor, keys: { key in
+ let peerId = PeerId(key.getInt64(16))
+ let messageNamespace: UInt8 = key.getUInt8(16 + 8)
+ let messageId = key.getInt32(16 + 8 + 1)
+
+ let reference = Reference(peerId: peerId, messageNamespace: messageNamespace, messageId: messageId)
+
+ currentReferences.append(reference)
+ return true
+ }, limit: 0)
+
+ if !currentReferences.isEmpty {
+ result.append(StorageBox.Entry(id: id, references: currentReferences))
+ }
+ }
+
+ self.valueBox.commit()
+
+ return result
+ }
+ }
+
+ private let queue: Queue
+ private let impl: QueueLocalObject
+
+ public init(queue: Queue = Queue(name: "StorageBox"), logger: StorageBox.Logger, basePath: String) {
+ self.queue = queue
+ self.impl = QueueLocalObject(queue: queue, generate: {
+ return Impl(queue: queue, logger: logger, basePath: basePath)
+ })
+ }
+
+ public func add(reference: Reference, to id: Data) {
+ self.impl.with { impl in
+ impl.add(reference: reference, to: id)
+ }
+ }
+
+ public func all() -> Signal<[Entry], NoError> {
+ return self.impl.signalWith { impl, subscriber in
+ subscriber.putNext(impl.all())
+ subscriber.putCompletion()
+
+ return EmptyDisposable
+ }
+ }
+
+ public func get(ids: [Data]) -> Signal<[Entry], NoError> {
+ return self.impl.signalWith { impl, subscriber in
+ subscriber.putNext(impl.get(ids: ids))
+ subscriber.putCompletion()
+
+ return EmptyDisposable
+ }
+ }
+}
diff --git a/submodules/Postbox/Sources/ValueBoxKey.swift b/submodules/Postbox/Sources/ValueBoxKey.swift
index e73b21ddf7..f192bde0f6 100644
--- a/submodules/Postbox/Sources/ValueBoxKey.swift
+++ b/submodules/Postbox/Sources/ValueBoxKey.swift
@@ -83,6 +83,15 @@ public struct ValueBoxKey: Equatable, Hashable, CustomStringConvertible, Compara
memcpy(self.memory + offset, &varValue, 2)
}
+ public func getData(_ offset: Int, length: Int) -> Data {
+ assert(offset >= 0 && offset + length <= self.length)
+ var value = Data(count: length)
+ let _ = value.withUnsafeMutableBytes { bytes in
+ memcpy(bytes.baseAddress!.assumingMemoryBound(to: UInt8.self), self.memory + offset, length)
+ }
+ return value
+ }
+
public func getInt32(_ offset: Int) -> Int32 {
assert(offset >= 0 && offset + 4 <= self.length)
var value: Int32 = 0
diff --git a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift
index 855f46ccee..c607410e30 100644
--- a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift
+++ b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift
@@ -2285,7 +2285,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
var packReference: StickerPackReference?
if let file = file {
for attribute in file.attributes {
- if case let .CustomEmoji(_, _, reference) = attribute {
+ if case let .CustomEmoji(_, _, _, reference) = attribute {
packReference = reference
}
}
@@ -2357,7 +2357,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
tapAction: { [weak state, weak environment] _, _ in
if let emojiFile = state?.emojiFile, let controller = environment?.controller() as? PremiumIntroScreen, let navigationController = controller.navigationController as? NavigationController {
for attribute in emojiFile.attributes {
- if case let .CustomEmoji(_, _, packReference) = attribute, let packReference = packReference {
+ if case let .CustomEmoji(_, _, _, packReference) = attribute, let packReference = packReference {
let controller = accountContext.sharedContext.makeStickerPackScreen(context: accountContext, updatedPresentationData: nil, mainStickerPack: packReference, stickerPacks: [packReference], loadedStickerPacks: loadedEmojiPack.flatMap { [$0] } ?? [], parentNavigationController: navigationController, sendSticker: { _, _, _ in
return false
})
diff --git a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift
index 482556ec01..9d704462be 100644
--- a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift
+++ b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift
@@ -425,7 +425,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
for item in featuredEmojiPack.topItems {
for attribute in item.file.attributes {
switch attribute {
- case let .CustomEmoji(_, alt, _):
+ case let .CustomEmoji(_, _, alt, _):
if filterList.contains(alt) {
filteredFiles.append(item.file)
}
@@ -1395,7 +1395,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
}
for attribute in item.file.attributes {
switch attribute {
- case let .CustomEmoji(_, alt, _):
+ case let .CustomEmoji(_, _, alt, _):
if !item.file.isPremiumEmoji || hasPremium {
if !alt.isEmpty, let keyword = allEmoticons[alt] {
result.append((alt, item.file, keyword))
@@ -1424,7 +1424,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
content: .animation(animationData),
itemFile: itemFile, subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: animationData.isTemplate ? .primary : .none
)
items.append(item)
}
@@ -1742,7 +1742,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
if additionalAnimation == nil && itemNode.item.isCustom {
outer: for attribute in itemNode.item.stillAnimation.attributes {
- if case let .CustomEmoji(_, alt, _) = attribute {
+ if case let .CustomEmoji(_, _, alt, _) = attribute {
if let availableReactions = self.availableReactions {
for availableReaction in availableReactions.reactions {
if availableReaction.value == .builtin(alt) {
diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPackEmojisItem.swift b/submodules/StickerPackPreviewUI/Sources/StickerPackEmojisItem.swift
index 98eca08ff2..60c0471896 100644
--- a/submodules/StickerPackPreviewUI/Sources/StickerPackEmojisItem.swift
+++ b/submodules/StickerPackPreviewUI/Sources/StickerPackEmojisItem.swift
@@ -203,7 +203,7 @@ final class StickerPackEmojisItemNode: GridItemNode {
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
loop: for attribute in file.attributes {
switch attribute {
- case let .CustomEmoji(_, displayText, _):
+ case let .CustomEmoji(_, _, displayText, _):
text = displayText
emojiAttribute = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file)
break loop
@@ -229,7 +229,7 @@ final class StickerPackEmojisItemNode: GridItemNode {
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
loop: for attribute in file.attributes {
switch attribute {
- case let .CustomEmoji(_, displayText, _):
+ case let .CustomEmoji(_, _, displayText, _):
text = displayText
emojiAttribute = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file)
break loop
@@ -354,7 +354,7 @@ final class StickerPackEmojisItemNode: GridItemNode {
} else {
updateItemLayerPlaceholder = true
itemTransition = .immediate
-
+
let animationData = EntityKeyboardAnimationData(file: item.file)
itemLayer = EmojiPagerContentComponent.View.ItemLayer(
item: EmojiPagerContentComponent.Item(
@@ -363,7 +363,7 @@ final class StickerPackEmojisItemNode: GridItemNode {
itemFile: item.file,
subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: animationData.isTemplate ? .primary : .none
),
context: context,
attemptSynchronousLoad: attemptSynchronousLoads,
@@ -425,6 +425,15 @@ final class StickerPackEmojisItemNode: GridItemNode {
self.visibleItemLayers[itemId] = itemLayer
}
+ switch itemLayer.item.tintMode {
+ case .none:
+ break
+ case .accent:
+ itemLayer.layerTintColor = theme.list.itemAccentColor.cgColor
+ case .primary:
+ itemLayer.layerTintColor = theme.list.itemPrimaryTextColor.cgColor
+ }
+
var itemFrame = itemLayout.frame(itemIndex: index)
itemFrame.origin.x += floor((itemFrame.width - itemVisibleFitSize.width) / 2.0)
diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift b/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift
index 0808de4c7d..934129b7f5 100644
--- a/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift
+++ b/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift
@@ -66,7 +66,7 @@ private struct StickerPackPreviewGridTransaction {
let scrollToItem: GridNodeScrollToItem?
init(previousList: [StickerPackPreviewGridEntry], list: [StickerPackPreviewGridEntry], context: AccountContext, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, strings: PresentationStrings, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, scrollToItem: GridNodeScrollToItem?) {
- let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: previousList, rightList: list)
+ let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: previousList, rightList: list)
self.deletions = deleteIndices
self.insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(context: context, interaction: interaction, theme: theme, strings: strings, animationCache: animationCache, animationRenderer: animationRenderer), previousIndex: $0.2) }
diff --git a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift
index eab7c442fe..99f83f6aba 100644
--- a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift
+++ b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift
@@ -112,8 +112,8 @@ func telegramMediaFileAttributesFromApiAttributes(_ attributes: [Api.DocumentAtt
result.append(.Audio(isVoice: isVoice, duration: Int(duration), title: title, performer: performer, waveform: waveformBuffer))
case let .documentAttributeCustomEmoji(flags, alt, stickerSet):
let isFree = (flags & (1 << 0)) != 0
- let paintToText = (flags & (1 << 1)) != 0
- result.append(.CustomEmoji(isPremium: !isFree, paintToText: paintToText, alt: alt, packReference: StickerPackReference(apiInputSet: stickerSet)))
+ let isSingleColor = (flags & (1 << 1)) != 0
+ result.append(.CustomEmoji(isPremium: !isFree, isSingleColor: isSingleColor, alt: alt, packReference: StickerPackReference(apiInputSet: stickerSet)))
}
}
return result
diff --git a/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift b/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift
index b1dff14b48..b15de96770 100644
--- a/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift
+++ b/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift
@@ -29,6 +29,26 @@ public func fetchedMediaResource(mediaBox: MediaBox, reference: MediaResourceRef
return fetchedMediaResource(mediaBox: mediaBox, reference: reference, ranges: range.flatMap({ [$0] }), statsCategory: statsCategory, reportResultStatus: reportResultStatus, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground)
}
+public extension MediaResourceStorageLocation {
+ convenience init?(reference: MediaResourceReference) {
+ switch reference {
+ case let .media(media, _):
+ switch media {
+ case let .message(message, _):
+ if let id = message.id {
+ self.init(peerId: id.peerId, messageId: id)
+ } else {
+ return nil
+ }
+ default:
+ return nil
+ }
+ default:
+ return nil
+ }
+ }
+}
+
public func fetchedMediaResource(mediaBox: MediaBox, reference: MediaResourceReference, ranges: [(Range, MediaBoxFetchPriority)]?, statsCategory: MediaResourceStatsCategory = .generic, reportResultStatus: Bool = false, preferBackgroundReferenceRevalidation: Bool = false, continueInBackground: Bool = false) -> Signal {
var isRandomAccessAllowed = true
switch reference {
@@ -44,14 +64,24 @@ public func fetchedMediaResource(mediaBox: MediaBox, reference: MediaResourceRef
if let ranges = ranges {
let signals = ranges.map { (range, priority) -> Signal in
- return mediaBox.fetchedResourceData(reference.resource, in: range, priority: priority, parameters: MediaResourceFetchParameters(tag: TelegramMediaResourceFetchTag(statsCategory: statsCategory), info: TelegramCloudMediaResourceFetchInfo(reference: reference, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground), isRandomAccessAllowed: isRandomAccessAllowed))
+ return mediaBox.fetchedResourceData(reference.resource, in: range, priority: priority, parameters: MediaResourceFetchParameters(
+ tag: TelegramMediaResourceFetchTag(statsCategory: statsCategory),
+ info: TelegramCloudMediaResourceFetchInfo(reference: reference, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground),
+ location: MediaResourceStorageLocation(reference: reference),
+ isRandomAccessAllowed: isRandomAccessAllowed
+ ))
}
return combineLatest(signals)
|> ignoreValues
|> map { _ -> FetchResourceSourceType in }
|> then(.single(.local))
} else {
- return mediaBox.fetchedResource(reference.resource, parameters: MediaResourceFetchParameters(tag: TelegramMediaResourceFetchTag(statsCategory: statsCategory), info: TelegramCloudMediaResourceFetchInfo(reference: reference, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground), isRandomAccessAllowed: isRandomAccessAllowed), implNext: reportResultStatus)
+ return mediaBox.fetchedResource(reference.resource, parameters: MediaResourceFetchParameters(
+ tag: TelegramMediaResourceFetchTag(statsCategory: statsCategory),
+ info: TelegramCloudMediaResourceFetchInfo(reference: reference, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground),
+ location: MediaResourceStorageLocation(reference: reference),
+ isRandomAccessAllowed: isRandomAccessAllowed
+ ), implNext: reportResultStatus)
}
}
diff --git a/submodules/TelegramCore/Sources/State/Fetch.swift b/submodules/TelegramCore/Sources/State/Fetch.swift
index b6bced6a66..7ec872f6b6 100644
--- a/submodules/TelegramCore/Sources/State/Fetch.swift
+++ b/submodules/TelegramCore/Sources/State/Fetch.swift
@@ -75,7 +75,12 @@ func fetchResource(account: Account, resource: MediaResource, intervals: Signal<
return .fail(.generic)
}
return .single(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: false))
- |> then(fetchCloudMediaLocation(account: account, resource: cloudResource, datacenterId: cloudResource.datacenterId, size: resource.size == 0 ? nil : resource.size, intervals: intervals, parameters: MediaResourceFetchParameters(tag: nil, info: TelegramCloudMediaResourceFetchInfo(reference: .standalone(resource: file.file.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), isRandomAccessAllowed: true)))
+ |> then(fetchCloudMediaLocation(account: account, resource: cloudResource, datacenterId: cloudResource.datacenterId, size: resource.size == 0 ? nil : resource.size, intervals: intervals, parameters: MediaResourceFetchParameters(
+ tag: nil,
+ info: TelegramCloudMediaResourceFetchInfo(reference: .standalone(resource: file.file.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false),
+ location: nil,
+ isRandomAccessAllowed: true
+ )))
}
}
return nil
diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift
index dce8c7ffc7..3f831c4da7 100644
--- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift
+++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift
@@ -190,7 +190,7 @@ public struct TelegramMediaVideoFlags: OptionSet {
public static let supportsStreaming = TelegramMediaVideoFlags(rawValue: 1 << 1)
}
-public struct StickerMaskCoords: PostboxCoding {
+public struct StickerMaskCoords: PostboxCoding, Equatable {
public let n: Int32
public let x: Double
public let y: Double
@@ -218,7 +218,7 @@ public struct StickerMaskCoords: PostboxCoding {
}
}
-public enum TelegramMediaFileAttribute: PostboxCoding {
+public enum TelegramMediaFileAttribute: PostboxCoding, Equatable {
case FileName(fileName: String)
case Sticker(displayText: String, packReference: StickerPackReference?, maskData: StickerMaskCoords?)
case ImageSize(size: PixelDimensions)
@@ -229,7 +229,7 @@ public enum TelegramMediaFileAttribute: PostboxCoding {
case hintFileIsLarge
case hintIsValidated
case NoPremium
- case CustomEmoji(isPremium: Bool, paintToText: Bool, alt: String, packReference: StickerPackReference?)
+ case CustomEmoji(isPremium: Bool, isSingleColor: Bool, alt: String, packReference: StickerPackReference?)
public init(decoder: PostboxDecoder) {
let type: Int32 = decoder.decodeInt32ForKey("t", orElse: 0)
@@ -260,7 +260,7 @@ public enum TelegramMediaFileAttribute: PostboxCoding {
case typeNoPremium:
self = .NoPremium
case typeCustomEmoji:
- self = .CustomEmoji(isPremium: decoder.decodeBoolForKey("ip", orElse: true), paintToText: decoder.decodeBoolForKey("ptt", orElse: false), alt: decoder.decodeStringForKey("dt", orElse: ""), packReference: decoder.decodeObjectForKey("pr", decoder: { StickerPackReference(decoder: $0) }) as? StickerPackReference)
+ self = .CustomEmoji(isPremium: decoder.decodeBoolForKey("ip", orElse: true), isSingleColor: decoder.decodeBoolForKey("sc", orElse: false), alt: decoder.decodeStringForKey("dt", orElse: ""), packReference: decoder.decodeObjectForKey("pr", decoder: { StickerPackReference(decoder: $0) }) as? StickerPackReference)
default:
preconditionFailure()
}
@@ -317,10 +317,10 @@ public enum TelegramMediaFileAttribute: PostboxCoding {
encoder.encodeInt32(typeHintIsValidated, forKey: "t")
case .NoPremium:
encoder.encodeInt32(typeNoPremium, forKey: "t")
- case let .CustomEmoji(isPremium, paintToText, alt, packReference):
+ case let .CustomEmoji(isPremium, isSingleColor, alt, packReference):
encoder.encodeInt32(typeCustomEmoji, forKey: "t")
encoder.encodeBool(isPremium, forKey: "ip")
- encoder.encodeBool(paintToText, forKey: "ptt")
+ encoder.encodeBool(isSingleColor, forKey: "sc")
encoder.encodeString(alt, forKey: "dt")
if let packReference = packReference {
encoder.encodeObject(packReference, forKey: "pr")
@@ -738,6 +738,10 @@ public final class TelegramMediaFile: Media, Equatable, Codable {
return false
}
+ if self.attributes != other.attributes {
+ return false
+ }
+
return true
}
diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift b/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift
index cc1e9fe5fc..8a48c5f4a7 100644
--- a/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift
+++ b/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift
@@ -53,6 +53,203 @@ private final class CacheUsageStatsState {
}
func _internal_collectCacheUsageStats(account: Account, peerId: PeerId? = nil, additionalCachePaths: [String] = [], logFilesPath: String? = nil) -> Signal {
+ if "".isEmpty {
+ return account.postbox.mediaBox.collectAllResourceUsage()
+ |> mapToSignal { resourceList -> Signal in
+ return account.postbox.mediaBox.storageBox.get(ids: resourceList.compactMap { item -> Data? in
+ return item.id?.data(using: .utf8)
+ })
+ |> mapToSignal { entries -> Signal in
+ return account.postbox.transaction { transaction -> CacheUsageStatsResult in
+ var media: [PeerId: [PeerCacheUsageCategory: [MediaId: Int64]]] = [:]
+ var mediaResourceIds: [MediaId: [MediaResourceId]] = [:]
+
+ media.removeAll()
+ mediaResourceIds.removeAll()
+
+ let mediaBox = account.postbox.mediaBox
+
+ var totalSize: Int64 = 0
+ var mediaSize: Int64 = 0
+
+ var processedResourceIds = Set()
+
+ for entry in entries {
+ let resourceId = MediaResourceId(String(data: entry.id, encoding: .utf8)!)
+ let resourceSize = mediaBox.resourceUsage(id: resourceId)
+ if resourceSize != 0 {
+ totalSize += resourceSize
+
+ for reference in entry.references {
+ if let message = transaction.getMessage(MessageId(peerId: reference.peerId, namespace: MessageId.Namespace(reference.messageNamespace), id: reference.messageId)) {
+ for mediaItem in message.media {
+ guard let mediaId = mediaItem.id else {
+ continue
+ }
+ var category: PeerCacheUsageCategory?
+ if let _ = mediaItem as? TelegramMediaImage {
+ category = .image
+ } else if let mediaItem = mediaItem as? TelegramMediaFile {
+ if mediaItem.isMusic || mediaItem.isVoice {
+ category = .audio
+ } else if mediaItem.isVideo {
+ category = .video
+ } else {
+ category = .file
+ }
+ }
+ if let category = category {
+ mediaSize += resourceSize
+ processedResourceIds.insert(resourceId.stringRepresentation)
+
+ media[reference.peerId, default: [:]][category, default: [:]][mediaId, default: 0] += resourceSize
+ if let index = mediaResourceIds.index(forKey: mediaId) {
+ if !mediaResourceIds[index].value.contains(resourceId) {
+ mediaResourceIds[mediaId]?.append(resourceId)
+ }
+ } else {
+ mediaResourceIds[mediaId] = [resourceId]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ var peers: [PeerId: Peer] = [:]
+ for peerId in media.keys {
+ if let peer = transaction.getPeer(peerId) {
+ peers[peer.id] = peer
+ }
+ }
+
+ var tempPaths: [String] = []
+ var tempSize: Int64 = 0
+ #if os(iOS)
+ if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: NSTemporaryDirectory()), includingPropertiesForKeys: [.isDirectoryKey, .fileAllocatedSizeKey, .isSymbolicLinkKey]) {
+ for url in enumerator {
+ if let url = url as? URL {
+ if let isDirectoryValue = (try? url.resourceValues(forKeys: Set([.isDirectoryKey])))?.isDirectory, isDirectoryValue {
+ tempPaths.append(url.path)
+ } else if let fileSizeValue = (try? url.resourceValues(forKeys: Set([.fileAllocatedSizeKey])))?.fileAllocatedSize {
+ tempPaths.append(url.path)
+
+ if let isSymbolicLinkValue = (try? url.resourceValues(forKeys: Set([.isSymbolicLinkKey])))?.isSymbolicLink, isSymbolicLinkValue {
+ } else {
+ tempSize += Int64(fileSizeValue)
+ }
+ }
+ }
+ }
+ }
+ #endif
+
+ var immutableSize: Int64 = 0
+ if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: account.basePath + "/postbox/db"), includingPropertiesForKeys: [URLResourceKey.fileSizeKey], options: []) {
+ for url in files {
+ if let fileSize = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize {
+ immutableSize += Int64(fileSize)
+ }
+ }
+ }
+ if let logFilesPath = logFilesPath, let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: logFilesPath), includingPropertiesForKeys: [URLResourceKey.fileSizeKey], options: []) {
+ for url in files {
+ if let fileSize = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize {
+ immutableSize += Int64(fileSize)
+ }
+ }
+ }
+
+ for additionalPath in additionalCachePaths {
+ if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: additionalPath), includingPropertiesForKeys: [.isDirectoryKey, .fileAllocatedSizeKey, .isSymbolicLinkKey]) {
+ for url in enumerator {
+ if let url = url as? URL {
+ if let isDirectoryValue = (try? url.resourceValues(forKeys: Set([.isDirectoryKey])))?.isDirectory, isDirectoryValue {
+ } else if let fileSizeValue = (try? url.resourceValues(forKeys: Set([.fileAllocatedSizeKey])))?.fileAllocatedSize {
+ tempPaths.append(url.path)
+
+ if let isSymbolicLinkValue = (try? url.resourceValues(forKeys: Set([.isSymbolicLinkKey])))?.isSymbolicLink, isSymbolicLinkValue {
+ } else {
+ tempSize += Int64(fileSizeValue)
+ }
+ }
+ }
+ }
+ }
+ }
+
+ var otherSize: Int64 = 0
+ var otherPaths: [String] = []
+
+ for (id, name, size) in resourceList {
+ if size == 0 {
+ continue
+ }
+ if let id = id, processedResourceIds.contains(id) {
+ continue
+ }
+ otherSize += size
+ otherPaths.append(name)
+ }
+
+ var cacheSize: Int64 = 0
+ let basePath = account.postbox.mediaBox.basePath
+ if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: basePath + "/cache"), includingPropertiesForKeys: [.fileSizeKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) {
+ loop: for url in enumerator {
+ if let url = url as? URL {
+ if let value = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize, value != 0 {
+ otherPaths.append("cache/" + url.lastPathComponent)
+ cacheSize += Int64(value)
+ }
+ }
+ }
+ }
+
+ func processRecursive(directoryPath: String, subdirectoryPath: String) {
+ if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: directoryPath), includingPropertiesForKeys: [.fileSizeKey, .isDirectoryKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) {
+ loop: for url in enumerator {
+ if let url = url as? URL {
+ if let isDirectory = (try? url.resourceValues(forKeys: Set([.isDirectoryKey])))?.isDirectory, isDirectory {
+ processRecursive(directoryPath: url.path, subdirectoryPath: subdirectoryPath + "/\(url.lastPathComponent)")
+ } else if let value = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize, value != 0 {
+ otherPaths.append("\(subdirectoryPath)/" + url.lastPathComponent)
+ cacheSize += Int64(value)
+ }
+ }
+ }
+ }
+ }
+
+ processRecursive(directoryPath: basePath + "/animation-cache", subdirectoryPath: "animation-cache")
+
+ if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: basePath + "/short-cache"), includingPropertiesForKeys: [.fileSizeKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) {
+ loop: for url in enumerator {
+ if let url = url as? URL {
+ if let value = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize, value != 0 {
+ otherPaths.append("short-cache/" + url.lastPathComponent)
+ cacheSize += Int64(value)
+ }
+ }
+ }
+ }
+
+ return .result(CacheUsageStats(
+ media: media,
+ mediaResourceIds: mediaResourceIds,
+ peers: peers,
+ otherSize: otherSize,
+ otherPaths: otherPaths,
+ cacheSize: 0,
+ tempPaths: tempPaths,
+ tempSize: tempSize,
+ immutableSize: immutableSize
+ ))
+ }
+ }
+ }
+ }
+
let initialState = CacheUsageStatsState()
if let peerId = peerId {
initialState.lowerBound = MessageIndex.lowerBound(peerId: peerId)
@@ -277,7 +474,8 @@ func _internal_collectCacheUsageStats(account: Account, peerId: PeerId? = nil, a
let signal = (fetch |> mapToSignal { mediaByPeer, mediaRefs, updatedLowerBound -> Signal in
return process(mediaByPeer, mediaRefs, updatedLowerBound)
- }) |> restart
+ })
+ |> restart
return signal |> `catch` { error in
switch error {
diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Resources/TelegramEngineResources.swift b/submodules/TelegramCore/Sources/TelegramEngine/Resources/TelegramEngineResources.swift
index 82e7fd11e1..dbf3f6febf 100644
--- a/submodules/TelegramCore/Sources/TelegramEngine/Resources/TelegramEngineResources.swift
+++ b/submodules/TelegramCore/Sources/TelegramEngine/Resources/TelegramEngineResources.swift
@@ -293,6 +293,7 @@ public extension TelegramEngine {
preferBackgroundReferenceRevalidation: false,
continueInBackground: false
),
+ location: nil,
isRandomAccessAllowed: true
))
|> map { result -> EngineMediaResource.Fetch.Result in
diff --git a/submodules/TelegramUI/Components/EmojiStatusComponent/Sources/EmojiStatusComponent.swift b/submodules/TelegramUI/Components/EmojiStatusComponent/Sources/EmojiStatusComponent.swift
index 1f962744bf..bf2fbcb135 100644
--- a/submodules/TelegramUI/Components/EmojiStatusComponent/Sources/EmojiStatusComponent.swift
+++ b/submodules/TelegramUI/Components/EmojiStatusComponent/Sources/EmojiStatusComponent.swift
@@ -442,7 +442,10 @@ public final class EmojiStatusComponent: Component {
var accentTint = false
if let _ = emojiThemeColor {
for attribute in emojiFile.attributes {
- if case let .CustomEmoji(_, _, packReference) = attribute {
+ if case let .CustomEmoji(_, isSingleColor, _, packReference) = attribute {
+ if isSingleColor {
+ accentTint = true
+ }
switch packReference {
case let .id(id, _):
if id == 773947703670341676 || id == 2964141614563343 {
@@ -456,8 +459,10 @@ public final class EmojiStatusComponent: Component {
}
if accentTint {
animationLayer.contentTintColor = emojiThemeColor
+ animationLayer.dynamicColor = emojiThemeColor
} else {
animationLayer.contentTintColor = nil
+ animationLayer.dynamicColor = nil
}
animationLayer.frame = CGRect(origin: CGPoint(), size: size)
diff --git a/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift b/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift
index dc34157515..d20bbd009d 100644
--- a/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift
+++ b/submodules/TelegramUI/Components/EmojiStatusSelectionComponent/Sources/EmojiStatusSelectionComponent.swift
@@ -329,7 +329,7 @@ public final class EmojiStatusSelectionController: ViewController {
for item in featuredEmojiPack.topItems {
for attribute in item.file.attributes {
switch attribute {
- case let .CustomEmoji(_, alt, _):
+ case let .CustomEmoji(_, _, alt, _):
if filterList.contains(alt) {
filteredFiles.append(item.file)
}
@@ -487,7 +487,7 @@ public final class EmojiStatusSelectionController: ViewController {
}
for attribute in item.file.attributes {
switch attribute {
- case let .CustomEmoji(_, alt, _):
+ case let .CustomEmoji(_, _, alt, _):
if !item.file.isPremiumEmoji || hasPremium {
if !alt.isEmpty, let keyword = allEmoticons[alt] {
result.append((alt, item.file, keyword))
@@ -516,7 +516,7 @@ public final class EmojiStatusSelectionController: ViewController {
content: .animation(animationData),
itemFile: itemFile, subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: animationData.isTemplate ? .primary : .none
)
items.append(item)
}
@@ -645,7 +645,10 @@ public final class EmojiStatusSelectionController: ViewController {
} else if let itemFile = item.itemFile {
var useCleanEffect = false
for attribute in itemFile.attributes {
- if case let .CustomEmoji(_, _, packReference) = attribute {
+ if case let .CustomEmoji(_, isSingleColor, _, packReference) = attribute {
+ if isSingleColor {
+ useCleanEffect = true
+ }
switch packReference {
case let .id(id, _):
if id == 773947703670341676 || id == 2964141614563343 {
@@ -692,8 +695,13 @@ public final class EmojiStatusSelectionController: ViewController {
placeholderColor: UIColor(white: 0.0, alpha: 0.0),
pointSize: CGSize(width: 32.0, height: 32.0)
)
- if item.accentTint {
+ switch item.tintMode {
+ case .accent:
baseItemLayer.contentTintColor = self.presentationData.theme.list.itemAccentColor
+ case .primary:
+ baseItemLayer.contentTintColor = self.presentationData.theme.list.itemPrimaryTextColor
+ case .none:
+ break
}
if let sublayers = animationLayer.sublayers {
@@ -1001,7 +1009,7 @@ public final class EmojiStatusSelectionController: ViewController {
if let itemFile = previewItem.item.itemFile {
attributeLoop: for attribute in itemFile.attributes {
switch attribute {
- case let .CustomEmoji(_, alt, _):
+ case let .CustomEmoji(_, _, alt, _):
emojiString = alt
break attributeLoop
default:
@@ -1165,7 +1173,7 @@ public final class EmojiStatusSelectionController: ViewController {
if let itemFile = item.itemFile {
attributeLoop: for attribute in itemFile.attributes {
switch attribute {
- case let .CustomEmoji(_, alt, _):
+ case let .CustomEmoji(_, _, alt, _):
emojiString = alt
break attributeLoop
default:
diff --git a/submodules/TelegramUI/Components/EmojiSuggestionsComponent/Sources/EmojiSuggestionsComponent.swift b/submodules/TelegramUI/Components/EmojiSuggestionsComponent/Sources/EmojiSuggestionsComponent.swift
index 7f928927f1..f79dadb7a6 100644
--- a/submodules/TelegramUI/Components/EmojiSuggestionsComponent/Sources/EmojiSuggestionsComponent.swift
+++ b/submodules/TelegramUI/Components/EmojiSuggestionsComponent/Sources/EmojiSuggestionsComponent.swift
@@ -59,7 +59,7 @@ public final class EmojiSuggestionsComponent: Component {
}
for attribute in item.file.attributes {
switch attribute {
- case let .CustomEmoji(_, alt, _):
+ case let .CustomEmoji(_, _, alt, _):
if alt == query || (!normalizedQuery.isEmpty && alt == normalizedQuery) {
if !item.file.isPremiumEmoji || hasPremium {
if !existingIds.contains(item.file.fileId) {
@@ -78,7 +78,7 @@ public final class EmojiSuggestionsComponent: Component {
for item in featuredPack.topItems {
for attribute in item.file.attributes {
switch attribute {
- case let .CustomEmoji(_, alt, _):
+ case let .CustomEmoji(_, _, alt, _):
if alt == query || (!normalizedQuery.isEmpty && alt == normalizedQuery) {
if !item.file.isPremiumEmoji || hasPremium {
if !existingIds.contains(item.file.fileId) {
diff --git a/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift b/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift
index adcf94e737..4a3215b924 100644
--- a/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift
+++ b/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift
@@ -96,7 +96,7 @@ public extension AnimationCacheAnimationType {
}
}
-public func animationCacheFetchFile(context: AccountContext, resource: MediaResourceReference, type: AnimationCacheAnimationType, keyframeOnly: Bool) -> (AnimationCacheFetchOptions) -> Disposable {
+public func animationCacheFetchFile(context: AccountContext, resource: MediaResourceReference, type: AnimationCacheAnimationType, keyframeOnly: Bool, customColor: UIColor?) -> (AnimationCacheFetchOptions) -> Disposable {
return { options in
let source = AnimatedStickerResourceSource(account: context.account, resource: resource.resource, fitzModifier: nil, isVideo: false)
@@ -107,15 +107,15 @@ public func animationCacheFetchFile(context: AccountContext, resource: MediaReso
switch type {
case .video:
- cacheVideoAnimation(path: result, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, firstFrameOnly: options.firstFrameOnly)
+ cacheVideoAnimation(path: result, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, firstFrameOnly: options.firstFrameOnly, customColor: customColor)
case .lottie:
guard let data = try? Data(contentsOf: URL(fileURLWithPath: result)) else {
options.writer.finish()
return
}
- cacheLottieAnimation(data: data, width: Int(options.size.width), height: Int(options.size.height), keyframeOnly: keyframeOnly, writer: options.writer, firstFrameOnly: options.firstFrameOnly)
+ cacheLottieAnimation(data: data, width: Int(options.size.width), height: Int(options.size.height), keyframeOnly: keyframeOnly, writer: options.writer, firstFrameOnly: options.firstFrameOnly, customColor: customColor)
case .still:
- cacheStillSticker(path: result, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer)
+ cacheStillSticker(path: result, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, customColor: customColor)
}
})
@@ -153,6 +153,7 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
private let pixelSize: CGSize
private var isDisplayingPlaceholder: Bool = false
+ private var didProcessTintColor: Bool = false
public private(set) var file: TelegramMediaFile?
private var infoDisposable: Disposable?
@@ -168,6 +169,14 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
}
}
+ public var dynamicColor: UIColor? {
+ didSet {
+ if self.dynamicColor != oldValue {
+ self.updateTintColor()
+ }
+ }
+ }
+
private var currentLoopCount: Int = 0
private var isInHierarchyValue: Bool = false
@@ -179,13 +188,14 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
}
}
- public init(context: AccountContext, attemptSynchronousLoad: Bool, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, unique: Bool = false, placeholderColor: UIColor, pointSize: CGSize, loopCount: Int? = nil) {
+ public init(context: AccountContext, attemptSynchronousLoad: Bool, emoji: ChatTextInputTextCustomEmojiAttribute, file: TelegramMediaFile?, cache: AnimationCache, renderer: MultiAnimationRenderer, unique: Bool = false, placeholderColor: UIColor, pointSize: CGSize, dynamicColor: UIColor? = nil, loopCount: Int? = nil) {
self.context = context
self.emoji = emoji
self.cache = cache
self.renderer = renderer
self.unique = unique
self.placeholderColor = placeholderColor
+ self.dynamicColor = dynamicColor
self.loopCount = loopCount
let scale = min(2.0, UIScreenScale)
@@ -239,7 +249,18 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
private func updateTintColor() {
if !self.isDisplayingPlaceholder {
- self.layerTintColor = self.contentTintColor?.cgColor
+ var customColor = self.contentTintColor
+ if let file = self.file {
+ for attribute in file.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ if isSingleColor {
+ customColor = self.dynamicColor
+ }
+ }
+ }
+ }
+
+ self.layerTintColor = customColor?.cgColor
} else {
self.layerTintColor = nil
}
@@ -311,10 +332,17 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
self.loadAnimation()
} else {
+ var isTemplate = false
+ for attribute in file.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ isTemplate = isSingleColor
+ }
+ }
+
let pointSize = self.pointSize
let placeholderColor = self.placeholderColor
let isThumbnailCancelled = Atomic(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
+ 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, customColor: isTemplate ? .white : nil), 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)
@@ -350,11 +378,18 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
return
}
+ var isTemplate = false
+ for attribute in file.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ isTemplate = isSingleColor
+ }
+ }
+
let context = self.context
if file.isAnimatedSticker || file.isVideoEmoji {
let keyframeOnly = self.pixelSize.width >= 120.0
- self.disposable = renderer.add(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, unique: self.unique, size: self.pixelSize, fetch: animationCacheFetchFile(context: context, resource: .media(media: .standalone(media: file), resource: file.resource), type: AnimationCacheAnimationType(file: file), keyframeOnly: keyframeOnly))
+ self.disposable = renderer.add(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, unique: self.unique, size: self.pixelSize, fetch: animationCacheFetchFile(context: context, resource: .media(media: .standalone(media: file), resource: file.resource), type: AnimationCacheAnimationType(file: file), keyframeOnly: keyframeOnly, customColor: isTemplate ? .white : nil))
} else {
self.disposable = renderer.add(target: self, cache: self.cache, itemId: file.resource.id.stringRepresentation, unique: self.unique, size: self.pixelSize, fetch: { options in
let dataDisposable = context.account.postbox.mediaBox.resourceData(file.resource).start(next: { result in
@@ -362,7 +397,7 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
return
}
- cacheStillSticker(path: result.path, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer)
+ cacheStillSticker(path: result.path, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, customColor: isTemplate ? .white : nil)
})
let fetchDisposable = freeMediaFileResourceInteractiveFetched(account: context.account, fileReference: .customEmoji(media: file), resource: file.resource).start()
@@ -405,6 +440,10 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
self.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
} else {
+ if !self.didProcessTintColor {
+ //self.didProcessTintColor = true
+ self.updateTintColor()
+ }
self.contents = contents
}
@@ -433,6 +472,10 @@ public final class EmojiTextAttachmentView: UIView {
fatalError("init(coder:) has not been implemented")
}
+ public func updateTextColor(_ textColor: UIColor) {
+ self.contentLayer.dynamicColor = textColor
+ }
+
override public func layoutSubviews() {
super.layoutSubviews()
diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift
index dde1f64f95..6421a421b7 100644
--- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift
+++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift
@@ -222,14 +222,16 @@ public final class EntityKeyboardAnimationData: Equatable {
public let dimensions: CGSize
public let immediateThumbnailData: Data?
public let isReaction: Bool
+ public let isTemplate: Bool
- public init(id: Id, type: ItemType, resource: MediaResourceReference, dimensions: CGSize, immediateThumbnailData: Data?, isReaction: Bool) {
+ public init(id: Id, type: ItemType, resource: MediaResourceReference, dimensions: CGSize, immediateThumbnailData: Data?, isReaction: Bool, isTemplate: Bool) {
self.id = id
self.type = type
self.resource = resource
self.dimensions = dimensions
self.immediateThumbnailData = immediateThumbnailData
self.isReaction = isReaction
+ self.isTemplate = isTemplate
}
public convenience init(file: TelegramMediaFile, isReaction: Bool = false) {
@@ -241,7 +243,13 @@ public final class EntityKeyboardAnimationData: Equatable {
} else {
type = .still
}
- self.init(id: .file(file.fileId), type: type, resource: .standalone(resource: file.resource), dimensions: file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0), immediateThumbnailData: file.immediateThumbnailData, isReaction: isReaction)
+ var isTemplate = false
+ for attribute in file.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ isTemplate = isSingleColor
+ }
+ }
+ self.init(id: .file(file.fileId), type: type, resource: .standalone(resource: file.resource), dimensions: file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0), immediateThumbnailData: file.immediateThumbnailData, isReaction: isReaction, isTemplate: isTemplate)
}
public static func ==(lhs: EntityKeyboardAnimationData, rhs: EntityKeyboardAnimationData) -> Bool {
@@ -2201,12 +2209,18 @@ public final class EmojiPagerContentComponent: Component {
case premium
}
+ public enum TintMode {
+ case none
+ case accent
+ case primary
+ }
+
public let animationData: EntityKeyboardAnimationData?
public let content: ItemContent
public let itemFile: TelegramMediaFile?
public let subgroupId: Int32?
public let icon: Icon
- public let accentTint: Bool
+ public let tintMode: TintMode
public init(
animationData: EntityKeyboardAnimationData?,
@@ -2214,14 +2228,14 @@ public final class EmojiPagerContentComponent: Component {
itemFile: TelegramMediaFile?,
subgroupId: Int32?,
icon: Icon,
- accentTint: Bool
+ tintMode: TintMode
) {
self.animationData = animationData
self.content = content
self.itemFile = itemFile
self.subgroupId = subgroupId
self.icon = icon
- self.accentTint = accentTint
+ self.tintMode = tintMode
}
public static func ==(lhs: Item, rhs: Item) -> Bool {
@@ -2243,7 +2257,7 @@ public final class EmojiPagerContentComponent: Component {
if lhs.icon != rhs.icon {
return false
}
- if lhs.accentTint != rhs.accentTint {
+ if lhs.tintMode != rhs.tintMode {
return false
}
@@ -2894,14 +2908,14 @@ public final class EmojiPagerContentComponent: Component {
return
}
- strongSelf.disposable = renderer.add(target: strongSelf, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, unique: false, size: pixelSize, fetch: animationCacheFetchFile(context: context, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: pixelSize.width >= 120.0))
+ strongSelf.disposable = renderer.add(target: strongSelf, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, unique: false, size: pixelSize, fetch: animationCacheFetchFile(context: context, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: pixelSize.width >= 120.0, customColor: animationData.isTemplate ? .white : nil))
}
if attemptSynchronousLoad {
if !renderer.loadFirstFrameSynchronously(target: self, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, size: pixelSize) {
self.updateDisplayPlaceholder(displayPlaceholder: true)
- self.fetchDisposable = renderer.loadFirstFrame(target: self, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, size: pixelSize, fetch: animationCacheFetchFile(context: context, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: true), completion: { [weak self] success, isFinal in
+ self.fetchDisposable = renderer.loadFirstFrame(target: self, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, size: pixelSize, fetch: animationCacheFetchFile(context: context, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: true, customColor: animationData.isTemplate ? .white : nil), completion: { [weak self] success, isFinal in
if !isFinal {
if !success {
Queue.mainQueue().async {
@@ -2931,7 +2945,7 @@ public final class EmojiPagerContentComponent: Component {
loadAnimation()
}
} else {
- self.fetchDisposable = renderer.loadFirstFrame(target: self, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, size: pixelSize, fetch: animationCacheFetchFile(context: context, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: true), completion: { [weak self] success, isFinal in
+ self.fetchDisposable = renderer.loadFirstFrame(target: self, cache: cache, itemId: animationData.resource.resource.id.stringRepresentation, size: pixelSize, fetch: animationCacheFetchFile(context: context, resource: animationData.resource, type: animationData.type.animationCacheAnimationType, keyframeOnly: true, customColor: animationData.isTemplate ? .white : nil), completion: { [weak self] success, isFinal in
if !isFinal {
if !success {
Queue.mainQueue().async {
@@ -5337,9 +5351,12 @@ public final class EmojiPagerContentComponent: Component {
itemLayer.update(transition: transition, size: itemFrame.size, badge: badge, blurredBadgeColor: UIColor(white: 0.0, alpha: 0.1), blurredBadgeBackgroundColor: keyboardChildEnvironment.theme.list.plainBackgroundColor)
- if item.accentTint {
+ switch item.tintMode {
+ case .accent:
itemLayer.layerTintColor = keyboardChildEnvironment.theme.list.itemAccentColor.cgColor
- } else {
+ case .primary:
+ itemLayer.layerTintColor = keyboardChildEnvironment.theme.list.itemPrimaryTextColor.cgColor
+ case .none:
itemLayer.layerTintColor = nil
}
@@ -5373,7 +5390,7 @@ public final class EmojiPagerContentComponent: Component {
self.visibleItemSelectionLayers[itemId] = itemSelectionLayer
}
- if item.accentTint {
+ if case .accent = item.tintMode {
itemSelectionLayer.backgroundColor = keyboardChildEnvironment.theme.list.itemAccentColor.withMultipliedAlpha(0.1).cgColor
itemSelectionLayer.tintContainerLayer.backgroundColor = UIColor.clear.cgColor
} else {
@@ -6392,7 +6409,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: nil,
subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: .none
)
let groupId = "recent"
@@ -6411,13 +6428,16 @@ public final class EmojiPagerContentComponent: Component {
}
existingIds.insert(file.fileId)
- var accentTint = false
+ var tintMode: Item.TintMode = .none
for attribute in file.attributes {
- if case let .CustomEmoji(_, _, packReference) = attribute {
+ if case let .CustomEmoji(_, isSingleColor, _, packReference) = attribute {
+ if isSingleColor {
+ tintMode = .accent
+ }
switch packReference {
case let .id(id, _):
if id == 773947703670341676 || id == 2964141614563343 {
- accentTint = true
+ tintMode = .accent
}
default:
break
@@ -6434,7 +6454,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: file,
subgroupId: nil,
icon: .none,
- accentTint: accentTint
+ tintMode: tintMode
)
if let groupIndex = itemGroupIndexById[groupId] {
@@ -6448,7 +6468,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: nil,
subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: .none
)
let groupId = "recent"
@@ -6467,13 +6487,16 @@ public final class EmojiPagerContentComponent: Component {
}
existingIds.insert(file.fileId)
- var accentTint = false
+ var tintMode: Item.TintMode = .none
for attribute in file.attributes {
- if case let .CustomEmoji(_, _, packReference) = attribute {
+ if case let .CustomEmoji(_, isSingleColor, _, packReference) = attribute {
+ if isSingleColor {
+ tintMode = .accent
+ }
switch packReference {
case let .id(id, _):
if id == 773947703670341676 || id == 2964141614563343 {
- accentTint = true
+ tintMode = .accent
}
default:
break
@@ -6490,7 +6513,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: file,
subgroupId: nil,
icon: .none,
- accentTint: accentTint
+ tintMode: tintMode
)
if let groupIndex = itemGroupIndexById[groupId] {
@@ -6510,13 +6533,16 @@ public final class EmojiPagerContentComponent: Component {
}
existingIds.insert(file.fileId)
- var accentTint = false
+ var tintMode: Item.TintMode = .none
for attribute in file.attributes {
- if case let .CustomEmoji(_, _, packReference) = attribute {
+ if case let .CustomEmoji(_, isSingleColor, _, packReference) = attribute {
+ if isSingleColor {
+ tintMode = .accent
+ }
switch packReference {
case let .id(id, _):
if id == 773947703670341676 || id == 2964141614563343 {
- accentTint = true
+ tintMode = .accent
}
default:
break
@@ -6533,7 +6559,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: file,
subgroupId: nil,
icon: .none,
- accentTint: accentTint
+ tintMode: tintMode
)
if let groupIndex = itemGroupIndexById[groupId] {
@@ -6559,13 +6585,16 @@ public final class EmojiPagerContentComponent: Component {
let resultItem: EmojiPagerContentComponent.Item
- var accentTint = false
+ var tintMode: Item.TintMode = .none
for attribute in file.attributes {
- if case let .CustomEmoji(_, _, packReference) = attribute {
+ if case let .CustomEmoji(_, isSingleColor, _, packReference) = attribute {
+ if isSingleColor {
+ tintMode = .accent
+ }
switch packReference {
case let .id(id, _):
if id == 773947703670341676 || id == 2964141614563343 {
- accentTint = true
+ tintMode = .accent
}
default:
break
@@ -6580,7 +6609,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: file,
subgroupId: nil,
icon: .none,
- accentTint: accentTint
+ tintMode: tintMode
)
if let groupIndex = itemGroupIndexById[groupId] {
@@ -6637,6 +6666,15 @@ public final class EmojiPagerContentComponent: Component {
icon = .none
}
+ var tintMode: Item.TintMode = .none
+ for attribute in reactionItem.file.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ if isSingleColor {
+ tintMode = .primary
+ }
+ }
+ }
+
let animationFile = reactionItem.file
let animationData = EntityKeyboardAnimationData(file: animationFile, isReaction: true)
let resultItem = EmojiPagerContentComponent.Item(
@@ -6645,7 +6683,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: animationFile,
subgroupId: nil,
icon: icon,
- accentTint: false
+ tintMode: tintMode
)
let groupId = "recent"
@@ -6692,6 +6730,15 @@ public final class EmojiPagerContentComponent: Component {
icon = .none
}
+ var tintMode: Item.TintMode = .none
+ for attribute in reactionItem.selectAnimation.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ if isSingleColor {
+ tintMode = .primary
+ }
+ }
+ }
+
let animationFile = reactionItem.selectAnimation
let animationData = EntityKeyboardAnimationData(file: animationFile, isReaction: true)
let resultItem = EmojiPagerContentComponent.Item(
@@ -6700,7 +6747,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: animationFile,
subgroupId: nil,
icon: icon,
- accentTint: false
+ tintMode: tintMode
)
if hasPremium {
@@ -6768,6 +6815,15 @@ public final class EmojiPagerContentComponent: Component {
}
}
+ var tintMode: Item.TintMode = .none
+ for attribute in animationFile.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ if isSingleColor {
+ tintMode = .primary
+ }
+ }
+ }
+
let animationData = EntityKeyboardAnimationData(file: animationFile, isReaction: true)
let resultItem = EmojiPagerContentComponent.Item(
animationData: animationData,
@@ -6775,7 +6831,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: animationFile,
subgroupId: nil,
icon: icon,
- accentTint: false
+ tintMode: tintMode
)
let groupId = "popular"
@@ -6811,6 +6867,15 @@ public final class EmojiPagerContentComponent: Component {
let resultItem: EmojiPagerContentComponent.Item
switch item.content {
case let .file(file):
+ var tintMode: Item.TintMode = .none
+ for attribute in file.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ if isSingleColor {
+ tintMode = .primary
+ }
+ }
+ }
+
let animationData = EntityKeyboardAnimationData(file: file)
resultItem = EmojiPagerContentComponent.Item(
animationData: animationData,
@@ -6818,7 +6883,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: file,
subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: tintMode
)
case let .text(text):
resultItem = EmojiPagerContentComponent.Item(
@@ -6827,7 +6892,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: nil,
subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: .none
)
}
@@ -6857,6 +6922,19 @@ public final class EmojiPagerContentComponent: Component {
icon = .locked
}
+ var tintMode: Item.TintMode = .none
+ for attribute in item.file.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ if isSingleColor {
+ if isStatusSelection {
+ tintMode = .accent
+ } else {
+ tintMode = .primary
+ }
+ }
+ }
+ }
+
let animationData = EntityKeyboardAnimationData(file: item.file)
let resultItem = EmojiPagerContentComponent.Item(
animationData: animationData,
@@ -6864,7 +6942,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: item.file,
subgroupId: nil,
icon: icon,
- accentTint: false
+ tintMode: tintMode
)
let supergroupId = entry.index.collectionId
@@ -6900,7 +6978,8 @@ public final class EmojiPagerContentComponent: Component {
resource: .stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource),
dimensions: thumbnail.dimensions.cgSize,
immediateThumbnailData: info.immediateThumbnailData,
- isReaction: false
+ isReaction: false,
+ isTemplate: false
)
}
@@ -6918,6 +6997,19 @@ public final class EmojiPagerContentComponent: Component {
}
for item in featuredEmojiPack.topItems {
+ var tintMode: Item.TintMode = .none
+ for attribute in item.file.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ if isSingleColor {
+ if isStatusSelection {
+ tintMode = .accent
+ } else {
+ tintMode = .primary
+ }
+ }
+ }
+ }
+
let animationData = EntityKeyboardAnimationData(file: item.file)
let resultItem = EmojiPagerContentComponent.Item(
animationData: animationData,
@@ -6925,7 +7017,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: item.file,
subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: tintMode
)
let supergroupId = featuredEmojiPack.info.id
@@ -6959,7 +7051,8 @@ public final class EmojiPagerContentComponent: Component {
resource: .stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource),
dimensions: thumbnail.dimensions.cgSize,
immediateThumbnailData: info.immediateThumbnailData,
- isReaction: false
+ isReaction: false,
+ isTemplate: false
)
}
@@ -6980,7 +7073,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: nil,
subgroupId: subgroupId.rawValue,
icon: .none,
- accentTint: false
+ tintMode: .none
)
if let groupIndex = itemGroupIndexById[groupId] {
@@ -7190,19 +7283,29 @@ public final class EmojiPagerContentComponent: Component {
resource: .stickerPackThumbnail(stickerPack: .id(id: featuredStickerPack.info.id.id, accessHash: featuredStickerPack.info.accessHash), resource: thumbnail.resource),
dimensions: thumbnail.dimensions.cgSize,
immediateThumbnailData: featuredStickerPack.info.immediateThumbnailData,
- isReaction: false
+ isReaction: false,
+ isTemplate: false
)
} else {
animationData = EntityKeyboardAnimationData(file: item.file)
}
+ var tintMode: Item.TintMode = .none
+ for attribute in item.file.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ if isSingleColor {
+ tintMode = .primary
+ }
+ }
+ }
+
let resultItem = EmojiPagerContentComponent.Item(
animationData: animationData,
content: .animation(animationData),
itemFile: item.file,
subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: tintMode
)
let supergroupId = "featuredTop"
@@ -7233,6 +7336,15 @@ public final class EmojiPagerContentComponent: Component {
continue
}
+ var tintMode: Item.TintMode = .none
+ for attribute in item.file.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ if isSingleColor {
+ tintMode = .primary
+ }
+ }
+ }
+
let animationData = EntityKeyboardAnimationData(file: item.file)
let resultItem = EmojiPagerContentComponent.Item(
animationData: animationData,
@@ -7240,7 +7352,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: item.file,
subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: tintMode
)
let groupId = "saved"
@@ -7262,6 +7374,15 @@ public final class EmojiPagerContentComponent: Component {
continue
}
+ var tintMode: Item.TintMode = .none
+ for attribute in item.media.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ if isSingleColor {
+ tintMode = .primary
+ }
+ }
+ }
+
let animationData = EntityKeyboardAnimationData(file: item.media)
let resultItem = EmojiPagerContentComponent.Item(
animationData: animationData,
@@ -7269,7 +7390,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: item.media,
subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: tintMode
)
let groupId = "recent"
@@ -7314,6 +7435,15 @@ public final class EmojiPagerContentComponent: Component {
}
processedIds.insert(item.file.fileId)
+ var tintMode: Item.TintMode = .none
+ for attribute in item.file.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ if isSingleColor {
+ tintMode = .primary
+ }
+ }
+ }
+
let animationData = EntityKeyboardAnimationData(file: item.file)
let resultItem = EmojiPagerContentComponent.Item(
animationData: animationData,
@@ -7321,7 +7451,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: item.file,
subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: tintMode
)
let groupId = "premium"
@@ -7348,6 +7478,15 @@ public final class EmojiPagerContentComponent: Component {
}
processedIds.insert(item.file.fileId)
+ var tintMode: Item.TintMode = .none
+ for attribute in item.file.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ if isSingleColor {
+ tintMode = .primary
+ }
+ }
+ }
+
let animationData = EntityKeyboardAnimationData(file: item.file)
let resultItem = EmojiPagerContentComponent.Item(
animationData: animationData,
@@ -7355,7 +7494,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: item.file,
subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: tintMode
)
let groupId = "peerSpecific"
@@ -7372,6 +7511,16 @@ public final class EmojiPagerContentComponent: Component {
guard let item = entry.item as? StickerPackItem else {
continue
}
+
+ var tintMode: Item.TintMode = .none
+ for attribute in item.file.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ if isSingleColor {
+ tintMode = .primary
+ }
+ }
+ }
+
let animationData = EntityKeyboardAnimationData(file: item.file)
let resultItem = EmojiPagerContentComponent.Item(
animationData: animationData,
@@ -7379,7 +7528,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: item.file,
subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: tintMode
)
let groupId = entry.index.collectionId
if let groupIndex = itemGroupIndexById[groupId] {
@@ -7409,7 +7558,8 @@ public final class EmojiPagerContentComponent: Component {
resource: .stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource),
dimensions: thumbnail.dimensions.cgSize,
immediateThumbnailData: info.immediateThumbnailData,
- isReaction: false
+ isReaction: false,
+ isTemplate: false
)
}
@@ -7426,6 +7576,15 @@ public final class EmojiPagerContentComponent: Component {
}
for item in featuredStickerPack.topItems {
+ var tintMode: Item.TintMode = .none
+ for attribute in item.file.attributes {
+ if case let .CustomEmoji(_, isSingleColor, _, _) = attribute {
+ if isSingleColor {
+ tintMode = .primary
+ }
+ }
+ }
+
let animationData = EntityKeyboardAnimationData(file: item.file)
let resultItem = EmojiPagerContentComponent.Item(
animationData: animationData,
@@ -7433,7 +7592,7 @@ public final class EmojiPagerContentComponent: Component {
itemFile: item.file,
subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: tintMode
)
let supergroupId = featuredStickerPack.info.id
@@ -7469,7 +7628,8 @@ public final class EmojiPagerContentComponent: Component {
resource: .stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource),
dimensions: thumbnail.dimensions.cgSize,
immediateThumbnailData: info.immediateThumbnailData,
- isReaction: false
+ isReaction: false,
+ isTemplate: false
)
}
diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboardTopPanelComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboardTopPanelComponent.swift
index 2a96109768..4f5cdf4ca0 100644
--- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboardTopPanelComponent.swift
+++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EntityKeyboardTopPanelComponent.swift
@@ -116,7 +116,7 @@ final class EntityKeyboardAnimationTopPanelComponent: Component {
itemFile: nil,
subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: component.item.isTemplate ? .primary : .none
),
context: component.context,
attemptSynchronousLoad: false,
@@ -158,6 +158,15 @@ final class EntityKeyboardAnimationTopPanelComponent: Component {
}
itemLayer.update(transition: transition, size: iconFrame.size, badge: badge, blurredBadgeColor: UIColor(white: 0.0, alpha: 0.1), blurredBadgeBackgroundColor: component.theme.list.plainBackgroundColor)
+ switch itemLayer.item.tintMode {
+ case .none:
+ break
+ case .primary:
+ itemLayer.layerTintColor = component.theme.list.itemPrimaryTextColor.cgColor
+ case .accent:
+ itemLayer.layerTintColor = component.theme.list.itemAccentColor.cgColor
+ }
+
itemLayer.isVisibleForAnimations = true
}
diff --git a/submodules/TelegramUI/Components/LottieAnimationCache/Sources/LottieAnimationCache.swift b/submodules/TelegramUI/Components/LottieAnimationCache/Sources/LottieAnimationCache.swift
index 96b56e41c0..21265ad2fa 100644
--- a/submodules/TelegramUI/Components/LottieAnimationCache/Sources/LottieAnimationCache.swift
+++ b/submodules/TelegramUI/Components/LottieAnimationCache/Sources/LottieAnimationCache.swift
@@ -6,7 +6,7 @@ import RLottieBinding
import GZip
import WebPBinding
-public func cacheLottieAnimation(data: Data, width: Int, height: Int, keyframeOnly: Bool, writer: AnimationCacheItemWriter, firstFrameOnly: Bool) {
+public func cacheLottieAnimation(data: Data, width: Int, height: Int, keyframeOnly: Bool, writer: AnimationCacheItemWriter, firstFrameOnly: Bool, customColor: UIColor?) {
let work: () -> Void = {
let decompressedData = TGGUnzipData(data, 2 * 1024 * 1024) ?? data
guard let animation = LottieInstance(data: decompressedData, fitzModifier: .none, colorReplacements: nil, cacheKey: "") else {
@@ -32,6 +32,19 @@ public func cacheLottieAnimation(data: Data, width: Int, height: Int, keyframeOn
}
writer.add(with: { surface in
animation.renderFrame(with: i, into: surface.argb, width: Int32(surface.width), height: Int32(surface.height), bytesPerRow: Int32(surface.bytesPerRow))
+ if customColor != nil {
+ for y in 0 ..< surface.height {
+ for x in 0 ..< surface.width {
+ let pixel = surface.argb.advanced(by: y * surface.bytesPerRow + x * 4)
+ let a = pixel.advanced(by: 3).pointee
+
+ pixel.advanced(by: 0).pointee = a
+ pixel.advanced(by: 1).pointee = a
+ pixel.advanced(by: 2).pointee = a
+ pixel.advanced(by: 3).pointee = a
+ }
+ }
+ }
return frameDuration
}, proposedWidth: width, proposedHeight: height, insertKeyframe: i == 0 || keyframeOnly)
@@ -46,7 +59,7 @@ public func cacheLottieAnimation(data: Data, width: Int, height: Int, keyframeOn
writer.queue.async(work)
}
-public func cacheStillSticker(path: String, width: Int, height: Int, writer: AnimationCacheItemWriter) {
+public func cacheStillSticker(path: String, width: Int, height: Int, writer: AnimationCacheItemWriter, customColor: UIColor?) {
let work: () -> Void = {
if let data = try? Data(contentsOf: URL(fileURLWithPath: path)), let image = WebP.convert(fromWebP: data) {
writer.add(with: { surface in
@@ -55,6 +68,12 @@ public func cacheStillSticker(path: String, width: Int, height: Int, writer: Ani
}
context.withFlippedContext { c in
UIGraphicsPushContext(c)
+
+ if let customColor = customColor {
+ c.setFillColor(customColor.cgColor)
+ c.setBlendMode(.sourceIn)
+ }
+
c.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: context.size))
UIGraphicsPopContext()
}
diff --git a/submodules/TelegramUI/Components/TextNodeWithEntities/Sources/TextNodeWithEntities.swift b/submodules/TelegramUI/Components/TextNodeWithEntities/Sources/TextNodeWithEntities.swift
index 178e56efa0..0a6b61facc 100644
--- a/submodules/TelegramUI/Components/TextNodeWithEntities/Sources/TextNodeWithEntities.swift
+++ b/submodules/TelegramUI/Components/TextNodeWithEntities/Sources/TextNodeWithEntities.swift
@@ -243,9 +243,10 @@ public final class TextNodeWithEntities {
let itemLayer: InlineStickerItemLayer
if let current = self.inlineStickerItemLayers[id] {
itemLayer = current
+ itemLayer.dynamicColor = item.textColor
} else {
let pointSize = floor(itemSize * 1.3)
- itemLayer = InlineStickerItemLayer(context: context, attemptSynchronousLoad: attemptSynchronousLoad, emoji: stickerItem.emoji, file: stickerItem.file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: CGSize(width: pointSize, height: pointSize))
+ itemLayer = InlineStickerItemLayer(context: context, attemptSynchronousLoad: attemptSynchronousLoad, emoji: stickerItem.emoji, file: stickerItem.file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: CGSize(width: pointSize, height: pointSize), dynamicColor: item.textColor)
self.inlineStickerItemLayers[id] = itemLayer
self.textNode.layer.addSublayer(itemLayer)
@@ -407,9 +408,10 @@ public class ImmediateTextNodeWithEntities: TextNode {
let itemLayer: InlineStickerItemLayer
if let current = self.inlineStickerItemLayers[id] {
itemLayer = current
+ itemLayer.dynamicColor = item.textColor
} else {
let pointSize = floor(itemSize * 1.3)
- itemLayer = InlineStickerItemLayer(context: context, attemptSynchronousLoad: false, emoji: stickerItem.emoji, file: stickerItem.file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: CGSize(width: pointSize, height: pointSize))
+ itemLayer = InlineStickerItemLayer(context: context, attemptSynchronousLoad: false, emoji: stickerItem.emoji, file: stickerItem.file, cache: cache, renderer: renderer, placeholderColor: placeholderColor, pointSize: CGSize(width: pointSize, height: pointSize), dynamicColor: item.textColor)
self.inlineStickerItemLayers[id] = itemLayer
self.layer.addSublayer(itemLayer)
diff --git a/submodules/TelegramUI/Components/VideoAnimationCache/Sources/VideoAnimationCache.swift b/submodules/TelegramUI/Components/VideoAnimationCache/Sources/VideoAnimationCache.swift
index d4cbd23f25..77a642802d 100644
--- a/submodules/TelegramUI/Components/VideoAnimationCache/Sources/VideoAnimationCache.swift
+++ b/submodules/TelegramUI/Components/VideoAnimationCache/Sources/VideoAnimationCache.swift
@@ -18,7 +18,7 @@ private func roundUp(_ numToRound: Int, multiple: Int) -> Int {
return numToRound + multiple - remainder
}
-public func cacheVideoAnimation(path: String, width: Int, height: Int, writer: AnimationCacheItemWriter, firstFrameOnly: Bool) {
+public func cacheVideoAnimation(path: String, width: Int, height: Int, writer: AnimationCacheItemWriter, firstFrameOnly: Bool, customColor: UIColor?) {
let work: () -> Void = {
guard let frameSource = makeVideoStickerDirectFrameSource(queue: writer.queue, path: path, width: roundUp(width, multiple: 16), height: roundUp(height, multiple: 16), cachePathPrefix: nil, unpremultiplyAlpha: false) else {
return
diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift
index e2d8d5f482..156613b17a 100644
--- a/submodules/TelegramUI/Sources/ChatController.swift
+++ b/submodules/TelegramUI/Sources/ChatController.swift
@@ -1195,7 +1195,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var existingIds = Set()
for (_, file) in files {
loop: for attribute in file.attributes {
- if case let .CustomEmoji(_, _, packReference) = attribute, let packReference = packReference {
+ if case let .CustomEmoji(_, _, _, packReference) = attribute, let packReference = packReference {
if case let .id(id, _) = packReference, !existingIds.contains(id) {
packReferences.append(packReference)
existingIds.insert(id)
@@ -1469,7 +1469,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var existingIds = Set()
for (_, file) in customEmoji {
loop: for attribute in file.attributes {
- if case let .CustomEmoji(_, _, packReference) = attribute, let packReference = packReference {
+ if case let .CustomEmoji(_, _, _, packReference) = attribute, let packReference = packReference {
if case let .id(id, _) = packReference, !existingIds.contains(id) {
packReferences.append(packReference)
existingIds.insert(id)
@@ -13694,7 +13694,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var stickerPackReference: StickerPackReference?
for attribute in file.attributes {
- if case let .CustomEmoji(_, _, packReference) = attribute {
+ if case let .CustomEmoji(_, _, _, packReference) = attribute {
stickerPackReference = packReference
break
}
diff --git a/submodules/TelegramUI/Sources/ChatEntityKeyboardInputNode.swift b/submodules/TelegramUI/Sources/ChatEntityKeyboardInputNode.swift
index 62de96da12..efeee55908 100644
--- a/submodules/TelegramUI/Sources/ChatEntityKeyboardInputNode.swift
+++ b/submodules/TelegramUI/Sources/ChatEntityKeyboardInputNode.swift
@@ -526,7 +526,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
loop: for attribute in file.attributes {
switch attribute {
- case let .CustomEmoji(_, displayText, _):
+ case let .CustomEmoji(_, _, displayText, _):
text = displayText
var packId: ItemCollectionId?
@@ -781,7 +781,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
}
for attribute in item.file.attributes {
switch attribute {
- case let .CustomEmoji(_, alt, _):
+ case let .CustomEmoji(_, _, alt, _):
if !item.file.isPremiumEmoji || hasPremium {
if !alt.isEmpty, let keyword = allEmoticons[alt] {
result.append((alt, item.file, keyword))
@@ -811,7 +811,7 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
itemFile: itemFile,
subgroupId: nil,
icon: .none,
- accentTint: false
+ tintMode: animationData.isTemplate ? .primary : .none
)
items.append(item)
}
@@ -824,8 +824,8 @@ final class ChatEntityKeyboardInputNode: ChatInputNode {
itemFile: nil,
subgroupId: nil,
icon: .none,
- accentTint: false)
- )
+ tintMode: .none
+ ))
}
return [EmojiPagerContentComponent.ItemGroup(
@@ -1731,7 +1731,7 @@ final class EntityInputView: UIView, AttachmentTextInputPanelInputView, UIInputV
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
loop: for attribute in file.attributes {
switch attribute {
- case let .CustomEmoji(_, displayText, _):
+ case let .CustomEmoji(_, _, displayText, _):
text = displayText
var packId: ItemCollectionId?
if let id = groupId.base as? ItemCollectionId {
@@ -2072,7 +2072,7 @@ private final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior {
loop: for attribute in file.attributes {
switch attribute {
- case let .CustomEmoji(_, _, packReference), let .Sticker(_, packReference, _):
+ case let .CustomEmoji(_, _, _, packReference), let .Sticker(_, packReference, _):
if let packReference = packReference {
let controller = strongSelf.context.sharedContext.makeStickerPackScreen(context: context, updatedPresentationData: nil, mainStickerPack: packReference, stickerPacks: [packReference], loadedStickerPacks: [], parentNavigationController: strongSelf.controllerInteraction.navigationController(), sendSticker: { file, sourceView, sourceRect in
sendSticker(file, false, false, nil, false, sourceView, sourceRect, nil)
diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift
index 496a1a4957..7cf50fa436 100644
--- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift
+++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift
@@ -1165,7 +1165,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
}
}
- if resourceAvailable, !message.containsSecretMedia {
+ if resourceAvailable, !message.containsSecretMedia, !chatPresentationInterfaceState.copyProtectionEnabled, !message.isCopyProtected() {
var mediaReference: AnyMediaReference?
var isVideo = false
for media in message.media {
@@ -2413,7 +2413,7 @@ private final class ChatReadReportContextItemNode: ASDisplayNode, ContextMenuCus
var firstCustomEmojiReaction: TelegramMediaFile?
for (_, file) in customEmoji {
loop: for attribute in file.attributes {
- if case let .CustomEmoji(_, _, packReference) = attribute, let packReference = packReference {
+ if case let .CustomEmoji(_, _, _, packReference) = attribute, let packReference = packReference {
if case let .id(id, _) = packReference, !existingIds.contains(id) {
if firstCustomEmojiReaction == nil {
firstCustomEmojiReaction = file
diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift
index dbde4459fc..5b82b8325e 100644
--- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift
+++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift
@@ -351,7 +351,7 @@ private func updatedContextQueryResultStateForQuery(context: AccountContext, pee
}
for attribute in item.file.attributes {
switch attribute {
- case let .CustomEmoji(_, alt, _):
+ case let .CustomEmoji(_, _, alt, _):
if alt == query {
if !item.file.isPremiumEmoji || hasPremium {
result.append((alt, item.file, alt))
@@ -415,7 +415,7 @@ private func updatedContextQueryResultStateForQuery(context: AccountContext, pee
}
for attribute in item.file.attributes {
switch attribute {
- case let .CustomEmoji(_, alt, _):
+ case let .CustomEmoji(_, _, alt, _):
if !alt.isEmpty, let keyword = allEmoticons[alt] {
if !item.file.isPremiumEmoji || hasPremium {
result.append((alt, item.file, keyword))
diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift
index 99837e02d7..3350e302f1 100644
--- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift
+++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift
@@ -1069,7 +1069,8 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
let maximumContentWidth = floor(tmpWidth - layoutConstants.bubble.edgeInset - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left - layoutConstants.bubble.contentInsets.right - avatarInset)
let font = Font.regular(fontSizeForEmojiString(item.message.text))
- let attributedText = stringWithAppliedEntities(item.message.text, entities: item.message.textEntitiesAttribute?.entities ?? [], baseColor: .black, linkColor: .black, baseFont: font, linkFont: font, boldFont: font, italicFont: font, boldItalicFont: font, fixedFont: font, blockQuoteFont: font, message: item.message)
+ let textColor = item.presentationData.theme.theme.list.itemPrimaryTextColor
+ let attributedText = stringWithAppliedEntities(item.message.text, entities: item.message.textEntitiesAttribute?.entities ?? [], baseColor: textColor, linkColor: textColor, baseFont: font, linkFont: font, boldFont: font, italicFont: font, boldItalicFont: font, fixedFont: font, blockQuoteFont: font, message: item.message)
textLayoutAndApply = textLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maximumContentWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural))
imageSize = CGSize(width: textLayoutAndApply!.0.size.width, height: textLayoutAndApply!.0.size.height)
diff --git a/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift
index d305d027ae..159951cb98 100644
--- a/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift
+++ b/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift
@@ -334,7 +334,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
let currentDict = updatedString.attributes(at: range.lowerBound, effectiveRange: nil)
var updatedAttributes: [NSAttributedString.Key: Any] = currentDict
- updatedAttributes[NSAttributedString.Key.foregroundColor] = UIColor.clear.cgColor
+ //updatedAttributes[NSAttributedString.Key.foregroundColor] = UIColor.clear.cgColor
updatedAttributes[ChatTextInputAttributes.customEmoji] = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: fileId, file: item.message.associatedMedia[MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)] as? TelegramMediaFile)
let insertString = NSAttributedString(string: updatedString.attributedSubstring(from: range).string, attributes: updatedAttributes)
diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift
index 755b518892..874a7f1293 100644
--- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift
+++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift
@@ -473,7 +473,7 @@ final class CustomEmojiContainerView: UIView {
preconditionFailure()
}
- func update(fontSize: CGFloat, emojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute)]) {
+ func update(fontSize: CGFloat, textColor: UIColor, emojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute)]) {
var nextIndexById: [Int64: Int] = [:]
var validKeys = Set()
@@ -499,6 +499,10 @@ final class CustomEmojiContainerView: UIView {
continue
}
+ if let view = view as? EmojiTextAttachmentView {
+ view.updateTextColor(textColor)
+ }
+
let itemSize: CGFloat = floor(24.0 * fontSize / 17.0)
let size = CGSize(width: itemSize, height: itemSize)
@@ -2352,7 +2356,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self.customEmojiContainerView = customEmojiContainerView
}
- customEmojiContainerView.update(fontSize: fontSize, emojiRects: customEmojiRects)
+ customEmojiContainerView.update(fontSize: fontSize, textColor: textColor, emojiRects: customEmojiRects)
} else if let customEmojiContainerView = self.customEmojiContainerView {
customEmojiContainerView.removeFromSuperview()
self.customEmojiContainerView = nil
@@ -2599,7 +2603,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
var emojiAttribute: ChatTextInputTextCustomEmojiAttribute?
loop: for attribute in file.attributes {
switch attribute {
- case let .CustomEmoji(_, displayText, _):
+ case let .CustomEmoji(_, _, displayText, _):
text = displayText
emojiAttribute = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file)
break loop
diff --git a/submodules/TelegramUI/Sources/DocumentPreviewController.swift b/submodules/TelegramUI/Sources/DocumentPreviewController.swift
index fc2adef437..21944e57b8 100644
--- a/submodules/TelegramUI/Sources/DocumentPreviewController.swift
+++ b/submodules/TelegramUI/Sources/DocumentPreviewController.swift
@@ -200,22 +200,32 @@ final class CompactDocumentPreviewController: QLPreviewController, QLPreviewCont
}
private func tick() {
- self.navigationItem.rightBarButtonItems = [UIBarButtonItem()]
- self.navigationItem.setRightBarButton(UIBarButtonItem(), animated: false)
-
- self.navigationController?.toolbar.isHidden = true
-
let (navigationBars, toolbars) = navigationAndToolbarsInSubviews(forView: self.view)
self.navigationBars = navigationBars
self.toolbars = toolbars
-
- for navigationBar in self.navigationBars {
- navigationBar.topItem?.rightBarButtonItem = UIBarButtonItem()
- navigationBar.topItem?.rightBarButtonItems = [UIBarButtonItem()]
- }
- for toolbar in self.toolbars {
- toolbar.isHidden = true
+ if #available(iOS 16.0, *) {
+ if let navigationController = self.children.first as? UINavigationController, let topController = navigationController.topViewController {
+ topController.navigationItem.titleMenuProvider = nil
+ }
+
+ for toolbar in self.toolbars {
+ toolbar.isHidden = true
+ }
+ } else {
+ self.navigationItem.rightBarButtonItems = [UIBarButtonItem()]
+ self.navigationItem.setRightBarButton(UIBarButtonItem(), animated: false)
+
+ self.navigationController?.toolbar.isHidden = true
+
+ for navigationBar in self.navigationBars {
+ navigationBar.topItem?.rightBarButtonItem = UIBarButtonItem()
+ navigationBar.topItem?.rightBarButtonItems = [UIBarButtonItem()]
+ }
+
+ for toolbar in self.toolbars {
+ toolbar.isHidden = true
+ }
}
}
diff --git a/submodules/TelegramUI/Sources/EmojisChatInputContextPanelNode.swift b/submodules/TelegramUI/Sources/EmojisChatInputContextPanelNode.swift
index 782187ba89..d8039260c7 100644
--- a/submodules/TelegramUI/Sources/EmojisChatInputContextPanelNode.swift
+++ b/submodules/TelegramUI/Sources/EmojisChatInputContextPanelNode.swift
@@ -206,7 +206,7 @@ final class EmojisChatInputContextPanelNode: ChatInputContextPanelNode {
if let file = file {
loop: for attribute in file.attributes {
switch attribute {
- case let .CustomEmoji(_, displayText, _):
+ case let .CustomEmoji(_, _, displayText, _):
text = displayText
emojiAttribute = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file)
break loop
diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift
index 376b650543..3ddb660643 100644
--- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift
+++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift
@@ -2505,7 +2505,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
strongSelf.emojiStatusFileAndPackTitle.set(.never())
for attribute in emojiFile.attributes {
- if case let .CustomEmoji(_, _, packReference) = attribute, let packReference = packReference {
+ if case let .CustomEmoji(_, _, _, packReference) = attribute, let packReference = packReference {
strongSelf.emojiStatusPackDisposable.set((strongSelf.context.engine.stickers.loadedStickerPack(reference: packReference, forceActualized: false)
|> filter { result in
if case .result = result {
diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift
index 52512980db..56e68c189d 100644
--- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift
+++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift
@@ -3514,7 +3514,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
if let file = files.first?.value {
var stickerPackReference: StickerPackReference?
for attribute in file.attributes {
- if case let .CustomEmoji(_, _, packReference) = attribute {
+ if case let .CustomEmoji(_, _, _, packReference) = attribute {
stickerPackReference = packReference
break
}
diff --git a/submodules/TelegramVoip/Sources/GroupCallContext.swift b/submodules/TelegramVoip/Sources/GroupCallContext.swift
index f71bd2aec1..9c61f22b10 100644
--- a/submodules/TelegramVoip/Sources/GroupCallContext.swift
+++ b/submodules/TelegramVoip/Sources/GroupCallContext.swift
@@ -415,9 +415,7 @@ public final class OngoingGroupCallContext {
private final class Impl {
let queue: Queue
let context: GroupCallThreadLocalContext
-#if os(iOS)
let audioDevice: SharedCallAudioDevice?
-#endif
let sessionId = UInt32.random(in: 0 ..< UInt32(Int32.max))
let joinPayload = Promise<(String, UInt32)>()
@@ -435,14 +433,8 @@ public final class OngoingGroupCallContext {
init(queue: Queue, inputDeviceId: String, outputDeviceId: String, audioSessionActive: Signal, video: OngoingCallVideoCapturer?, requestMediaChannelDescriptions: @escaping (Set, @escaping ([MediaChannelDescription]) -> Void) -> Disposable, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, videoContentType: VideoContentType, enableNoiseSuppression: Bool, disableAudioInput: Bool, preferX264: Bool, logPath: String) {
self.queue = queue
- #if os(iOS)
self.audioDevice = nil
- #endif
- /*#if DEBUG
- self.audioDevice = SharedCallAudioDevice(disableRecording: disableAudioInput)
- #else
- self.audioDevice = nil
- #endif*/
+ let audioDevice = self.audioDevice
var networkStateUpdatedImpl: ((GroupCallNetworkState) -> Void)?
var audioLevelsUpdatedImpl: (([NSNumber]) -> Void)?
@@ -549,7 +541,8 @@ public final class OngoingGroupCallContext {
enableNoiseSuppression: enableNoiseSuppression,
disableAudioInput: disableAudioInput,
preferX264: preferX264,
- logPath: logPath
+ logPath: logPath,
+ audioDevice: audioDevice
)
let queue = self.queue
@@ -602,8 +595,8 @@ public final class OngoingGroupCallContext {
guard let `self` = self else {
return
}
- #if os(iOS)
self.audioDevice?.setManualAudioSessionIsActive(isActive)
+ #if os(iOS)
self.context.setManualAudioSessionIsActive(isActive)
#endif
}))