import Foundation #if os(macOS) import PostboxMac import SwiftSignalKitMac import MtProtoKitMac #else import Postbox import SwiftSignalKit import MtProtoKitDynamic #endif public enum UpdatePeerPhotoStatus { case progress(Float) case complete([TelegramMediaImageRepresentation]) } public enum UploadPeerPhotoError { case generic } public func updateAccountPhoto(account:Account, resource:MediaResource) -> Signal { return updatePeerPhoto(account: account, peerId: account.peerId, resource: resource) } public func updatePeerPhoto(account:Account, peerId:PeerId, resource:MediaResource) -> Signal { return account.postbox.loadedPeerWithId(peerId) |> mapError {_ in return .generic} |> mapToSignal { peer in return multipartUpload(network: account.network, postbox: account.postbox, source: .resource(resource), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image)) |> mapError {_ in return .generic} |> mapToSignal { result -> Signal in switch result { case let .progress(progress): return .single(.progress(progress)) case let .inputFile(file): if peer is TelegramUser { return account.network.request(Api.functions.photos.uploadProfilePhoto(file: file)) |> mapError {_ in return UploadPeerPhotoError.generic} |> mapToSignal { photo -> Signal in let representations:[TelegramMediaImageRepresentation] switch photo { case let .photo(photo: apiPhoto, users: _): switch apiPhoto { case .photoEmpty: representations = [] case let .photo(flags: _, id: _, accessHash: _, date: _, sizes: sizes): var sizes = sizes if sizes.count == 3 { sizes.remove(at: 1) } representations = telegramMediaImageRepresentationsFromApiSizes(sizes) if let resource = resource as? LocalFileReferenceMediaResource { if let data = try? Data(contentsOf: URL(fileURLWithPath: resource.localFilePath)) { for representation in representations { account.postbox.mediaBox.storeResourceData(representation.resource.id, data: data) } } } } } return account.postbox.modify { modifier -> UpdatePeerPhotoStatus in if let peer = modifier.getPeer(peer.id) { updatePeers(modifier: modifier, peers: [peer], update: { (_, peer) -> Peer? in if let peer = peer as? TelegramUser { return peer.withUpdatedPhoto(representations) } else { return peer } }) } return .complete(representations) } |> mapError {_ in return UploadPeerPhotoError.generic} } } else { let request:Signal if let peer = peer as? TelegramGroup { request = account.network.request(Api.functions.messages.editChatPhoto(chatId: peer.id.id, photo: .inputChatUploadedPhoto(file: file))) } else if let peer = peer as? TelegramChannel, let inputChannel = apiInputChannel(peer) { request = account.network.request(Api.functions.channels.editPhoto(channel: inputChannel, photo: .inputChatUploadedPhoto(file: file))) } else { assertionFailure() request = .complete() } return request |> mapError {_ in return UploadPeerPhotoError.generic} |> mapToSignal { updates -> Signal in account.stateManager.addUpdates(updates) for chat in updates.chats { if chat.peerId == peerId { if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { return account.postbox.modify { modifier -> UpdatePeerPhotoStatus in updatePeers(modifier: modifier, peers: [groupOrChannel], update: { _, updated in return updated }) return .complete(groupOrChannel.profileImageRepresentations) } |> mapError { _ in return .generic } } } } return .fail(.generic) } } default: return .fail(.generic) } } } |> map { result in switch result { case let .complete(representations): if let resource = resource as? LocalFileReferenceMediaResource { if let data = try? Data(contentsOf: URL(fileURLWithPath: resource.localFilePath)) { for representation in representations { account.postbox.mediaBox.storeResourceData(representation.resource.id, data: data) } } } default: break } return result } }