diff --git a/submodules/ItemListUI/Sources/Items/ItemListCheckboxItem.swift b/submodules/ItemListUI/Sources/Items/ItemListCheckboxItem.swift index 2f12df9694..1ce3ca2adb 100644 --- a/submodules/ItemListUI/Sources/Items/ItemListCheckboxItem.swift +++ b/submodules/ItemListUI/Sources/Items/ItemListCheckboxItem.swift @@ -204,7 +204,7 @@ public class ItemListCheckboxItemNode: ItemListRevealOptionsItemNode { titleColor = item.presentationData.theme.list.itemAccentColor } - let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: titleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 20.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: titleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 28.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let separatorHeight = UIScreenPixel diff --git a/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift b/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift index 3acc8d5853..beaee162e1 100644 --- a/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift +++ b/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift @@ -262,7 +262,7 @@ private final class AudioPlayerWrapper: NSObject, AVAudioPlayerDelegate { super.init() - self.player = try? AVAudioPlayer(contentsOf: url, fileTypeHint: "m4a") + self.player = try? AVAudioPlayer(contentsOf: url, fileTypeHint: "mp3") self.player?.delegate = self } @@ -304,7 +304,7 @@ public func fileNameForNotificationSound(account: Account, notificationSoundList } for sound in notificationSoundList.sounds { if sound.file.fileId.id == fileId { - if let path = account.postbox.mediaBox.completedResourcePath(sound.file.resource, pathExtension: "mp3") { + if let path = account.postbox.mediaBox.completedResourcePath(sound.file.resource, pathExtension: nil) { return path } } @@ -329,7 +329,7 @@ public func playSound(context: AccountContext, notificationSoundList: Notificati deactivateImpl?() }) currentPlayer?.play() - } else { + } else if !filePath.isEmpty { if let url = getAppBundle().url(forResource: filePath, withExtension: "m4a") { currentPlayer = AudioPlayerWrapper(url: url, completed: { deactivateImpl?() diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index e5a4a4123e..896054be6f 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -68,7 +68,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1071145937] = { return Api.BotCommandScope.parse_botCommandScopePeerAdmins($0) } dict[169026035] = { return Api.BotCommandScope.parse_botCommandScopePeerUser($0) } dict[1011811544] = { return Api.BotCommandScope.parse_botCommandScopeUsers($0) } - dict[-863263529] = { return Api.BotInfo.parse_botInfo($0) } + dict[-1892676777] = { return Api.BotInfo.parse_botInfo($0) } dict[1984755728] = { return Api.BotInlineMessage.parse_botInlineMessageMediaAuto($0) } dict[416402882] = { return Api.BotInlineMessage.parse_botInlineMessageMediaContact($0) } dict[85477117] = { return Api.BotInlineMessage.parse_botInlineMessageMediaGeo($0) } diff --git a/submodules/TelegramApi/Sources/Api1.swift b/submodules/TelegramApi/Sources/Api1.swift index a50e19438e..e540e8f7ef 100644 --- a/submodules/TelegramApi/Sources/Api1.swift +++ b/submodules/TelegramApi/Sources/Api1.swift @@ -856,18 +856,19 @@ public extension Api { } public extension Api { enum BotInfo: TypeConstructorDescription { - case botInfo(flags: Int32, userId: Int64?, description: String?, descriptionPhoto: Api.Photo?, commands: [Api.BotCommand]?, menuButton: Api.BotMenuButton?) + case botInfo(flags: Int32, userId: Int64?, description: String?, descriptionPhoto: Api.Photo?, descriptionDocument: Api.Document?, commands: [Api.BotCommand]?, menuButton: Api.BotMenuButton?) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .botInfo(let flags, let userId, let description, let descriptionPhoto, let commands, let menuButton): + case .botInfo(let flags, let userId, let description, let descriptionPhoto, let descriptionDocument, let commands, let menuButton): if boxed { - buffer.appendInt32(-863263529) + buffer.appendInt32(-1892676777) } serializeInt32(flags, buffer: buffer, boxed: false) if Int(flags) & Int(1 << 0) != 0 {serializeInt64(userId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 1) != 0 {serializeString(description!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 4) != 0 {descriptionPhoto!.serialize(buffer, true)} + if Int(flags) & Int(1 << 5) != 0 {descriptionDocument!.serialize(buffer, true)} if Int(flags) & Int(1 << 2) != 0 {buffer.appendInt32(481674261) buffer.appendInt32(Int32(commands!.count)) for item in commands! { @@ -880,8 +881,8 @@ public extension Api { public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .botInfo(let flags, let userId, let description, let descriptionPhoto, let commands, let menuButton): - return ("botInfo", [("flags", String(describing: flags)), ("userId", String(describing: userId)), ("description", String(describing: description)), ("descriptionPhoto", String(describing: descriptionPhoto)), ("commands", String(describing: commands)), ("menuButton", String(describing: menuButton))]) + case .botInfo(let flags, let userId, let description, let descriptionPhoto, let descriptionDocument, let commands, let menuButton): + return ("botInfo", [("flags", String(describing: flags)), ("userId", String(describing: userId)), ("description", String(describing: description)), ("descriptionPhoto", String(describing: descriptionPhoto)), ("descriptionDocument", String(describing: descriptionDocument)), ("commands", String(describing: commands)), ("menuButton", String(describing: menuButton))]) } } @@ -896,22 +897,27 @@ public extension Api { if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() { _4 = Api.parse(reader, signature: signature) as? Api.Photo } } - var _5: [Api.BotCommand]? - if Int(_1!) & Int(1 << 2) != 0 {if let _ = reader.readInt32() { - _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotCommand.self) + var _5: Api.Document? + if Int(_1!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.Document } } - var _6: Api.BotMenuButton? + var _6: [Api.BotCommand]? + if Int(_1!) & Int(1 << 2) != 0 {if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BotCommand.self) + } } + var _7: Api.BotMenuButton? if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() { - _6 = Api.parse(reader, signature: signature) as? Api.BotMenuButton + _7 = Api.parse(reader, signature: signature) as? Api.BotMenuButton } } let _c1 = _1 != nil let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil let _c4 = (Int(_1!) & Int(1 << 4) == 0) || _4 != nil - let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil - let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { - return Api.BotInfo.botInfo(flags: _1!, userId: _2, description: _3, descriptionPhoto: _4, commands: _5, menuButton: _6) + let _c5 = (Int(_1!) & Int(1 << 5) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 3) == 0) || _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.BotInfo.botInfo(flags: _1!, userId: _2, description: _3, descriptionPhoto: _4, descriptionDocument: _5, commands: _6, menuButton: _7) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api27.swift b/submodules/TelegramApi/Sources/Api27.swift index 45cc0835b2..6bfe54fccb 100644 --- a/submodules/TelegramApi/Sources/Api27.swift +++ b/submodules/TelegramApi/Sources/Api27.swift @@ -6697,6 +6697,22 @@ public extension Api.functions.phone { }) } } +public extension Api.functions.phone { + static func saveCallLog(peer: Api.InputPhoneCall, file: Api.InputFile) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1092913030) + peer.serialize(buffer, true) + file.serialize(buffer, true) + return (FunctionDescription(name: "phone.saveCallLog", parameters: [("peer", String(describing: peer)), ("file", String(describing: file))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} public extension Api.functions.phone { static func saveDefaultGroupCallJoinAs(peer: Api.InputPeer, joinAs: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() diff --git a/submodules/TelegramCore/Sources/ApiUtils/BotInfo.swift b/submodules/TelegramCore/Sources/ApiUtils/BotInfo.swift index b497a0bb16..33a38190f7 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/BotInfo.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/BotInfo.swift @@ -16,7 +16,7 @@ extension BotMenuButton { extension BotInfo { convenience init(apiBotInfo: Api.BotInfo) { switch apiBotInfo { - case let .botInfo(_, _, description, descriptionPhoto, apiCommands, apiMenuButton): + case let .botInfo(_, _, description, descriptionPhoto, _, apiCommands, apiMenuButton): let photo: TelegramMediaImage? = descriptionPhoto.flatMap(telegramMediaImageFromApiPhoto) var commands: [BotCommand] = [] if let apiCommands = apiCommands { diff --git a/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift b/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift index 1fedee246d..500e026693 100644 --- a/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift +++ b/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift @@ -226,6 +226,7 @@ private enum MediaReferenceRevalidationKey: Hashable { case themes case peerAvatars(peer: PeerReference) case attachBot(peer: PeerReference) + case notificationSoundList } private final class MediaReferenceRevalidationItemContext { @@ -556,6 +557,24 @@ final class MediaReferenceRevalidationContext { } } } + + func notificationSoundList(postbox: Postbox, network: Network, background: Bool) -> Signal<[TelegramMediaFile], RevalidateMediaReferenceError> { + return self.genericItem(key: .notificationSoundList, background: background, request: { next, error in + return (requestNotificationSoundList(network: network, hash: 0) + |> map { result -> [TelegramMediaFile] in + guard let result = result else { + return [] + } + return result.sounds.map(\.file) + }).start(next: next) + }) |> mapToSignal { next -> Signal<[TelegramMediaFile], RevalidateMediaReferenceError> in + if let next = next as? [TelegramMediaFile] { + return .single(next) + } else { + return .fail(.generic) + } + } + } } struct RevalidatedMediaResource { @@ -799,6 +818,16 @@ func revalidateMediaResourceReference(postbox: Postbox, network: Network, revali } return .fail(.generic) } + case let .soundList(resource): + return revalidationContext.notificationSoundList(postbox: postbox, network: network, background: info.preferBackgroundReferenceRevalidation) + |> mapToSignal { files -> Signal in + for file in files { + if file.resource.id == resource.id { + return .single(RevalidatedMediaResource(updatedResource: file.resource, updatedReference: nil)) + } + } + return .fail(.generic) + } case .standalone: return .fail(.generic) } diff --git a/submodules/TelegramCore/Sources/State/CallSessionManager.swift b/submodules/TelegramCore/Sources/State/CallSessionManager.swift index 234b29fc0c..ed29ae4bbe 100644 --- a/submodules/TelegramCore/Sources/State/CallSessionManager.swift +++ b/submodules/TelegramCore/Sources/State/CallSessionManager.swift @@ -627,7 +627,7 @@ private final class CallSessionManagerContext { if let strongSelf = self { if let context = strongSelf.contexts[internalId] { context.state = .terminated(id: id, accessHash: accessHash, reason: .ended(.hungUp), reportRating: reportRating, sendDebugLogs: sendDebugLogs) - if sendDebugLogs { + /*if sendDebugLogs { let network = strongSelf.network let _ = (debugLog |> timeout(5.0, queue: strongSelf.queue, alternate: .single(nil)) @@ -636,7 +636,7 @@ private final class CallSessionManagerContext { let _ = _internal_saveCallDebugLog(network: network, callId: CallId(id: id, accessHash: accessHash), log: debugLog).start() } }) - } + }*/ strongSelf.contextUpdated(internalId: internalId) if context.isEmpty { strongSelf.contexts.removeValue(forKey: internalId) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift index 7a39a049e0..2516478eec 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift @@ -569,6 +569,7 @@ public enum MediaResourceReference: Equatable { case wallpaper(wallpaper: WallpaperReference?, resource: MediaResource) case stickerPackThumbnail(stickerPack: StickerPackReference, resource: MediaResource) case theme(theme: ThemeReference, resource: MediaResource) + case soundList(resource: MediaResource) public var resource: MediaResource { switch self { @@ -588,6 +589,8 @@ public enum MediaResourceReference: Equatable { return resource case let .theme(_, resource): return resource + case let .soundList(resource): + return resource } } @@ -641,6 +644,12 @@ public enum MediaResourceReference: Equatable { } else { return false } + case let .soundList(lhsResource): + if case let .soundList(rhsResource) = rhs, lhsResource.isEqual(to: rhsResource) { + return true + } else { + return false + } } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Calls/RateCall.swift b/submodules/TelegramCore/Sources/TelegramEngine/Calls/RateCall.swift index 7a8ed6ebee..297aef9f70 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Calls/RateCall.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Calls/RateCall.swift @@ -14,13 +14,74 @@ func _internal_rateCall(account: Account, callId: CallId, starsCount: Int32, com |> map { _ in } } -func _internal_saveCallDebugLog(network: Network, callId: CallId, log: String) -> Signal { +public enum SaveCallDebugLogResult { + case done + case sendFullLog +} + +func _internal_saveCallDebugLog(network: Network, callId: CallId, log: String) -> Signal { if log.count > 1024 * 16 { return .complete() } return network.request(Api.functions.phone.saveCallDebug(peer: Api.InputPhoneCall.inputPhoneCall(id: callId.id, accessHash: callId.accessHash), debug: .dataJSON(data: log))) |> `catch` { _ -> Signal in - return .single(.boolFalse) + return .single(.boolTrue) + } + |> map { result -> SaveCallDebugLogResult in + switch result { + case .boolFalse: + return .sendFullLog + case .boolTrue: + return .done + } + } +} + +func _internal_saveCompleteCallDebugLog(account: Account, callId: CallId, logPath: String) -> Signal { + let tempFile = TempBox.shared.tempFile(fileName: "log.txt.gz") + + do { + guard let data = try? Data(contentsOf: URL(fileURLWithPath: logPath), options: .mappedIfSafe) else { + Logger.shared.log("saveCompleteCallDebugLog", "Failed to open log file") + + return .complete() + } + + guard let gzippedData = MTGzip.compress(data) else { + Logger.shared.log("saveCompleteCallDebugLog", "Failed to compress log file") + + return .complete() + } + + guard let _ = try? gzippedData.write(to: URL(fileURLWithPath: tempFile.path), options: .atomic) else { + Logger.shared.log("saveCompleteCallDebugLog", "Failed to write compressed log file") + + return .complete() + } + } + + guard let size = fileSize(tempFile.path) else { + Logger.shared.log("saveCompleteCallDebugLog", "Could not get log file size") + + return .complete() + } + + return multipartUpload(network: account.network, postbox: account.postbox, source: .tempFile(tempFile), encrypt: false, tag: nil, hintFileSize: size, hintFileIsLarge: false, forceNoBigParts: true, useLargerParts: false) + |> mapToSignal { value -> Signal in + switch value { + case .progress: + return .complete() + case let .inputFile(inputFile): + return account.network.request(Api.functions.phone.saveCallLog(peer: Api.InputPhoneCall.inputPhoneCall(id: callId.id, accessHash: callId.accessHash), file: inputFile)) + |> mapError { _ -> MultipartUploadError in + return .generic + } + |> ignoreValues + case .inputSecretFile: + return .fail(.generic) + } + } + |> `catch` { _ -> Signal in + return .complete() } - |> map { _ in } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Calls/TelegramEngineCalls.swift b/submodules/TelegramCore/Sources/TelegramEngine/Calls/TelegramEngineCalls.swift index dd5b309556..57349eb832 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Calls/TelegramEngineCalls.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Calls/TelegramEngineCalls.swift @@ -25,9 +25,13 @@ public extension TelegramEngine { return _internal_rateCall(account: self.account, callId: callId, starsCount: starsCount, comment: comment, userInitiated: userInitiated) } - public func saveCallDebugLog(callId: CallId, log: String) -> Signal { + public func saveCallDebugLog(callId: CallId, log: String) -> Signal { return _internal_saveCallDebugLog(network: self.account.network, callId: callId, log: log) } + + public func saveCompleteCallDebugLog(callId: CallId, logPath: String) -> Signal { + return _internal_saveCompleteCallDebugLog(account: self.account, callId: callId, logPath: logPath) + } public func getCurrentGroupCall(callId: Int64, accessHash: Int64, peerId: PeerId? = nil) -> Signal { return _internal_getCurrentGroupCall(account: self.account, callId: callId, accessHash: accessHash, peerId: peerId) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationSoundList.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationSoundList.swift index 427fcb6aa9..0b5b46378d 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationSoundList.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationSoundList.swift @@ -152,7 +152,7 @@ public func ensureDownloadedNotificationSoundList(postbox: Postbox) -> Signal ignoreValues |> `catch` { _ -> Signal in return .complete() @@ -168,6 +168,30 @@ public func ensureDownloadedNotificationSoundList(postbox: Postbox) -> Signal ignoreValues } +func requestNotificationSoundList(network: Network, hash: Int64) -> Signal { + return network.request(Api.functions.account.getSavedRingtones(hash: hash)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> map { result -> NotificationSoundList? in + guard let result = result else { + return nil + } + + switch result { + case let .savedRingtones(hash, ringtones): + let notificationSoundList = NotificationSoundList( + hash: hash, + sounds: ringtones.compactMap(NotificationSoundList.NotificationSound.init(apiDocument:)) + ) + return notificationSoundList + case .savedRingtonesNotModified: + return nil + } + } +} + private func pollNotificationSoundList(postbox: Postbox, network: Network) -> Signal { return Signal { subscriber in let signal: Signal = _internal_cachedNotificationSoundList(postbox: postbox) @@ -204,7 +228,7 @@ private func pollNotificationSoundList(postbox: Postbox, network: Network) -> Si for resource in resources { signals.append( - fetchedMediaResource(mediaBox: postbox.mediaBox, reference: .standalone(resource: resource)) + fetchedMediaResource(mediaBox: postbox.mediaBox, reference: .soundList(resource: resource)) |> ignoreValues |> `catch` { _ -> Signal in return .complete() diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift index 0eb33288f1..fed43d2ada 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift @@ -278,7 +278,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee var botInfos: [CachedPeerBotInfo] = [] for botInfo in chatFullBotInfo ?? [] { switch botInfo { - case let .botInfo(_, userId, _, _, _, _): + case let .botInfo(_, userId, _, _, _, _, _): if let userId = userId { let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)) let parsedBotInfo = BotInfo(apiBotInfo: botInfo) @@ -451,7 +451,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee var botInfos: [CachedPeerBotInfo] = [] for botInfo in apiBotInfos { switch botInfo { - case let .botInfo(_, userId, _, _, _, _): + case let .botInfo(_, userId, _, _, _, _, _): if let userId = userId { let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)) let parsedBotInfo = BotInfo(apiBotInfo: botInfo) diff --git a/submodules/TelegramVoip/Sources/OngoingCallContext.swift b/submodules/TelegramVoip/Sources/OngoingCallContext.swift index e1e177c300..9cc3d9832c 100644 --- a/submodules/TelegramVoip/Sources/OngoingCallContext.swift +++ b/submodules/TelegramVoip/Sources/OngoingCallContext.swift @@ -943,9 +943,17 @@ public final class OngoingCallContext { if let callId = callId, !statsLogPath.isEmpty, let data = try? Data(contentsOf: URL(fileURLWithPath: statsLogPath)), let dataString = String(data: data, encoding: .utf8) { debugLogValue.set(.single(dataString)) - if sendDebugLogs { - let _ = TelegramEngine(account: self.account).calls.saveCallDebugLog(callId: callId, log: dataString).start() - } + let engine = TelegramEngine(account: self.account) + let _ = engine.calls.saveCallDebugLog(callId: callId, log: dataString).start(next: { result in + switch result { + case .sendFullLog: + if !logPath.isEmpty { + let _ = engine.calls.saveCompleteCallDebugLog(callId: callId, logPath: logPath).start() + } + case .done: + break + } + }) } } let derivedState = context.nativeGetDerivedState()