Cloud themes improvements

This commit is contained in:
Ilya Laktyushin 2019-09-03 11:51:28 +03:00
parent 167b9289d3
commit ec6526b07d
22 changed files with 633 additions and 177 deletions

View file

@ -825,7 +825,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
super.updateRevealOffset(offset: offset, transition: transition)
if let item = self.item, let params = self.layoutParams?.1 {
var leftInset: CGFloat = 65.0
var leftInset: CGFloat = 65.0 + params.leftInset
switch item.selection {
case .none:

View file

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
091EABA5231DAC7500A0EC14 /* ThemeNameGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091EABA4231DAC7500A0EC14 /* ThemeNameGenerator.swift */; };
09B4A9B823102B7A005C2E08 /* EditThemeController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09B4A9B723102B7A005C2E08 /* EditThemeController.swift */; };
D03E465223075D930049C28B /* SettingsUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E465023075D930049C28B /* SettingsUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
D03E466823075E660049C28B /* TabBarAccountSwitchControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E465C23075E630049C28B /* TabBarAccountSwitchControllerNode.swift */; };
@ -191,6 +192,7 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
091EABA4231DAC7500A0EC14 /* ThemeNameGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeNameGenerator.swift; sourceTree = "<group>"; };
09B4A9B723102B7A005C2E08 /* EditThemeController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditThemeController.swift; sourceTree = "<group>"; };
D03E464D23075D930049C28B /* SettingsUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SettingsUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D03E465023075D930049C28B /* SettingsUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SettingsUI.h; sourceTree = "<group>"; };
@ -650,6 +652,7 @@
D03E46EB23075FD60049C28B /* WallpaperPatternPanelNode.swift */,
D03E46EE23075FD60049C28B /* WallpaperSearchRecentQueries.swift */,
09B4A9B723102B7A005C2E08 /* EditThemeController.swift */,
091EABA4231DAC7500A0EC14 /* ThemeNameGenerator.swift */,
);
path = Themes;
sourceTree = "<group>";
@ -915,6 +918,7 @@
D03E471523075FE40049C28B /* ThemeSettingsFontSizeItem.swift in Sources */,
D03E46AA23075F2C0049C28B /* DataPrivacySettingsController.swift in Sources */,
D03E467123075E660049C28B /* SettingsController.swift in Sources */,
091EABA5231DAC7500A0EC14 /* ThemeNameGenerator.swift in Sources */,
D03E46A923075F2C0049C28B /* BlockedPeersController.swift in Sources */,
D03E469F23075F2C0049C28B /* TwoStepVerificationResetController.swift in Sources */,
D03E472A230760330049C28B /* LocalizationListItem.swift in Sources */,

View file

@ -247,12 +247,12 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
switch mode {
case .create:
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
initialState = EditThemeControllerState(mode: mode, title: "", slug: "", updatedTheme: nil, updating: false)
initialState = EditThemeControllerState(mode: mode, title: generateThemeName(accentColor: presentationData.theme.rootController.navigationBar.buttonColor), slug: "", updatedTheme: nil, updating: false)
previewThemePromise.set(.single(presentationData.theme.withUpdated(name: "", defaultWallpaper: presentationData.chatWallpaper)))
case let .edit(info):
if let file = info.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: info.resolvedWallpaper) {
if case let .file(file) = theme.chat.defaultWallpaper, file.id == 0 {
previewThemePromise.set(cachedWallpaper(account: context.account, slug: file.slug)
previewThemePromise.set(cachedWallpaper(account: context.account, slug: file.slug, settings: file.settings)
|> map ({ wallpaper -> PresentationTheme in
if let wallpaper = wallpaper {
return theme.withUpdated(name: nil, defaultWallpaper: wallpaper.wallpaper)
@ -287,7 +287,7 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
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)
let _ = (cachedWallpaper(account: context.account, slug: file.slug, settings: file.settings)
|> mapToSignal { wallpaper -> Signal<TelegramWallpaper?, NoError> in
if let wallpaper = wallpaper, case let .file(file) = wallpaper.wallpaper {
var convertedRepresentations: [ImageRepresentationWithReference] = []
@ -447,7 +447,7 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
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, install: true).start()
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

View file

@ -0,0 +1,352 @@
import UIKit
private let colors: [UInt32: String] = [
0x8e0000: "Berry",
0xdec196: "Brandy",
0x800b47: "Cherry",
0xff7f50: "Coral",
0xdb5079: "Cranberry",
0xdc143c: "Crimson",
0xe0b0ff: "Mauve",
0xffc0cb: "Pink",
0xff0000: "Red",
0xff007f: "Rose",
0x80461b: "Russet",
0xff2400: "Scarlet",
0xf1f1f1: "Seashell",
0xff3399: "Strawberry",
0xffbf00: "Amber",
0xeb9373: "Apricot",
0xfbe7b2: "Banana",
0xa1c50a: "Citrus",
0xb06500: "Ginger",
0xffd700: "Gold",
0xfde910: "Lemon",
0xffa500: "Orange",
0xffe5b4: "Peach",
0xff6b53: "Persimmon",
0xe4d422: "Sunflower",
0xf28500: "Tangerine",
0xffc87c: "Topaz",
0xffff00: "Yellow",
0x384910: "Clover",
0x83aa5d: "Cucumber",
0x50c878: "Emerald",
0xb5b35c: "Olive",
0x00ff00: "Green",
0x00a86b: "Jade",
0x29ab87: "Jungle",
0xbfff00: "Lime",
0x0bda51: "Malachite",
0x98ff98: "Mint",
0xaddfad: "Moss",
0x315ba1: "Azure",
0x0000ff: "Blue",
0x0047ab: "Cobalt",
0x4f69c6: "Indigo",
0x017987: "Lagoon",
0x71d9e2: "Aquamarine",
0x120a8f: "Ultramarine",
0x000080: "Navy",
0x2f519e: "Sapphire",
0x76d7ea: "Sky",
0x008080: "Teal",
0x40e0d0: "Turquoise",
0x9966cc: "Amethyst",
0x4d0135: "Blackberry",
0x614051: "Eggplant",
0xc8a2c8: "Lilac",
0xb57edc: "Lavender",
0xccccff: "Periwinkle",
0x843179: "Plum",
0x660099: "Purple",
0xd8bfd8: "Thistle",
0xda70d6: "Orchid",
0x240a40: "Violet",
0x3f2109: "Bronze",
0x370202: "Chocolate",
0x7b3f00: "Cinnamon",
0x301f1e: "Cocoa",
0x706555: "Coffee",
0x796989: "Rum",
0x4e0606: "Mahogany",
0x782d19: "Mocha",
0xc2b280: "Sand",
0x882d17: "Sienna",
0x780109: "Maple",
0xf0e68c: "Khaki",
0xb87333: "Copper",
0xb94e48: "Chestnut",
0xeed9c4: "Almond",
0xfffdd0: "Cream",
0xb9f2ff: "Diamond",
0xa98307: "Honey",
0xfffff0: "Ivory",
0xeae0c8: "Pearl",
0xeff2f3: "Porcelain",
0xd1bea8: "Vanilla",
0xffffff: "White",
0x808080: "Gray",
0x000000: "Black",
0xe8f1d4: "Chrome",
0x36454f: "Charcoal",
0x0c0b1d: "Ebony",
0xc0c0c0: "Silver",
0xf5f5f5: "Smoke",
0x262335: "Steel",
0x4fa83d: "Apple",
0x80b3c4: "Glacier",
0xfebaad: "Melon",
0xc54b8c: "Mulberry",
0xa9c6c2: "Opal"
]
private let adjectives = [
"Always",
"Ancient",
"Antique",
"Autumn",
"Baby",
"Barely",
"Baroque",
"Blazing",
"Blushing",
"Bohemian",
"Bubbly",
"Burning",
"Buttered",
"Classic",
"Clear",
"Cool",
"Cosmic",
"Cotton",
"Cozy",
"Crystal",
"Dark",
"Daring",
"Darling",
"Dawn",
"Dazzling",
"Deep",
"Deepest",
"Delicate",
"Delightful",
"Divine",
"Double",
"Downtown",
"Dreamy",
"Dusky",
"Dusty",
"Electric",
"Enchanted",
"Endless",
"Evening",
"Fantastic",
"Flirty",
"Forever",
"Frigid",
"Frosty",
"Frozen",
"Gentle",
"Golden",
"Heavenly",
"Hyper",
"Icy",
"Infinite",
"Innocent",
"Instant",
"Luscious",
"Lunar",
"Lustrous",
"Magic",
"Majestic",
"Mambo",
"Midnight",
"Millenium",
"Morning",
"Mystic",
"Natural",
"Neon",
"Night",
"Opaque",
"Paradise",
"Perfect",
"Perky",
"Polished",
"Powerful",
"Rich",
"Royal",
"Sheer",
"Simply",
"Sizzling",
"Solar",
"Sparkling",
"Splendid",
"Spicy",
"Spring",
"Stellar",
"Sugared",
"Summer",
"Sunny",
"Super",
"Sweet",
"Tender",
"Tenacious",
"Tidal",
"Toasted",
"Totally",
"Tranquil",
"Tropical",
"True",
"Twilight",
"Twinkling",
"Ultimate",
"Ultra",
"Uptown",
"Velvety",
"Vibrant",
"Vintage",
"Virtual",
"Warm",
"Warmest",
"Whipped",
"Wild",
"Winsome"
]
private let subjectives = [
"Ambrosia",
"Attack",
"Avalanche",
"Blast",
"Bliss",
"Blossom",
"Blush",
"Burst",
"Butter",
"Candy",
"Carnival",
"Charm",
"Chiffon",
"Cloud",
"Comet",
"Delight",
"Dream",
"Dust",
"Fantasy",
"Flame",
"Flash",
"Fire",
"Freeze",
"Frost",
"Glade",
"Glaze",
"Gleam",
"Glimmer",
"Glitter",
"Glow",
"Grande",
"Haze",
"Highlight",
"Ice",
"Illusion",
"Intrigue",
"Jewel",
"Jubilee",
"Kiss",
"Lights",
"Lollypop",
"Love",
"Luster",
"Madness",
"Matte",
"Mirage",
"Mist",
"Moon",
"Muse",
"Myth",
"Nectar",
"Nova",
"Parfait",
"Passion",
"Pop",
"Rain",
"Reflection",
"Rhapsody",
"Romance",
"Satin",
"Sensation",
"Silk",
"Shine",
"Shadow",
"Shimmer",
"Sky",
"Spice",
"Star",
"Sugar",
"Sunrise",
"Sunset",
"Sun",
"Twist",
"Unbound",
"Velvet",
"Vibrant",
"Waters",
"Wine",
"Wink",
"Wonder",
"Zone"
]
private extension UIColor {
var colorComponents: (r: Int32, g: Int32, b: Int32) {
var r: CGFloat = 0.0
var g: CGFloat = 0.0
var b: CGFloat = 0.0
if self.getRed(&r, green: &g, blue: &b, alpha: nil) {
return (Int32(max(0.0, r) * 255.0), Int32(max(0.0, g) * 255.0), Int32(max(0.0, b) * 255.0))
} else if self.getWhite(&r, alpha: nil) {
return (Int32(max(0.0, r) * 255.0), Int32(max(0.0, r) * 255.0), Int32(max(0.0, r) * 255.0))
}
return (0, 0, 0)
}
func distance(to other: UIColor) -> Int32 {
let e1 = self.colorComponents
let e2 = other.colorComponents
let rMean = (e1.r + e2.r) / 2
let r = e1.r - e2.r
let g = e1.g - e2.g
let b = e1.b - e2.b
return ((512 + rMean) * r * r) >> 8 + 4 * g * g + ((767 - rMean) * b * b) >> 8
}
}
func generateThemeName(accentColor: UIColor) -> String {
var nearest: (color: UInt32, distance: Int32)?
for (color, _) in colors {
let distance = accentColor.distance(to: UIColor(rgb: color))
if let currentNearest = nearest {
if distance < currentNearest.distance {
nearest = (color, distance)
}
} else {
nearest = (color, distance)
}
}
if let color = nearest?.color, let colorName = colors[color]?.capitalized {
if arc4random() % 2 == 0 {
return "\(adjectives[Int(arc4random()) % adjectives.count].capitalized) \(colorName)"
} else {
if false, arc4random() % 3 == 0 {
return "\(adjectives[Int(arc4random()) % adjectives.count].capitalized) \(colorName) \(subjectives[Int(arc4random()) % subjectives.count].capitalized)"
} else {
return "\(colorName) \(subjectives[Int(arc4random()) % subjectives.count].capitalized)"
}
}
} else {
return ""
}
}

View file

@ -127,7 +127,7 @@ public final class ThemePreviewController: ViewController {
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)
self.controllerNode.wallpaperPromise.set(cachedWallpaper(account: self.context.account, slug: file.slug, settings: file.settings)
|> mapToSignal { wallpaper in
return .single(wallpaper?.wallpaper ?? .color(Int32(bitPattern: previewTheme.chatList.backgroundColor.rgb)))
})
@ -252,7 +252,7 @@ public final class ThemePreviewController: ViewController {
}
|> mapToSignal { theme -> Signal<Void, NoError> in
if case let .cloud(info) = theme {
let _ = applyTheme(accountManager: context.sharedContext.accountManager, account: context.account, theme: info.theme, install: true).start()
let _ = applyTheme(accountManager: context.sharedContext.accountManager, account: context.account, theme: info.theme).start()
let _ = saveThemeInteractively(account: context.account, accountManager: context.sharedContext.accountManager, theme: info.theme).start()
}
return context.sharedContext.accountManager.transaction { transaction -> Void in
@ -278,7 +278,7 @@ public final class ThemePreviewController: ViewController {
}
}
|> runOn(Queue.mainQueue())
|> delay(0.7, queue: Queue.mainQueue())
|> delay(0.35, queue: Queue.mainQueue())
let progressDisposable = progressSignal.start()
cancelImpl = {

View file

@ -10,6 +10,7 @@ import TelegramUIPreferences
import AccountContext
import ChatListUI
import WallpaperResources
import LegacyComponents
private func generateMaskImage(color: UIColor) -> UIImage? {
return generateImage(CGSize(width: 1.0, height: 80.0), opaque: false, rotatedContext: { size, context in
@ -46,6 +47,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
private let chatContainerNode: ASDisplayNode
private let instantChatBackgroundNode: WallpaperBackgroundNode
private let remoteChatBackgroundNode: TransformImageNode
private let blurredNode: BlurredImageNode
private var messageNodes: [ListViewItemNode]?
private let toolbarNode: WallpaperGalleryToolbarNode
@ -89,6 +91,9 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.remoteChatBackgroundNode = TransformImageNode()
self.remoteChatBackgroundNode.backgroundColor = previewTheme.chatList.backgroundColor
self.blurredNode = BlurredImageNode()
self.blurredNode.clipsToBounds = true
self.toolbarNode = WallpaperGalleryToolbarNode(theme: self.previewTheme, strings: self.presentationData.strings)
if case let .file(file) = previewTheme.chat.defaultWallpaper, file.id == 0 {
@ -140,6 +145,26 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
apply()
}
if case let .file(file) = self.previewTheme.chat.defaultWallpaper {
if file.settings.blur {
self.chatContainerNode.addSubnode(self.blurredNode)
}
}
self.remoteChatBackgroundNode.imageUpdated = { [weak self] image in
if let strongSelf = self, strongSelf.blurredNode.supernode != nil {
var image = image
if let imageToScale = image {
let actualSize = CGSize(width: imageToScale.size.width * imageToScale.scale, height: imageToScale.size.height * imageToScale.scale)
if actualSize.width > 1280.0 || actualSize.height > 1280.0 {
image = TGScaleImageToPixelSize(image, actualSize.fitted(CGSize(width: 1280.0, height: 1280.0)))
}
}
strongSelf.blurredNode.image = image
strongSelf.blurredNode.blurView.blurRadius = 45.0
}
}
self.colorDisposable = (self.wallpaperPromise.get()
|> mapToSignal { wallpaper -> Signal<UIColor, NoError> in
if case let .file(file) = wallpaper, file.id == 0 {
@ -173,12 +198,17 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.file.resource), reference: .media(media: .standalone(media: file.file), resource: file.file.resource)))
let signal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>
let fileReference = FileMediaReference.standalone(media: file.file)
let signal = wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: fileReference, representations: convertedRepresentations, alwaysShowThumbnailFirst: false, autoFetchFullSize: false)
|> afterNext { next in
if let _ = context.sharedContext.accountManager.mediaBox.completedResourcePath(file.file.resource) {
} else if let path = context.account.postbox.mediaBox.completedResourcePath(file.file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path)) {
context.sharedContext.accountManager.mediaBox.storeResourceData(file.file.resource.id, data: data)
if file.isPattern {
signal = patternWallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, representations: convertedRepresentations, mode: .screen, autoFetchFullSize: false)
} else {
signal = wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: fileReference, representations: convertedRepresentations, alwaysShowThumbnailFirst: false, autoFetchFullSize: false)
|> afterNext { next in
if let _ = context.sharedContext.accountManager.mediaBox.completedResourcePath(file.file.resource) {
} else if let path = context.account.postbox.mediaBox.completedResourcePath(file.file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path)) {
context.sharedContext.accountManager.mediaBox.storeResourceData(file.file.resource.id, data: data)
}
}
}
strongSelf.remoteChatBackgroundNode.setSignal(signal)
@ -203,7 +233,16 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
})
strongSelf.remoteChatBackgroundNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets(), emptyColor: nil))()
var patternColor: UIColor?
var patternIntensity: CGFloat = 0.5
if let color = file.settings.color {
if let intensity = file.settings.intensity {
patternIntensity = CGFloat(intensity) / 100.0
}
patternColor = UIColor(rgb: UInt32(bitPattern: color), alpha: patternIntensity)
}
strongSelf.remoteChatBackgroundNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets(), emptyColor: patternColor))()
}
})
}
@ -402,6 +441,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
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.blurredNode.frame = self.chatContainerNode.bounds
self.scrollNode.view.contentSize = CGSize(width: bounds.width * 2.0, height: bounds.height)

View file

@ -570,7 +570,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
let resolvedWallpaper: Signal<TelegramWallpaper?, NoError>
if case let .file(file) = presentationTheme.chat.defaultWallpaper, file.id == 0 {
resolvedWallpaper = cachedWallpaper(account: context.account, slug: file.slug)
resolvedWallpaper = cachedWallpaper(account: context.account, slug: file.slug, settings: file.settings)
|> map { wallpaper -> TelegramWallpaper? in
return wallpaper?.wallpaper
}

View file

@ -18,13 +18,13 @@ private func generateBorderImage(theme: PresentationTheme, bordered: Bool, selec
if let image = borderImages[key] {
return image
} else {
let image = generateImage(CGSize(width: 30.0, height: 30.0), rotatedContext: { size, context in
let image = generateImage(CGSize(width: 32.0, height: 32.0), rotatedContext: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.setFillColor(theme.list.itemBlocksBackgroundColor.cgColor)
context.fill(bounds)
context.setBlendMode(.clear)
context.fillEllipse(in: bounds)
context.fillEllipse(in: bounds.insetBy(dx: 1.0, dy: 1.0))
context.setBlendMode(.normal)
let lineWidth: CGFloat
@ -42,9 +42,9 @@ private func generateBorderImage(theme: PresentationTheme, bordered: Bool, selec
if bordered || selected {
context.setLineWidth(lineWidth)
context.strokeEllipse(in: bounds.insetBy(dx: lineWidth / 2.0, dy: lineWidth / 2.0))
context.strokeEllipse(in: bounds.insetBy(dx: 1.0 + lineWidth / 2.0, dy: 1.0 + lineWidth / 2.0))
}
})?.stretchableImage(withLeftCapWidth: 15, topCapHeight: 15)
})?.stretchableImage(withLeftCapWidth: 16, topCapHeight: 16)
borderImages[key] = image
return image
}
@ -54,7 +54,7 @@ private func createThemeImage(theme: PresentationTheme) -> Signal<(TransformImag
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 context = DrawingContext(size: arguments.drawingSize, scale: arguments.scale ?? 0.0, clear: false)
let drawingRect = arguments.drawingRect
context.withContext { c in
@ -155,7 +155,7 @@ private final class ThemeSettingsThemeItemIconNode : ASDisplayNode {
self.imageNode.isLayerBacked = true
self.overlayNode = ASImageNode()
self.overlayNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 98.0, height: 62.0))
self.overlayNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 100.0, height: 64.0))
self.overlayNode.isLayerBacked = true
self.textNode = ASTextNode()
@ -170,8 +170,9 @@ 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) {
let updatedTheme = self.currentTheme == nil || currentTheme !== self.currentTheme!
if case let .cloud(theme) = theme, theme.theme.file == nil {
if self.currentTheme == nil || currentTheme !== self.currentTheme! || accentColor != self.accentColor {
if updatedTheme || accentColor != self.accentColor {
self.imageNode.setSignal(createThemeImage(theme: currentTheme))
self.currentTheme = currentTheme
self.accentColor = accentColor
@ -183,7 +184,7 @@ private final class ThemeSettingsThemeItemIconNode : ASDisplayNode {
self.accentColor = accentColor
}
}
if self.currentTheme == nil || currentTheme !== self.currentTheme! || bordered != self.bordered || selected != self.selected {
if updatedTheme || bordered != self.bordered || selected != self.selected {
self.overlayNode.image = generateBorderImage(theme: currentTheme, bordered: bordered, selected: selected)
self.currentTheme = currentTheme
self.bordered = bordered
@ -238,7 +239,7 @@ private final class ThemeSettingsThemeItemIconNode : ASDisplayNode {
let applyLayout = makeLayout(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: .clear))
applyLayout()
self.overlayNode.frame = CGRect(origin: CGPoint(x: 10.0, y: 14.0), size: CGSize(width: 98.0, height: 62.0))
self.overlayNode.frame = CGRect(origin: CGPoint(x: 9.0, y: 13.0), size: CGSize(width: 100.0, height: 64.0))
self.textNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 14.0 + 60.0 + 4.0 + 9.0), size: CGSize(width: bounds.size.width, height: 16.0))
}
}
@ -295,8 +296,6 @@ class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode {
}
func asyncLayout() -> (_ item: ThemeSettingsThemeItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
let currentItem = self.item
return { item, params, neighbors in
let contentSize: CGSize
let insets: UIEdgeInsets

View file

@ -5717,12 +5717,13 @@ public extension Api {
})
}
public static func installTheme(format: String, theme: Api.InputTheme) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
public static func installTheme(flags: Int32, format: String?, theme: Api.InputTheme?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(-520600676)
serializeString(format, buffer: buffer, boxed: false)
theme.serialize(buffer, true)
return (FunctionDescription(name: "account.installTheme", parameters: [("format", format), ("theme", theme)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
buffer.appendInt32(2061776695)
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {serializeString(format!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {theme!.serialize(buffer, true)}
return (FunctionDescription(name: "account.installTheme", parameters: [("flags", flags), ("format", format), ("theme", theme)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {

View file

@ -178,8 +178,21 @@ private func saveUnsaveTheme(account: Account, accountManager: AccountManager, t
} |> switchToLatest
}
private func installTheme(account: Account, theme: TelegramTheme) -> Signal<Never, NoError> {
return account.network.request(Api.functions.account.installTheme(format: themeFormat, theme: Api.InputTheme.inputTheme(id: theme.id, accessHash: theme.accessHash)))
private func installTheme(account: Account, theme: TelegramTheme?, autoNight: Bool) -> Signal<Never, NoError> {
var flags: Int32 = 0
if autoNight {
flags |= 1 << 0
}
let inputTheme: Api.InputTheme?
if let theme = theme {
inputTheme = .inputTheme(id: theme.id, accessHash: theme.accessHash)
flags |= 1 << 1
} else {
inputTheme = nil
}
return account.network.request(Api.functions.account.installTheme(flags: flags, format: themeFormat, theme: inputTheme))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .complete()
}
@ -461,14 +474,14 @@ public func deleteThemeInteractively(account: Account, accountManager: AccountMa
return saveUnsaveTheme(account: account, accountManager: accountManager, theme: theme, unsave: true)
}
public func applyTheme(accountManager: AccountManager, account: Account, theme: TelegramTheme?, install: Bool = false) -> Signal<Never, NoError> {
public func applyTheme(accountManager: AccountManager, account: Account, theme: TelegramTheme?, autoNight: Bool = false) -> Signal<Never, NoError> {
return accountManager.transaction { transaction -> Signal<Never, NoError> in
transaction.updateSharedData(SharedDataKeys.themeSettings, { _ in
return ThemeSettings(currentTheme: theme)
})
if let theme = theme, install {
return installTheme(account: account, theme: theme)
if let theme = theme {
return installTheme(account: account, theme: theme, autoNight: autoNight)
} else {
return .complete()
}

View file

@ -157,7 +157,7 @@ public enum TelegramWallpaper: OrderedItemListEntryContents, Equatable {
case let .image(representations, _):
return .image(representations, settings)
case let .file(id, accessHash, isCreator, isDefault, isPattern, isDark, slug, file, _):
return .file(id: id, accessHash: accessHash, isCreator: isCreator, isDefault: isDefault, isPattern: isPattern, isDark: isDark, slug: slug, file: file, settings: settings)
return .file(id: id, accessHash: accessHash, isCreator: isCreator, isDefault: isDefault, isPattern: settings.color != nil ? true : isPattern, isDark: isDark, slug: slug, file: file, settings: settings)
}
}
}

View file

@ -123,11 +123,11 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
freeMonoIconColor: mainFreeTextColor,
itemSwitchColors: switchColors,
itemDisclosureActions: PresentationThemeItemDisclosureActions(
neutral1: PresentationThemeFillForeground(fillColor: UIColor(rgb: 0x007cd6), foregroundColor: .white),
neutral1: PresentationThemeFillForeground(fillColor: accentColor, foregroundColor: .white),
neutral2: PresentationThemeFillForeground(fillColor: UIColor(rgb: 0xcd7800), foregroundColor: .white),
destructive: PresentationThemeFillForeground(fillColor: UIColor(rgb: 0xc70c0c), foregroundColor: .white),
constructive: PresentationThemeFillForeground(fillColor: constructiveColor, foregroundColor: .white),
accent: PresentationThemeFillForeground(fillColor: UIColor(rgb: 0x007cd6), foregroundColor: .white),
accent: PresentationThemeFillForeground(fillColor: accentColor, foregroundColor: .white),
warning: PresentationThemeFillForeground(fillColor: UIColor(rgb: 0xcd7800), foregroundColor: .white),
inactive: PresentationThemeFillForeground(fillColor: accentColor.withMultiplied(hue: 1.029, saturation: 0.609, brightness: 0.3), foregroundColor: .white)
),

View file

@ -39,7 +39,7 @@ public struct PresentationAppIcon: Equatable {
public let imageName: String
public let isDefault: Bool
public init(name: String, imageName: String, isDefault: Bool) {
public init(name: String, imageName: String, isDefault: Bool = false) {
self.name = name
self.imageName = imageName
self.isDefault = isDefault

View file

@ -985,10 +985,6 @@ public final class PresentationTheme: Equatable {
switch wallpaper {
case .image:
defaultWallpaper = nil
case let .file(file):
if file.isPattern {
defaultWallpaper = nil
}
default:
break
}

View file

@ -45,10 +45,10 @@ extension TelegramWallpaper: Codable {
if !components.isEmpty {
slug = components[0]
}
if components.count > 1, !["motion", "blur"].contains(components[1]), [6,7].contains(components[1].count), let value = Int32(components[1]) {
color = value
if components.count > 1, !["motion", "blur"].contains(components[1]), components[1].count == 6, let value = UIColor(hexString: components[1]) {
color = Int32(bitPattern: value.rgb)
}
if components.count > 2, !["motion", "blur"].contains(components[2]), [6,7].contains(components[2].count), let value = Int32(components[2]) {
if components.count > 2, !["motion", "blur"].contains(components[2]), let value = Int32(components[2]) {
if value >= 0 && value <= 100 {
intensity = value
} else {
@ -85,18 +85,17 @@ extension TelegramWallpaper: Codable {
components.append(file.slug)
if file.isPattern {
if let color = file.settings.color {
components.removeAll()
components.append(String(format: "%06x", color))
}
// if let intensity = file.settings.intensity {
// components.append("\(intensity)")
// }
// if file.settings.motion {
// components.append("motion")
// }
// if file.settings.blur {
// components.append("blur")
// }
if let intensity = file.settings.intensity {
components.append("\(intensity)")
}
}
if file.settings.motion {
components.append("motion")
}
if file.settings.blur {
components.append("blur")
}
try container.encode(components.joined(separator: " "))
default:

View file

@ -594,12 +594,12 @@ final class SharedApplicationContext {
if #available(iOS 10.3, *) {
var icons = [PresentationAppIcon(name: "Blue", imageName: "BlueIcon", isDefault: buildConfig.isAppStoreBuild),
PresentationAppIcon(name: "Black", imageName: "BlackIcon", isDefault: buildConfig.isInternalBuild),
PresentationAppIcon(name: "BlueClassic", imageName: "BlueClassicIcon", isDefault: false),
PresentationAppIcon(name: "BlackClassic", imageName: "BlackClassicIcon", isDefault: false),
PresentationAppIcon(name: "BlueFilled", imageName: "BlueFilledIcon", isDefault: false),
PresentationAppIcon(name: "BlackFilled", imageName: "BlackFilledIcon", isDefault: false)]
PresentationAppIcon(name: "BlueClassic", imageName: "BlueClassicIcon"),
PresentationAppIcon(name: "BlackClassic", imageName: "BlackClassicIcon"),
PresentationAppIcon(name: "BlueFilled", imageName: "BlueFilledIcon"),
PresentationAppIcon(name: "BlackFilled", imageName: "BlackFilledIcon")]
if buildConfig.isInternalBuild {
icons.append(PresentationAppIcon(name: "WhiteFilled", imageName: "WhiteFilledIcon", isDefault: false))
icons.append(PresentationAppIcon(name: "WhiteFilled", imageName: "WhiteFilledIcon"))
}
return icons
} else {

View file

@ -3973,90 +3973,93 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
switch self.chatLocation {
case let .peer(peerId):
let unreadCountsKey: PostboxViewKey = .unreadCounts(items: [.peer(peerId), .total(nil)])
let notificationSettingsKey: PostboxViewKey = .peerNotificationSettings(peerIds: Set([peerId]))
self.chatUnreadCountDisposable = (self.context.account.postbox.combinedView(keys: [unreadCountsKey, notificationSettingsKey])
|> deliverOnMainQueue).start(next: { [weak self] views in
if let strongSelf = self {
var unreadCount: Int32 = 0
var totalChatCount: Int32 = 0
let inAppSettings = strongSelf.context.sharedContext.currentInAppNotificationSettings.with { $0 }
if let view = views.views[unreadCountsKey] as? UnreadMessageCountsView {
if let count = view.count(for: .peer(peerId)) {
unreadCount = count
}
if let (_, state) = view.total() {
let (count, _) = renderedTotalUnreadCount(inAppSettings: inAppSettings, totalUnreadState: state)
totalChatCount = count
}
}
strongSelf.chatDisplayNode.navigateButtons.unreadCount = unreadCount
if let view = views.views[notificationSettingsKey] as? PeerNotificationSettingsView, let notificationSettings = view.notificationSettings[peerId] {
var globalRemainingUnreadChatCount = totalChatCount
if !notificationSettings.isRemovedFromTotalUnreadCount && unreadCount > 0 {
if case .messages = inAppSettings.totalUnreadCountDisplayCategory {
globalRemainingUnreadChatCount -= unreadCount
} else {
globalRemainingUnreadChatCount -= 1
if let subject = self.subject, case .scheduledMessages = subject {
} else {
let unreadCountsKey: PostboxViewKey = .unreadCounts(items: [.peer(peerId), .total(nil)])
let notificationSettingsKey: PostboxViewKey = .peerNotificationSettings(peerIds: Set([peerId]))
self.chatUnreadCountDisposable = (self.context.account.postbox.combinedView(keys: [unreadCountsKey, notificationSettingsKey])
|> deliverOnMainQueue).start(next: { [weak self] views in
if let strongSelf = self {
var unreadCount: Int32 = 0
var totalChatCount: Int32 = 0
let inAppSettings = strongSelf.context.sharedContext.currentInAppNotificationSettings.with { $0 }
if let view = views.views[unreadCountsKey] as? UnreadMessageCountsView {
if let count = view.count(for: .peer(peerId)) {
unreadCount = count
}
if let (_, state) = view.total() {
let (count, _) = renderedTotalUnreadCount(inAppSettings: inAppSettings, totalUnreadState: state)
totalChatCount = count
}
}
if globalRemainingUnreadChatCount > 0 {
strongSelf.navigationItem.badge = "\(globalRemainingUnreadChatCount)"
} else {
strongSelf.navigationItem.badge = ""
}
}
}
})
self.chatUnreadMentionCountDisposable = (self.context.account.viewTracker.unseenPersonalMessagesCount(peerId: peerId) |> deliverOnMainQueue).start(next: { [weak self] count in
if let strongSelf = self {
strongSelf.chatDisplayNode.navigateButtons.mentionCount = count
}
})
let postbox = self.context.account.postbox
let previousPeerCache = Atomic<[PeerId: Peer]>(value: [:])
self.peerInputActivitiesDisposable = (self.context.account.peerInputActivities(peerId: peerId)
|> mapToSignal { activities -> Signal<[(Peer, PeerInputActivity)], NoError> in
var foundAllPeers = true
var cachedResult: [(Peer, PeerInputActivity)] = []
previousPeerCache.with { dict -> Void in
for (peerId, activity) in activities {
if let peer = dict[peerId] {
cachedResult.append((peer, activity))
} else {
foundAllPeers = false
break
}
}
}
if foundAllPeers {
return .single(cachedResult)
} else {
return postbox.transaction { transaction -> [(Peer, PeerInputActivity)] in
var result: [(Peer, PeerInputActivity)] = []
var peerCache: [PeerId: Peer] = [:]
for (peerId, activity) in activities {
if let peer = transaction.getPeer(peerId) {
result.append((peer, activity))
peerCache[peerId] = peer
strongSelf.chatDisplayNode.navigateButtons.unreadCount = unreadCount
if let view = views.views[notificationSettingsKey] as? PeerNotificationSettingsView, let notificationSettings = view.notificationSettings[peerId] {
var globalRemainingUnreadChatCount = totalChatCount
if !notificationSettings.isRemovedFromTotalUnreadCount && unreadCount > 0 {
if case .messages = inAppSettings.totalUnreadCountDisplayCategory {
globalRemainingUnreadChatCount -= unreadCount
} else {
globalRemainingUnreadChatCount -= 1
}
}
if globalRemainingUnreadChatCount > 0 {
strongSelf.navigationItem.badge = "\(globalRemainingUnreadChatCount)"
} else {
strongSelf.navigationItem.badge = ""
}
}
let _ = previousPeerCache.swap(peerCache)
return result
}
})
self.chatUnreadMentionCountDisposable = (self.context.account.viewTracker.unseenPersonalMessagesCount(peerId: peerId) |> deliverOnMainQueue).start(next: { [weak self] count in
if let strongSelf = self {
strongSelf.chatDisplayNode.navigateButtons.mentionCount = count
}
})
let postbox = self.context.account.postbox
let previousPeerCache = Atomic<[PeerId: Peer]>(value: [:])
self.peerInputActivitiesDisposable = (self.context.account.peerInputActivities(peerId: peerId)
|> mapToSignal { activities -> Signal<[(Peer, PeerInputActivity)], NoError> in
var foundAllPeers = true
var cachedResult: [(Peer, PeerInputActivity)] = []
previousPeerCache.with { dict -> Void in
for (peerId, activity) in activities {
if let peer = dict[peerId] {
cachedResult.append((peer, activity))
} else {
foundAllPeers = false
break
}
}
}
if foundAllPeers {
return .single(cachedResult)
} else {
return postbox.transaction { transaction -> [(Peer, PeerInputActivity)] in
var result: [(Peer, PeerInputActivity)] = []
var peerCache: [PeerId: Peer] = [:]
for (peerId, activity) in activities {
if let peer = transaction.getPeer(peerId) {
result.append((peer, activity))
peerCache[peerId] = peer
}
}
let _ = previousPeerCache.swap(peerCache)
return result
}
}
}
|> deliverOnMainQueue).start(next: { [weak self] activities in
if let strongSelf = self {
strongSelf.chatTitleView?.inputActivities = (peerId, activities)
}
})
}
|> deliverOnMainQueue).start(next: { [weak self] activities in
if let strongSelf = self {
strongSelf.chatTitleView?.inputActivities = (peerId, activities)
}
})
self.sentMessageEventsDisposable.set(self.context.account.pendingMessageManager.deliveredMessageEvents(peerId: peerId).start(next: { [weak self] _ in
if let strongSelf = self {

View file

@ -311,7 +311,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
unboundSize = CGSize(width: floor(dimensions.width * 0.5), height: floor(dimensions.height * 0.5)).fitted(CGSize(width: 240.0, height: 240.0))
} else if isTheme {
if isSupported {
unboundSize = CGSize(width: 160.0, height: 240.0)
unboundSize = CGSize(width: 160.0, height: 240.0).fitted(CGSize(width: 240.0, height: 240.0))
} else if let thumbnail = file.previewRepresentations.first {
unboundSize = CGSize(width: floor(thumbnail.dimensions.width), height: floor(thumbnail.dimensions.height)).fitted(CGSize(width: 240.0, height: 240.0))
} else {

View file

@ -370,7 +370,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
let inputHeight = layout.inputHeight ?? 0.0
var clipDelta = delta
if inputHeight.isZero {
if inputHeight.isZero || layout.isNonExclusive {
clipDelta -= self.contentContainerNode.frame.height + 16.0
}
@ -466,7 +466,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
let inputHeight = layout.inputHeight ?? 0.0
var clipDelta = delta
if inputHeight.isZero {
if inputHeight.isZero || layout.isNonExclusive {
clipDelta -= self.contentContainerNode.frame.height + 16.0
}
@ -527,7 +527,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
let contentOffset = self.scrollNode.view.contentOffset.y
var contentOrigin = CGPoint(x: layout.size.width - sideInset - contentSize.width - layout.safeInsets.right, y: layout.size.height - 6.0 - insets.bottom - contentSize.height)
if inputHeight > 0.0 {
if inputHeight > 0.0 && !layout.isNonExclusive {
contentOrigin.y += menuHeightWithInset
}
contentOrigin.y = min(contentOrigin.y + contentOffset, layout.size.height - 6.0 - layout.intrinsicInsets.bottom - contentSize.height)
@ -542,7 +542,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
let initialSendButtonFrame = self.sendButtonFrame
var sendButtonFrame = CGRect(origin: CGPoint(x: layout.size.width - initialSendButtonFrame.width + 1.0 - UIScreenPixel - layout.safeInsets.right, y: layout.size.height - insets.bottom - initialSendButtonFrame.height), size: initialSendButtonFrame.size)
if inputHeight.isZero {
if inputHeight.isZero || layout.isNonExclusive {
sendButtonFrame.origin.y -= menuHeightWithInset
}
sendButtonFrame.origin.y = min(sendButtonFrame.origin.y + contentOffset, layout.size.height - layout.intrinsicInsets.bottom - initialSendButtonFrame.height)
@ -552,7 +552,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
messageFrame.size.width += 32.0
messageFrame.origin.x -= 13.0
messageFrame.origin.y = layout.size.height - messageFrame.origin.y - messageFrame.size.height - 1.0
if inputHeight.isZero {
if inputHeight.isZero || layout.isNonExclusive {
messageFrame.origin.y += menuHeightWithInset
}

View file

@ -87,7 +87,7 @@ final class ThemeUpdateManagerImpl: ThemeUpdateManager {
let resolvedWallpaper: Signal<TelegramWallpaper?, NoError>
if case let .file(file) = presentationTheme.chat.defaultWallpaper, file.id == 0 {
resolvedWallpaper = cachedWallpaper(account: account, slug: file.slug)
resolvedWallpaper = cachedWallpaper(account: account, slug: file.slug, settings: file.settings)
|> map { wallpaper in
return wallpaper?.wallpaper
}

View file

@ -25,12 +25,16 @@ public final class CachedWallpaper: PostboxCoding {
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 10000, highWaterItemCount: 20000)
public func cachedWallpaper(account: Account, slug: String) -> Signal<CachedWallpaper?, NoError> {
public func cachedWallpaper(account: Account, slug: String, settings: WallpaperSettings?) -> Signal<CachedWallpaper?, NoError> {
return account.postbox.transaction { transaction -> Signal<CachedWallpaper?, NoError> in
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: Int64(bitPattern: slug.persistentHashValue))
if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedWallpapers, key: key)) as? CachedWallpaper {
return .single(entry)
if let settings = settings {
return .single(CachedWallpaper(wallpaper: entry.wallpaper.withUpdatedSettings(settings)))
} else {
return .single(entry)
}
} else {
return getWallpaper(account: account, slug: slug)
|> map(Optional.init)
@ -45,7 +49,11 @@ public func cachedWallpaper(account: Account, slug: String) -> Signal<CachedWall
if let wallpaper = wallpaper {
let entry = CachedWallpaper(wallpaper: wallpaper)
transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec)
return entry
if let settings = settings {
return CachedWallpaper(wallpaper: wallpaper.withUpdatedSettings(settings))
} else {
return CachedWallpaper(wallpaper: wallpaper)
}
} else {
transaction.removeItemCacheEntry(id: id)
return nil

View file

@ -311,8 +311,11 @@ private func patternWallpaperDatas(account: Account, accountManager: AccountMana
|> take(1)
|> mapToSignal { maybeSharedData, maybeData -> Signal<(Data?, Data?, Bool), NoError> in
if maybeSharedData.complete {
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeSharedData.path), options: [])
return .single((nil, loadedData, true))
if let loadedData = try? Data(contentsOf: URL(fileURLWithPath: maybeSharedData.path), options: [.mappedRead]) {
return .single((nil, loadedData, true))
} else {
return .single((nil, nil, true))
}
} else if maybeData.complete {
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
return .single((nil, loadedData, true))
@ -806,7 +809,7 @@ public func themeImage(account: Account, accountManager: AccountManager, fileRef
|> mapToSignal { (fullSizeData, thumbnailData) -> Signal<(PresentationTheme?, UIImage?, Data?), NoError> in
if let fullSizeData = fullSizeData, let theme = makePresentationTheme(data: fullSizeData) {
if case let .file(file) = theme.chat.defaultWallpaper, file.id == 0 {
return cachedWallpaper(account: account, slug: file.slug)
return cachedWallpaper(account: account, slug: file.slug, settings: file.settings)
|> mapToSignal { wallpaper -> Signal<(PresentationTheme?, UIImage?, Data?), NoError> in
if let wallpaper = wallpaper, case let .file(file) = wallpaper.wallpaper {
var convertedRepresentations: [ImageRepresentationWithReference] = []
@ -817,11 +820,30 @@ public func themeImage(account: Account, accountManager: AccountManager, fileRef
return .complete()
}
accountManager.mediaBox.storeResourceData(file.file.resource.id, data: fullSizeData)
let _ = accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: true, fetch: true).start()
if let image = UIImage(data: fullSizeData) {
if file.isPattern, let color = file.settings.color, let intensity = file.settings.intensity {
return accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedPatternWallpaperRepresentation(color: color, intensity: intensity), complete: true, fetch: true)
|> mapToSignal { data in
if data.complete, let data = try? Data(contentsOf: URL(fileURLWithPath: data.path)), let image = UIImage(data: data) {
return .single((theme, image, thumbnailData))
} else {
return .complete()
}
}
} else if file.settings.blur {
return accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true)
|> mapToSignal { data in
if data.complete, let data = try? Data(contentsOf: URL(fileURLWithPath: data.path)), let image = UIImage(data: data) {
return .single((theme, image, thumbnailData))
} else {
return .complete()
}
}
} else if let image = UIImage(data: fullSizeData) {
return .single((theme, image, thumbnailData))
} else {
return .single((theme, nil, thumbnailData))
return .complete()
}
}
} else {
@ -907,15 +929,15 @@ public func themeIconImage(account: Account, accountManager: AccountManager, the
let signal: Signal<(UIColor, UIColor, UIColor, UIImage?), NoError>
if case let .builtin(theme) = theme {
switch theme {
case .dayClassic:
signal = .single((UIColor(rgb: 0xd6e2ee), UIColor(rgb: 0xffffff), UIColor(rgb: 0xe1ffc7), nil))
case .day:
signal = .single((.white, UIColor(rgb: 0xd5dde6), accentColor ?? UIColor(rgb: 0x007aff), nil))
case .night:
signal = .single((.black, UIColor(rgb: 0x1f1f1f), accentColor ?? UIColor(rgb: 0x313131), nil))
case .nightAccent:
let accentColor = accentColor ?? UIColor(rgb: 0x007aff)
signal = .single((accentColor.withMultiplied(hue: 1.024, saturation: 0.573, brightness: 0.18), accentColor.withMultiplied(hue: 1.024, saturation: 0.585, brightness: 0.25), accentColor.withMultiplied(hue: 1.019, saturation: 0.731, brightness: 0.59), nil))
case .dayClassic:
signal = .single((UIColor(rgb: 0xd6e2ee), UIColor(rgb: 0xffffff), UIColor(rgb: 0xe1ffc7), nil))
case .day:
signal = .single((.white, UIColor(rgb: 0xd5dde6), accentColor ?? UIColor(rgb: 0x007aff), nil))
case .night:
signal = .single((.black, UIColor(rgb: 0x1f1f1f), accentColor ?? UIColor(rgb: 0x313131), nil))
case .nightAccent:
let accentColor = accentColor ?? UIColor(rgb: 0x007aff)
signal = .single((accentColor.withMultiplied(hue: 1.024, saturation: 0.573, brightness: 0.18), accentColor.withMultiplied(hue: 1.024, saturation: 0.585, brightness: 0.25), accentColor.withMultiplied(hue: 1.019, saturation: 0.731, brightness: 0.59), nil))
}
} else {
var resource: MediaResource?
@ -926,13 +948,13 @@ public func themeIconImage(account: Account, accountManager: AccountManager, the
}
if let resource = resource {
signal = telegramThemeData(account: account, accountManager: accountManager, resource: resource, synchronousLoad: false)
|> mapToSignal { data -> Signal<(UIColor, UIColor, UIColor, UIImage?), NoError> in
if let data = data, let theme = makePresentationTheme(data: data) {
var wallpaperSignal: Signal<(UIColor, UIColor, UIColor, UIImage?), NoError> = .complete()
let backgroundColor: UIColor
let incomingColor = theme.chat.message.incoming.bubble.withoutWallpaper.fill
let outgoingColor = theme.chat.message.outgoing.bubble.withoutWallpaper.fill
switch theme.chat.defaultWallpaper {
|> mapToSignal { data -> Signal<(UIColor, UIColor, UIColor, UIImage?), NoError> in
if let data = data, let theme = makePresentationTheme(data: data) {
var wallpaperSignal: Signal<(UIColor, UIColor, UIColor, UIImage?), NoError> = .complete()
let backgroundColor: UIColor
let incomingColor = theme.chat.message.incoming.bubble.withoutWallpaper.fill
let outgoingColor = theme.chat.message.outgoing.bubble.withoutWallpaper.fill
switch theme.chat.defaultWallpaper {
case .builtin:
backgroundColor = UIColor(rgb: 0xd6e2ee)
case let .color(color):
@ -940,8 +962,12 @@ public func themeIconImage(account: Account, accountManager: AccountManager, the
case .image:
backgroundColor = .black
case let .file(file):
backgroundColor = theme.chatList.backgroundColor
wallpaperSignal = cachedWallpaper(account: account, slug: file.slug)
if file.isPattern, let color = file.settings.color {
backgroundColor = UIColor(rgb: UInt32(bitPattern: color))
} else {
backgroundColor = theme.chatList.backgroundColor
}
wallpaperSignal = cachedWallpaper(account: account, slug: file.slug, settings: file.settings)
|> mapToSignal { wallpaper in
if let wallpaper = wallpaper, case let .file(file) = wallpaper.wallpaper {
var convertedRepresentations: [ImageRepresentationWithReference] = []
@ -952,8 +978,23 @@ public func themeIconImage(account: Account, accountManager: AccountManager, the
return .complete()
}
accountManager.mediaBox.storeResourceData(file.file.resource.id, data: fullSizeData)
let _ = accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: true, fetch: true).start()
if let image = UIImage(data: fullSizeData) {
if file.isPattern, let color = file.settings.color, let intensity = file.settings.intensity {
return accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedPatternWallpaperRepresentation(color: color, intensity: intensity), complete: true, fetch: true)
|> mapToSignal { _ in
return .complete()
}
} else if file.settings.blur {
return accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true)
|> mapToSignal { _ in
if let image = UIImage(data: fullSizeData) {
return .single((backgroundColor, incomingColor, outgoingColor, image))
} else {
return .complete()
}
}
} else if let image = UIImage(data: fullSizeData) {
return .single((backgroundColor, incomingColor, outgoingColor, image))
} else {
return .complete()
@ -963,12 +1004,12 @@ public func themeIconImage(account: Account, accountManager: AccountManager, the
return .complete()
}
}
}
return .single((backgroundColor, incomingColor, outgoingColor, nil))
|> then(wallpaperSignal)
} else {
return .complete()
}
return .single((backgroundColor, incomingColor, outgoingColor, nil))
|> then(wallpaperSignal)
} else {
return .complete()
}
}
} else {
signal = .never()