mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
API update
This commit is contained in:
@@ -23,7 +23,6 @@ public final class ThemePreviewController: ViewController {
|
||||
private let previewTheme: PresentationTheme
|
||||
private let source: ThemePreviewSource
|
||||
private let theme = Promise<TelegramTheme?>()
|
||||
private let wallpaper = Promise<TelegramWallpaper>()
|
||||
|
||||
private var controllerNode: ThemePreviewControllerNode {
|
||||
return self.displayNode as! ThemePreviewControllerNode
|
||||
@@ -59,15 +58,6 @@ public final class ThemePreviewController: ViewController {
|
||||
themeName = previewTheme.name.string
|
||||
}
|
||||
|
||||
if case let .file(file) = previewTheme.chat.defaultWallpaper, file.id == 0 {
|
||||
self.wallpaper.set(cachedWallpaper(account: context.account, slug: file.slug)
|
||||
|> mapToSignal { wallpaper in
|
||||
return .single(wallpaper?.wallpaper ?? .color(Int32(bitPattern: previewTheme.chatList.backgroundColor.rgb)))
|
||||
})
|
||||
} else {
|
||||
self.wallpaper.set(.single(previewTheme.chat.defaultWallpaper))
|
||||
}
|
||||
|
||||
if let author = previewTheme.author {
|
||||
let titleView = CounterContollerTitleView(theme: self.previewTheme)
|
||||
titleView.title = CounterContollerTitle(title: themeName, counter: author)
|
||||
@@ -123,11 +113,14 @@ public final class ThemePreviewController: ViewController {
|
||||
|
||||
switch strongSelf.source {
|
||||
case .theme, .slug:
|
||||
theme = strongSelf.theme.get()
|
||||
|> take(1)
|
||||
|> map { theme in
|
||||
theme = combineLatest(strongSelf.theme.get() |> take(1), strongSelf.controllerNode.wallpaperPromise.get() |> take(1))
|
||||
|> map { theme, wallpaper in
|
||||
if let theme = theme {
|
||||
return .cloud(PresentationCloudTheme(theme: theme, resolvedWallpaper: nil))
|
||||
if case let .file(file) = wallpaper, file.id != 0 {
|
||||
return .cloud(PresentationCloudTheme(theme: theme, resolvedWallpaper: wallpaper))
|
||||
} else {
|
||||
return .cloud(PresentationCloudTheme(theme: theme, resolvedWallpaper: nil))
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
@@ -175,6 +168,16 @@ public final class ThemePreviewController: ViewController {
|
||||
}
|
||||
})
|
||||
self.displayNodeDidLoad()
|
||||
|
||||
let previewTheme = self.previewTheme
|
||||
if case let .file(file) = previewTheme.chat.defaultWallpaper, file.id == 0 {
|
||||
self.controllerNode.wallpaperPromise.set(cachedWallpaper(account: self.context.account, slug: file.slug)
|
||||
|> mapToSignal { wallpaper in
|
||||
return .single(wallpaper?.wallpaper ?? .color(Int32(bitPattern: previewTheme.chatList.backgroundColor.rgb)))
|
||||
})
|
||||
} else {
|
||||
self.controllerNode.wallpaperPromise.set(.single(previewTheme.chat.defaultWallpaper))
|
||||
}
|
||||
}
|
||||
|
||||
private func updateStrings() {
|
||||
|
||||
@@ -9,6 +9,7 @@ import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import ChatListUI
|
||||
import WallpaperResources
|
||||
|
||||
private func generateMaskImage(color: UIColor) -> UIImage? {
|
||||
return generateImage(CGSize(width: 1.0, height: 60.0), opaque: false, rotatedContext: { size, context in
|
||||
@@ -42,6 +43,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private var chatNodes: [ListViewItemNode]?
|
||||
private let maskNode: ASImageNode
|
||||
|
||||
private let chatContainerNode: ASDisplayNode
|
||||
private let instantChatBackgroundNode: WallpaperBackgroundNode
|
||||
private let remoteChatBackgroundNode: TransformImageNode
|
||||
private var messageNodes: [ListViewItemNode]?
|
||||
@@ -52,6 +54,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
private var wallpaperDisposable: Disposable?
|
||||
private var colorDisposable: Disposable?
|
||||
private var statusDisposable: Disposable?
|
||||
|
||||
init(context: AccountContext, previewTheme: PresentationTheme, dismiss: @escaping () -> Void, apply: @escaping () -> Void) {
|
||||
self.context = context
|
||||
@@ -75,15 +78,25 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self.pageControlNode = PageControlNode(dotColor: previewTheme.chatList.unreadBadgeActiveBackgroundColor, inactiveDotColor: previewTheme.list.pageIndicatorInactiveColor)
|
||||
|
||||
self.chatListBackgroundNode = ASDisplayNode()
|
||||
|
||||
self.chatContainerNode = ASDisplayNode()
|
||||
self.instantChatBackgroundNode = WallpaperBackgroundNode()
|
||||
self.instantChatBackgroundNode.displaysAsynchronously = false
|
||||
self.instantChatBackgroundNode.image = chatControllerBackgroundImage(theme: previewTheme, wallpaper: previewTheme.chat.defaultWallpaper, mediaBox: context.sharedContext.accountManager.mediaBox, knockoutMode: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper)
|
||||
self.instantChatBackgroundNode.motionEnabled = previewTheme.chat.defaultWallpaper.settings?.motion ?? false
|
||||
|
||||
self.remoteChatBackgroundNode = TransformImageNode()
|
||||
self.remoteChatBackgroundNode.backgroundColor = previewTheme.chatList.backgroundColor
|
||||
|
||||
self.toolbarNode = WallpaperGalleryToolbarNode(theme: self.previewTheme, strings: self.presentationData.strings)
|
||||
|
||||
if case let .file(file) = previewTheme.chat.defaultWallpaper, file.id == 0 {
|
||||
self.remoteChatBackgroundNode.isHidden = false
|
||||
self.toolbarNode.setDoneEnabled(false)
|
||||
} else {
|
||||
self.remoteChatBackgroundNode.isHidden = true
|
||||
}
|
||||
|
||||
self.maskNode = ASImageNode()
|
||||
self.maskNode.displaysAsynchronously = false
|
||||
self.maskNode.displayWithoutProcessing = true
|
||||
@@ -114,8 +127,10 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self.addSubnode(self.toolbarNode)
|
||||
|
||||
self.scrollNode.addSubnode(self.chatListBackgroundNode)
|
||||
self.scrollNode.addSubnode(self.instantChatBackgroundNode)
|
||||
self.scrollNode.addSubnode(self.remoteChatBackgroundNode)
|
||||
self.scrollNode.addSubnode(self.chatContainerNode)
|
||||
|
||||
self.chatContainerNode.addSubnode(self.instantChatBackgroundNode)
|
||||
self.chatContainerNode.addSubnode(self.remoteChatBackgroundNode)
|
||||
|
||||
self.toolbarNode.cancel = {
|
||||
dismiss()
|
||||
@@ -137,10 +152,53 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
self.wallpaperDisposable = (self.wallpaperPromise.get()
|
||||
|> deliverOnMainQueue).start(next: { [weak self] wallpaper in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if case let .file(file) = wallpaper {
|
||||
let dimensions = file.file.dimensions ?? CGSize(width: 100.0, height: 100.0)
|
||||
let displaySize = dimensions.dividedByScreenScale().integralFloor
|
||||
|
||||
var convertedRepresentations: [ImageRepresentationWithReference] = []
|
||||
for representation in file.file.previewRepresentations {
|
||||
convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: .wallpaper(resource: representation.resource)))
|
||||
}
|
||||
convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.file.resource), reference: .wallpaper(resource: file.file.resource)))
|
||||
|
||||
let fileReference = FileMediaReference.standalone(media: file.file)
|
||||
let signal = wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: fileReference, representations: convertedRepresentations, alwaysShowThumbnailFirst: true, autoFetchFullSize: false)
|
||||
strongSelf.remoteChatBackgroundNode.setSignal(signal)
|
||||
|
||||
let account = strongSelf.context.account
|
||||
let statusSignal = strongSelf.context.sharedContext.accountManager.mediaBox.resourceStatus(file.file.resource)
|
||||
|> take(1)
|
||||
|> mapToSignal { status -> Signal<MediaResourceStatus, NoError> in
|
||||
if case .Local = status {
|
||||
return .single(status)
|
||||
} else {
|
||||
return account.postbox.mediaBox.resourceStatus(file.file.resource)
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.statusDisposable = (statusSignal
|
||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||
if let strongSelf = self, case .Local = status {
|
||||
strongSelf.toolbarNode.setDoneEnabled(true)
|
||||
}
|
||||
})
|
||||
|
||||
strongSelf.remoteChatBackgroundNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets(), emptyColor: nil))()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.colorDisposable?.dispose()
|
||||
self.wallpaperDisposable?.dispose()
|
||||
self.statusDisposable?.dispose()
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
@@ -305,7 +363,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
itemNode!.subnodeTransform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
|
||||
itemNode!.isUserInteractionEnabled = false
|
||||
messageNodes.append(itemNode!)
|
||||
self.instantChatBackgroundNode.addSubnode(itemNode!)
|
||||
self.chatContainerNode.addSubnode(itemNode!)
|
||||
}
|
||||
self.messageNodes = messageNodes
|
||||
}
|
||||
@@ -326,8 +384,9 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
let toolbarHeight = 49.0 + layout.intrinsicInsets.bottom
|
||||
self.chatListBackgroundNode.frame = CGRect(x: bounds.width, y: 0.0, width: bounds.width, height: bounds.height)
|
||||
self.instantChatBackgroundNode.frame = CGRect(x: 0.0, y: 0.0, width: bounds.width, height: bounds.height)
|
||||
self.remoteChatBackgroundNode.frame = CGRect(x: 0.0, y: 0.0, width: bounds.width, height: bounds.height)
|
||||
self.chatContainerNode.frame = CGRect(x: 0.0, y: 0.0, width: bounds.width, height: bounds.height)
|
||||
self.instantChatBackgroundNode.frame = self.chatContainerNode.bounds
|
||||
self.remoteChatBackgroundNode.frame = self.chatContainerNode.bounds
|
||||
|
||||
self.scrollNode.view.contentSize = CGSize(width: bounds.width * 2.0, height: bounds.height)
|
||||
|
||||
|
||||
@@ -562,7 +562,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
let cloudThemes: [PresentationThemeReference] = cloudThemes.map { .cloud(PresentationCloudTheme(theme: $0, resolvedWallpaper: nil)) }
|
||||
|
||||
var availableThemes = defaultThemes
|
||||
if !defaultThemes.contains(settings.theme) && !cloudThemes.contains(settings.theme) {
|
||||
if defaultThemes.first(where: { $0.index == settings.theme.index }) == nil && cloudThemes.first(where: { $0.index == settings.theme.index }) == nil {
|
||||
availableThemes.append(settings.theme)
|
||||
}
|
||||
availableThemes.append(contentsOf: cloudThemes)
|
||||
|
||||
@@ -412,7 +412,7 @@ class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode {
|
||||
updated = true
|
||||
}
|
||||
|
||||
let selected = theme == item.currentTheme
|
||||
let selected = theme.index == item.currentTheme.index
|
||||
if selected {
|
||||
selectedNode = imageNode
|
||||
}
|
||||
|
||||
@@ -1305,6 +1305,7 @@ public class Account {
|
||||
self.managedOperationsDisposable.add(managedPendingPeerNotificationSettings(postbox: self.postbox, network: self.network).start())
|
||||
self.managedOperationsDisposable.add(managedSynchronizeAppLogEventsOperations(postbox: self.postbox, network: self.network).start())
|
||||
self.managedOperationsDisposable.add(managedNotificationSettingsBehaviors(postbox: self.postbox).start())
|
||||
self.managedOperationsDisposable.add(managedThemesUpdates(accountManager: accountManager, postbox: self.postbox, network: self.network).start())
|
||||
|
||||
if !self.supplementary {
|
||||
self.managedOperationsDisposable.add(managedAnimatedEmojiUpdates(postbox: self.postbox, network: self.network).start())
|
||||
|
||||
@@ -2955,6 +2955,14 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
|
||||
updatedEntries.append(OrderedItemListEntry(id: id, contents: theme))
|
||||
}
|
||||
transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudThemes, items: updatedEntries)
|
||||
accountManager.transaction { transaction in
|
||||
transaction.updateSharedData(SharedDataKeys.themeSettings, { current in
|
||||
if let current = current as? ThemeSettings, let theme = current.currentTheme, let updatedTheme = updatedThemes[theme.id] {
|
||||
return ThemeSettings(currentTheme: updatedTheme)
|
||||
}
|
||||
return current
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
addedIncomingMessageIds.append(contentsOf: addedSecretMessageIds)
|
||||
|
||||
@@ -115,18 +115,18 @@ public func getTheme(account: Account, slug: String) -> Signal<TelegramTheme, Ge
|
||||
}
|
||||
}
|
||||
|
||||
public enum CheckThemeUpdatedResult {
|
||||
public enum ThemeUpdatedResult {
|
||||
case updated(TelegramTheme)
|
||||
case notModified
|
||||
}
|
||||
|
||||
public func checkThemeUpdated(account: Account, theme: TelegramTheme) -> Signal<CheckThemeUpdatedResult, GetThemeError> {
|
||||
private func checkThemeUpdated(network: Network, theme: TelegramTheme) -> Signal<ThemeUpdatedResult, GetThemeError> {
|
||||
guard let file = theme.file, let fileId = file.id?.id else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
return account.network.request(Api.functions.account.getTheme(format: themeFormat, theme: .inputTheme(id: theme.id, accessHash: theme.accessHash), documentId: fileId))
|
||||
return network.request(Api.functions.account.getTheme(format: themeFormat, theme: .inputTheme(id: theme.id, accessHash: theme.accessHash), documentId: fileId))
|
||||
|> mapError { _ -> GetThemeError in return .generic }
|
||||
|> map { theme -> CheckThemeUpdatedResult in
|
||||
|> map { theme -> ThemeUpdatedResult in
|
||||
if let theme = TelegramTheme(apiTheme: theme) {
|
||||
return .updated(theme)
|
||||
} else {
|
||||
@@ -448,3 +448,48 @@ public func applyTheme(accountManager: AccountManager, account: Account, theme:
|
||||
}
|
||||
|> switchToLatest
|
||||
}
|
||||
|
||||
func managedThemesUpdates(accountManager: AccountManager, postbox: Postbox, network: Network) -> Signal<Void, NoError> {
|
||||
return accountManager.sharedData(keys: [SharedDataKeys.themeSettings])
|
||||
|> mapToSignal { sharedData -> Signal<Void, NoError> in
|
||||
let themeSettings = (sharedData.entries[SharedDataKeys.themeSettings] as? ThemeSettings) ?? ThemeSettings(currentTheme: nil)
|
||||
if let currentTheme = themeSettings.currentTheme {
|
||||
let poll = Signal<Void, NoError> { subscriber in
|
||||
return checkThemeUpdated(network: network, theme: currentTheme).start(next: { result in
|
||||
if case let .updated(updatedTheme) = result {
|
||||
let _ = accountManager.transaction { transaction in
|
||||
transaction.updateSharedData(SharedDataKeys.themeSettings, { _ in
|
||||
return ThemeSettings(currentTheme: updatedTheme)
|
||||
})
|
||||
}.start()
|
||||
let _ = postbox.transaction { transaction in
|
||||
|
||||
}
|
||||
}
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
}
|
||||
return ((.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue())) |> then(poll)) |> restart
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func actualizedTheme(accountManager: AccountManager, theme: TelegramTheme) -> Signal<TelegramTheme, NoError> {
|
||||
var currentTheme = theme
|
||||
return accountManager.sharedData(keys: [SharedDataKeys.themeSettings])
|
||||
|> map { sharedData -> TelegramTheme in
|
||||
let themeSettings = (sharedData.entries[SharedDataKeys.themeSettings] as? ThemeSettings) ?? ThemeSettings(currentTheme: nil)
|
||||
if let updatedTheme = themeSettings.currentTheme, updatedTheme.id == currentTheme.id {
|
||||
if updatedTheme != currentTheme {
|
||||
currentTheme = updatedTheme
|
||||
return updatedTheme
|
||||
} else {
|
||||
return currentTheme
|
||||
}
|
||||
} else {
|
||||
return theme
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user