mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Chat wallpaper improvements
This commit is contained in:
parent
15ecbd1136
commit
4b6f32fc17
@ -197,15 +197,18 @@ func uploadCustomWallpaper(context: AccountContext, wallpaper: WallpaperGalleryE
|
||||
}
|
||||
|
||||
public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: WallpaperGalleryEntry, mode: WallpaperPresentationOptions, cropRect: CGRect?, brightness: CGFloat?, peerId: PeerId, completion: @escaping () -> Void) {
|
||||
let imageSignal: Signal<UIImage, NoError>
|
||||
var imageSignal: Signal<UIImage, NoError>
|
||||
switch wallpaper {
|
||||
case let .wallpaper(wallpaper, _):
|
||||
imageSignal = .complete()
|
||||
switch wallpaper {
|
||||
case let .file(file):
|
||||
if let path = context.account.postbox.mediaBox.completedResourcePath(file.file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
||||
if let path = context.account.postbox.mediaBox.completedResourcePath(file.file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead), let image = UIImage(data: data) {
|
||||
context.sharedContext.accountManager.mediaBox.storeResourceData(file.file.resource.id, data: data, synchronous: true)
|
||||
let _ = context.sharedContext.accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: true, fetch: true).start()
|
||||
let _ = context.sharedContext.accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start()
|
||||
|
||||
imageSignal = .single(image)
|
||||
}
|
||||
case let .image(representations, _):
|
||||
for representation in representations {
|
||||
@ -218,7 +221,6 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa
|
||||
default:
|
||||
break
|
||||
}
|
||||
imageSignal = .complete()
|
||||
completion()
|
||||
case let .asset(asset):
|
||||
imageSignal = fetchPhotoLibraryImage(localIdentifier: asset.localIdentifier, thumbnail: false)
|
||||
@ -299,31 +301,11 @@ public func uploadCustomPeerWallpaper(context: AccountContext, wallpaper: Wallpa
|
||||
let settings = WallpaperSettings(blur: mode.contains(.blur), motion: mode.contains(.motion), colors: [], intensity: intensity)
|
||||
let temporaryWallpaper: TelegramWallpaper = .image([TelegramMediaImageRepresentation(dimensions: PixelDimensions(thumbnailDimensions), resource: thumbnailResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false), TelegramMediaImageRepresentation(dimensions: PixelDimensions(croppedImage.size), resource: resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false)], settings)
|
||||
|
||||
let _ = context.account.postbox.transaction({ transaction in
|
||||
transaction.updatePeerCachedData(peerIds: Set([peerId])) { _, cachedData in
|
||||
if let cachedData = cachedData as? CachedUserData {
|
||||
return cachedData.withUpdatedWallpaper(temporaryWallpaper)
|
||||
} else {
|
||||
return cachedData
|
||||
}
|
||||
}
|
||||
}).start()
|
||||
|
||||
Queue.mainQueue().async {
|
||||
completion()
|
||||
}
|
||||
|
||||
let _ = uploadWallpaper(account: context.account, resource: resource, settings: WallpaperSettings(blur: false, motion: mode.contains(.motion), colors: [], intensity: intensity), forChat: true).start(next: { status in
|
||||
if case let .complete(wallpaper) = status {
|
||||
if case let .file(file) = wallpaper {
|
||||
context.account.postbox.mediaBox.copyResourceData(from: resource.id, to: file.file.resource.id, synchronous: true)
|
||||
for representation in file.file.previewRepresentations {
|
||||
context.account.postbox.mediaBox.copyResourceData(from: resource.id, to: representation.resource.id, synchronous: true)
|
||||
}
|
||||
}
|
||||
let _ = context.engine.themes.setChatWallpaper(peerId: peerId, wallpaper: wallpaper).start()
|
||||
}
|
||||
})
|
||||
context.account.pendingPeerMediaUploadManager.add(peerId: peerId, content: .wallpaper(temporaryWallpaper))
|
||||
}
|
||||
return croppedImage
|
||||
}).start()
|
||||
|
@ -142,7 +142,7 @@ public final class ThemePreviewController: ViewController {
|
||||
let titleView = CounterContollerTitleView(theme: self.previewTheme)
|
||||
titleView.title = CounterContollerTitle(title: themeName, counter: hasInstallsCount ? " " : "")
|
||||
self.navigationItem.titleView = titleView
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: UIView())
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
|
||||
|
||||
self.statusBar.statusBarStyle = self.previewTheme.rootController.statusBarStyle.style
|
||||
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
@ -179,6 +179,10 @@ public final class ThemePreviewController: ViewController {
|
||||
self.applyDisposable.dispose()
|
||||
}
|
||||
|
||||
@objc private func cancelPressed() {
|
||||
self.dismiss(animated: true)
|
||||
}
|
||||
|
||||
override public func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
|
@ -244,6 +244,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var useDarkButton = true
|
||||
if case let .file(file) = wallpaper {
|
||||
let dimensions = file.file.dimensions ?? PixelDimensions(width: 100, height: 100)
|
||||
let displaySize = dimensions.cgSize.dividedByScreenScale().integralFloor
|
||||
@ -258,6 +259,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
if wallpaper.isPattern {
|
||||
signal = .complete()
|
||||
} else {
|
||||
useDarkButton = false
|
||||
signal = .complete()
|
||||
}
|
||||
strongSelf.remoteChatBackgroundNode.setSignal(signal)
|
||||
@ -296,6 +298,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
|
||||
strongSelf.remoteChatBackgroundNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets(), custom: patternArguments))()
|
||||
strongSelf.toolbarNode.dark = useDarkButton
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
self.patternButtonNode = WallpaperOptionButtonNode(title: self.presentationData.strings.WallpaperPreview_Pattern, value: .check(false))
|
||||
self.patternButtonNode.setEnabled(false)
|
||||
|
||||
self.serviceBackgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x333333, alpha: 0.33))
|
||||
self.serviceBackgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x333333, alpha: 0.45))
|
||||
self.serviceBackgroundNode.isHidden = true
|
||||
|
||||
var sliderValueChangedImpl: ((CGFloat) -> Void)?
|
||||
@ -1567,7 +1567,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
if let strongSelf = self, (count < 2 && currentTimestamp > timestamp + 24 * 60 * 60) {
|
||||
strongSelf.displayedPreviewTooltip = true
|
||||
|
||||
let controller = TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: isDark ? strongSelf.presentationData.strings.WallpaperPreview_PreviewInDayMode : strongSelf.presentationData.strings.WallpaperPreview_PreviewInNightMode, style: .customBlur(UIColor(rgb: 0x333333, alpha: 0.33)), icon: nil, location: .point(frame.offsetBy(dx: 1.0, dy: 6.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in
|
||||
let controller = TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: isDark ? strongSelf.presentationData.strings.WallpaperPreview_PreviewInDayMode : strongSelf.presentationData.strings.WallpaperPreview_PreviewInNightMode, style: .customBlur(UIColor(rgb: 0x333333, alpha: 0.45)), icon: nil, location: .point(frame.offsetBy(dx: 1.0, dy: 6.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in
|
||||
return .dismiss(consume: false)
|
||||
})
|
||||
strongSelf.galleryController()?.present(controller, in: .current)
|
||||
|
@ -41,7 +41,7 @@ final class WallpaperLightButtonBackgroundNode: ASDisplayNode {
|
||||
private let lightNode: ASDisplayNode
|
||||
|
||||
override init() {
|
||||
self.backgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x333333, alpha: 0.3), enableBlur: true, enableSaturation: false)
|
||||
self.backgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x333333, alpha: 0.45), enableBlur: true, enableSaturation: false)
|
||||
self.overlayNode = ASDisplayNode()
|
||||
self.overlayNode.backgroundColor = UIColor(rgb: 0xffffff, alpha: 0.75)
|
||||
self.overlayNode.layer.compositingFilter = "overlayBlendMode"
|
||||
@ -72,7 +72,7 @@ final class WallpaperOptionBackgroundNode: ASDisplayNode {
|
||||
private let backgroundNode: NavigationBackgroundNode
|
||||
|
||||
init(enableSaturation: Bool = false) {
|
||||
self.backgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x333333, alpha: 0.3), enableBlur: true, enableSaturation: enableSaturation)
|
||||
self.backgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x333333, alpha: 0.45), enableBlur: true, enableSaturation: enableSaturation)
|
||||
|
||||
super.init()
|
||||
|
||||
@ -488,7 +488,7 @@ final class WallpaperSliderNode: ASDisplayNode {
|
||||
self.value = value
|
||||
self.valueChanged = valueChanged
|
||||
|
||||
self.backgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x333333, alpha: 0.3), enableBlur: true, enableSaturation: false)
|
||||
self.backgroundNode = NavigationBackgroundNode(color: UIColor(rgb: 0x333333, alpha: 0.45), enableBlur: true, enableSaturation: false)
|
||||
|
||||
self.foregroundNode = ASDisplayNode()
|
||||
self.foregroundNode.clipsToBounds = true
|
||||
|
@ -915,6 +915,7 @@ public class Account {
|
||||
public private(set) var pendingUpdateMessageManager: PendingUpdateMessageManager!
|
||||
private(set) var messageMediaPreuploadManager: MessageMediaPreuploadManager!
|
||||
private(set) var mediaReferenceRevalidationContext: MediaReferenceRevalidationContext!
|
||||
public private(set) var pendingPeerMediaUploadManager: PendingPeerMediaUploadManager!
|
||||
private var peerInputActivityManager: PeerInputActivityManager!
|
||||
private var localInputActivityManager: PeerInputActivityManager!
|
||||
private var accountPresenceManager: AccountPresenceManager!
|
||||
@ -1029,6 +1030,7 @@ public class Account {
|
||||
self.messageMediaPreuploadManager = MessageMediaPreuploadManager()
|
||||
self.pendingMessageManager = PendingMessageManager(network: network, postbox: postbox, accountPeerId: peerId, auxiliaryMethods: auxiliaryMethods, stateManager: self.stateManager, localInputActivityManager: self.localInputActivityManager, messageMediaPreuploadManager: self.messageMediaPreuploadManager, revalidationContext: self.mediaReferenceRevalidationContext)
|
||||
self.pendingUpdateMessageManager = PendingUpdateMessageManager(postbox: postbox, network: network, stateManager: self.stateManager, messageMediaPreuploadManager: self.messageMediaPreuploadManager, mediaReferenceRevalidationContext: self.mediaReferenceRevalidationContext)
|
||||
self.pendingPeerMediaUploadManager = PendingPeerMediaUploadManager(postbox: postbox, network: network, stateManager: self.stateManager, accountPeerId: self.peerId)
|
||||
|
||||
self.network.loggedOut = { [weak self] in
|
||||
Logger.shared.log("Account", "network logged out")
|
||||
@ -1138,13 +1140,15 @@ public class Account {
|
||||
self.managedOperationsDisposable.add(managedPeerTimestampAttributeOperations(network: self.network, postbox: self.postbox).start())
|
||||
self.managedOperationsDisposable.add(managedLocalTypingActivities(activities: self.localInputActivityManager.allActivities(), postbox: self.stateManager.postbox, network: self.stateManager.network, accountPeerId: self.stateManager.accountPeerId).start())
|
||||
|
||||
let importantBackgroundOperations: [Signal<AccountRunningImportantTasks, NoError>] = [
|
||||
let extractedExpr: [Signal<AccountRunningImportantTasks, NoError>] = [
|
||||
managedSynchronizeChatInputStateOperations(postbox: self.postbox, network: self.network) |> map { $0 ? AccountRunningImportantTasks.other : [] },
|
||||
self.pendingMessageManager.hasPendingMessages |> map { !$0.isEmpty ? AccountRunningImportantTasks.pendingMessages : [] },
|
||||
self.pendingUpdateMessageManager.updatingMessageMedia |> map { !$0.isEmpty ? AccountRunningImportantTasks.pendingMessages : [] },
|
||||
self.pendingPeerMediaUploadManager.uploadingPeerMedia |> map { !$0.isEmpty ? AccountRunningImportantTasks.pendingMessages : [] },
|
||||
self.accountPresenceManager.isPerformingUpdate() |> map { $0 ? AccountRunningImportantTasks.other : [] },
|
||||
self.notificationAutolockReportManager.isPerformingUpdate() |> map { $0 ? AccountRunningImportantTasks.other : [] }
|
||||
]
|
||||
let importantBackgroundOperations: [Signal<AccountRunningImportantTasks, NoError>] = extractedExpr
|
||||
let importantBackgroundOperationsRunning = combineLatest(queue: Queue(), importantBackgroundOperations)
|
||||
|> map { values -> AccountRunningImportantTasks in
|
||||
var result: AccountRunningImportantTasks = []
|
||||
|
@ -0,0 +1,403 @@
|
||||
import Foundation
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramApi
|
||||
|
||||
public final class PeerMediaUploadingItem: Equatable {
|
||||
public enum ProgressValue {
|
||||
case progress(Float)
|
||||
case done(Api.Updates)
|
||||
}
|
||||
|
||||
public enum Error {
|
||||
case generic
|
||||
}
|
||||
|
||||
public enum PreviousState: Equatable {
|
||||
case wallpaper(TelegramWallpaper?)
|
||||
}
|
||||
|
||||
public enum Content: Equatable {
|
||||
case wallpaper(TelegramWallpaper)
|
||||
}
|
||||
|
||||
public let content: Content
|
||||
public let messageId: EngineMessage.Id?
|
||||
public let previousState: PreviousState?
|
||||
public let progress: Float
|
||||
|
||||
init(content: Content, messageId: EngineMessage.Id?, previousState: PreviousState?, progress: Float) {
|
||||
self.content = content
|
||||
self.messageId = messageId
|
||||
self.previousState = previousState
|
||||
self.progress = progress
|
||||
}
|
||||
|
||||
public static func ==(lhs: PeerMediaUploadingItem, rhs: PeerMediaUploadingItem) -> Bool {
|
||||
if lhs.content != rhs.content {
|
||||
return false
|
||||
}
|
||||
if lhs.messageId != rhs.messageId {
|
||||
return false
|
||||
}
|
||||
if lhs.previousState != rhs.previousState {
|
||||
return false
|
||||
}
|
||||
if lhs.progress != rhs.progress {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func withMessageId(_ messageId: EngineMessage.Id) -> PeerMediaUploadingItem {
|
||||
return PeerMediaUploadingItem(content: self.content, messageId: messageId, previousState: self.previousState, progress: self.progress)
|
||||
}
|
||||
|
||||
func withProgress(_ progress: Float) -> PeerMediaUploadingItem {
|
||||
return PeerMediaUploadingItem(content: self.content, messageId: self.messageId, previousState: self.previousState, progress: progress)
|
||||
}
|
||||
|
||||
func withPreviousState(_ previousState: PreviousState?) -> PeerMediaUploadingItem {
|
||||
return PeerMediaUploadingItem(content: self.content, messageId: self.messageId, previousState: previousState, progress: self.progress)
|
||||
}
|
||||
}
|
||||
|
||||
private func uploadPeerMedia(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: EnginePeer.Id, content: PeerMediaUploadingItem.Content) -> Signal<PeerMediaUploadingItem.ProgressValue, PeerMediaUploadingItem.Error> {
|
||||
switch content {
|
||||
case let .wallpaper(wallpaper):
|
||||
if case let .image(representations, settings) = wallpaper, let resource = representations.last?.resource as? LocalFileMediaResource {
|
||||
return _internal_uploadWallpaper(postbox: postbox, network: network, resource: resource, settings: settings, forChat: true)
|
||||
|> mapError { error -> PeerMediaUploadingItem.Error in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { value -> Signal<PeerMediaUploadingItem.ProgressValue, PeerMediaUploadingItem.Error> in
|
||||
switch value {
|
||||
case let .progress(progress):
|
||||
return .single(.progress(progress))
|
||||
case let .complete(result):
|
||||
if case let .file(file) = result {
|
||||
postbox.mediaBox.copyResourceData(from: resource.id, to: file.file.resource.id, synchronous: true)
|
||||
for representation in file.file.previewRepresentations {
|
||||
postbox.mediaBox.copyResourceData(from: resource.id, to: representation.resource.id, synchronous: true)
|
||||
}
|
||||
}
|
||||
return _internal_setChatWallpaper(postbox: postbox, network: network, stateManager: stateManager, peerId: peerId, wallpaper: result, applyUpdates: false)
|
||||
|> castError(PeerMediaUploadingItem.Error.self)
|
||||
|> map { updates -> PeerMediaUploadingItem.ProgressValue in
|
||||
return .done(updates)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
return _internal_setChatWallpaper(postbox: postbox, network: network, stateManager: stateManager, peerId: peerId, wallpaper: wallpaper, applyUpdates: false)
|
||||
|> castError(PeerMediaUploadingItem.Error.self)
|
||||
|> map { updates -> PeerMediaUploadingItem.ProgressValue in
|
||||
return .done(updates)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func generatePeerMediaMessage(network: Network, accountPeerId: EnginePeer.Id, transaction: Transaction, peerId: PeerId, content: PeerMediaUploadingItem.Content) -> StoreMessage {
|
||||
var randomId: Int64 = 0
|
||||
arc4random_buf(&randomId, 8)
|
||||
|
||||
var timestamp = Int32(network.context.globalTime())
|
||||
switch peerId.namespace {
|
||||
case Namespaces.Peer.CloudChannel, Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudUser:
|
||||
if let topIndex = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) {
|
||||
timestamp = max(timestamp, topIndex.timestamp)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
var flags = StoreMessageFlags()
|
||||
flags.insert(.Unsent)
|
||||
flags.insert(.Sending)
|
||||
|
||||
var attributes: [MessageAttribute] = []
|
||||
attributes.append(OutgoingMessageInfoAttribute(uniqueId: randomId, flags: [], acknowledged: false, correlationId: nil, bubbleUpEmojiOrStickersets: []))
|
||||
|
||||
var media: [Media] = []
|
||||
switch content {
|
||||
case let .wallpaper(wallpaper):
|
||||
media.append(TelegramMediaAction(action: .setChatWallpaper(wallpaper: wallpaper)))
|
||||
}
|
||||
|
||||
return StoreMessage(peerId: peerId, namespace: Namespaces.Message.Local, globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: accountPeerId, text: "", attributes: attributes, media: media)
|
||||
}
|
||||
|
||||
private func preparePeerMediaUpload(transaction: Transaction, peerId: EnginePeer.Id, content: PeerMediaUploadingItem.Content) -> PeerMediaUploadingItem.PreviousState? {
|
||||
var previousState: PeerMediaUploadingItem.PreviousState?
|
||||
switch content {
|
||||
case let .wallpaper(wallpaper):
|
||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData in
|
||||
if let cachedData = cachedData as? CachedUserData {
|
||||
previousState = .wallpaper(cachedData.wallpaper)
|
||||
return cachedData.withUpdatedWallpaper(wallpaper)
|
||||
} else {
|
||||
return cachedData
|
||||
}
|
||||
})
|
||||
}
|
||||
return previousState
|
||||
}
|
||||
|
||||
private func cancelPeerMediaUpload(transaction: Transaction, peerId: EnginePeer.Id, previousState: PeerMediaUploadingItem.PreviousState?) {
|
||||
guard let previousState = previousState else {
|
||||
return
|
||||
}
|
||||
switch previousState {
|
||||
case let .wallpaper(previousWallpaper):
|
||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData in
|
||||
if let cachedData = cachedData as? CachedUserData {
|
||||
return cachedData.withUpdatedWallpaper(previousWallpaper)
|
||||
} else {
|
||||
return cachedData
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private final class PendingPeerMediaUploadContext {
|
||||
var value: PeerMediaUploadingItem
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
init(value: PeerMediaUploadingItem) {
|
||||
self.value = value
|
||||
}
|
||||
}
|
||||
|
||||
private final class PendingPeerMediaUploadManagerImpl {
|
||||
let queue: Queue
|
||||
let postbox: Postbox
|
||||
let network: Network
|
||||
let stateManager: AccountStateManager
|
||||
let accountPeerId: EnginePeer.Id
|
||||
|
||||
private var uploadingPeerMediaValue: [EnginePeer.Id: PeerMediaUploadingItem] = [:] {
|
||||
didSet {
|
||||
if self.uploadingPeerMediaValue != oldValue {
|
||||
self.uploadingPeerMediaPromise.set(.single(self.uploadingPeerMediaValue))
|
||||
}
|
||||
}
|
||||
}
|
||||
private let uploadingPeerMediaPromise = Promise<[EnginePeer.Id: PeerMediaUploadingItem]>()
|
||||
fileprivate var uploadingPeerMedia: Signal<[EnginePeer.Id: PeerMediaUploadingItem], NoError> {
|
||||
return self.uploadingPeerMediaPromise.get()
|
||||
}
|
||||
|
||||
private var contexts: [PeerId: PendingPeerMediaUploadContext] = [:]
|
||||
|
||||
init(queue: Queue, postbox: Postbox, network: Network, stateManager: AccountStateManager, accountPeerId: EnginePeer.Id) {
|
||||
self.queue = queue
|
||||
self.postbox = postbox
|
||||
self.network = network
|
||||
self.stateManager = stateManager
|
||||
self.accountPeerId = accountPeerId
|
||||
|
||||
self.uploadingPeerMediaPromise.set(.single(self.uploadingPeerMediaValue))
|
||||
}
|
||||
|
||||
deinit {
|
||||
for (_, context) in self.contexts {
|
||||
context.disposable.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
private func updateValues() {
|
||||
self.uploadingPeerMediaValue = self.contexts.mapValues { context in
|
||||
return context.value
|
||||
}
|
||||
}
|
||||
|
||||
func add(peerId: EnginePeer.Id, content: PeerMediaUploadingItem.Content) {
|
||||
if let context = self.contexts[peerId] {
|
||||
self.contexts.removeValue(forKey: peerId)
|
||||
context.disposable.dispose()
|
||||
}
|
||||
|
||||
let postbox = self.postbox
|
||||
let network = self.network
|
||||
let stateManager = self.stateManager
|
||||
let accountPeerId = self.accountPeerId
|
||||
|
||||
let queue = self.queue
|
||||
let context = PendingPeerMediaUploadContext(value: PeerMediaUploadingItem(content: content, messageId: nil, previousState: nil, progress: 0.0))
|
||||
self.contexts[peerId] = context
|
||||
|
||||
context.disposable.set(
|
||||
(self.postbox.transaction({ transaction -> (EngineMessage.Id, PeerMediaUploadingItem.PreviousState?)? in
|
||||
let storeMessage = generatePeerMediaMessage(network: network, accountPeerId: accountPeerId, transaction: transaction, peerId: peerId, content: content)
|
||||
let globallyUniqueIdToMessageId = transaction.addMessages([storeMessage], location: .Random)
|
||||
guard let globallyUniqueId = storeMessage.globallyUniqueId, let messageId = globallyUniqueIdToMessageId[globallyUniqueId] else {
|
||||
return nil
|
||||
}
|
||||
let previousState = preparePeerMediaUpload(transaction: transaction, peerId: peerId, content: content)
|
||||
return (messageId, previousState)
|
||||
})
|
||||
|> deliverOn(queue)).start(next: { [weak self, weak context] messageIdAndPreviousState in
|
||||
guard let strongSelf = self, let initialContext = context else {
|
||||
return
|
||||
}
|
||||
if let context = strongSelf.contexts[peerId], context === initialContext {
|
||||
guard let (messageId, previousState) = messageIdAndPreviousState else {
|
||||
strongSelf.contexts.removeValue(forKey: peerId)
|
||||
context.disposable.dispose()
|
||||
strongSelf.updateValues()
|
||||
return
|
||||
}
|
||||
context.value = context.value.withMessageId(messageId).withPreviousState(previousState)
|
||||
strongSelf.updateValues()
|
||||
|
||||
context.disposable.set((uploadPeerMedia(postbox: postbox, network: network, stateManager: stateManager, peerId: peerId, content: content)
|
||||
|> deliverOn(queue)).start(next: { [weak self, weak context] value in
|
||||
queue.async {
|
||||
guard let strongSelf = self, let initialContext = context else {
|
||||
return
|
||||
}
|
||||
if let context = strongSelf.contexts[peerId], context === initialContext {
|
||||
switch value {
|
||||
case let .done(result):
|
||||
context.disposable.set(
|
||||
(postbox.transaction({ transaction -> Message? in
|
||||
return transaction.getMessage(messageId)
|
||||
})
|
||||
|> deliverOn(queue)
|
||||
).start(next: { [weak self, weak context] message in
|
||||
guard let strongSelf = self, let initialContext = context else {
|
||||
return
|
||||
}
|
||||
if let context = strongSelf.contexts[peerId], context === initialContext {
|
||||
guard let message = message else {
|
||||
strongSelf.contexts.removeValue(forKey: peerId)
|
||||
context.disposable.dispose()
|
||||
strongSelf.updateValues()
|
||||
return
|
||||
}
|
||||
context.disposable.set(
|
||||
(applyUpdateMessage(
|
||||
postbox: postbox,
|
||||
stateManager: stateManager,
|
||||
message: message,
|
||||
cacheReferenceKey: nil,
|
||||
result: result,
|
||||
accountPeerId: accountPeerId
|
||||
)
|
||||
|> deliverOn(queue)).start(completed: { [weak self, weak context] in
|
||||
guard let strongSelf = self, let initialContext = context else {
|
||||
return
|
||||
}
|
||||
if let context = strongSelf.contexts[peerId], context === initialContext {
|
||||
strongSelf.contexts.removeValue(forKey: peerId)
|
||||
context.disposable.dispose()
|
||||
strongSelf.updateValues()
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
)
|
||||
strongSelf.updateValues()
|
||||
case let .progress(progress):
|
||||
context.value = context.value.withProgress(progress)
|
||||
strongSelf.updateValues()
|
||||
}
|
||||
}
|
||||
}
|
||||
}, error: { [weak self, weak context] error in
|
||||
queue.async {
|
||||
guard let strongSelf = self, let initialContext = context else {
|
||||
return
|
||||
}
|
||||
if let context = strongSelf.contexts[peerId], context === initialContext {
|
||||
strongSelf.contexts.removeValue(forKey: peerId)
|
||||
context.disposable.dispose()
|
||||
strongSelf.updateValues()
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
func cancel(peerId: EnginePeer.Id) {
|
||||
if let context = self.contexts[peerId] {
|
||||
self.contexts.removeValue(forKey: peerId)
|
||||
|
||||
if let messageId = context.value.messageId {
|
||||
context.disposable.set(self.postbox.transaction({ transaction in
|
||||
cancelPeerMediaUpload(transaction: transaction, peerId: peerId, previousState: context.value.previousState)
|
||||
transaction.deleteMessages([messageId], forEachMedia: nil)
|
||||
}).start())
|
||||
} else {
|
||||
context.disposable.dispose()
|
||||
}
|
||||
|
||||
self.updateValues()
|
||||
}
|
||||
}
|
||||
|
||||
func uploadProgress(messageId: EngineMessage.Id) -> Signal<Float?, NoError> {
|
||||
return self.uploadingPeerMedia
|
||||
|> map { uploadingPeerMedia in
|
||||
if let item = uploadingPeerMedia[messageId.peerId], item.messageId == messageId {
|
||||
return item.progress
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
}
|
||||
}
|
||||
|
||||
public final class PendingPeerMediaUploadManager {
|
||||
private let queue = Queue()
|
||||
private let impl: QueueLocalObject<PendingPeerMediaUploadManagerImpl>
|
||||
|
||||
public var uploadingPeerMedia: Signal<[EnginePeer.Id: PeerMediaUploadingItem], NoError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
self.impl.with { impl in
|
||||
disposable.set(impl.uploadingPeerMedia.start(next: { value in
|
||||
subscriber.putNext(value)
|
||||
}))
|
||||
}
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
|
||||
init(postbox: Postbox, network: Network, stateManager: AccountStateManager, accountPeerId: EnginePeer.Id) {
|
||||
let queue = self.queue
|
||||
self.impl = QueueLocalObject(queue: queue, generate: {
|
||||
return PendingPeerMediaUploadManagerImpl(queue: queue, postbox: postbox, network: network, stateManager: stateManager, accountPeerId: accountPeerId)
|
||||
})
|
||||
}
|
||||
|
||||
public func add(peerId: EnginePeer.Id, content: PeerMediaUploadingItem.Content) {
|
||||
self.impl.with { impl in
|
||||
impl.add(peerId: peerId, content: content)
|
||||
}
|
||||
}
|
||||
|
||||
public func cancel(peerId: EnginePeer.Id) {
|
||||
self.impl.with { impl in
|
||||
impl.cancel(peerId: peerId)
|
||||
}
|
||||
}
|
||||
|
||||
public func uploadProgress(messageId: EngineMessage.Id) -> Signal<Float?, NoError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
self.impl.with { impl in
|
||||
disposable.set(impl.uploadProgress(messageId: messageId).start(next: { value in
|
||||
subscriber.putNext(value)
|
||||
}))
|
||||
}
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
}
|
@ -118,14 +118,14 @@ func managedChatThemesUpdates(accountManager: AccountManager<TelegramAccountMana
|
||||
return (poll |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart
|
||||
}
|
||||
|
||||
func _internal_setChatWallpaper(account: Account, peerId: PeerId, wallpaper: TelegramWallpaper?) -> Signal<Void, NoError> {
|
||||
return account.postbox.loadedPeerWithId(peerId)
|
||||
func _internal_setChatWallpaper(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, wallpaper: TelegramWallpaper?, applyUpdates: Bool = true) -> Signal<Api.Updates, NoError> {
|
||||
return postbox.loadedPeerWithId(peerId)
|
||||
|> mapToSignal { peer in
|
||||
guard let inputPeer = apiInputPeer(peer) else {
|
||||
return .complete()
|
||||
}
|
||||
|
||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
return postbox.transaction { transaction -> Signal<Api.Updates, NoError> in
|
||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
|
||||
if let current = current as? CachedUserData {
|
||||
return current.withUpdatedWallpaper(wallpaper)
|
||||
@ -144,13 +144,15 @@ func _internal_setChatWallpaper(account: Account, peerId: PeerId, wallpaper: Tel
|
||||
inputWallpaper = inputWallpaperAndInputSettings.0
|
||||
inputSettings = inputWallpaperAndInputSettings.1
|
||||
}
|
||||
return account.network.request(Api.functions.messages.setChatWallPaper(flags: flags, peer: inputPeer, wallpaper: inputWallpaper, settings: inputSettings, id: nil), automaticFloodWait: false)
|
||||
return network.request(Api.functions.messages.setChatWallPaper(flags: flags, peer: inputPeer, wallpaper: inputWallpaper, settings: inputSettings, id: nil), automaticFloodWait: false)
|
||||
|> `catch` { error in
|
||||
return .complete()
|
||||
}
|
||||
|> mapToSignal { updates -> Signal<Void, NoError> in
|
||||
account.stateManager.addUpdates(updates)
|
||||
return .complete()
|
||||
|> mapToSignal { updates -> Signal<Api.Updates, NoError> in
|
||||
if applyUpdates {
|
||||
stateManager.addUpdates(updates)
|
||||
}
|
||||
return .single(updates)
|
||||
}
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
@ -17,8 +17,9 @@ public extension TelegramEngine {
|
||||
return _internal_setChatTheme(account: self.account, peerId: peerId, emoticon: emoticon)
|
||||
}
|
||||
|
||||
public func setChatWallpaper(peerId: PeerId, wallpaper: TelegramWallpaper?) -> Signal<Void, NoError> {
|
||||
return _internal_setChatWallpaper(account: self.account, peerId: peerId, wallpaper: wallpaper)
|
||||
public func setChatWallpaper(peerId: PeerId, wallpaper: TelegramWallpaper?) -> Signal<Never, NoError> {
|
||||
return _internal_setChatWallpaper(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, peerId: peerId, wallpaper: wallpaper)
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
public func setExistingChatWallpaper(messageId: MessageId, settings: WallpaperSettings?) -> Signal<Void, SetExistingChatWallpaperError> {
|
||||
|
@ -119,7 +119,11 @@ private func uploadedWallpaper(postbox: Postbox, network: Network, resource: Med
|
||||
}
|
||||
|
||||
public func uploadWallpaper(account: Account, resource: MediaResource, mimeType: String = "image/jpeg", settings: WallpaperSettings, forChat: Bool) -> Signal<UploadWallpaperStatus, UploadWallpaperError> {
|
||||
return uploadedWallpaper(postbox: account.postbox, network: account.network, resource: resource)
|
||||
return _internal_uploadWallpaper(postbox: account.postbox, network: account.network, resource: resource, settings: settings, forChat: forChat)
|
||||
}
|
||||
|
||||
func _internal_uploadWallpaper(postbox: Postbox, network: Network, resource: MediaResource, mimeType: String = "image/jpeg", settings: WallpaperSettings, forChat: Bool) -> Signal<UploadWallpaperStatus, UploadWallpaperError> {
|
||||
return uploadedWallpaper(postbox: postbox, network: network, resource: resource)
|
||||
|> mapError { _ -> UploadWallpaperError in }
|
||||
|> mapToSignal { result -> Signal<(UploadWallpaperStatus, MediaResource?), UploadWallpaperError> in
|
||||
switch result.content {
|
||||
@ -134,11 +138,11 @@ public func uploadWallpaper(account: Account, resource: MediaResource, mimeType:
|
||||
if forChat {
|
||||
flags |= 1 << 0
|
||||
}
|
||||
return account.network.request(Api.functions.account.uploadWallPaper(flags: flags, file: file, mimeType: mimeType, settings: apiWallpaperSettings(settings)))
|
||||
|> mapError { _ in return UploadWallpaperError.generic }
|
||||
|> map { wallpaper -> (UploadWallpaperStatus, MediaResource?) in
|
||||
return (.complete(TelegramWallpaper(apiWallpaper: wallpaper)), result.resource)
|
||||
}
|
||||
return network.request(Api.functions.account.uploadWallPaper(flags: flags, file: file, mimeType: mimeType, settings: apiWallpaperSettings(settings)))
|
||||
|> mapError { _ in return UploadWallpaperError.generic }
|
||||
|> map { wallpaper -> (UploadWallpaperStatus, MediaResource?) in
|
||||
return (.complete(TelegramWallpaper(apiWallpaper: wallpaper)), result.resource)
|
||||
}
|
||||
default:
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
@ -18655,7 +18655,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let strongSelf = self, let peerId else {
|
||||
return
|
||||
}
|
||||
if canResetWallpaper {
|
||||
if canResetWallpaper && emoticon != nil {
|
||||
let _ = context.engine.themes.setChatWallpaper(peerId: peerId, wallpaper: nil).start()
|
||||
}
|
||||
strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon ?? "", nil)))
|
||||
|
@ -733,7 +733,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
||||
} else {
|
||||
unboundSize = CGSize(width: 54.0, height: 54.0)
|
||||
}
|
||||
case .themeSettings:
|
||||
case .themeSettings, .image:
|
||||
unboundSize = CGSize(width: 160.0, height: 240.0).fitted(CGSize(width: 240.0, height: 240.0))
|
||||
case .color, .gradient:
|
||||
unboundSize = CGSize(width: 128.0, height: 128.0)
|
||||
@ -1116,6 +1116,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
||||
return wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: FileMediaReference.message(message: MessageReference(message), media: file), representations: representations, alwaysShowThumbnailFirst: false, thumbnail: true, autoFetchFullSize: true)
|
||||
}
|
||||
}
|
||||
case let .image(representations):
|
||||
return wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: nil, representations: representations.map({ ImageRepresentationWithReference(representation: $0, reference: .standalone(resource: $0.resource)) }), alwaysShowThumbnailFirst: false, thumbnail: true, autoFetchFullSize: true)
|
||||
case let .themeSettings(settings):
|
||||
return themeImage(account: context.account, accountManager: context.sharedContext.accountManager, source: .settings(settings))
|
||||
case let .color(color):
|
||||
@ -1182,7 +1184,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
||||
|> map { resourceStatus -> (MediaResourceStatus, MediaResourceStatus?) in
|
||||
return (resourceStatus, nil)
|
||||
}
|
||||
case .themeSettings, .color, .gradient:
|
||||
case .themeSettings, .color, .gradient, .image:
|
||||
updatedStatusSignal = .single((.Local, nil))
|
||||
}
|
||||
}
|
||||
|
@ -15,12 +15,16 @@ import WallpaperBackgroundNode
|
||||
import PhotoResources
|
||||
import WallpaperResources
|
||||
import Markdown
|
||||
import RadialStatusNode
|
||||
|
||||
class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private var mediaBackgroundContent: WallpaperBubbleBackgroundNode?
|
||||
private let mediaBackgroundNode: NavigationBackgroundNode
|
||||
private let subtitleNode: TextNode
|
||||
private let imageNode: TransformImageNode
|
||||
|
||||
private var statusOverlayNode: ASDisplayNode
|
||||
private var statusNode: RadialStatusNode
|
||||
|
||||
private let buttonNode: HighlightTrackingButtonNode
|
||||
private let buttonTitleNode: TextNode
|
||||
@ -28,6 +32,7 @@ class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private var absoluteRect: (CGRect, CGSize)?
|
||||
|
||||
private let fetchDisposable = MetaDisposable()
|
||||
private let statusDisposable = MetaDisposable()
|
||||
|
||||
required init() {
|
||||
self.mediaBackgroundNode = NavigationBackgroundNode(color: .clear)
|
||||
@ -48,6 +53,15 @@ class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
self.buttonTitleNode.isUserInteractionEnabled = false
|
||||
self.buttonTitleNode.displaysAsynchronously = false
|
||||
|
||||
self.statusOverlayNode = ASDisplayNode()
|
||||
self.statusOverlayNode.alpha = 0.0
|
||||
self.statusOverlayNode.clipsToBounds = true
|
||||
self.statusOverlayNode.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.4)
|
||||
self.statusOverlayNode.cornerRadius = 50.0
|
||||
|
||||
self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(rgb: 0x000000, alpha: 0.6))
|
||||
self.statusNode.isUserInteractionEnabled = false
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.mediaBackgroundNode)
|
||||
@ -57,6 +71,9 @@ class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
self.addSubnode(self.buttonNode)
|
||||
self.addSubnode(self.buttonTitleNode)
|
||||
|
||||
self.addSubnode(self.statusOverlayNode)
|
||||
self.statusOverlayNode.addSubnode(self.statusNode)
|
||||
|
||||
self.buttonNode.highligthedChanged = { [weak self] highlighted in
|
||||
if let strongSelf = self {
|
||||
if highlighted {
|
||||
@ -82,6 +99,25 @@ class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
deinit {
|
||||
self.fetchDisposable.dispose()
|
||||
self.statusDisposable.dispose()
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
if #available(iOS 13.0, *) {
|
||||
self.statusOverlayNode.layer.cornerCurve = .circular
|
||||
}
|
||||
|
||||
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.progressPressed))
|
||||
self.statusOverlayNode.view.addGestureRecognizer(tapGestureRecognizer)
|
||||
}
|
||||
|
||||
@objc private func progressPressed() {
|
||||
guard let item = self.item else {
|
||||
return
|
||||
}
|
||||
item.context.account.pendingPeerMediaUploadManager.cancel(peerId: item.message.id.peerId)
|
||||
}
|
||||
|
||||
override func transitionNode(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
|
||||
@ -134,6 +170,18 @@ class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
let _ = item.controllerInteraction.openMessage(item.message, .default)
|
||||
}
|
||||
|
||||
private func updateProgress(_ progress: Float?) {
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.2, curve: .easeInOut)
|
||||
if let progress {
|
||||
let progressValue = CGFloat(max(0.027, progress))
|
||||
self.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: progressValue, cancelEnabled: true, animateRotation: true))
|
||||
transition.updateAlpha(node: self.statusOverlayNode, alpha: 1.0)
|
||||
} else {
|
||||
self.statusNode.transitionToState(.none)
|
||||
transition.updateAlpha(node: self.statusOverlayNode, alpha: 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
|
||||
let makeImageLayout = self.imageNode.asyncLayout()
|
||||
@ -223,6 +271,11 @@ class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
updateImageSignal = wallpaperImage(account: item.context.account, accountManager: item.context.sharedContext.accountManager, fileReference: FileMediaReference.message(message: MessageReference(item.message), media: file), representations: representations, alwaysShowThumbnailFirst: true, thumbnail: true, autoFetchFullSize: true)
|
||||
}
|
||||
case let .image(representations):
|
||||
if let dimensions = representations.last?.dimensions.cgSize {
|
||||
imageSize = dimensions.aspectFilled(boundingSize)
|
||||
}
|
||||
updateImageSignal = wallpaperImage(account: item.context.account, accountManager: item.context.sharedContext.accountManager, fileReference: nil, representations: representations.map({ ImageRepresentationWithReference(representation: $0, reference: .standalone(resource: $0.resource)) }), alwaysShowThumbnailFirst: true, thumbnail: true, autoFetchFullSize: true)
|
||||
case let .color(color):
|
||||
updateImageSignal = solidColorImage(color)
|
||||
case let .gradient(colors, rotation):
|
||||
@ -240,6 +293,24 @@ class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
strongSelf.imageNode.frame = imageFrame
|
||||
}
|
||||
|
||||
let radialStatusSize: CGFloat = 50.0
|
||||
strongSelf.statusOverlayNode.frame = imageFrame
|
||||
strongSelf.statusNode.frame = CGRect(origin: CGPoint(x: floor((imageFrame.width - radialStatusSize) / 2.0), y: floor((imageFrame.height - radialStatusSize) / 2.0)), size: CGSize(width: radialStatusSize, height: radialStatusSize))
|
||||
|
||||
if mediaUpdated {
|
||||
if item.message.id.namespace == Namespaces.Message.Local {
|
||||
strongSelf.statusDisposable.set((item.context.account.pendingPeerMediaUploadManager.uploadProgress(messageId: item.message.id)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] progress in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateProgress(progress)
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
strongSelf.statusDisposable.set(nil)
|
||||
strongSelf.updateProgress(nil)
|
||||
}
|
||||
}
|
||||
|
||||
let mediaBackgroundFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - width) / 2.0), y: 0.0), size: backgroundSize)
|
||||
strongSelf.mediaBackgroundNode.frame = mediaBackgroundFrame
|
||||
|
||||
@ -299,7 +370,9 @@ class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
|
||||
override func tapActionAtPoint(_ point: CGPoint, gesture: TapLongTapOrDoubleTapGesture, isEstimating: Bool) -> ChatMessageBubbleContentTapAction {
|
||||
if self.mediaBackgroundNode.frame.contains(point) {
|
||||
if self.statusOverlayNode.alpha > 0.0 {
|
||||
return .none
|
||||
} else if self.mediaBackgroundNode.frame.contains(point) {
|
||||
return .openMessage
|
||||
} else {
|
||||
return .none
|
||||
|
@ -5,6 +5,7 @@ import TelegramCore
|
||||
|
||||
enum WallpaperPreviewMediaContent: Equatable {
|
||||
case file(file: TelegramMediaFile, colors: [UInt32], rotation: Int32?, intensity: Int32?, Bool, Bool)
|
||||
case image(representations: [TelegramMediaImageRepresentation])
|
||||
case color(UIColor)
|
||||
case gradient([UInt32], Int32?)
|
||||
case themeSettings(TelegramThemeSettings)
|
||||
@ -55,6 +56,8 @@ extension WallpaperPreviewMedia {
|
||||
self.init(content: .gradient(gradient.colors, gradient.settings.rotation))
|
||||
case let .file(file):
|
||||
self.init(content: .file(file: file.file, colors: file.settings.colors, rotation: file.settings.rotation, intensity: file.settings.intensity, false, false))
|
||||
case let .image(representations, _):
|
||||
self.init(content: .image(representations: representations))
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user