diff --git a/submodules/SettingsUI/Sources/Themes/EditThemeController.swift b/submodules/SettingsUI/Sources/Themes/EditThemeController.swift index bdc257b773..f487613827 100644 --- a/submodules/SettingsUI/Sources/Themes/EditThemeController.swift +++ b/submodules/SettingsUI/Sources/Themes/EditThemeController.swift @@ -176,12 +176,11 @@ private struct EditThemeControllerState: Equatable { var mode: EditThemeControllerMode var title: String var slug: String - var previewTheme: PresentationTheme var updatedTheme: PresentationTheme? var updating: Bool } -private func editThemeControllerEntries(presentationData: PresentationData, state: EditThemeControllerState) -> [EditThemeControllerEntry] { +private func editThemeControllerEntries(presentationData: PresentationData, state: EditThemeControllerState, previewTheme: PresentationTheme) -> [EditThemeControllerEntry] { var entries: [EditThemeControllerEntry] = [] var isCreate = false @@ -196,7 +195,7 @@ private func editThemeControllerEntries(presentationData: PresentationData, stat } entries.append(.chatPreviewHeader(presentationData.theme, presentationData.strings.EditTheme_Preview.uppercased())) - entries.append(.chatPreview(presentationData.theme, state.previewTheme, state.previewTheme.chat.defaultWallpaper, presentationData.fontSize, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder)) + entries.append(.chatPreview(presentationData.theme, previewTheme, previewTheme.chat.defaultWallpaper, presentationData.fontSize, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder)) let uploadText: String let uploadInfo: String @@ -221,18 +220,26 @@ private func editThemeControllerEntries(presentationData: PresentationData, stat public func editThemeController(context: AccountContext, mode: EditThemeControllerMode, navigateToChat: ((PeerId) -> Void)? = nil) -> ViewController { let initialState: EditThemeControllerState + let previewThemePromise = Promise() switch mode { case .create: let presentationData = context.sharedContext.currentPresentationData.with { $0 } - initialState = EditThemeControllerState(mode: mode, title: "", slug: "", previewTheme: presentationData.theme.withUpdated(name: "", author: nil, defaultWallpaper: presentationData.chatWallpaper), updatedTheme: nil, updating: false) + initialState = EditThemeControllerState(mode: mode, title: "", slug: "", updatedTheme: nil, updating: false) + previewThemePromise.set(.single(presentationData.theme.withUpdated(name: "", author: nil, defaultWallpaper: presentationData.chatWallpaper))) case let .edit(theme): - let previewTheme: PresentationTheme - if let file = theme.theme.file, let path = context.sharedContext.accountManager.mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path)), let theme = makePresentationTheme(data: data, resolvedWallpaper: theme.resolvedWallpaper) { - previewTheme = theme + if let file = theme.theme.file, let path = context.sharedContext.accountManager.mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path)), let theme = makePresentationTheme(data: data) { + if case let .file(file) = theme.chat.defaultWallpaper, file.id == 0 { + previewThemePromise.set(cachedWallpaper(account: context.account, slug: file.slug) + |> map ({ wallpaper -> PresentationTheme in + return theme.withUpdated(name: nil, author: nil, defaultWallpaper: wallpaper?.wallpaper) + })) + } else { + previewThemePromise.set(.single(theme)) + } } else { - previewTheme = context.sharedContext.currentPresentationData.with { $0 }.theme + previewThemePromise.set(.single(context.sharedContext.currentPresentationData.with { $0 }.theme)) } - initialState = EditThemeControllerState(mode: mode, title: theme.theme.title, slug: theme.theme.slug, previewTheme: previewTheme, updatedTheme: nil, updating: false) + initialState = EditThemeControllerState(mode: mode, title: theme.theme.title, slug: theme.theme.slug, updatedTheme: nil, updating: false) } let statePromise = ValuePromise(initialState, ignoreRepeated: true) let stateValue = Atomic(value: initialState) @@ -249,22 +256,50 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll }, openFile: { let presentationData = context.sharedContext.currentPresentationData.with { $0 } let controller = legacyICloudFilePicker(theme: presentationData.theme, mode: .import, documentTypes: ["org.telegram.Telegram-iOS.theme"], completion: { urls in - if let url = urls.first, let data = try? Data(contentsOf: url), let theme = makePresentationTheme(data: data) { - updateState { current in - var state = current - state.previewTheme = theme - state.updatedTheme = theme - return state + if let url = urls.first{ + if let data = try? Data(contentsOf: url), let theme = makePresentationTheme(data: data) { + if case let .file(file) = theme.chat.defaultWallpaper, file.id == 0 { + let _ = (cachedWallpaper(account: context.account, slug: file.slug) + |> mapToSignal { wallpaper -> Signal in + if let wallpaper = wallpaper, case let .file(file) = wallpaper.wallpaper { + var convertedRepresentations: [ImageRepresentationWithReference] = [] + convertedRepresentations.append(ImageRepresentationWithReference(representation: TelegramMediaImageRepresentation(dimensions: CGSize(width: 100.0, height: 100.0), resource: file.file.resource), reference: .wallpaper(resource: file.file.resource))) + return wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: .standalone(media: file.file), representations: convertedRepresentations, alwaysShowThumbnailFirst: false, thumbnail: false, onlyFullSize: true, autoFetchFullSize: true, synchronousLoad: false) + |> map { _ -> TelegramWallpaper? in + return wallpaper.wallpaper + } + } else { + return .single(nil) + } + } + |> deliverOnMainQueue).start(next: { wallpaper in + let updatedTheme = theme.withUpdated(name: nil, author: nil, defaultWallpaper: wallpaper) + updateState { current in + var state = current + previewThemePromise.set(.single(updatedTheme)) + state.updatedTheme = updatedTheme + return state + } + }) + } else { + updateState { current in + var state = current + previewThemePromise.set(.single(theme)) + state.updatedTheme = theme + return state + } + } + } + else { + presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.EditTheme_FileReadError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) } - } else { - presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.EditTheme_FileReadError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) } }) presentControllerImpl?(controller, nil) }) - let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, statePromise.get()) - |> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, EditThemeControllerEntry.ItemGenerationArguments)) in + let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, statePromise.get(), previewThemePromise.get()) + |> map { presentationData, state, previewTheme -> (ItemListControllerState, (ItemListNodeState, EditThemeControllerEntry.ItemGenerationArguments)) in let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: { dismissImpl?() }) @@ -293,75 +328,121 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll return state } - let saveThemeTemplateFile: (String, LocalFileMediaResource, @escaping () -> Void) -> Void = { title, resource, completion in - let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: resource.fileId), partialReference: nil, resource: resource, previewRepresentations: [], immediateThumbnailData: nil, mimeType: "application/x-tgtheme-ios", size: nil, attributes: [.FileName(fileName: "\(title).tgios-theme")]) - let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil) + let _ = (previewThemePromise.get() + |> deliverOnMainQueue).start(next: { previewTheme in + let saveThemeTemplateFile: (String, LocalFileMediaResource, @escaping () -> Void) -> Void = { title, resource, completion in + let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: resource.fileId), partialReference: nil, resource: resource, previewRepresentations: [], immediateThumbnailData: nil, mimeType: "application/x-tgtheme-ios", size: nil, attributes: [.FileName(fileName: "\(title).tgios-theme")]) + let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil) - let _ = enqueueMessages(account: context.account, peerId: context.account.peerId, messages: [message]).start() + let _ = enqueueMessages(account: context.account, peerId: context.account.peerId, messages: [message]).start() - if let navigateToChat = navigateToChat { - presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.EditTheme_ThemeTemplateAlert, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Settings_SavedMessages, action: { + if let navigateToChat = navigateToChat { + presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.EditTheme_ThemeTemplateAlert, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Settings_SavedMessages, action: { + completion() + navigateToChat(context.account.peerId) + }), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: { + completion() + })], actionLayout: .vertical), nil) + } else { completion() - navigateToChat(context.account.peerId) - }), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: { - completion() - })], actionLayout: .vertical), nil) - } else { - completion() + } } - } - - let theme: PresentationTheme? - let hasCustomFile: Bool - if let updatedTheme = state.updatedTheme { - theme = updatedTheme.withUpdated(name: state.title, author: "", defaultWallpaper: nil) - hasCustomFile = true - } else { - if case let .edit(info) = mode, let _ = info.theme.file { - theme = nil + + let theme: PresentationTheme? + let hasCustomFile: Bool + if let updatedTheme = state.updatedTheme { + theme = updatedTheme.withUpdated(name: state.title, author: "", defaultWallpaper: nil) hasCustomFile = true } else { - theme = state.previewTheme.withUpdated(name: state.title, author: "", defaultWallpaper: nil) - hasCustomFile = false - } - } - - let themeResource: LocalFileMediaResource? - let themeData: Data? - let themeThumbnailData: Data? - if let theme = theme, let themeString = encodePresentationTheme(theme), let data = themeString.data(using: .utf8) { - let resource = LocalFileMediaResource(fileId: arc4random64()) - context.account.postbox.mediaBox.storeResourceData(resource.id, data: data) - context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data) - themeResource = resource - themeData = data - - let themeThumbnail = generateImage(CGSize(width: 213, height: 320.0), contextGenerator: { size, context in - if let image = generateImage(CGSize(width: 194.0, height: 291.0), contextGenerator: { size, c in - drawThemeImage(context: c, theme: theme, size: size) - })?.cgImage { - context.draw(image, in: CGRect(origin: CGPoint(), size: size)) + if case let .edit(info) = mode, let _ = info.theme.file { + theme = nil + hasCustomFile = true + } else { + theme = previewTheme.withUpdated(name: state.title, author: "", defaultWallpaper: nil) + hasCustomFile = false } - }, scale: 1.0) - themeThumbnailData = themeThumbnail?.jpegData(compressionQuality: 0.6) - } else { - themeResource = nil - themeData = nil - themeThumbnailData = nil - } - - let resolvedWallpaper: TelegramWallpaper? - if let theme = theme, case let .file(file) = theme.chat.defaultWallpaper, file.id != 0 { - resolvedWallpaper = theme.chat.defaultWallpaper - updateCachedWallpaper(account: context.account, wallpaper: theme.chat.defaultWallpaper) - } else { - resolvedWallpaper = nil - } - - switch mode { - case .create: - if let themeResource = themeResource { - let _ = (createTheme(account: context.account, title: state.title, resource: themeResource, thumbnailData: themeThumbnailData) + } + + let themeResource: LocalFileMediaResource? + let themeData: Data? + let themeThumbnailData: Data? + if let theme = theme, let themeString = encodePresentationTheme(theme), let data = themeString.data(using: .utf8) { + let resource = LocalFileMediaResource(fileId: arc4random64()) + context.account.postbox.mediaBox.storeResourceData(resource.id, data: data) + context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data) + themeResource = resource + themeData = data + + let themeThumbnail = generateImage(CGSize(width: 213, height: 320.0), contextGenerator: { size, context in + if let image = generateImage(CGSize(width: 194.0, height: 291.0), contextGenerator: { size, c in + drawThemeImage(context: c, theme: theme, size: size) + })?.cgImage { + context.draw(image, in: CGRect(origin: CGPoint(), size: size)) + } + }, scale: 1.0) + themeThumbnailData = themeThumbnail?.jpegData(compressionQuality: 0.6) + } else { + themeResource = nil + themeData = nil + themeThumbnailData = nil + } + + let resolvedWallpaper: TelegramWallpaper? + if let theme = theme, case let .file(file) = theme.chat.defaultWallpaper, file.id != 0 { + resolvedWallpaper = theme.chat.defaultWallpaper + updateCachedWallpaper(account: context.account, wallpaper: theme.chat.defaultWallpaper) + } else { + resolvedWallpaper = nil + } + + switch mode { + case .create: + if let themeResource = themeResource { + let _ = (createTheme(account: context.account, title: state.title, resource: themeResource, thumbnailData: themeThumbnailData) + |> deliverOnMainQueue).start(next: { next in + if case let .result(resultTheme) = next { + let _ = applyTheme(accountManager: context.sharedContext.accountManager, account: context.account, theme: resultTheme).start() + let _ = (context.sharedContext.accountManager.transaction { transaction -> Void in + transaction.updateSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings, { entry in + let current: PresentationThemeSettings + if let entry = entry as? PresentationThemeSettings { + current = entry + } else { + current = PresentationThemeSettings.defaultSettings + } + + if let resource = resultTheme.file?.resource, let data = themeData { + context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data) + } + + let themeReference: PresentationThemeReference = .cloud(PresentationCloudTheme(theme: resultTheme, resolvedWallpaper: resolvedWallpaper)) + var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers + if let theme = theme { + themeSpecificChatWallpapers[themeReference.index] = theme.chat.defaultWallpaper + } + + return PresentationThemeSettings(chatWallpaper: theme?.chat.defaultWallpaper ?? current.chatWallpaper, theme: themeReference, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations) + }) + } |> deliverOnMainQueue).start(completed: { + if !hasCustomFile { + saveThemeTemplateFile(state.title, themeResource, { + dismissImpl?() + }) + } else { + dismissImpl?() + } + }) + } + }, error: { error in + arguments.updateState { current in + var state = current + state.updating = false + return state + } + }) + } + case let .edit(info): + let _ = (updateTheme(account: context.account, theme: info.theme, title: state.title, slug: state.slug, resource: themeResource) |> deliverOnMainQueue).start(next: { next in if case let .result(resultTheme) = next { let _ = applyTheme(accountManager: context.sharedContext.accountManager, account: context.account, theme: resultTheme).start() @@ -387,7 +468,7 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll return PresentationThemeSettings(chatWallpaper: theme?.chat.defaultWallpaper ?? current.chatWallpaper, theme: themeReference, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations) }) } |> deliverOnMainQueue).start(completed: { - if !hasCustomFile { + if let themeResource = themeResource, !hasCustomFile { saveThemeTemplateFile(state.title, themeResource, { dismissImpl?() }) @@ -403,51 +484,8 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll return state } }) - } - case let .edit(info): - let _ = (updateTheme(account: context.account, theme: info.theme, title: state.title, slug: state.slug, resource: themeResource) - |> deliverOnMainQueue).start(next: { next in - if case let .result(resultTheme) = next { - let _ = applyTheme(accountManager: context.sharedContext.accountManager, account: context.account, theme: resultTheme).start() - let _ = (context.sharedContext.accountManager.transaction { transaction -> Void in - transaction.updateSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings, { entry in - let current: PresentationThemeSettings - if let entry = entry as? PresentationThemeSettings { - current = entry - } else { - current = PresentationThemeSettings.defaultSettings - } - - if let resource = resultTheme.file?.resource, let data = themeData { - context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data) - } - - let themeReference: PresentationThemeReference = .cloud(PresentationCloudTheme(theme: resultTheme, resolvedWallpaper: resolvedWallpaper)) - var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers - if let theme = theme { - themeSpecificChatWallpapers[themeReference.index] = theme.chat.defaultWallpaper - } - - return PresentationThemeSettings(chatWallpaper: theme?.chat.defaultWallpaper ?? current.chatWallpaper, theme: themeReference, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations) - }) - } |> deliverOnMainQueue).start(completed: { - if let themeResource = themeResource, !hasCustomFile { - saveThemeTemplateFile(state.title, themeResource, { - dismissImpl?() - }) - } else { - dismissImpl?() - } - }) - } - }, error: { error in - arguments.updateState { current in - var state = current - state.updating = false - return state - } - }) - } + } + }) }) } @@ -463,7 +501,7 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll } } let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) - let listState = ItemListNodeState(entries: editThemeControllerEntries(presentationData: presentationData, state: state), style: .blocks, focusItemTag: focusItemTag, emptyStateItem: nil, animateChanges: false) + let listState = ItemListNodeState(entries: editThemeControllerEntries(presentationData: presentationData, state: state, previewTheme: previewTheme), style: .blocks, focusItemTag: focusItemTag, emptyStateItem: nil, animateChanges: false) return (controllerState, (listState, arguments)) } diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift index 3cf4de2a2d..411c10018d 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift @@ -124,9 +124,6 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode { let replyMessageId = MessageId(peerId: peerId, namespace: 0, id: 3) messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: item.strings.Appearance_PreviewReplyText, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: []) - //let chatPresentationData = ChatPresentationData(theme: ChatPresentationThemeData(theme: item.componentTheme, wallpaper: item.wallpaper), fontSize: item.fontSize, strings: item.strings, dateTimeFormat: item.dateTimeFormat, nameDisplayOrder: item.nameDisplayOrder, disableAnimations: false, largeEmoji: false) - - //let item2: ChatMessageItem = ChatMessageItem(presentationData: chatPresentationData, context: item.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: nil, text: item.strings.Appearance_PreviewIncomingText, attributes: [ReplyMessageAttribute(messageId: replyMessageId)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, attributes: ChatMessageEntryAttributes()), disableDate: true) let message2 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: nil, text: item.strings.Appearance_PreviewIncomingText, attributes: [ReplyMessageAttribute(messageId: replyMessageId)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []) let message1 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: TelegramUser(id: item.context.account.peerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []), text: item.strings.Appearance_PreviewOutgoingText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []) diff --git a/submodules/TelegramCore/TelegramCore/Themes.swift b/submodules/TelegramCore/TelegramCore/Themes.swift index bada345a5b..ccff559eb4 100644 --- a/submodules/TelegramCore/TelegramCore/Themes.swift +++ b/submodules/TelegramCore/TelegramCore/Themes.swift @@ -260,6 +260,7 @@ private func uploadTheme(account: Account, resource: MediaResource, thumbnailDat public enum CreateThemeError { case generic + case slugOccupied } public enum CreateThemeResult { @@ -319,6 +320,7 @@ public func updateTheme(account: Account, theme: TelegramTheme, title: String?, } let uploadSignal: Signal if let resource = resource { + flags |= 1 << 2 uploadSignal = uploadTheme(account: account, resource: resource, thumbnailData: thumbnailData) |> map(Optional.init) } else { @@ -346,7 +348,12 @@ public func updateTheme(account: Account, theme: TelegramTheme, title: String?, } return account.network.request(Api.functions.account.updateTheme(flags: flags, theme: .inputTheme(id: theme.id, accessHash: theme.accessHash), slug: slug, title: title, document: inputDocument)) - |> mapError { _ in return CreateThemeError.generic } + |> mapError { error -> CreateThemeError in + if error.errorDescription.hasPrefix("THEME_SLUG_OCCUPIED") { + return .slugOccupied + } + return .generic + } |> mapToSignal { apiTheme -> Signal in if let result = TelegramTheme(apiTheme: apiTheme) { return account.postbox.transaction { transaction -> CreateThemeResult in diff --git a/submodules/TelegramUI/TelegramUI/DeclareEncodables.swift b/submodules/TelegramUI/TelegramUI/DeclareEncodables.swift index 11cc745962..5ba39fe5e9 100644 --- a/submodules/TelegramUI/TelegramUI/DeclareEncodables.swift +++ b/submodules/TelegramUI/TelegramUI/DeclareEncodables.swift @@ -8,6 +8,7 @@ import LocalMediaResources import WebSearchUI import InstantPageCache import SettingsUI +import WallpaperResources private var telegramUIDeclaredEncodables: Void = { declareEncodable(InAppNotificationSettings.self, f: { InAppNotificationSettings(decoder: $0) }) @@ -40,6 +41,7 @@ private var telegramUIDeclaredEncodables: Void = { declareEncodable(InstantPageStoredState.self, f: { InstantPageStoredState(decoder: $0) }) declareEncodable(InstantPageStoredDetailsState.self, f: { InstantPageStoredDetailsState(decoder: $0) }) declareEncodable(CachedInstantPage.self, f: { CachedInstantPage(decoder: $0) }) + declareEncodable(CachedWallpaper.self, f: { CachedWallpaper(decoder: $0) }) declareEncodable(WatchPresetSettings.self, f: { WatchPresetSettings(decoder: $0) }) declareEncodable(WebSearchSettings.self, f: { WebSearchSettings(decoder: $0) }) declareEncodable(RecentWebSearchQueryItem.self, f: { RecentWebSearchQueryItem(decoder: $0) }) diff --git a/submodules/TelegramUI/TelegramUI/OpenChatMessage.swift b/submodules/TelegramUI/TelegramUI/OpenChatMessage.swift index 2eaeceb1b5..447b148095 100644 --- a/submodules/TelegramUI/TelegramUI/OpenChatMessage.swift +++ b/submodules/TelegramUI/TelegramUI/OpenChatMessage.swift @@ -462,9 +462,8 @@ func openChatTheme(context: AccountContext, message: Message, present: @escaping if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content { let _ = (context.sharedContext.resolveUrl(account: context.account, url: content.url) |> deliverOnMainQueue).start(next: { resolvedUrl in - if case let .theme(slug) = resolvedUrl { - let file = content.files!.first! - if let path = context.account.postbox.mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead), let theme = makePresentationTheme(data: data) { + if case let .theme(slug) = resolvedUrl, let files = content.files { + if let file = files.filter({ $0.mimeType == "application/x-tgtheme-ios" }).first, let path = context.sharedContext.accountManager.mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead), let theme = makePresentationTheme(data: data) { let controller = ThemePreviewController(context: context, previewTheme: theme, source: .slug(slug, file)) present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) } diff --git a/submodules/WallpaperResources/Sources/WallpaperResources.swift b/submodules/WallpaperResources/Sources/WallpaperResources.swift index 205b3fb165..f46d37391e 100644 --- a/submodules/WallpaperResources/Sources/WallpaperResources.swift +++ b/submodules/WallpaperResources/Sources/WallpaperResources.swift @@ -11,7 +11,7 @@ import PhotoResources import LocalMediaResources import TelegramPresentationData -private func wallpaperDatas(account: Account, accountManager: AccountManager, fileReference: FileMediaReference? = nil, representations: [ImageRepresentationWithReference], alwaysShowThumbnailFirst: Bool = false, thumbnail: Bool = false, autoFetchFullSize: Bool = false, synchronousLoad: Bool = false) -> Signal<(Data?, Data?, Bool), NoError> { +private func wallpaperDatas(account: Account, accountManager: AccountManager, fileReference: FileMediaReference? = nil, representations: [ImageRepresentationWithReference], alwaysShowThumbnailFirst: Bool = false, thumbnail: Bool = false, onlyFullSize: Bool = false, autoFetchFullSize: Bool = false, synchronousLoad: Bool = false) -> Signal<(Data?, Data?, Bool), NoError> { if let smallestRepresentation = smallestImageRepresentation(representations.map({ $0.representation })), let largestRepresentation = largestImageRepresentation(representations.map({ $0.representation })), let smallestIndex = representations.firstIndex(where: { $0.representation == smallestRepresentation }), let largestIndex = representations.firstIndex(where: { $0.representation == largestRepresentation }) { let maybeFullSize: Signal @@ -143,10 +143,15 @@ private func wallpaperDatas(account: Account, accountManager: AccountManager, fi } } } else { - - return thumbnailData |> mapToSignal { thumbnailData in + if onlyFullSize { return fullSizeData |> map { (fullSizeData, complete) in - return (thumbnailData, fullSizeData, complete) + return (nil, fullSizeData, complete) + } + } else { + return thumbnailData |> mapToSignal { thumbnailData in + return fullSizeData |> map { (fullSizeData, complete) in + return (thumbnailData, fullSizeData, complete) + } } } } @@ -158,11 +163,14 @@ private func wallpaperDatas(account: Account, accountManager: AccountManager, fi } } -public func wallpaperImage(account: Account, accountManager: AccountManager, fileReference: FileMediaReference? = nil, representations: [ImageRepresentationWithReference], alwaysShowThumbnailFirst: Bool = false, thumbnail: Bool = false, autoFetchFullSize: Bool = false, synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { - let signal = wallpaperDatas(account: account, accountManager: accountManager, fileReference: fileReference, representations: representations, alwaysShowThumbnailFirst: alwaysShowThumbnailFirst, thumbnail: thumbnail, autoFetchFullSize: autoFetchFullSize, synchronousLoad: synchronousLoad) +public func wallpaperImage(account: Account, accountManager: AccountManager, fileReference: FileMediaReference? = nil, representations: [ImageRepresentationWithReference], alwaysShowThumbnailFirst: Bool = false, thumbnail: Bool = false, onlyFullSize: Bool = false, autoFetchFullSize: Bool = false, synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { + let signal = wallpaperDatas(account: account, accountManager: accountManager, fileReference: fileReference, representations: representations, alwaysShowThumbnailFirst: alwaysShowThumbnailFirst, thumbnail: thumbnail, onlyFullSize: onlyFullSize, autoFetchFullSize: autoFetchFullSize, synchronousLoad: synchronousLoad) return signal |> map { (thumbnailData, fullSizeData, fullSizeComplete) in + if let fullSizeData = fullSizeData, let fileReference = fileReference { + accountManager.mediaBox.storeResourceData(fileReference.media.resource.id, data: fullSizeData) + } return { arguments in let drawingRect = arguments.drawingRect var fittedSize = arguments.imageSize