Cloud themes improvements

This commit is contained in:
Ilya Laktyushin 2019-08-29 13:17:35 +03:00
parent 4ed6cbeb9b
commit a706852dfc
14 changed files with 279 additions and 88 deletions

View File

@ -239,9 +239,9 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
statePromise.set(stateValue.modify { f($0) })
}
var pushControllerImpl: ((ViewController) -> Void)?
var presentControllerImpl: ((ViewController, Any?) -> Void)?
var dismissImpl: (() -> Void)?
var dismissInputImpl: (() -> Void)?
let arguments = EditThemeControllerArguments(context: context, updateState: { f in
updateState(f)
@ -285,6 +285,7 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
}
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: isComplete, action: {
dismissInputImpl?()
arguments.updateState { current in
var state = current
state.updating = true
@ -326,52 +327,106 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
}
let themeResource: LocalFileMediaResource?
if let theme = theme, let themeString = encodePresentationTheme(theme), let themeData = themeString.data(using: .utf8) {
let themeData: 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: themeData)
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: themeData)
context.account.postbox.mediaBox.storeResourceData(resource.id, data: data)
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data)
themeResource = resource
themeData = data
} else {
themeResource = nil
themeData = nil
}
switch mode {
case .create:
if let themeResource = themeResource {
let _ = (createTheme(account: context.account, resource: themeResource, title: state.title)
|> deliverOnMainQueue).start(error: { error in
|> 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: nil))
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 !custom {
saveThemeTemplateFile(state.title, themeResource, {
dismissImpl?()
})
} else {
dismissImpl?()
}
})
}
}, error: { error in
arguments.updateState { current in
var state = current
state.updating = false
return state
}
}, completed: {
if !custom {
saveThemeTemplateFile(state.title, themeResource, {
dismissImpl?()
})
} else {
dismissImpl?()
}
})
}
case let .edit(theme):
let _ = (updateTheme(account: context.account, theme: theme.theme, title: state.title, slug: state.slug, resource: themeResource)
|> deliverOnMainQueue).start(error: { error in
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: nil))
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, !custom {
saveThemeTemplateFile(state.title, themeResource, {
dismissImpl?()
})
} else {
dismissImpl?()
}
})
}
}, error: { error in
arguments.updateState { current in
var state = current
state.updating = false
return state
}
}, completed: {
if let themeResource = themeResource, !custom {
saveThemeTemplateFile(state.title, themeResource, {
dismissImpl?()
})
} else {
dismissImpl?()
}
})
}
})
@ -395,9 +450,6 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
}
let controller = ItemListController(context: context, state: signal)
pushControllerImpl = { [weak controller] c in
(controller?.navigationController as? NavigationController)?.pushViewController(c)
}
presentControllerImpl = { [weak controller] c, a in
controller?.present(c, in: .window(.root), with: a)
}
@ -405,5 +457,8 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
controller?.view.endEditing(true)
let _ = controller?.dismiss()
}
dismissInputImpl = { [weak controller] in
controller?.view.endEditing(true)
}
return controller
}

View File

@ -45,8 +45,9 @@ private final class ThemeSettingsControllerArguments {
let disableAnimations: (Bool) -> Void
let selectAppIcon: (String) -> Void
let presentThemeMenu: (PresentationThemeReference, Bool) -> Void
let editTheme: (PresentationCloudTheme) -> Void
init(context: AccountContext, selectTheme: @escaping (PresentationThemeReference) -> Void, selectFontSize: @escaping (PresentationFontSize) -> Void, openWallpaperSettings: @escaping () -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor) -> Void, openAccentColorPicker: @escaping (PresentationThemeReference, PresentationThemeAccentColor?) -> Void, openAutoNightTheme: @escaping () -> Void, toggleLargeEmoji: @escaping (Bool) -> Void, disableAnimations: @escaping (Bool) -> Void, selectAppIcon: @escaping (String) -> Void, presentThemeMenu: @escaping (PresentationThemeReference, Bool) -> Void) {
init(context: AccountContext, selectTheme: @escaping (PresentationThemeReference) -> Void, selectFontSize: @escaping (PresentationFontSize) -> Void, openWallpaperSettings: @escaping () -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor) -> Void, openAccentColorPicker: @escaping (PresentationThemeReference, PresentationThemeAccentColor?) -> Void, openAutoNightTheme: @escaping () -> Void, toggleLargeEmoji: @escaping (Bool) -> Void, disableAnimations: @escaping (Bool) -> Void, selectAppIcon: @escaping (String) -> Void, presentThemeMenu: @escaping (PresentationThemeReference, Bool) -> Void, editTheme: @escaping (PresentationCloudTheme) -> Void) {
self.context = context
self.selectTheme = selectTheme
self.selectFontSize = selectFontSize
@ -58,6 +59,7 @@ private final class ThemeSettingsControllerArguments {
self.disableAnimations = disableAnimations
self.selectAppIcon = selectAppIcon
self.presentThemeMenu = presentThemeMenu
self.editTheme = editTheme
}
}
@ -289,7 +291,13 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
case let .themeItem(theme, strings, themes, currentTheme, themeSpecificAccentColors, currentColor):
return ThemeSettingsThemeItem(context: arguments.context, theme: theme, strings: strings, sectionId: self.section, themes: themes, themeSpecificAccentColors: themeSpecificAccentColors, currentTheme: currentTheme, updatedTheme: { theme in
arguments.selectTheme(theme)
if case let .cloud(theme) = theme, theme.theme.file == nil {
if theme.theme.isCreator {
arguments.editTheme(theme)
}
} else {
arguments.selectTheme(theme)
}
}, longTapped: { theme in
arguments.presentThemeMenu(theme, theme == currentTheme)
})
@ -485,24 +493,32 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
items.append(ActionSheetButtonItem(title: presentationData.strings.Appearance_RemoveTheme, color: .destructive, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
// let _ = (cloudThemes.get()
// |> take(1)
// |> deliverOnMainQueue).start(next: { themes in
// if isCurrent, let themeIndex = themes.firstIndex(where: { $0.id == theme.id }) {
// let newTheme: PresentationThemeReference
// if themeIndex > 0 {
// newTheme = .cloud(themes[themeIndex - 1])
// } else {
// newTheme = .builtin(.nightAccent)
// }
// selectThemeImpl?(newTheme)
// }
//
// let updatedThemes = themes.filter { $0.id != theme.id }
// cloudThemes.set(.single(updatedThemes) |> then(updatedCloudThemes))
//
// let _ = (deleteTheme(account: context.account, theme: theme)).start()
// })
let actionSheet = ActionSheetController(presentationTheme: presentationData.theme)
var items: [ActionSheetItem] = []
items.append(ActionSheetButtonItem(title: presentationData.strings.Appearance_RemoveThemeConfirmation, color: .destructive, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
let _ = (cloudThemes.get() |> delay(0.5, queue: Queue.mainQueue())
|> take(1)
|> deliverOnMainQueue).start(next: { themes in
if isCurrent, let themeIndex = themes.firstIndex(where: { $0.id == theme.theme.id }) {
let newTheme: PresentationThemeReference
if themeIndex > 0 {
newTheme = .cloud(PresentationCloudTheme(theme: themes[themeIndex - 1], resolvedWallpaper: nil))
} else {
newTheme = .builtin(.nightAccent)
}
selectThemeImpl?(newTheme)
}
let _ = deleteThemeInteractively(account: context.account, theme: theme.theme).start()
})
}))
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
})
])])
presentControllerImpl?(actionSheet, nil)
}))
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
@ -510,6 +526,13 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
})
])])
presentControllerImpl?(actionSheet, nil)
}, editTheme: { theme in
let controller = editThemeController(context: context, mode: .edit(theme), navigateToChat: { peerId in
if let navigationController = getNavigationControllerImpl?() {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
}
})
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
})
let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings]), cloudThemes.get(), availableAppIcons, currentAppIconName.get(), statePromise.get())

View File

@ -41,6 +41,31 @@ private func generateBorderImage(theme: PresentationTheme, bordered: Bool, selec
})?.stretchableImage(withLeftCapWidth: 15, topCapHeight: 15)
}
private func createThemeImage(theme: PresentationTheme) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return .single(theme)
|> map { theme -> (TransformImageArguments) -> DrawingContext? in
return { arguments in
let context = DrawingContext(size: arguments.drawingSize, scale: arguments.scale ?? 0.0, clear: arguments.emptyColor == nil)
let drawingRect = arguments.drawingRect
context.withContext { c in
c.setFillColor(theme.list.itemBlocksBackgroundColor.cgColor)
c.fill(drawingRect)
c.translateBy(x: drawingRect.width / 2.0, y: drawingRect.height / 2.0)
c.scaleBy(x: 1.0, y: -1.0)
c.translateBy(x: -drawingRect.width / 2.0, y: -drawingRect.height / 2.0)
if let icon = generateTintedImage(image: UIImage(bundleImageName: "Settings/CreateThemeIcon"), color: theme.list.itemAccentColor) {
c.draw(icon.cgImage!, in: CGRect(origin: CGPoint(x: floor((drawingRect.width - icon.size.width) / 2.0) - 3.0, y: floor((drawingRect.height - icon.size.height) / 2.0)), size: icon.size))
}
}
return context
}
}
}
private func themeIconImage(context: AccountContext, theme: PresentationThemeReference, accentColor: UIColor?) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal: Signal<(UIColor, UIColor, UIColor), NoError>
if case let .builtin(theme) = theme {
@ -202,7 +227,11 @@ private final class ThemeSettingsThemeItemIconNode : ASDisplayNode {
}
func setup(context: AccountContext, theme: PresentationThemeReference, accentColor: UIColor?, currentTheme: PresentationTheme, title: NSAttributedString, bordered: Bool, selected: Bool, action: @escaping () -> Void, longTapAction: @escaping () -> Void) {
self.imageNode.setSignal(themeIconImage(context: context, theme: theme, accentColor: accentColor))
if case let .cloud(theme) = theme, theme.theme.file == nil {
self.imageNode.setSignal(createThemeImage(theme: currentTheme))
} else {
self.imageNode.setSignal(themeIconImage(context: context, theme: theme, accentColor: accentColor))
}
self.textNode.attributedText = title
self.overlayNode.image = generateBorderImage(theme: currentTheme, bordered: bordered, selected: selected)
self.action = {
@ -395,7 +424,7 @@ class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode {
self?.scrollToNode(imageNode, animated: true)
}
}, longTapAction: {
item.longTapped(theme)
item.longTapped(theme)
})
imageNode.frame = CGRect(origin: CGPoint(x: nodeOffset, y: 0.0), size: nodeSize)

View File

@ -2939,8 +2939,8 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
}
if !updatedThemes.isEmpty {
let items = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudThemes)
let themes = items.map { entry -> TelegramTheme in
let entries = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudThemes)
let themes = entries.map { entry -> TelegramTheme in
let theme = entry.contents as! TelegramTheme
if let updatedTheme = updatedThemes[theme.id] {
return updatedTheme
@ -2948,13 +2948,13 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
return theme
}
}
var entries: [OrderedItemListEntry] = []
var updatedEntries: [OrderedItemListEntry] = []
for theme in themes {
var intValue = Int32(entries.count)
var intValue = Int32(updatedEntries.count)
let id = MemoryBuffer(data: Data(bytes: &intValue, count: 4))
entries.append(OrderedItemListEntry(id: id, contents: theme))
updatedEntries.append(OrderedItemListEntry(id: id, contents: theme))
}
transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudThemes, items: entries)
transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudThemes, items: updatedEntries)
}
addedIncomingMessageIds.append(contentsOf: addedSecretMessageIds)

View File

@ -62,7 +62,16 @@ public func telegramThemes(postbox: Postbox, network: Network, forceUpdate: Bool
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedThemesConfiguration, key: ValueBoxKey(length: 0)), entry: CachedThemesConfiguration(hash: hash), collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1))
return items
}
}
} |> then(
postbox.combinedView(keys: [PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudThemes)])
|> map { view -> [TelegramTheme] in
if let view = view.views[.orderedItemList(id: Namespaces.OrderedItemList.CloudThemes)] as? OrderedItemListView {
return view.items.compactMap { $0.contents as? TelegramTheme }
} else {
return []
}
}
)
}
if forceUpdate {
@ -122,22 +131,35 @@ public func checkThemeUpdated(account: Account, theme: TelegramTheme) -> Signal<
}
}
public func saveTheme(account: Account, theme: TelegramTheme) -> Signal<Void, NoError> {
return saveUnsaveTheme(account: account, theme: theme, unsave: false)
}
public func deleteTheme(account: Account, theme: TelegramTheme) -> Signal<Void, NoError> {
return saveUnsaveTheme(account: account, theme: theme, unsave: true)
}
private func saveUnsaveTheme(account: Account, theme: TelegramTheme, unsave: Bool) -> Signal<Void, NoError> {
return account.network.request(Api.functions.account.saveTheme(theme: Api.InputTheme.inputTheme(id: theme.id, accessHash: theme.accessHash), unsave: unsave ? Api.Bool.boolTrue : Api.Bool.boolFalse))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .complete()
}
|> mapToSignal { _ -> Signal<Void, NoError> in
return .single(Void())
}
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
let entries = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudThemes)
var items = entries.map { $0.contents as! TelegramTheme }
if unsave {
items = items.filter { $0.id != theme.id }
} else {
items.insert(theme, at: 0)
}
var updatedEntries: [OrderedItemListEntry] = []
for item in items {
var intValue = Int32(updatedEntries.count)
let id = MemoryBuffer(data: Data(bytes: &intValue, count: 4))
updatedEntries.append(OrderedItemListEntry(id: id, contents: item))
}
transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudThemes, items: updatedEntries)
return account.network.request(Api.functions.account.saveTheme(theme: Api.InputTheme.inputTheme(id: theme.id, accessHash: theme.accessHash), unsave: unsave ? Api.Bool.boolTrue : Api.Bool.boolFalse))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .complete()
}
|> mapToSignal { _ -> Signal<Void, NoError> in
return telegramThemes(postbox: account.postbox, network: account.network, forceUpdate: true)
|> take(1)
|> mapToSignal { _ -> Signal<Void, NoError> in
return .complete()
}
}
} |> switchToLatest
}
private func installTheme(account: Account, theme: TelegramTheme) -> Signal<Never, NoError> {
@ -234,7 +256,16 @@ public func createTheme(account: Account, resource: MediaResource, title: String
|> mapToSignal { apiTheme -> Signal<CreateThemeResult, CreateThemeError> in
if let theme = TelegramTheme(apiTheme: apiTheme) {
return account.postbox.transaction { transaction -> CreateThemeResult in
let entries = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudThemes)
var items = entries.map { $0.contents as! TelegramTheme }
items.insert(theme, at: 0)
var updatedEntries: [OrderedItemListEntry] = []
for item in items {
var intValue = Int32(updatedEntries.count)
let id = MemoryBuffer(data: Data(bytes: &intValue, count: 4))
updatedEntries.append(OrderedItemListEntry(id: id, contents: item))
}
transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudThemes, items: updatedEntries)
return .result(theme)
}
|> introduceError(CreateThemeError.self)
@ -295,8 +326,27 @@ 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 }
|> mapToSignal { apiTheme -> Signal<CreateThemeResult, CreateThemeError> in
if let theme = TelegramTheme(apiTheme: apiTheme) {
return .single(.result(theme))
if let result = TelegramTheme(apiTheme: apiTheme) {
return account.postbox.transaction { transaction -> CreateThemeResult in
let entries = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudThemes)
let items = entries.map { entry -> TelegramTheme in
let theme = entry.contents as! TelegramTheme
if theme.id == result.id {
return result
} else {
return theme
}
}
var updatedEntries: [OrderedItemListEntry] = []
for item in items {
var intValue = Int32(updatedEntries.count)
let id = MemoryBuffer(data: Data(bytes: &intValue, count: 4))
updatedEntries.append(OrderedItemListEntry(id: id, contents: item))
}
transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudThemes, items: updatedEntries)
return .result(result)
}
|> introduceError(CreateThemeError.self)
} else {
return .fail(.generic)
}
@ -336,6 +386,14 @@ public final class ThemeSettings: PreferencesEntry, Equatable {
}
}
public func saveThemeInteractively(account: Account, theme: TelegramTheme) -> Signal<Void, NoError> {
return saveUnsaveTheme(account: account, theme: theme, unsave: false)
}
public func deleteThemeInteractively(account: Account, theme: TelegramTheme) -> Signal<Void, NoError> {
return saveUnsaveTheme(account: account, theme: theme, unsave: true)
}
public func applyTheme(accountManager: AccountManager, account: Account, theme: TelegramTheme?) -> Signal<Never, NoError> {
return accountManager.transaction { transaction -> Signal<Never, NoError> in
transaction.updateSharedData(SharedDataKeys.themeSettings, { _ in

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "ic_iphonetheme.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -165,7 +165,7 @@ final class ChatMediaInputGifPane: ChatMediaInputPane, UIScrollViewDelegate {
}))
multiplexedNode.fileSelected = { [weak self] fileReference, sourceNode, sourceRect in
self?.controllerInteraction.sendGif(fileReference, sourceNode, sourceRect)
let _ = self?.controllerInteraction.sendGif(fileReference, sourceNode, sourceRect)
}
multiplexedNode.didScroll = { [weak self] offset, height in

View File

@ -382,7 +382,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
var needShareButton = false
if isFailed {
if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) {
needShareButton = false
} else if item.message.id.peerId == item.context.account.peerId {
for attribute in item.content.firstMessage.attributes {

View File

@ -699,7 +699,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
var needShareButton = false
if isFailed {
if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) {
needShareButton = false
} else if item.message.id.peerId == item.context.account.peerId {
if let _ = sourceReference {

View File

@ -144,8 +144,13 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
avatarInset = 0.0
}
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
var needShareButton = false
if item.message.id.peerId == item.context.account.peerId {
if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) {
needShareButton = false
}
else if item.message.id.peerId == item.context.account.peerId {
for attribute in item.content.firstMessage.attributes {
if let _ = attribute as? SourceReferenceMessageAttribute {
needShareButton = true
@ -189,7 +194,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
}
var deliveryFailedInset: CGFloat = 0.0
if item.content.firstMessage.flags.contains(.Failed) {
if isFailed {
deliveryFailedInset += 24.0
}
@ -474,7 +479,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
strongSelf.replyInfoNode = nil
}
if item.content.firstMessage.flags.contains(.Failed) {
if isFailed {
let deliveryFailedNode: ChatMessageDeliveryFailedNode
var isAppearing = false
if let current = strongSelf.deliveryFailedNode {

View File

@ -184,7 +184,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
var needShareButton = false
if isFailed {
if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) {
needShareButton = false
} else if item.message.id.peerId == item.context.account.peerId {
for attribute in item.content.firstMessage.attributes {

View File

@ -53,11 +53,13 @@ public struct ApplicationSpecificSharedDataKeys {
private enum ApplicationSpecificItemCacheCollectionIdValues: Int8 {
case instantPageStoredState = 0
case cachedInstantPages = 1
case resolvedWallpapers = 2
}
public struct ApplicationSpecificItemCacheCollectionId {
public static let instantPageStoredState = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.instantPageStoredState.rawValue)
public static let cachedInstantPages = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.cachedInstantPages.rawValue)
public static let resolvedWallpapers = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.resolvedWallpapers.rawValue)
}
private enum ApplicationSpecificOrderedItemListCollectionIdValues: Int32 {

View File

@ -634,7 +634,6 @@ private func generateBackArrowImage(color: UIColor) -> UIImage? {
}
public func themeImage(account: Account, accountManager: AccountManager, fileReference: FileMediaReference, synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return telegramThemeData(account: account, accountManager: accountManager, resource: fileReference.media.resource, synchronousLoad: synchronousLoad)
|> map { data in
let theme: PresentationTheme?
@ -649,12 +648,20 @@ public func themeImage(account: Account, accountManager: AccountManager, fileRef
context.withFlippedContext { c in
c.setBlendMode(.normal)
if let theme = theme {
if case let .color(value) = theme.chat.defaultWallpaper {
c.setFillColor(UIColor(rgb: UInt32(bitPattern: value)).cgColor)
} else {
c.setFillColor(theme.chatList.backgroundColor.cgColor)
switch theme.chat.defaultWallpaper {
case .builtin:
if let filePath = frameworkBundle.path(forResource: "ChatWallpaperBuiltin0", ofType: "jpg"), let image = UIImage(contentsOfFile: filePath), let cgImage = image.cgImage {
c.draw(cgImage, in: CGRect(x: 0.0, y: 0.0, width: drawingRect.width, height: drawingRect.height))
}
case let .color(value):
c.setFillColor(UIColor(rgb: UInt32(bitPattern: value)).cgColor)
c.fill(drawingRect)
case let .file(file):
c.setFillColor(theme.chatList.backgroundColor.cgColor)
c.fill(drawingRect)
default:
break
}
c.fill(drawingRect)
c.setFillColor(theme.rootController.navigationBar.backgroundColor.cgColor)
c.fill(CGRect(origin: CGPoint(x: 0.0, y: drawingRect.height - 42.0), size: CGSize(width: drawingRect.width, height: 42.0)))