mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Local audio transcription experiment and UI fixes
This commit is contained in:
parent
f6190e347d
commit
54788f60de
@ -7601,3 +7601,6 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Premium.AboutTitle" = "ABOUT TELEGRAM PREMIUM";
|
||||
"Premium.AboutText" = "While the free version of Telegram already gives its users more than any other messaging application, **Telegram Premium** pushes its capabilities even further.\n\n**Telegram Premium** is a paid option, because most Premium Features require additional expenses from Telegram to third parties such as data center providers and server manufacturers. Contributions from **Telegram Premium** users allow us to cover such costs and also help Telegram stay free for everyone.";
|
||||
|
||||
"Conversation.CopyProtectionSavingDisabledSecret" = "Saving is restricted";
|
||||
"Conversation.CopyProtectionForwardingDisabledSecret" = "Forwards are restricted";
|
||||
|
@ -28,8 +28,9 @@ public final class ChatMessageItemAssociatedData: Equatable {
|
||||
public let isCopyProtectionEnabled: Bool
|
||||
public let availableReactions: AvailableReactions?
|
||||
public let defaultReaction: String?
|
||||
public let isPremium: Bool
|
||||
|
||||
public init(automaticDownloadPeerType: MediaAutoDownloadPeerType, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, isRecentActions: Bool = false, subject: ChatControllerSubject? = nil, contactsPeerIds: Set<EnginePeer.Id> = Set(), channelDiscussionGroup: ChannelDiscussionGroupStatus = .unknown, animatedEmojiStickers: [String: [StickerPackItem]] = [:], additionalAnimatedEmojiStickers: [String: [Int: StickerPackItem]] = [:], forcedResourceStatus: FileMediaResourceStatus? = nil, currentlyPlayingMessageId: EngineMessage.Index? = nil, isCopyProtectionEnabled: Bool = false, availableReactions: AvailableReactions?, defaultReaction: String?) {
|
||||
public init(automaticDownloadPeerType: MediaAutoDownloadPeerType, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, isRecentActions: Bool = false, subject: ChatControllerSubject? = nil, contactsPeerIds: Set<EnginePeer.Id> = Set(), channelDiscussionGroup: ChannelDiscussionGroupStatus = .unknown, animatedEmojiStickers: [String: [StickerPackItem]] = [:], additionalAnimatedEmojiStickers: [String: [Int: StickerPackItem]] = [:], forcedResourceStatus: FileMediaResourceStatus? = nil, currentlyPlayingMessageId: EngineMessage.Index? = nil, isCopyProtectionEnabled: Bool = false, availableReactions: AvailableReactions?, defaultReaction: String?, isPremium: Bool) {
|
||||
self.automaticDownloadPeerType = automaticDownloadPeerType
|
||||
self.automaticDownloadNetworkType = automaticDownloadNetworkType
|
||||
self.isRecentActions = isRecentActions
|
||||
@ -43,6 +44,7 @@ public final class ChatMessageItemAssociatedData: Equatable {
|
||||
self.isCopyProtectionEnabled = isCopyProtectionEnabled
|
||||
self.availableReactions = availableReactions
|
||||
self.defaultReaction = defaultReaction
|
||||
self.isPremium = isPremium
|
||||
}
|
||||
|
||||
public static func == (lhs: ChatMessageItemAssociatedData, rhs: ChatMessageItemAssociatedData) -> Bool {
|
||||
@ -82,6 +84,9 @@ public final class ChatMessageItemAssociatedData: Equatable {
|
||||
if lhs.availableReactions != rhs.availableReactions {
|
||||
return false
|
||||
}
|
||||
if lhs.isPremium != rhs.isPremium {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -656,11 +656,16 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
case group
|
||||
case channel
|
||||
case bot
|
||||
case user
|
||||
}
|
||||
var type: PeerType = .group
|
||||
for message in messages {
|
||||
if let user = message.author?._asPeer() as? TelegramUser, user.botInfo != nil {
|
||||
type = .bot
|
||||
if let user = message.author?._asPeer() as? TelegramUser {
|
||||
if user.botInfo != nil {
|
||||
type = .bot
|
||||
} else {
|
||||
type = .user
|
||||
}
|
||||
break
|
||||
} else if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = channel.info {
|
||||
type = .channel
|
||||
@ -676,6 +681,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
text = save ? strongSelf.presentationData.strings.Conversation_CopyProtectionSavingDisabledChannel : strongSelf.presentationData.strings.Conversation_CopyProtectionForwardingDisabledChannel
|
||||
case .bot:
|
||||
text = save ? strongSelf.presentationData.strings.Conversation_CopyProtectionSavingDisabledBot : strongSelf.presentationData.strings.Conversation_CopyProtectionForwardingDisabledBot
|
||||
case .user:
|
||||
text = save ? strongSelf.presentationData.strings.Conversation_CopyProtectionSavingDisabledSecret : strongSelf.presentationData.strings.Conversation_CopyProtectionForwardingDisabledSecret
|
||||
}
|
||||
|
||||
strongSelf.copyProtectionTooltipController?.dismiss()
|
||||
|
@ -17,11 +17,16 @@ private func findTaggedViewImpl(view: UIView, tag: Any) -> UIView? {
|
||||
return nil
|
||||
}
|
||||
|
||||
public final class ComponentHostViewSkipSettingFrame {
|
||||
public init() {
|
||||
}
|
||||
}
|
||||
|
||||
public final class ComponentHostView<EnvironmentType>: UIView {
|
||||
private var currentComponent: AnyComponent<EnvironmentType>?
|
||||
private var currentContainerSize: CGSize?
|
||||
private var currentSize: CGSize?
|
||||
private var componentView: UIView?
|
||||
public private(set) var componentView: UIView?
|
||||
private(set) var isUpdating: Bool = false
|
||||
|
||||
public init() {
|
||||
@ -89,7 +94,9 @@ public final class ComponentHostView<EnvironmentType>: UIView {
|
||||
}
|
||||
|
||||
let updatedSize = component._update(view: componentView, availableSize: containerSize, environment: context.erasedEnvironment, transition: transition)
|
||||
transition.setFrame(view: componentView, frame: CGRect(origin: CGPoint(), size: updatedSize))
|
||||
if transition.userData(ComponentHostViewSkipSettingFrame.self) == nil {
|
||||
transition.setFrame(view: componentView, frame: CGRect(origin: CGPoint(), size: updatedSize))
|
||||
}
|
||||
|
||||
self.isUpdating = false
|
||||
|
||||
|
@ -85,6 +85,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
case acceleratedStickers(Bool)
|
||||
case experimentalBackground(Bool)
|
||||
case inlineStickers(Bool)
|
||||
case localTranscription(Bool)
|
||||
case snow(Bool)
|
||||
case playerEmbedding(Bool)
|
||||
case playlistPlayback(Bool)
|
||||
@ -107,7 +108,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
return DebugControllerSection.logging.rawValue
|
||||
case .enableRaiseToSpeak, .keepChatNavigationStack, .skipReadHistory, .crashOnSlowQueries:
|
||||
return DebugControllerSection.experiments.rawValue
|
||||
case .clearTips, .crash, .resetData, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .reindexUnread, .resetBiometricsData, .resetWebViewCache, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .playerEmbedding, .playlistPlayback, .voiceConference, .experimentalCompatibility, .enableDebugDataDisplay, .acceleratedStickers, .experimentalBackground, .inlineStickers, .snow:
|
||||
case .clearTips, .crash, .resetData, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .reindexUnread, .resetBiometricsData, .resetWebViewCache, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .playerEmbedding, .playlistPlayback, .voiceConference, .experimentalCompatibility, .enableDebugDataDisplay, .acceleratedStickers, .experimentalBackground, .inlineStickers, .localTranscription, .snow:
|
||||
return DebugControllerSection.experiments.rawValue
|
||||
case .preferredVideoCodec:
|
||||
return DebugControllerSection.videoExperiments.rawValue
|
||||
@ -184,16 +185,18 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
return 30
|
||||
case .inlineStickers:
|
||||
return 31
|
||||
case .snow:
|
||||
case .localTranscription:
|
||||
return 32
|
||||
case .playerEmbedding:
|
||||
case .snow:
|
||||
return 33
|
||||
case .playlistPlayback:
|
||||
case .playerEmbedding:
|
||||
return 34
|
||||
case .voiceConference:
|
||||
case .playlistPlayback:
|
||||
return 35
|
||||
case .voiceConference:
|
||||
return 36
|
||||
case let .preferredVideoCodec(index, _, _, _):
|
||||
return 36 + index
|
||||
return 37 + index
|
||||
case .disableVideoAspectScaling:
|
||||
return 100
|
||||
case .enableVoipTcp:
|
||||
@ -961,6 +964,16 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
})
|
||||
}).start()
|
||||
})
|
||||
case let .localTranscription(value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: "Local Transcription", value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in
|
||||
var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings
|
||||
settings.localTranscription = value
|
||||
return PreferencesEntry(settings)
|
||||
})
|
||||
}).start()
|
||||
})
|
||||
case let .snow(value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: "Snow", value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in
|
||||
@ -1087,6 +1100,7 @@ private func debugControllerEntries(sharedContext: SharedAccountContext, present
|
||||
entries.append(.acceleratedStickers(experimentalSettings.acceleratedStickers))
|
||||
entries.append(.experimentalBackground(experimentalSettings.experimentalBackground))
|
||||
entries.append(.inlineStickers(experimentalSettings.inlineStickers))
|
||||
entries.append(.localTranscription(experimentalSettings.localTranscription))
|
||||
entries.append(.playerEmbedding(experimentalSettings.playerEmbedding))
|
||||
entries.append(.playlistPlayback(experimentalSettings.playlistPlayback))
|
||||
}
|
||||
|
@ -10,11 +10,14 @@ public let nullAction = NullActionClass()
|
||||
open class SimpleLayer: CALayer {
|
||||
public var didEnterHierarchy: (() -> Void)?
|
||||
public var didExitHierarchy: (() -> Void)?
|
||||
public private(set) var isInHierarchy: Bool = false
|
||||
|
||||
override open func action(forKey event: String) -> CAAction? {
|
||||
if event == kCAOnOrderIn {
|
||||
self.isInHierarchy = true
|
||||
self.didEnterHierarchy?()
|
||||
} else if event == kCAOnOrderOut {
|
||||
self.isInHierarchy = false
|
||||
self.didExitHierarchy?()
|
||||
}
|
||||
return nullAction
|
||||
|
@ -205,9 +205,9 @@ public func chatMessageGalleryControllerData(context: AccountContext, chatLocati
|
||||
} else if ext == "wav" || ext == "opus" {
|
||||
return .audio(file)
|
||||
}
|
||||
if ext == "mkv" {
|
||||
/*if ext == "mkv" {
|
||||
return .document(file, true)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
if internalDocumentItemSupportsMimeType(file.mimeType, fileName: file.fileName ?? "file") {
|
||||
|
@ -23,7 +23,7 @@ public func convertOpusToAAC(sourcePath: String, allocateTempFile: @escaping ()
|
||||
let outputSettings: [String: Any] = [
|
||||
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
|
||||
AVSampleRateKey: 48000,
|
||||
AVEncoderBitRateKey: 96000,
|
||||
AVEncoderBitRateKey: 32000,
|
||||
AVNumberOfChannelsKey: 1,
|
||||
AVChannelLayoutKey: NSData(bytes: &channelLayout, length: MemoryLayout<AudioChannelLayout>.size)
|
||||
]
|
||||
|
@ -2,64 +2,83 @@ import Foundation
|
||||
import SwiftSignalKit
|
||||
import Speech
|
||||
|
||||
private var sharedRecognizer: Any?
|
||||
private var sharedRecognizers: [String: NSObject] = [:]
|
||||
|
||||
public func transcribeAudio(path: String) -> Signal<String?, NoError> {
|
||||
private struct TranscriptionResult {
|
||||
var text: String
|
||||
var confidence: Float
|
||||
}
|
||||
|
||||
private func transcribeAudio(path: String, locale: String) -> Signal<TranscriptionResult?, NoError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
if #available(iOS 13.0, *) {
|
||||
SFSpeechRecognizer.requestAuthorization { (status) in
|
||||
switch status {
|
||||
case .notDetermined:
|
||||
subscriber.putNext(nil)
|
||||
subscriber.putCompletion()
|
||||
case .restricted:
|
||||
subscriber.putNext(nil)
|
||||
subscriber.putCompletion()
|
||||
case .denied:
|
||||
subscriber.putNext(nil)
|
||||
subscriber.putCompletion()
|
||||
case .authorized:
|
||||
let speechRecognizer: SFSpeechRecognizer
|
||||
if let sharedRecognizer = sharedRecognizer as? SFSpeechRecognizer {
|
||||
speechRecognizer = sharedRecognizer
|
||||
} else {
|
||||
guard let speechRecognizerValue = SFSpeechRecognizer(locale: Locale(identifier: "ru-RU")), speechRecognizerValue.isAvailable else {
|
||||
subscriber.putNext(nil)
|
||||
subscriber.putCompletion()
|
||||
|
||||
return
|
||||
}
|
||||
speechRecognizerValue.defaultTaskHint = .unspecified
|
||||
sharedRecognizer = speechRecognizerValue
|
||||
speechRecognizer = speechRecognizerValue
|
||||
|
||||
speechRecognizer.supportsOnDeviceRecognition = false
|
||||
}
|
||||
|
||||
let request = SFSpeechURLRecognitionRequest(url: URL(fileURLWithPath: path))
|
||||
request.requiresOnDeviceRecognition = speechRecognizer.supportsOnDeviceRecognition
|
||||
request.shouldReportPartialResults = false
|
||||
|
||||
let task = speechRecognizer.recognitionTask(with: request, resultHandler: { result, error in
|
||||
if let result = result {
|
||||
subscriber.putNext(result.bestTranscription.formattedString)
|
||||
subscriber.putCompletion()
|
||||
SFSpeechRecognizer.requestAuthorization { status in
|
||||
Queue.mainQueue().async {
|
||||
switch status {
|
||||
case .notDetermined:
|
||||
subscriber.putNext(nil)
|
||||
subscriber.putCompletion()
|
||||
case .restricted:
|
||||
subscriber.putNext(nil)
|
||||
subscriber.putCompletion()
|
||||
case .denied:
|
||||
subscriber.putNext(nil)
|
||||
subscriber.putCompletion()
|
||||
case .authorized:
|
||||
let speechRecognizer: SFSpeechRecognizer
|
||||
if let sharedRecognizer = sharedRecognizers[locale] as? SFSpeechRecognizer {
|
||||
speechRecognizer = sharedRecognizer
|
||||
} else {
|
||||
print("transcribeAudio: \(String(describing: error))")
|
||||
guard let speechRecognizerValue = SFSpeechRecognizer(locale: Locale(identifier: locale)), speechRecognizerValue.isAvailable else {
|
||||
subscriber.putNext(nil)
|
||||
subscriber.putCompletion()
|
||||
|
||||
return
|
||||
}
|
||||
speechRecognizerValue.defaultTaskHint = .unspecified
|
||||
sharedRecognizers[locale] = speechRecognizerValue
|
||||
speechRecognizer = speechRecognizerValue
|
||||
|
||||
subscriber.putNext(nil)
|
||||
subscriber.putCompletion()
|
||||
if locale == "en-US" {
|
||||
speechRecognizer.supportsOnDeviceRecognition = true
|
||||
} else {
|
||||
speechRecognizer.supportsOnDeviceRecognition = false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
disposable.set(ActionDisposable {
|
||||
task.cancel()
|
||||
})
|
||||
@unknown default:
|
||||
subscriber.putNext(nil)
|
||||
subscriber.putCompletion()
|
||||
|
||||
let tempFilePath = NSTemporaryDirectory() + "/\(UInt64.random(in: 0 ... UInt64.max)).m4a"
|
||||
let _ = try? FileManager.default.copyItem(atPath: path, toPath: tempFilePath)
|
||||
|
||||
let request = SFSpeechURLRecognitionRequest(url: URL(fileURLWithPath: tempFilePath))
|
||||
request.requiresOnDeviceRecognition = speechRecognizer.supportsOnDeviceRecognition
|
||||
request.shouldReportPartialResults = false
|
||||
|
||||
let task = speechRecognizer.recognitionTask(with: request, resultHandler: { result, error in
|
||||
if let result = result {
|
||||
var confidence: Float = 0.0
|
||||
for segment in result.bestTranscription.segments {
|
||||
confidence += segment.confidence
|
||||
}
|
||||
confidence /= Float(result.bestTranscription.segments.count)
|
||||
subscriber.putNext(TranscriptionResult(text: result.bestTranscription.formattedString, confidence: confidence))
|
||||
subscriber.putCompletion()
|
||||
} else {
|
||||
print("transcribeAudio: locale: \(locale), error: \(String(describing: error))")
|
||||
|
||||
subscriber.putNext(nil)
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
})
|
||||
|
||||
disposable.set(ActionDisposable {
|
||||
task.cancel()
|
||||
})
|
||||
@unknown default:
|
||||
subscriber.putNext(nil)
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -71,3 +90,33 @@ public func transcribeAudio(path: String) -> Signal<String?, NoError> {
|
||||
}
|
||||
|> runOn(.mainQueue())
|
||||
}
|
||||
|
||||
public func transcribeAudio(path: String, appLocale: String) -> Signal<String?, NoError> {
|
||||
var signals: [Signal<TranscriptionResult?, NoError>] = []
|
||||
var locales: [String] = []
|
||||
if !locales.contains(Locale.current.identifier) {
|
||||
locales.append(Locale.current.identifier)
|
||||
}
|
||||
if locales.isEmpty {
|
||||
locales.append("en-US")
|
||||
}
|
||||
for locale in locales {
|
||||
signals.append(transcribeAudio(path: path, locale: locale))
|
||||
}
|
||||
var resultSignal: Signal<[TranscriptionResult?], NoError> = .single([])
|
||||
for signal in signals {
|
||||
resultSignal = resultSignal |> mapToSignal { result -> Signal<[TranscriptionResult?], NoError> in
|
||||
return signal |> map { next in
|
||||
return result + [next]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resultSignal
|
||||
|> map { results -> String? in
|
||||
let sortedResults = results.compactMap({ $0 }).sorted(by: { lhs, rhs in
|
||||
return lhs.confidence > rhs.confidence
|
||||
})
|
||||
return sortedResults.first?.text
|
||||
}
|
||||
}
|
||||
|
@ -900,9 +900,33 @@ static int32_t fixedTimeDifferenceValue = 0;
|
||||
} else {
|
||||
[results addObjectsFromArray:[self _allTransportSchemesForDatacenterWithId:datacenterId]];
|
||||
}
|
||||
MTTransportScheme *manualScheme = _datacenterManuallySelectedSchemeById[[[MTTransportSchemeKey alloc] initWithDatacenterId:datacenterId isProxy:isProxy isMedia:media]];
|
||||
if (manualScheme != nil && ![results containsObject:manualScheme]) {
|
||||
[results addObject:manualScheme];
|
||||
|
||||
MTDatacenterAddressSet *addressSet = [self addressSetForDatacenterWithId:datacenterId];
|
||||
if (addressSet != nil) {
|
||||
MTTransportScheme *manualScheme = _datacenterManuallySelectedSchemeById[[[MTTransportSchemeKey alloc] initWithDatacenterId:datacenterId isProxy:isProxy isMedia:media]];
|
||||
if (manualScheme != nil) {
|
||||
bool addressValid = false;
|
||||
for (MTDatacenterAddress *address in addressSet.addressList) {
|
||||
if ([manualScheme.address isEqualToAddress:address]) {
|
||||
addressValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (addressValid) {
|
||||
bool found = false;
|
||||
for (MTTransportScheme *result in results) {
|
||||
if ([result isEqualToScheme:manualScheme]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
[results addObject:manualScheme];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} synchronous:true];
|
||||
|
||||
@ -914,6 +938,23 @@ static int32_t fixedTimeDifferenceValue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (media) {
|
||||
bool hasMedia = false;
|
||||
for (MTTransportScheme *scheme in results) {
|
||||
if (scheme.address.preferForMedia) {
|
||||
hasMedia = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasMedia) {
|
||||
for (int i = (int)(results.count - 1); i >= 0; i--) {
|
||||
if (!results[i].address.preferForMedia) {
|
||||
[results removeObjectAtIndex:i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,13 @@
|
||||
[aCoder encodeBool:_media forKey:@"media"];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
if (![object isKindOfClass:[MTTransportScheme class]]) {
|
||||
return false;
|
||||
}
|
||||
return [self isEqualToScheme:(MTTransportScheme *)object];
|
||||
}
|
||||
|
||||
- (BOOL)isEqualToScheme:(MTTransportScheme *)other
|
||||
{
|
||||
if (![other isKindOfClass:[MTTransportScheme class]])
|
||||
|
@ -184,6 +184,12 @@ public func combineLatest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13
|
||||
}, initialValues: [:], queue: queue)
|
||||
}
|
||||
|
||||
public func combineLatest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, E>(queue: Queue? = nil, _ s1: Signal<T1, E>, _ s2: Signal<T2, E>, _ s3: Signal<T3, E>, _ s4: Signal<T4, E>, _ s5: Signal<T5, E>, _ s6: Signal<T6, E>, _ s7: Signal<T7, E>, _ s8: Signal<T8, E>, _ s9: Signal<T9, E>, _ s10: Signal<T10, E>, _ s11: Signal<T11, E>, _ s12: Signal<T12, E>, _ s13: Signal<T13, E>, _ s14: Signal<T14, E>, _ s15: Signal<T15, E>, _ s16: Signal<T16, E>, _ s17: Signal<T17, E>) -> Signal<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17), E> {
|
||||
return combineLatestAny([signalOfAny(s1), signalOfAny(s2), signalOfAny(s3), signalOfAny(s4), signalOfAny(s5), signalOfAny(s6), signalOfAny(s7), signalOfAny(s8), signalOfAny(s9), signalOfAny(s10), signalOfAny(s11), signalOfAny(s12), signalOfAny(s13), signalOfAny(s14), signalOfAny(s15), signalOfAny(s16), signalOfAny(s17)], combine: { values in
|
||||
return (values[0] as! T1, values[1] as! T2, values[2] as! T3, values[3] as! T4, values[4] as! T5, values[5] as! T6, values[6] as! T7, values[7] as! T8, values[8] as! T9, values[9] as! T10, values[10] as! T11, values[11] as! T12, values[12] as! T13, values[13] as! T14, values[14] as! T15, values[15] as! T16, values[16] as! T17)
|
||||
}, initialValues: [:], queue: queue)
|
||||
}
|
||||
|
||||
public func combineLatest<T, E>(queue: Queue? = nil, _ signals: [Signal<T, E>]) -> Signal<[T], E> {
|
||||
if signals.count == 0 {
|
||||
return single([T](), E.self)
|
||||
|
@ -187,6 +187,7 @@ private var declaredEncodables: Void = {
|
||||
declareEncodable(WallpaperDataResource.self, f: { WallpaperDataResource(decoder: $0) })
|
||||
declareEncodable(ForwardOptionsMessageAttribute.self, f: { ForwardOptionsMessageAttribute(decoder: $0) })
|
||||
declareEncodable(SendAsMessageAttribute.self, f: { SendAsMessageAttribute(decoder: $0) })
|
||||
declareEncodable(AudioTranscriptionMessageAttribute.self, f: { AudioTranscriptionMessageAttribute(decoder: $0) })
|
||||
|
||||
return
|
||||
}()
|
||||
|
@ -0,0 +1,35 @@
|
||||
import Postbox
|
||||
|
||||
public class AudioTranscriptionMessageAttribute: MessageAttribute, Equatable {
|
||||
public let locale: String
|
||||
public let text: String
|
||||
|
||||
public var associatedPeerIds: [PeerId] {
|
||||
return []
|
||||
}
|
||||
|
||||
public init(locale: String, text: String) {
|
||||
self.locale = locale
|
||||
self.text = text
|
||||
}
|
||||
|
||||
required public init(decoder: PostboxDecoder) {
|
||||
self.locale = decoder.decodeStringForKey("locale", orElse: "")
|
||||
self.text = decoder.decodeStringForKey("text", orElse: "")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeString(self.locale, forKey: "locale")
|
||||
encoder.encodeString(self.text, forKey: "text")
|
||||
}
|
||||
|
||||
public static func ==(lhs: AudioTranscriptionMessageAttribute, rhs: AudioTranscriptionMessageAttribute) -> Bool {
|
||||
if lhs.locale != rhs.locale {
|
||||
return false
|
||||
}
|
||||
if lhs.text != rhs.text {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
@ -13,6 +13,9 @@ swift_library(
|
||||
"//submodules/ComponentFlow:ComponentFlow",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/ShimmerEffect:ShimmerEffect",
|
||||
"//submodules/MediaPlayer:UniversalMediaPlayer",
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -2,23 +2,32 @@ import Foundation
|
||||
import UIKit
|
||||
import ComponentFlow
|
||||
import Display
|
||||
import ShimmerEffect
|
||||
import UniversalMediaPlayer
|
||||
import SwiftSignalKit
|
||||
|
||||
public final class AudioWaveformComponent: Component {
|
||||
public let backgroundColor: UIColor
|
||||
public let foregroundColor: UIColor
|
||||
public let shimmerColor: UIColor?
|
||||
public let samples: Data
|
||||
public let peak: Int32
|
||||
public let status: Signal<MediaPlayerStatus, NoError>
|
||||
|
||||
public init(
|
||||
backgroundColor: UIColor,
|
||||
foregroundColor: UIColor,
|
||||
shimmerColor: UIColor?,
|
||||
samples: Data,
|
||||
peak: Int32
|
||||
peak: Int32,
|
||||
status: Signal<MediaPlayerStatus, NoError>
|
||||
) {
|
||||
self.backgroundColor = backgroundColor
|
||||
self.foregroundColor = foregroundColor
|
||||
self.shimmerColor = shimmerColor
|
||||
self.samples = samples
|
||||
self.peak = peak
|
||||
self.status = status
|
||||
}
|
||||
|
||||
public static func ==(lhs: AudioWaveformComponent, rhs: AudioWaveformComponent) -> Bool {
|
||||
@ -28,6 +37,9 @@ public final class AudioWaveformComponent: Component {
|
||||
if lhs.foregroundColor != rhs.foregroundColor {
|
||||
return false
|
||||
}
|
||||
if lhs.shimmerColor != rhs.shimmerColor {
|
||||
return false
|
||||
}
|
||||
if lhs.samples != rhs.samples {
|
||||
return false
|
||||
}
|
||||
@ -38,18 +50,412 @@ public final class AudioWaveformComponent: Component {
|
||||
}
|
||||
|
||||
public final class View: UIView {
|
||||
private struct ShimmerParams: Equatable {
|
||||
var backgroundColor: UIColor
|
||||
var foregroundColor: UIColor
|
||||
}
|
||||
|
||||
private final class LayerImpl: SimpleLayer {
|
||||
private var shimmerNode: ShimmerEffectNode?
|
||||
private var shimmerMask: SimpleLayer?
|
||||
|
||||
var shimmerParams: ShimmerParams? {
|
||||
didSet {
|
||||
if (self.shimmerParams != nil) != (oldValue != nil) {
|
||||
if self.shimmerParams != nil {
|
||||
if self.shimmerNode == nil {
|
||||
let shimmerNode = ShimmerEffectNode()
|
||||
shimmerNode.isLayerBacked = true
|
||||
self.shimmerNode = shimmerNode
|
||||
self.addSublayer(shimmerNode.layer)
|
||||
|
||||
let shimmerMask = SimpleLayer()
|
||||
shimmerNode.layer.mask = shimmerMask
|
||||
shimmerMask.contents = self.contents
|
||||
shimmerMask.frame = self.bounds
|
||||
self.shimmerMask = shimmerMask
|
||||
}
|
||||
|
||||
self.updateShimmer()
|
||||
} else {
|
||||
if let shimmerNode = self.shimmerNode {
|
||||
self.shimmerNode = nil
|
||||
shimmerNode.layer.removeFromSuperlayer()
|
||||
|
||||
self.shimmerMask = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func updateShimmer() {
|
||||
guard let shimmerNode = self.shimmerNode, !self.bounds.width.isZero, let shimmerParams = self.shimmerParams else {
|
||||
return
|
||||
}
|
||||
|
||||
shimmerNode.frame = self.bounds
|
||||
shimmerNode.updateAbsoluteRect(self.bounds, within: CGSize(width: self.bounds.size.width + 60.0, height: self.bounds.size.height + 4.0))
|
||||
|
||||
var shapes: [ShimmerEffectNode.Shape] = []
|
||||
shapes.append(.rect(rect: CGRect(origin: CGPoint(), size: self.bounds.size)))
|
||||
shimmerNode.update(
|
||||
backgroundColor: .clear,
|
||||
foregroundColor: shimmerParams.backgroundColor,
|
||||
shimmeringColor: shimmerParams.foregroundColor,
|
||||
shapes: shapes,
|
||||
horizontal: true,
|
||||
effectSize: 60.0,
|
||||
globalTimeOffset: false,
|
||||
duration: 0.7,
|
||||
size: self.bounds.size
|
||||
)
|
||||
}
|
||||
|
||||
override func display() {
|
||||
if self.bounds.size.width.isZero {
|
||||
return
|
||||
}
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0.0)
|
||||
if let view = self.delegate as? View {
|
||||
view.draw(CGRect(origin: CGPoint(), size: self.bounds.size))
|
||||
}
|
||||
let image = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
if let image = image {
|
||||
let previousContents = self.contents
|
||||
|
||||
self.contents = image.cgImage
|
||||
|
||||
if let shimmerMask = self.shimmerMask {
|
||||
shimmerMask.contents = image.cgImage
|
||||
shimmerMask.frame = self.bounds
|
||||
|
||||
self.updateShimmer()
|
||||
}
|
||||
|
||||
if let previousContents = previousContents, let contents = self.contents {
|
||||
self.animate(from: previousContents as AnyObject, to: contents as AnyObject, keyPath: "contents", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 0.15)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override public static var layerClass: AnyClass {
|
||||
return LayerImpl.self
|
||||
}
|
||||
|
||||
private var component: AudioWaveformComponent?
|
||||
private var validSize: CGSize?
|
||||
|
||||
private var playbackStatus: MediaPlayerStatus?
|
||||
private var scrubbingTimestampValue: Double?
|
||||
private var statusDisposable: Disposable?
|
||||
private var playbackStatusAnimator: ConstantDisplayLinkAnimator?
|
||||
|
||||
private var revealProgress: CGFloat = 1.0
|
||||
private var animator: DisplayLinkAnimator?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
self.backgroundColor = nil
|
||||
self.isOpaque = false
|
||||
|
||||
(self.layer as! LayerImpl).didEnterHierarchy = { [weak self] in
|
||||
self?.updatePlaybackAnimation()
|
||||
}
|
||||
(self.layer as! LayerImpl).didExitHierarchy = { [weak self] in
|
||||
self?.updatePlaybackAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.statusDisposable?.dispose()
|
||||
}
|
||||
|
||||
public func animateIn() {
|
||||
if self.animator == nil {
|
||||
self.revealProgress = 0.0
|
||||
self.setNeedsDisplay()
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.08, execute: {
|
||||
self.animator = DisplayLinkAnimator(duration: 0.8, from: 0.0, to: 1.0, update: { [weak self] progress in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.revealProgress = progress
|
||||
strongSelf.setNeedsDisplay()
|
||||
}, completion: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.animator?.invalidate()
|
||||
strongSelf.animator = nil
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func update(component: AudioWaveformComponent, availableSize: CGSize, transition: Transition) -> CGSize {
|
||||
return CGSize(width: availableSize.width, height: availableSize.height)
|
||||
let size = CGSize(width: availableSize.width, height: availableSize.height)
|
||||
|
||||
if self.validSize != size || self.component?.samples != component.samples || self.component?.peak != component.peak {
|
||||
self.setNeedsDisplay()
|
||||
}
|
||||
|
||||
(self.layer as! LayerImpl).shimmerParams = component.shimmerColor.flatMap { shimmerColor in
|
||||
return ShimmerParams(
|
||||
backgroundColor: component.backgroundColor,
|
||||
foregroundColor: shimmerColor
|
||||
)
|
||||
}
|
||||
|
||||
self.component = component
|
||||
self.validSize = size
|
||||
|
||||
if self.statusDisposable == nil {
|
||||
self.statusDisposable = (component.status
|
||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if strongSelf.playbackStatus != value {
|
||||
strongSelf.playbackStatus = value
|
||||
strongSelf.setNeedsDisplay()
|
||||
strongSelf.updatePlaybackAnimation()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return size
|
||||
}
|
||||
|
||||
private func updatePlaybackAnimation() {
|
||||
var needsAnimation = false
|
||||
if let playbackStatus = self.playbackStatus {
|
||||
switch playbackStatus.status {
|
||||
case .playing:
|
||||
needsAnimation = true
|
||||
default:
|
||||
needsAnimation = false
|
||||
}
|
||||
}
|
||||
|
||||
if needsAnimation != (self.playbackStatusAnimator != nil) {
|
||||
if needsAnimation {
|
||||
self.playbackStatusAnimator = ConstantDisplayLinkAnimator(update: { [weak self] in
|
||||
self?.setNeedsDisplay()
|
||||
})
|
||||
self.playbackStatusAnimator?.isPaused = false
|
||||
} else {
|
||||
self.playbackStatusAnimator?.invalidate()
|
||||
self.playbackStatusAnimator = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override public func draw(_ rect: CGRect) {
|
||||
guard let component = self.component else {
|
||||
return
|
||||
}
|
||||
guard let context = UIGraphicsGetCurrentContext() else {
|
||||
return
|
||||
}
|
||||
|
||||
let timestampAndDuration: (timestamp: Double, duration: Double)?
|
||||
var isPlaying = false
|
||||
if let statusValue = self.playbackStatus, Double(0.0).isLess(than: statusValue.duration) {
|
||||
switch statusValue.status {
|
||||
case .playing:
|
||||
isPlaying = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if let scrubbingTimestampValue = self.scrubbingTimestampValue {
|
||||
timestampAndDuration = (max(0.0, min(scrubbingTimestampValue, statusValue.duration)), statusValue.duration)
|
||||
} else {
|
||||
timestampAndDuration = (statusValue.timestamp, statusValue.duration)
|
||||
}
|
||||
} else {
|
||||
timestampAndDuration = nil
|
||||
}
|
||||
|
||||
let playbackProgress: CGFloat
|
||||
if let (timestamp, duration) = timestampAndDuration {
|
||||
if let scrubbingTimestampValue = self.scrubbingTimestampValue {
|
||||
var progress = CGFloat(scrubbingTimestampValue / duration)
|
||||
if progress.isNaN || !progress.isFinite {
|
||||
progress = 0.0
|
||||
}
|
||||
progress = max(0.0, min(1.0, progress))
|
||||
playbackProgress = progress
|
||||
} else if let statusValue = self.playbackStatus {
|
||||
let actualTimestamp: Double
|
||||
if statusValue.generationTimestamp.isZero || !isPlaying {
|
||||
actualTimestamp = timestamp
|
||||
} else {
|
||||
let currentTimestamp = CACurrentMediaTime()
|
||||
actualTimestamp = timestamp + (currentTimestamp - statusValue.generationTimestamp) * statusValue.baseRate
|
||||
}
|
||||
var progress = CGFloat(actualTimestamp / duration)
|
||||
if progress.isNaN || !progress.isFinite {
|
||||
progress = 0.0
|
||||
}
|
||||
progress = max(0.0, min(1.0, progress))
|
||||
playbackProgress = progress
|
||||
} else {
|
||||
playbackProgress = 0.0
|
||||
}
|
||||
} else {
|
||||
playbackProgress = 0.0
|
||||
}
|
||||
|
||||
let sampleWidth: CGFloat = 2.0
|
||||
let halfSampleWidth: CGFloat = 1.0
|
||||
let distance: CGFloat = 2.0
|
||||
|
||||
let size = bounds.size
|
||||
|
||||
component.samples.withUnsafeBytes { rawSamples -> Void in
|
||||
let samples = rawSamples.baseAddress!.assumingMemoryBound(to: UInt16.self)
|
||||
|
||||
let peakHeight: CGFloat = 18.0
|
||||
let maxReadSamples = rawSamples.count / 2
|
||||
|
||||
var maxSample: UInt16 = 0
|
||||
for i in 0 ..< maxReadSamples {
|
||||
let sample = samples[i]
|
||||
if maxSample < sample {
|
||||
maxSample = sample
|
||||
}
|
||||
}
|
||||
|
||||
let numSamples = Int(floor(size.width / (sampleWidth + distance)))
|
||||
|
||||
let adjustedSamplesMemory = malloc(numSamples * 2)!
|
||||
let adjustedSamples = adjustedSamplesMemory.assumingMemoryBound(to: UInt16.self)
|
||||
defer {
|
||||
free(adjustedSamplesMemory)
|
||||
}
|
||||
memset(adjustedSamplesMemory, 0, numSamples * 2)
|
||||
|
||||
var generateFakeSamples = false
|
||||
|
||||
var bins: [UInt16: Int] = [:]
|
||||
for i in 0 ..< maxReadSamples {
|
||||
let index = i * numSamples / maxReadSamples
|
||||
let sample = samples[i]
|
||||
if adjustedSamples[index] < sample {
|
||||
adjustedSamples[index] = sample
|
||||
}
|
||||
|
||||
if let count = bins[sample] {
|
||||
bins[sample] = count + 1
|
||||
} else {
|
||||
bins[sample] = 1
|
||||
}
|
||||
}
|
||||
|
||||
var sortedSamples: [(UInt16, Int)] = []
|
||||
var totalCount: Int = 0
|
||||
for (sample, count) in bins {
|
||||
if sample > 0 {
|
||||
sortedSamples.append((sample, count))
|
||||
totalCount += count
|
||||
}
|
||||
}
|
||||
sortedSamples.sort { $0.1 > $1.1 }
|
||||
|
||||
let topSamples = sortedSamples.prefix(1)
|
||||
let topCount = topSamples.map{ $0.1 }.reduce(.zero, +)
|
||||
var topCountPercent: Float = 0.0
|
||||
if bins.count > 0 {
|
||||
topCountPercent = Float(topCount) / Float(totalCount)
|
||||
}
|
||||
|
||||
if topCountPercent > 0.75 {
|
||||
generateFakeSamples = true
|
||||
}
|
||||
|
||||
if generateFakeSamples {
|
||||
if maxSample < 10 {
|
||||
maxSample = 20
|
||||
}
|
||||
for i in 0 ..< maxReadSamples {
|
||||
let index = i * numSamples / maxReadSamples
|
||||
adjustedSamples[index] = UInt16.random(in: 6...maxSample)
|
||||
}
|
||||
}
|
||||
|
||||
let invScale = 1.0 / max(1.0, CGFloat(maxSample))
|
||||
|
||||
let commonRevealFraction = listViewAnimationCurveSystem(self.revealProgress)
|
||||
|
||||
for i in 0 ..< numSamples {
|
||||
let offset = CGFloat(i) * (sampleWidth + distance)
|
||||
let peakSample = adjustedSamples[i]
|
||||
|
||||
var sampleHeight = CGFloat(peakSample) * peakHeight * invScale
|
||||
if abs(sampleHeight) > peakHeight {
|
||||
sampleHeight = peakHeight
|
||||
}
|
||||
|
||||
let startFraction = CGFloat(i) / CGFloat(numSamples)
|
||||
let nextStartFraction = CGFloat(i + 1) / CGFloat(numSamples)
|
||||
|
||||
if startFraction < commonRevealFraction {
|
||||
let currentVerticalProgress: CGFloat = max(0.0, min(1.0, max(0.0, commonRevealFraction - startFraction) / (1.0 - startFraction)))
|
||||
sampleHeight *= currentVerticalProgress
|
||||
} else {
|
||||
sampleHeight *= 0.0
|
||||
}
|
||||
|
||||
let colorMixFraction: CGFloat
|
||||
if startFraction < playbackProgress {
|
||||
colorMixFraction = max(0.0, min(1.0, (playbackProgress - startFraction) / (playbackProgress - nextStartFraction)))
|
||||
} else {
|
||||
colorMixFraction = 0.0
|
||||
}
|
||||
|
||||
let diff: CGFloat
|
||||
diff = sampleWidth * 1.5
|
||||
|
||||
let gravityMultiplierY: CGFloat
|
||||
gravityMultiplierY = 1.0
|
||||
|
||||
/*switch parameters.gravity ?? .bottom {
|
||||
case .bottom:
|
||||
return 1
|
||||
case .center:
|
||||
return 0.5
|
||||
}*/
|
||||
|
||||
context.setFillColor(component.backgroundColor.mixedWith(component.foregroundColor, alpha: colorMixFraction).cgColor)
|
||||
|
||||
let adjustedSampleHeight = sampleHeight - diff
|
||||
if adjustedSampleHeight.isLessThanOrEqualTo(sampleWidth) {
|
||||
context.fillEllipse(in: CGRect(x: offset, y: (size.height - sampleWidth) * gravityMultiplierY, width: sampleWidth, height: sampleWidth))
|
||||
} else {
|
||||
let adjustedRect = CGRect(
|
||||
x: offset,
|
||||
y: (size.height - adjustedSampleHeight) * gravityMultiplierY,
|
||||
width: sampleWidth,
|
||||
height: adjustedSampleHeight - halfSampleWidth
|
||||
)
|
||||
context.fill(adjustedRect)
|
||||
context.fillEllipse(in: CGRect(x: adjustedRect.minX, y: adjustedRect.minY - halfSampleWidth, width: sampleWidth, height: sampleWidth))
|
||||
context.fillEllipse(in: CGRect(x: adjustedRect.minX, y: adjustedRect.maxY - halfSampleWidth, width: sampleWidth, height: sampleWidth))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8463,6 +8463,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
case group
|
||||
case channel
|
||||
case bot
|
||||
case user
|
||||
}
|
||||
var isBot = false
|
||||
for message in messages {
|
||||
@ -8474,8 +8475,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let type: PeerType
|
||||
if isBot {
|
||||
type = .bot
|
||||
} else if let user = peer as? TelegramUser, user.botInfo != nil {
|
||||
type = .bot
|
||||
} else if let user = peer as? TelegramUser {
|
||||
if user.botInfo != nil {
|
||||
type = .bot
|
||||
} else {
|
||||
type = .user
|
||||
}
|
||||
} else if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
type = .channel
|
||||
} else {
|
||||
@ -8490,6 +8495,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
text = save ? strongSelf.presentationInterfaceState.strings.Conversation_CopyProtectionSavingDisabledChannel : strongSelf.presentationInterfaceState.strings.Conversation_CopyProtectionForwardingDisabledChannel
|
||||
case .bot:
|
||||
text = save ? strongSelf.presentationInterfaceState.strings.Conversation_CopyProtectionSavingDisabledBot : strongSelf.presentationInterfaceState.strings.Conversation_CopyProtectionForwardingDisabledBot
|
||||
case .user:
|
||||
text = save ? strongSelf.presentationData.strings.Conversation_CopyProtectionSavingDisabledSecret : strongSelf.presentationData.strings.Conversation_CopyProtectionForwardingDisabledSecret
|
||||
}
|
||||
|
||||
strongSelf.copyProtectionTooltipController?.dismiss()
|
||||
|
@ -314,7 +314,7 @@ private final class ChatHistoryTransactionOpaqueState {
|
||||
}
|
||||
}
|
||||
|
||||
private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHistoryView, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, animatedEmojiStickers: [String: [StickerPackItem]], additionalAnimatedEmojiStickers: [String: [Int: StickerPackItem]], subject: ChatControllerSubject?, currentlyPlayingMessageId: MessageIndex?, isCopyProtectionEnabled: Bool, availableReactions: AvailableReactions?, defaultReaction: String?) -> ChatMessageItemAssociatedData {
|
||||
private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHistoryView, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, animatedEmojiStickers: [String: [StickerPackItem]], additionalAnimatedEmojiStickers: [String: [Int: StickerPackItem]], subject: ChatControllerSubject?, currentlyPlayingMessageId: MessageIndex?, isCopyProtectionEnabled: Bool, availableReactions: AvailableReactions?, defaultReaction: String?, isPremium: Bool) -> ChatMessageItemAssociatedData {
|
||||
var automaticMediaDownloadPeerType: MediaAutoDownloadPeerType = .channel
|
||||
var contactsPeerIds: Set<PeerId> = Set()
|
||||
var channelDiscussionGroup: ChatMessageItemAssociatedData.ChannelDiscussionGroupStatus = .unknown
|
||||
@ -363,7 +363,7 @@ private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHist
|
||||
}
|
||||
}
|
||||
|
||||
return ChatMessageItemAssociatedData(automaticDownloadPeerType: automaticMediaDownloadPeerType, automaticDownloadNetworkType: automaticDownloadNetworkType, isRecentActions: false, subject: subject, contactsPeerIds: contactsPeerIds, channelDiscussionGroup: channelDiscussionGroup, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, currentlyPlayingMessageId: currentlyPlayingMessageId, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, defaultReaction: defaultReaction)
|
||||
return ChatMessageItemAssociatedData(automaticDownloadPeerType: automaticMediaDownloadPeerType, automaticDownloadNetworkType: automaticDownloadNetworkType, isRecentActions: false, subject: subject, contactsPeerIds: contactsPeerIds, channelDiscussionGroup: channelDiscussionGroup, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, currentlyPlayingMessageId: currentlyPlayingMessageId, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, defaultReaction: defaultReaction, isPremium: isPremium)
|
||||
}
|
||||
|
||||
private extension ChatHistoryLocationInput {
|
||||
@ -1002,6 +1002,16 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
let isPremium = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
|> map { peer -> Bool in
|
||||
switch peer {
|
||||
case let .user(user):
|
||||
return user.isPremium
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
let historyViewTransitionDisposable = combineLatest(queue: messageViewQueue,
|
||||
historyViewUpdate,
|
||||
self.chatPresentationDataPromise.get(),
|
||||
@ -1018,8 +1028,9 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
self.currentlyPlayingMessageIdPromise.get(),
|
||||
adMessages,
|
||||
availableReactions,
|
||||
defaultReaction
|
||||
).start(next: { [weak self] update, chatPresentationData, selectedMessages, updatingMedia, networkType, historyAppearsCleared, pendingUnpinnedAllMessages, pendingRemovedMessages, animatedEmojiStickers, additionalAnimatedEmojiStickers, customChannelDiscussionReadState, customThreadOutgoingReadState, currentlyPlayingMessageId, adMessages, availableReactions, defaultReaction in
|
||||
defaultReaction,
|
||||
isPremium
|
||||
).start(next: { [weak self] update, chatPresentationData, selectedMessages, updatingMedia, networkType, historyAppearsCleared, pendingUnpinnedAllMessages, pendingRemovedMessages, animatedEmojiStickers, additionalAnimatedEmojiStickers, customChannelDiscussionReadState, customThreadOutgoingReadState, currentlyPlayingMessageId, adMessages, availableReactions, defaultReaction, isPremium in
|
||||
func applyHole() {
|
||||
Queue.mainQueue().async {
|
||||
if let strongSelf = self {
|
||||
@ -1145,7 +1156,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
isCopyProtectionEnabled = peer.isCopyProtectionEnabled
|
||||
}
|
||||
}
|
||||
let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, subject: subject, currentlyPlayingMessageId: currentlyPlayingMessageId, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, defaultReaction: defaultReaction)
|
||||
let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, subject: subject, currentlyPlayingMessageId: currentlyPlayingMessageId, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, defaultReaction: defaultReaction, isPremium: isPremium)
|
||||
|
||||
let filteredEntries = chatHistoryEntriesForView(
|
||||
location: chatLocation,
|
||||
|
@ -1460,7 +1460,7 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
|
||||
optionsMap[id] = []
|
||||
}
|
||||
if let message = getMessage(id) {
|
||||
if message.isCopyProtected() {
|
||||
if message.isCopyProtected() || message.containsSecretMedia {
|
||||
isCopyProtected = true
|
||||
}
|
||||
for media in message.media {
|
||||
|
@ -788,6 +788,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
})
|
||||
|
||||
transition.horizontal.animateTransformScale(node: statusContainerNode.contentNode, from: 1.0 / scale)
|
||||
|
||||
contentNode.interactiveFileNode.animateSent()
|
||||
|
||||
return statusContainerNode
|
||||
}
|
||||
|
@ -102,11 +102,15 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
private let descriptionMeasuringNode: TextNode
|
||||
private let fetchingTextNode: ImmediateTextNode
|
||||
private let fetchingCompactTextNode: ImmediateTextNode
|
||||
private let waveformNode: AudioWaveformNode
|
||||
|
||||
private var waveformView: ComponentHostView<Empty>?
|
||||
|
||||
/*private let waveformNode: AudioWaveformNode
|
||||
private let waveformForegroundNode: AudioWaveformNode
|
||||
private var waveformShimmerNode: ShimmerEffectNode?
|
||||
private var waveformMaskNode: AudioWaveformNode?
|
||||
private var waveformScrubbingNode: MediaPlayerScrubbingNode?
|
||||
private var waveformScrubbingNode: MediaPlayerScrubbingNode?*/
|
||||
|
||||
private var audioTranscriptionButton: ComponentHostView<Empty>?
|
||||
private let textNode: TextNode
|
||||
let dateAndStatusNode: ChatMessageDateAndStatusNode
|
||||
@ -201,10 +205,10 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
self.fetchingCompactTextNode.contentsScale = UIScreenScale
|
||||
self.fetchingCompactTextNode.isHidden = true
|
||||
|
||||
self.waveformNode = AudioWaveformNode()
|
||||
/*self.waveformNode = AudioWaveformNode()
|
||||
self.waveformNode.isLayerBacked = true
|
||||
self.waveformForegroundNode = AudioWaveformNode()
|
||||
self.waveformForegroundNode.isLayerBacked = true
|
||||
self.waveformForegroundNode.isLayerBacked = true*/
|
||||
|
||||
self.textNode = TextNode()
|
||||
self.textNode.displaysAsynchronously = false
|
||||
@ -298,7 +302,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
private func transcribe() {
|
||||
guard let context = self.context, let message = self.message else {
|
||||
guard let context = self.context, let message = self.message, let presentationData = self.presentationData else {
|
||||
return
|
||||
}
|
||||
if self.transcribedText == nil {
|
||||
@ -306,7 +310,9 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
self.audioTranscriptionState = .inProgress
|
||||
self.requestUpdateLayout(true)
|
||||
|
||||
if !"".isEmpty {
|
||||
if context.sharedContext.immediateExperimentalUISettings.localTranscription {
|
||||
let appLocale = presentationData.strings.baseLanguageCode
|
||||
|
||||
let signal: Signal<String?, NoError> = context.account.postbox.transaction { transaction -> Message? in
|
||||
return transaction.getMessage(message.id)
|
||||
}
|
||||
@ -338,7 +344,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
guard let result = result else {
|
||||
return .single(nil)
|
||||
}
|
||||
return transcribeAudio(path: result)
|
||||
return transcribeAudio(path: result, appLocale: appLocale)
|
||||
}
|
||||
|
||||
let _ = signal.start(next: { [weak self] result in
|
||||
@ -346,8 +352,12 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
return
|
||||
}
|
||||
strongSelf.transcribeDisposable = nil
|
||||
strongSelf.audioTranscriptionState = .expanded
|
||||
strongSelf.transcribedText = result
|
||||
if strongSelf.transcribedText != nil {
|
||||
strongSelf.audioTranscriptionState = .expanded
|
||||
} else {
|
||||
strongSelf.audioTranscriptionState = .collapsed
|
||||
}
|
||||
strongSelf.requestUpdateLayout(true)
|
||||
})
|
||||
} else {
|
||||
@ -470,6 +480,8 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
var isVoice = false
|
||||
var audioDuration: Int32 = 0
|
||||
|
||||
let canTranscribe = arguments.associatedData.isPremium || arguments.context.sharedContext.immediateExperimentalUISettings.localTranscription
|
||||
|
||||
let messageTheme = arguments.incoming ? arguments.presentationData.theme.theme.chat.message.incoming : arguments.presentationData.theme.theme.chat.message.outgoing
|
||||
|
||||
for attribute in arguments.file.attributes {
|
||||
@ -571,7 +583,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
let (textLayout, textApply) = textAsyncLayout(TextNodeLayoutArguments(attributedString: textString, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: inlineTextConstrainedSize.width - horizontalInset, height: .greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let minVoiceWidth: CGFloat = 120.0
|
||||
let maxVoiceWidth = constrainedSize.width
|
||||
let maxVoiceWidth = constrainedSize.width - 36.0
|
||||
let maxVoiceLength: CGFloat = 30.0
|
||||
let minVoiceLength: CGFloat = 2.0
|
||||
|
||||
@ -666,7 +678,10 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
let descriptionAndStatusWidth = descriptionLayout.size.width
|
||||
|
||||
let calcDuration = max(minVoiceLength, min(maxVoiceLength, CGFloat(audioDuration)))
|
||||
minLayoutWidth = 30.0 + 8.0 + minVoiceWidth + (maxVoiceWidth - minVoiceWidth) * (calcDuration - minVoiceLength) / (maxVoiceLength - minVoiceLength)
|
||||
minLayoutWidth = minVoiceWidth + (maxVoiceWidth - minVoiceWidth) * (calcDuration - minVoiceLength) / (maxVoiceLength - minVoiceLength)
|
||||
if canTranscribe {
|
||||
minLayoutWidth += 30.0 + 8.0
|
||||
}
|
||||
minLayoutWidth = max(descriptionAndStatusWidth + 56, minLayoutWidth)
|
||||
} else {
|
||||
minLayoutWidth = max(titleLayout.size.width, descriptionMaxWidth) + 44.0 + 8.0
|
||||
@ -729,9 +744,11 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
if let statusSizeAndApply = statusSizeAndApply {
|
||||
fittedLayoutSize.width = max(fittedLayoutSize.width, statusSizeAndApply.0.width)
|
||||
fittedLayoutSize.height += statusSizeAndApply.0.height
|
||||
if !statusSizeAndApply.0.height.isZero && iconFrame == nil {
|
||||
statusOffset = -10.0
|
||||
fittedLayoutSize.height += statusOffset
|
||||
if textString == nil {
|
||||
if !statusSizeAndApply.0.height.isZero && iconFrame == nil {
|
||||
statusOffset = -10.0
|
||||
fittedLayoutSize.height += statusOffset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -806,7 +823,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
if let statusSizeAndApply = statusSizeAndApply {
|
||||
let statusFrame: CGRect
|
||||
if textString != nil {
|
||||
statusFrame = CGRect(origin: CGPoint(x: fittedLayoutSize.width - 5.0 - statusSizeAndApply.0.width, y: textFrame.maxY + 4.0), size: statusSizeAndApply.0)
|
||||
statusFrame = CGRect(origin: CGPoint(x: fittedLayoutSize.width - 6.0 - statusSizeAndApply.0.width, y: textFrame.maxY + 4.0), size: statusSizeAndApply.0)
|
||||
} else {
|
||||
statusFrame = CGRect(origin: CGPoint(x: statusReferenceFrame.minX, y: statusReferenceFrame.maxY + statusOffset), size: statusSizeAndApply.0)
|
||||
}
|
||||
@ -822,7 +839,12 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
if isVoice {
|
||||
if strongSelf.waveformScrubbingNode == nil {
|
||||
var scrubbingFrame = CGRect(origin: CGPoint(x: 57.0, y: 1.0), size: CGSize(width: boundingWidth - 60.0, height: 18.0))
|
||||
if canTranscribe {
|
||||
scrubbingFrame.size.width -= 30.0 + 4.0
|
||||
}
|
||||
|
||||
/*if strongSelf.waveformScrubbingNode == nil {
|
||||
let waveformScrubbingNode = MediaPlayerScrubbingNode(content: .custom(backgroundNode: strongSelf.waveformNode, foregroundContentNode: strongSelf.waveformForegroundNode))
|
||||
waveformScrubbingNode.hitTestSlop = UIEdgeInsets(top: -10.0, left: 0.0, bottom: -10.0, right: 0.0)
|
||||
waveformScrubbingNode.seek = { timestamp in
|
||||
@ -835,8 +857,6 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
strongSelf.addSubnode(waveformScrubbingNode)
|
||||
}
|
||||
|
||||
let scrubbingFrame = CGRect(origin: CGPoint(x: 57.0, y: 1.0), size: CGSize(width: boundingWidth - 60.0 - 30.0 - 8.0, height: 15.0))
|
||||
|
||||
if case .inProgress = audioTranscriptionState {
|
||||
if strongSelf.waveformShimmerNode == nil {
|
||||
let waveformShimmerNode = ShimmerEffectNode()
|
||||
@ -899,36 +919,97 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
waveformColor = messageTheme.mediaInactiveControlColor
|
||||
}
|
||||
strongSelf.waveformNode.setup(color: waveformColor, gravity: .bottom, waveform: audioWaveform)
|
||||
strongSelf.waveformForegroundNode.setup(color: messageTheme.mediaActiveControlColor, gravity: .bottom, waveform: audioWaveform)
|
||||
strongSelf.waveformForegroundNode.setup(color: messageTheme.mediaActiveControlColor, gravity: .bottom, waveform: audioWaveform)*/
|
||||
|
||||
let audioTranscriptionButton: ComponentHostView<Empty>
|
||||
if let current = strongSelf.audioTranscriptionButton {
|
||||
audioTranscriptionButton = current
|
||||
let waveformView: ComponentHostView<Empty>
|
||||
let waveformTransition: Transition
|
||||
if let current = strongSelf.waveformView {
|
||||
waveformView = current
|
||||
switch animation.transition {
|
||||
case .immediate:
|
||||
waveformTransition = .immediate
|
||||
case let .animated(duration, _):
|
||||
waveformTransition = .easeInOut(duration: duration)
|
||||
}
|
||||
} else {
|
||||
audioTranscriptionButton = ComponentHostView<Empty>()
|
||||
strongSelf.audioTranscriptionButton = audioTranscriptionButton
|
||||
strongSelf.view.addSubview(audioTranscriptionButton)
|
||||
waveformView = ComponentHostView<Empty>()
|
||||
strongSelf.waveformView = waveformView
|
||||
strongSelf.view.addSubview(waveformView)
|
||||
waveformTransition = .immediate
|
||||
}
|
||||
let audioTranscriptionButtonSize = audioTranscriptionButton.update(
|
||||
transition: animation.isAnimated ? .easeInOut(duration: 0.3) : .immediate,
|
||||
component: AnyComponent(AudioTranscriptionButtonComponent(
|
||||
theme: arguments.incoming ? arguments.presentationData.theme.theme.chat.message.incoming : arguments.presentationData.theme.theme.chat.message.outgoing,
|
||||
transcriptionState: audioTranscriptionState,
|
||||
pressed: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.transcribe()
|
||||
}
|
||||
|
||||
let waveformColor: UIColor
|
||||
if arguments.incoming {
|
||||
if consumableContentIcon != nil {
|
||||
waveformColor = messageTheme.mediaActiveControlColor
|
||||
} else {
|
||||
waveformColor = messageTheme.mediaInactiveControlColor
|
||||
}
|
||||
} else {
|
||||
waveformColor = messageTheme.mediaInactiveControlColor
|
||||
}
|
||||
|
||||
var isTranscriptionInProgress = false
|
||||
if case .inProgress = audioTranscriptionState {
|
||||
isTranscriptionInProgress = true
|
||||
}
|
||||
|
||||
let _ = waveformView.update(
|
||||
transition: waveformTransition.withUserData(ComponentHostViewSkipSettingFrame()),
|
||||
component: AnyComponent(AudioWaveformComponent(
|
||||
backgroundColor: waveformColor,
|
||||
foregroundColor: messageTheme.mediaActiveControlColor,
|
||||
shimmerColor: isTranscriptionInProgress ? messageTheme.mediaActiveControlColor : nil,
|
||||
samples: audioWaveform?.samples ?? Data(),
|
||||
peak: audioWaveform?.peak ?? 0,
|
||||
status: strongSelf.playbackStatus.get()
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 30.0, height: 30.0)
|
||||
containerSize: scrubbingFrame.size
|
||||
)
|
||||
animation.animator.updateFrame(layer: audioTranscriptionButton.layer, frame: CGRect(origin: CGPoint(x: boundingWidth - 30.0 + 3.0, y: -6.0), size: audioTranscriptionButtonSize), completion: nil)
|
||||
|
||||
animation.animator.updateFrame(layer: waveformView.layer, frame: scrubbingFrame, completion: nil)
|
||||
animation.animator.updateFrame(layer: waveformView.componentView!.layer, frame: CGRect(origin: CGPoint(), size: scrubbingFrame.size), completion: nil)
|
||||
|
||||
if canTranscribe {
|
||||
let audioTranscriptionButton: ComponentHostView<Empty>
|
||||
if let current = strongSelf.audioTranscriptionButton {
|
||||
audioTranscriptionButton = current
|
||||
} else {
|
||||
audioTranscriptionButton = ComponentHostView<Empty>()
|
||||
strongSelf.audioTranscriptionButton = audioTranscriptionButton
|
||||
strongSelf.view.addSubview(audioTranscriptionButton)
|
||||
}
|
||||
let audioTranscriptionButtonSize = audioTranscriptionButton.update(
|
||||
transition: animation.isAnimated ? .easeInOut(duration: 0.3) : .immediate,
|
||||
component: AnyComponent(AudioTranscriptionButtonComponent(
|
||||
theme: arguments.incoming ? arguments.presentationData.theme.theme.chat.message.incoming : arguments.presentationData.theme.theme.chat.message.outgoing,
|
||||
transcriptionState: audioTranscriptionState,
|
||||
pressed: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.transcribe()
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 30.0, height: 30.0)
|
||||
)
|
||||
animation.animator.updateFrame(layer: audioTranscriptionButton.layer, frame: CGRect(origin: CGPoint(x: boundingWidth - 30.0 + 3.0, y: -6.0), size: audioTranscriptionButtonSize), completion: nil)
|
||||
} else {
|
||||
if let audioTranscriptionButton = strongSelf.audioTranscriptionButton {
|
||||
strongSelf.audioTranscriptionButton = nil
|
||||
audioTranscriptionButton.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let waveformScrubbingNode = strongSelf.waveformScrubbingNode {
|
||||
/*if let waveformScrubbingNode = strongSelf.waveformScrubbingNode {
|
||||
strongSelf.waveformScrubbingNode = nil
|
||||
waveformScrubbingNode.removeFromSupernode()
|
||||
}*/
|
||||
if let waveformView = strongSelf.waveformView {
|
||||
strongSelf.waveformView = nil
|
||||
waveformView.removeFromSuperview()
|
||||
}
|
||||
if let audioTranscriptionButton = strongSelf.audioTranscriptionButton {
|
||||
strongSelf.audioTranscriptionButton = nil
|
||||
@ -996,7 +1077,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
}))
|
||||
}
|
||||
|
||||
strongSelf.waveformNode.displaysAsynchronously = !arguments.presentationData.isPreview
|
||||
//strongSelf.waveformNode.displaysAsynchronously = !arguments.presentationData.isPreview
|
||||
strongSelf.statusNode?.displaysAsynchronously = !arguments.presentationData.isPreview
|
||||
strongSelf.statusNode?.frame = CGRect(origin: CGPoint(), size: progressFrame.size)
|
||||
|
||||
@ -1168,7 +1249,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
if self.message?.forwardInfo != nil {
|
||||
fetchStatus = resourceStatus.fetchStatus
|
||||
}
|
||||
self.waveformScrubbingNode?.enableScrubbing = false
|
||||
//self.waveformScrubbingNode?.enableScrubbing = false
|
||||
switch fetchStatus {
|
||||
case let .Fetching(_, progress):
|
||||
let adjustedProgress = max(progress, 0.027)
|
||||
@ -1202,7 +1283,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
case let .playbackStatus(playbackStatus):
|
||||
self.waveformScrubbingNode?.enableScrubbing = true
|
||||
//self.waveformScrubbingNode?.enableScrubbing = true
|
||||
switch playbackStatus {
|
||||
case .playing:
|
||||
state = .pause
|
||||
@ -1474,6 +1555,12 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func animateSent() {
|
||||
if let view = self.waveformView?.componentView as? AudioWaveformComponent.View {
|
||||
view.animateIn()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -75,7 +75,7 @@ private final class InlineStickerItemLayer: SimpleLayer {
|
||||
private var disposable: Disposable?
|
||||
private var fetchDisposable: Disposable?
|
||||
|
||||
private var isInHierarchy: Bool = false
|
||||
private var isInHierarchyValue: Bool = false
|
||||
var isVisibleForAnimations: Bool = false {
|
||||
didSet {
|
||||
self.updatePlayback()
|
||||
@ -132,16 +132,16 @@ private final class InlineStickerItemLayer: SimpleLayer {
|
||||
|
||||
override func action(forKey event: String) -> CAAction? {
|
||||
if event == kCAOnOrderIn {
|
||||
self.isInHierarchy = true
|
||||
self.isInHierarchyValue = true
|
||||
} else if event == kCAOnOrderOut {
|
||||
self.isInHierarchy = false
|
||||
self.isInHierarchyValue = false
|
||||
}
|
||||
self.updatePlayback()
|
||||
return nullAction
|
||||
}
|
||||
|
||||
private func updatePlayback() {
|
||||
let shouldBePlaying = self.isInHierarchy && self.isVisibleForAnimations && self.frameSource != nil
|
||||
let shouldBePlaying = self.isInHierarchyValue && self.isVisibleForAnimations && self.frameSource != nil
|
||||
if shouldBePlaying != (self.displayLink != nil) {
|
||||
if shouldBePlaying {
|
||||
self.displayLink = ConstantDisplayLinkAnimator(update: { [weak self] in
|
||||
|
@ -114,7 +114,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.titleUpdated(title: new)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeAbout(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -145,14 +145,14 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .content:
|
||||
let peers = SimpleDictionary<PeerId, Peer>()
|
||||
let attributes: [MessageAttribute] = []
|
||||
let prevMessage = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: prev, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: new, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.isEmpty ? .eventLogPreviousDescription(prevMessage) : nil)
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.isEmpty ? .eventLogPreviousDescription(prevMessage) : nil)
|
||||
}
|
||||
case let .changeUsername(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -183,7 +183,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
let action: TelegramMediaActionType = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .content:
|
||||
var previousAttributes: [MessageAttribute] = []
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -202,7 +202,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let prevMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: prevText, attributes: previousAttributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.isEmpty ? .eventLogPreviousLink(prevMessage) : nil)
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.isEmpty ? .eventLogPreviousLink(prevMessage) : nil)
|
||||
}
|
||||
case let .changePhoto(_, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -221,7 +221,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.photoUpdated(image: photo)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .toggleInvites(value):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -248,7 +248,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .toggleSignatures(value):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -275,7 +275,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .updatePinned(message):
|
||||
switch self.id.contentIndex {
|
||||
case .header:
|
||||
@ -306,7 +306,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .content:
|
||||
if let message = message {
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -324,7 +324,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
} else {
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -346,7 +346,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
}
|
||||
}
|
||||
case let .editMessage(prev, message):
|
||||
@ -391,7 +391,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .content:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -408,7 +408,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.text.isEmpty || !message.text.isEmpty ? .eventLogPreviousMessage(filterOriginalMessageFlags(prev)) : nil)
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.text.isEmpty || !message.text.isEmpty ? .eventLogPreviousMessage(filterOriginalMessageFlags(prev)) : nil)
|
||||
}
|
||||
case let .deleteMessage(message):
|
||||
switch self.id.contentIndex {
|
||||
@ -434,7 +434,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .content:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -458,7 +458,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
}
|
||||
case .participantJoin, .participantLeave:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -476,7 +476,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
action = TelegramMediaActionType.removedMembers(peerIds: [self.entry.event.peerId])
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .participantInvite(participant):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -493,7 +493,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action: TelegramMediaActionType
|
||||
action = TelegramMediaActionType.addedMembers(peerIds: [participant.peer.id])
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .participantToggleBan(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -623,7 +623,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .participantToggleAdmin(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -856,7 +856,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeStickerPack(_, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -885,7 +885,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .togglePreHistoryHidden(value):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -915,7 +915,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .updateDefaultBannedRights(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -973,7 +973,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .pollStopped(message):
|
||||
switch self.id.contentIndex {
|
||||
case .header:
|
||||
@ -1001,7 +1001,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .content:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -1018,7 +1018,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: message.author, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: nil)
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: nil)
|
||||
}
|
||||
case let .linkedPeerUpdated(previous, updated):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -1074,7 +1074,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeGeoLocation(_, updated):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1096,12 +1096,12 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let mediaMap = TelegramMediaMap(latitude: updated.latitude, longitude: updated.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: nil, liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: text, attributes: [], media: [mediaMap], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
} else {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
}
|
||||
case let .updateSlowmode(_, newValue):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -1132,7 +1132,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .startGroupCall, .endGroupCall:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1169,7 +1169,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .groupCallUpdateParticipantMuteStatus(participantId, isMuted):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1203,7 +1203,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .updateGroupCallSettings(joinMuted):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1232,7 +1232,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .groupCallUpdateParticipantVolume(participantId, volume):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1263,7 +1263,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .deleteExportedInvitation(invite):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1289,7 +1289,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .revokeExportedInvitation(invite):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1315,7 +1315,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .editExportedInvitation(_, updatedInvite):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1341,7 +1341,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .participantJoinedViaInvite(invite):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1367,7 +1367,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeHistoryTTL(_, updatedValue):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1398,7 +1398,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeAvailableReactions(_, updatedValue):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1430,7 +1430,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeTheme(_, updatedValue):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1461,7 +1461,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .participantJoinByRequest(invite, approvedBy):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1501,7 +1501,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .toggleCopyProtection(value):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1528,7 +1528,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .sendMessage(message):
|
||||
switch self.id.contentIndex {
|
||||
case .header:
|
||||
@ -1553,7 +1553,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .content:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -1570,7 +1570,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7275,19 +7275,26 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
case group
|
||||
case channel
|
||||
case bot
|
||||
case user
|
||||
}
|
||||
var isBot = false
|
||||
for message in messages {
|
||||
if let author = message.author, case let .user(user) = author, user.botInfo != nil {
|
||||
isBot = true
|
||||
if let author = message.author, case let .user(user) = author {
|
||||
if user.botInfo != nil {
|
||||
isBot = true
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
let type: PeerType
|
||||
if isBot {
|
||||
type = .bot
|
||||
} else if let user = peer as? TelegramUser, user.botInfo != nil {
|
||||
type = .bot
|
||||
} else if let user = peer as? TelegramUser {
|
||||
if user.botInfo != nil {
|
||||
type = .bot
|
||||
} else {
|
||||
type = .user
|
||||
}
|
||||
} else if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
type = .channel
|
||||
} else {
|
||||
@ -7302,6 +7309,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
text = save ? strongSelf.presentationData.strings.Conversation_CopyProtectionSavingDisabledChannel : strongSelf.presentationData.strings.Conversation_CopyProtectionForwardingDisabledChannel
|
||||
case .bot:
|
||||
text = save ? strongSelf.presentationData.strings.Conversation_CopyProtectionSavingDisabledBot : strongSelf.presentationData.strings.Conversation_CopyProtectionForwardingDisabledBot
|
||||
case .user:
|
||||
text = save ? strongSelf.presentationData.strings.Conversation_CopyProtectionSavingDisabledSecret : strongSelf.presentationData.strings.Conversation_CopyProtectionForwardingDisabledSecret
|
||||
}
|
||||
|
||||
strongSelf.copyProtectionTooltipController?.dismiss()
|
||||
|
@ -1347,7 +1347,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
chatLocation = .peer(id: messages.first!.id.peerId)
|
||||
}
|
||||
|
||||
return ChatMessageItem(presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), fontSize: fontSize, strings: strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameOrder, disableAnimations: false, largeEmoji: false, chatBubbleCorners: chatBubbleCorners, animatedEmojiScale: 1.0, isPreview: true), context: context, chatLocation: chatLocation, associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false, subject: nil, contactsPeerIds: Set(), animatedEmojiStickers: [:], forcedResourceStatus: forcedResourceStatus, availableReactions: availableReactions, defaultReaction: nil), controllerInteraction: controllerInteraction, content: content, disableDate: true, additionalContent: nil)
|
||||
return ChatMessageItem(presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), fontSize: fontSize, strings: strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameOrder, disableAnimations: false, largeEmoji: false, chatBubbleCorners: chatBubbleCorners, animatedEmojiScale: 1.0, isPreview: true), context: context, chatLocation: chatLocation, associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false, subject: nil, contactsPeerIds: Set(), animatedEmojiStickers: [:], forcedResourceStatus: forcedResourceStatus, availableReactions: availableReactions, defaultReaction: nil, isPremium: false), controllerInteraction: controllerInteraction, content: content, disableDate: true, additionalContent: nil)
|
||||
}
|
||||
|
||||
public func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader {
|
||||
|
@ -21,6 +21,7 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
||||
public var experimentalBackground: Bool
|
||||
public var snow: Bool
|
||||
public var inlineStickers: Bool
|
||||
public var localTranscription: Bool
|
||||
|
||||
public static var defaultSettings: ExperimentalUISettings {
|
||||
return ExperimentalUISettings(
|
||||
@ -40,7 +41,8 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
||||
acceleratedStickers: false,
|
||||
experimentalBackground: false,
|
||||
snow: false,
|
||||
inlineStickers: false
|
||||
inlineStickers: false,
|
||||
localTranscription: false
|
||||
)
|
||||
}
|
||||
|
||||
@ -61,7 +63,8 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
||||
acceleratedStickers: Bool,
|
||||
experimentalBackground: Bool,
|
||||
snow: Bool,
|
||||
inlineStickers: Bool
|
||||
inlineStickers: Bool,
|
||||
localTranscription: Bool
|
||||
) {
|
||||
self.keepChatNavigationStack = keepChatNavigationStack
|
||||
self.skipReadHistory = skipReadHistory
|
||||
@ -80,6 +83,7 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
||||
self.experimentalBackground = experimentalBackground
|
||||
self.snow = snow
|
||||
self.inlineStickers = inlineStickers
|
||||
self.localTranscription = localTranscription
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
@ -102,6 +106,7 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
||||
self.experimentalBackground = (try container.decodeIfPresent(Int32.self, forKey: "experimentalBackground") ?? 0) != 0
|
||||
self.snow = (try container.decodeIfPresent(Int32.self, forKey: "snow") ?? 0) != 0
|
||||
self.inlineStickers = (try container.decodeIfPresent(Int32.self, forKey: "inlineStickers") ?? 0) != 0
|
||||
self.localTranscription = (try container.decodeIfPresent(Int32.self, forKey: "localTranscription") ?? 0) != 0
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -124,6 +129,7 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
||||
try container.encode((self.experimentalBackground ? 1 : 0) as Int32, forKey: "experimentalBackground")
|
||||
try container.encode((self.snow ? 1 : 0) as Int32, forKey: "snow")
|
||||
try container.encode((self.inlineStickers ? 1 : 0) as Int32, forKey: "inlineStickers")
|
||||
try container.encode((self.localTranscription ? 1 : 0) as Int32, forKey: "localTranscription")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,9 +431,9 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
}
|
||||
private static var cachedSharedPattern: (PatternKey, UIImage)?
|
||||
|
||||
private var inlineAnimationNodes: [(AnimatedStickerNode, CGPoint)] = []
|
||||
private let hierarchyTrackingLayer = HierarchyTrackingLayer()
|
||||
private var activateInlineAnimationTimer: SwiftSignalKit.Timer?
|
||||
//private var inlineAnimationNodes: [(AnimatedStickerNode, CGPoint)] = []
|
||||
//private let hierarchyTrackingLayer = HierarchyTrackingLayer()
|
||||
//private var activateInlineAnimationTimer: SwiftSignalKit.Timer?
|
||||
|
||||
private let _isReady = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||
var isReady: Signal<Bool, NoError> {
|
||||
@ -460,7 +460,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
self.addSubnode(self.contentNode)
|
||||
self.addSubnode(self.patternImageNode)
|
||||
|
||||
let animationList: [(String, CGPoint)] = [
|
||||
/*let animationList: [(String, CGPoint)] = [
|
||||
("ptrnCAT_1162_1918", CGPoint(x: 1162 - 256, y: 1918 - 256)),
|
||||
("ptrnDOG_0440_2284", CGPoint(x: 440 - 256, y: 2284 - 256)),
|
||||
("ptrnGLOB_0438_1553", CGPoint(x: 438 - 256, y: 1553 - 256)),
|
||||
@ -470,7 +470,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
let animationNode = AnimatedStickerNode()
|
||||
animationNode.automaticallyLoadFirstFrame = true
|
||||
animationNode.autoplay = true
|
||||
self.inlineAnimationNodes.append((animationNode, relativePosition))
|
||||
//self.inlineAnimationNodes.append((animationNode, relativePosition))
|
||||
self.patternImageNode.addSubnode(animationNode)
|
||||
animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: animation), width: 256, height: 256, playbackMode: .once, mode: .direct(cachePathPrefix: nil))
|
||||
}
|
||||
@ -500,7 +500,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
animationNode.visibility = false
|
||||
}
|
||||
strongSelf.activateInlineAnimationTimer?.invalidate()
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
deinit {
|
||||
@ -725,8 +725,8 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
return
|
||||
}
|
||||
|
||||
if var generator = generator {
|
||||
generator = { arguments in
|
||||
if let generator = generator {
|
||||
/*generator = { arguments in
|
||||
let scale = arguments.scale ?? UIScreenScale
|
||||
let context = DrawingContext(size: arguments.drawingSize, scale: scale, clear: true)
|
||||
|
||||
@ -739,7 +739,7 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
}*/
|
||||
|
||||
strongSelf.validPatternImage = ValidPatternImage(wallpaper: wallpaper, generate: generator)
|
||||
strongSelf.validPatternGeneratedImage = nil
|
||||
@ -860,12 +860,12 @@ final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgroundNode
|
||||
|
||||
self.loadPatternForSizeIfNeeded(size: size, transition: transition)
|
||||
|
||||
for (animationNode, relativePosition) in self.inlineAnimationNodes {
|
||||
/*for (animationNode, relativePosition) in self.inlineAnimationNodes {
|
||||
let sizeNorm = CGSize(width: 1440, height: 2960)
|
||||
let animationSize = CGSize(width: 512.0 / sizeNorm.width * size.width, height: 512.0 / sizeNorm.height * size.height)
|
||||
animationNode.frame = CGRect(origin: CGPoint(x: relativePosition.x / sizeNorm.width * size.width, y: relativePosition.y / sizeNorm.height * size.height), size: animationSize)
|
||||
animationNode.updateLayout(size: animationNode.frame.size)
|
||||
}
|
||||
}*/
|
||||
|
||||
if isFirstLayout && !self.frame.isEmpty {
|
||||
self.updateScale()
|
||||
|
Loading…
x
Reference in New Issue
Block a user