mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Update themes
This commit is contained in:
parent
efacf13a9e
commit
e27d764dae
@ -3,7 +3,7 @@
|
|||||||
@implementation Serialization
|
@implementation Serialization
|
||||||
|
|
||||||
- (NSUInteger)currentLayer {
|
- (NSUInteger)currentLayer {
|
||||||
return 107;
|
return 108;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id _Nullable)parseMessage:(NSData * _Nullable)data {
|
- (id _Nullable)parseMessage:(NSData * _Nullable)data {
|
||||||
|
@ -153,6 +153,11 @@ public enum WallpaperUrlParameter {
|
|||||||
case gradient(UIColor, UIColor, Int32?)
|
case gradient(UIColor, UIColor, Int32?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ResolvedUrlSettingsSection {
|
||||||
|
case theme
|
||||||
|
case devices
|
||||||
|
}
|
||||||
|
|
||||||
public enum ResolvedUrl {
|
public enum ResolvedUrl {
|
||||||
case externalUrl(String)
|
case externalUrl(String)
|
||||||
case peer(PeerId?, ChatControllerInteractionNavigateToPeer)
|
case peer(PeerId?, ChatControllerInteractionNavigateToPeer)
|
||||||
@ -171,6 +176,7 @@ public enum ResolvedUrl {
|
|||||||
case wallpaper(WallpaperUrlParameter)
|
case wallpaper(WallpaperUrlParameter)
|
||||||
case theme(String)
|
case theme(String)
|
||||||
case wallet(address: String, amount: Int64?, comment: String?)
|
case wallet(address: String, amount: Int64?, comment: String?)
|
||||||
|
case settings(ResolvedUrlSettingsSection)
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum NavigateToChatKeepStack {
|
public enum NavigateToChatKeepStack {
|
||||||
|
@ -628,7 +628,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
|
|||||||
let frame = CGRect(origin: CGPoint(x: floor((boundingWidth - size.width) / 2.0), y: 0.0), size: size)
|
let frame = CGRect(origin: CGPoint(x: floor((boundingWidth - size.width) / 2.0), y: 0.0), size: size)
|
||||||
let item: InstantPageItem
|
let item: InstantPageItem
|
||||||
if let url = url, let coverId = coverId, let image = media[coverId] as? TelegramMediaImage {
|
if let url = url, let coverId = coverId, let image = media[coverId] as? TelegramMediaImage {
|
||||||
let loadedContent = TelegramMediaWebpageLoadedContent(url: url, displayUrl: url, hash: 0, type: "video", websiteName: nil, title: nil, text: nil, embedUrl: url, embedType: "video", embedSize: PixelDimensions(size), duration: nil, author: nil, image: image, file: nil, files: nil, instantPage: nil)
|
let loadedContent = TelegramMediaWebpageLoadedContent(url: url, displayUrl: url, hash: 0, type: "video", websiteName: nil, title: nil, text: nil, embedUrl: url, embedType: "video", embedSize: PixelDimensions(size), duration: nil, author: nil, image: image, file: nil, attributes: [], instantPage: nil)
|
||||||
let content = TelegramMediaWebpageContent.Loaded(loadedContent)
|
let content = TelegramMediaWebpageContent.Loaded(loadedContent)
|
||||||
|
|
||||||
item = InstantPageImageItem(frame: frame, webPage: webpage, media: InstantPageMedia(index: embedIndex, media: TelegramMediaWebpage(webpageId: MediaId(namespace: Namespaces.Media.LocalWebpage, id: -1), content: content), url: nil, caption: nil, credit: nil), attributes: [], interactive: true, roundCorners: false, fit: false)
|
item = InstantPageImageItem(frame: frame, webPage: webpage, media: InstantPageMedia(index: embedIndex, media: TelegramMediaWebpage(webpageId: MediaId(namespace: Namespaces.Media.LocalWebpage, id: -1), content: content), url: nil, caption: nil, credit: nil), attributes: [], interactive: true, roundCorners: false, fit: false)
|
||||||
|
@ -36,13 +36,34 @@ private class PickerAnnotationContainerView: UIView {
|
|||||||
|
|
||||||
private class LocationMapView: MKMapView, UIGestureRecognizerDelegate {
|
private class LocationMapView: MKMapView, UIGestureRecognizerDelegate {
|
||||||
var customHitTest: ((CGPoint) -> Bool)?
|
var customHitTest: ((CGPoint) -> Bool)?
|
||||||
|
private var allowSelectionChanges = true
|
||||||
|
|
||||||
@objc override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
@objc override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
if let customHitTest = self.customHitTest, customHitTest(gestureRecognizer.location(in: self)) {
|
if let customHitTest = self.customHitTest, customHitTest(gestureRecognizer.location(in: self)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
return self.allowSelectionChanges
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
||||||
|
let pointInside = super.point(inside: point, with: event)
|
||||||
|
if !pointInside {
|
||||||
|
return pointInside
|
||||||
|
}
|
||||||
|
|
||||||
|
for annotation in self.annotations(in: self.visibleMapRect) where annotation is LocationPinAnnotation {
|
||||||
|
guard let view = self.view(for: annotation as! MKAnnotation) else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if view.frame.insetBy(dx: -16.0, dy: -16.0).contains(point) {
|
||||||
|
self.allowSelectionChanges = true
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
self.allowSelectionChanges = false
|
||||||
|
|
||||||
|
return pointInside
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||||
|
@ -13,6 +13,7 @@ import AuthorizationUI
|
|||||||
private func generateButtonImage(backgroundColor: UIColor, borderColor: UIColor, highlightColor: UIColor?) -> UIImage? {
|
private func generateButtonImage(backgroundColor: UIColor, borderColor: UIColor, highlightColor: UIColor?) -> UIImage? {
|
||||||
return generateImage(CGSize(width: 1.0, height: 44.0), contextGenerator: { size, context in
|
return generateImage(CGSize(width: 1.0, height: 44.0), contextGenerator: { size, context in
|
||||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||||
|
context.clear(bounds)
|
||||||
|
|
||||||
if let highlightColor = highlightColor {
|
if let highlightColor = highlightColor {
|
||||||
context.setFillColor(highlightColor.cgColor)
|
context.setFillColor(highlightColor.cgColor)
|
||||||
|
@ -150,7 +150,7 @@ final class ThemeAccentColorController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let prepare: Signal<Void, NoError>
|
let prepare: Signal<CreateThemeResult, CreateThemeError>
|
||||||
if let patternWallpaper = state.patternWallpaper, case let .file(file) = patternWallpaper, let backgroundColors = state.backgroundColors {
|
if let patternWallpaper = state.patternWallpaper, case let .file(file) = patternWallpaper, let backgroundColors = state.backgroundColors {
|
||||||
let resource = file.file.resource
|
let resource = file.file.resource
|
||||||
let representation = CachedPatternWallpaperRepresentation(color: Int32(bitPattern: backgroundColors.0.rgb), bottomColor: backgroundColors.1.flatMap { Int32(bitPattern: $0.rgb) }, intensity: state.patternIntensity, rotation: state.rotation)
|
let representation = CachedPatternWallpaperRepresentation(color: Int32(bitPattern: backgroundColors.0.rgb), bottomColor: backgroundColors.1.flatMap { Int32(bitPattern: $0.rgb) }, intensity: state.patternIntensity, rotation: state.rotation)
|
||||||
@ -167,7 +167,8 @@ final class ThemeAccentColorController: ViewController {
|
|||||||
prepare = (strongSelf.context.sharedContext.accountManager.mediaBox.cachedResourceRepresentation(resource, representation: representation, complete: true, fetch: true)
|
prepare = (strongSelf.context.sharedContext.accountManager.mediaBox.cachedResourceRepresentation(resource, representation: representation, complete: true, fetch: true)
|
||||||
|> filter({ $0.complete })
|
|> filter({ $0.complete })
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
|> castError(CreateThemeError.self)
|
||||||
|
|> mapToSignal { _ -> Signal<CreateThemeResult, CreateThemeError> in
|
||||||
return .complete()
|
return .complete()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -201,68 +202,117 @@ final class ThemeAccentColorController: ViewController {
|
|||||||
|
|
||||||
completion(updatedTheme, settings)
|
completion(updatedTheme, settings)
|
||||||
})
|
})
|
||||||
|
} else if case let .colors(theme, create) = strongSelf.mode {
|
||||||
|
var baseTheme: TelegramBaseTheme
|
||||||
|
var telegramTheme: TelegramTheme?
|
||||||
|
if case let .cloud(theme) = theme, let settings = theme.theme.settings {
|
||||||
|
telegramTheme = theme.theme
|
||||||
|
baseTheme = settings.baseTheme
|
||||||
} else {
|
} else {
|
||||||
let _ = (prepare
|
baseTheme = .classic
|
||||||
|> then(updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in
|
|
||||||
let autoNightModeTriggered = context.sharedContext.currentPresentationData.with { $0 }.autoNightModeTriggered
|
|
||||||
var currentTheme = current.theme
|
|
||||||
if autoNightModeTriggered {
|
|
||||||
currentTheme = current.automaticThemeSwitchSetting.theme
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
let accentColor = Int32(bitPattern: state.accentColor.rgb)
|
||||||
var themeSpecificAccentColors = current.themeSpecificAccentColors
|
var bubbleColors: (Int32, Int32)?
|
||||||
var themeSpecificCustomColors = current.themeSpecificCustomColors
|
|
||||||
var customColors = themeSpecificCustomColors[currentTheme.index]?.colors ?? []
|
|
||||||
|
|
||||||
var bubbleColors: (Int32, Int32?)?
|
|
||||||
if let messagesColors = state.messagesColors {
|
if let messagesColors = state.messagesColors {
|
||||||
if let secondColor = messagesColors.1 {
|
if let secondColor = messagesColors.1 {
|
||||||
bubbleColors = (Int32(bitPattern: messagesColors.0.rgb), Int32(bitPattern: secondColor.rgb))
|
bubbleColors = (Int32(bitPattern: messagesColors.0.rgb), Int32(bitPattern: secondColor.rgb))
|
||||||
} else {
|
} else {
|
||||||
bubbleColors = (Int32(bitPattern: messagesColors.0.rgb), nil)
|
bubbleColors = (Int32(bitPattern: messagesColors.0.rgb), Int32(bitPattern: messagesColors.0.rgb))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let index: Int32
|
var wallpaper: TelegramWallpaper? = nil // themeSpecificChatWallpapers[currentTheme.index]
|
||||||
var exists: Bool
|
|
||||||
if let initialIndex = initialAccentColor?.index, initialIndex != -1 {
|
|
||||||
index = initialIndex
|
|
||||||
exists = true
|
|
||||||
} else {
|
|
||||||
index = Int32(bitPattern: arc4random())
|
|
||||||
exists = false
|
|
||||||
}
|
|
||||||
|
|
||||||
let color = PresentationThemeAccentColor(index: index, baseColor: .custom, accentColor: Int32(bitPattern: state.accentColor.rgb), bubbleColors: bubbleColors)
|
|
||||||
themeSpecificAccentColors[currentTheme.index] = color
|
|
||||||
|
|
||||||
if exists {
|
|
||||||
if let index = customColors.firstIndex(where: { $0.index == index }) {
|
|
||||||
customColors[index] = color
|
|
||||||
} else {
|
|
||||||
customColors.append(color)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
customColors.append(color)
|
|
||||||
}
|
|
||||||
|
|
||||||
var wallpaper = themeSpecificChatWallpapers[currentTheme.index]
|
|
||||||
if let coloredWallpaper = coloredWallpaper {
|
if let coloredWallpaper = coloredWallpaper {
|
||||||
wallpaper = coloredWallpaper
|
wallpaper = coloredWallpaper
|
||||||
}
|
}
|
||||||
|
|
||||||
themeSpecificChatWallpapers[coloredThemeIndex(reference: currentTheme, accentColor: color)] = wallpaper
|
let settings = TelegramThemeSettings(baseTheme: baseTheme, accentColor: accentColor, messageColors: bubbleColors, wallpaper: wallpaper)
|
||||||
themeSpecificCustomColors[currentTheme.index] = PresentationThemeCustomColors(colors: customColors)
|
|
||||||
|
|
||||||
return PresentationThemeSettings(theme: current.theme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificCustomColors: themeSpecificCustomColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
let save: Signal<Void, NoError>
|
||||||
})) |> deliverOnMainQueue).start(completed: { [weak self] in
|
|
||||||
|
if !create, let theme = telegramTheme {
|
||||||
|
let _ = (prepare |> then(updateTheme(account: context.account, accountManager: context.sharedContext.accountManager, theme: theme, title: theme.title, slug: theme.slug, resource: nil, settings: settings))
|
||||||
|
|> deliverOnMainQueue).start(next: { next in
|
||||||
|
if case let .result(resultTheme) = next {
|
||||||
|
let _ = applyTheme(accountManager: context.sharedContext.accountManager, account: context.account, theme: resultTheme).start()
|
||||||
|
let _ = (updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in
|
||||||
|
// if let resource = resultTheme.file?.resource, let data = themeData {
|
||||||
|
// context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
|
||||||
|
// }
|
||||||
|
|
||||||
|
let themeReference: PresentationThemeReference = .cloud(PresentationCloudTheme(theme: resultTheme, resolvedWallpaper: wallpaper))
|
||||||
|
|
||||||
|
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
||||||
|
themeSpecificChatWallpapers[themeReference.index] = nil
|
||||||
|
|
||||||
|
return PresentationThemeSettings(theme: themeReference, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificCustomColors: current.themeSpecificCustomColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||||
|
}) |> deliverOnMainQueue).start(completed: {
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.completion?()
|
strongSelf.completion?()
|
||||||
strongSelf.dismiss()
|
strongSelf.dismiss()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}, error: { error in
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let title = generateThemeName(accentColor: state.accentColor)
|
||||||
|
let _ = (prepare |> then(createTheme(account: context.account, title: title, resource: nil, thumbnailData: nil, settings: settings))
|
||||||
|
|> deliverOnMainQueue).start(next: { next in
|
||||||
|
if case let .result(resultTheme) = next {
|
||||||
|
let _ = applyTheme(accountManager: context.sharedContext.accountManager, account: context.account, theme: resultTheme).start()
|
||||||
|
let _ = (updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in
|
||||||
|
// if let resource = resultTheme.file?.resource, let data = themeData {
|
||||||
|
// context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
|
||||||
|
// }
|
||||||
|
|
||||||
|
let themeReference: PresentationThemeReference = .cloud(PresentationCloudTheme(theme: resultTheme, resolvedWallpaper: wallpaper))
|
||||||
|
|
||||||
|
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
||||||
|
themeSpecificChatWallpapers[themeReference.index] = nil
|
||||||
|
|
||||||
|
return PresentationThemeSettings(theme: themeReference, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificCustomColors: current.themeSpecificCustomColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||||
|
}) |> deliverOnMainQueue).start(completed: {
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.completion?()
|
||||||
|
strongSelf.dismiss()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, error: { error in
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// let _ = (prepare
|
||||||
|
// |> then(updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in
|
||||||
|
// let autoNightModeTriggered = context.sharedContext.currentPresentationData.with { $0 }.autoNightModeTriggered
|
||||||
|
// var currentTheme = current.theme
|
||||||
|
// if autoNightModeTriggered {
|
||||||
|
// currentTheme = current.automaticThemeSwitchSetting.theme
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// if create {
|
||||||
|
//
|
||||||
|
// } else {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// themeSpecificChatWallpapers[coloredThemeIndex(reference: currentTheme, accentColor: nil)] = wallpaper
|
||||||
|
//
|
||||||
|
// return PresentationThemeSettings(theme: current.theme, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificCustomColors: current.themeSpecificCustomColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||||
|
// })) |> deliverOnMainQueue).start(completed: { [weak self] in
|
||||||
|
// if let strongSelf = self {
|
||||||
|
// strongSelf.completion?()
|
||||||
|
// strongSelf.dismiss()
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
self.controllerNode.themeUpdated = { [weak self] theme in
|
self.controllerNode.themeUpdated = { [weak self] theme in
|
||||||
@ -326,13 +376,12 @@ final class ThemeAccentColorController: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let themeReference = strongSelf.mode.themeReference {
|
if let themeReference = strongSelf.mode.themeReference {
|
||||||
let themeSpecificAccentColor = settings.themeSpecificAccentColors[themeReference.index]
|
|
||||||
if case .colors(_, true) = strongSelf.mode {
|
|
||||||
} else if themeSpecificAccentColor?.baseColor == .custom {
|
|
||||||
strongSelf.initialAccentColor = themeSpecificAccentColor
|
|
||||||
}
|
|
||||||
accentColor = themeSpecificAccentColor?.color ?? defaultDayAccentColor
|
|
||||||
var wallpaper: TelegramWallpaper
|
var wallpaper: TelegramWallpaper
|
||||||
|
|
||||||
|
if case .colors(_, true) = strongSelf.mode {
|
||||||
|
let themeSpecificAccentColor = settings.themeSpecificAccentColors[themeReference.index]
|
||||||
|
accentColor = themeSpecificAccentColor?.color ?? defaultDayAccentColor
|
||||||
|
|
||||||
if let accentColor = themeSpecificAccentColor, let customWallpaper = settings.themeSpecificChatWallpapers[coloredThemeIndex(reference: themeReference, accentColor: accentColor)] {
|
if let accentColor = themeSpecificAccentColor, let customWallpaper = settings.themeSpecificChatWallpapers[coloredThemeIndex(reference: themeReference, accentColor: accentColor)] {
|
||||||
wallpaper = customWallpaper
|
wallpaper = customWallpaper
|
||||||
} else if let customWallpaper = settings.themeSpecificChatWallpapers[themeReference.index] {
|
} else if let customWallpaper = settings.themeSpecificChatWallpapers[themeReference.index] {
|
||||||
@ -391,6 +440,54 @@ final class ThemeAccentColorController: ViewController {
|
|||||||
messageColors = nil
|
messageColors = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
let presentationTheme = makePresentationTheme(mediaBox: strongSelf.context.sharedContext.accountManager.mediaBox, themeReference: themeReference)!
|
||||||
|
if case let .cloud(theme) = themeReference, let themeSettings = theme.theme.settings {
|
||||||
|
accentColor = UIColor(rgb: UInt32(bitPattern: themeSettings.accentColor))
|
||||||
|
|
||||||
|
if let customWallpaper = settings.themeSpecificChatWallpapers[themeReference.index] {
|
||||||
|
wallpaper = customWallpaper
|
||||||
|
} else {
|
||||||
|
wallpaper = presentationTheme.chat.defaultWallpaper
|
||||||
|
}
|
||||||
|
extractWallpaperParameters(wallpaper)
|
||||||
|
if !wallpaper.isColorOrGradient {
|
||||||
|
initialWallpaper = wallpaper
|
||||||
|
}
|
||||||
|
|
||||||
|
if let colors = themeSettings.messageColors {
|
||||||
|
let topMessageColor = UIColor(rgb: UInt32(bitPattern: colors.top))
|
||||||
|
let bottomMessageColor = UIColor(rgb: UInt32(bitPattern: colors.bottom))
|
||||||
|
if topMessageColor.rgb == bottomMessageColor.rgb {
|
||||||
|
messageColors = (topMessageColor, nil)
|
||||||
|
} else {
|
||||||
|
messageColors = (topMessageColor, bottomMessageColor)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
messageColors = nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let theme = makePresentationTheme(mediaBox: strongSelf.context.sharedContext.accountManager.mediaBox, themeReference: themeReference)!
|
||||||
|
|
||||||
|
accentColor = theme.rootController.navigationBar.accentTextColor
|
||||||
|
|
||||||
|
let wallpaper = theme.chat.defaultWallpaper
|
||||||
|
extractWallpaperParameters(wallpaper)
|
||||||
|
|
||||||
|
if !wallpaper.isColorOrGradient {
|
||||||
|
initialWallpaper = wallpaper
|
||||||
|
}
|
||||||
|
|
||||||
|
let topMessageColor = theme.chat.message.outgoing.bubble.withWallpaper.fill
|
||||||
|
let bottomMessageColor = theme.chat.message.outgoing.bubble.withWallpaper.gradientFill
|
||||||
|
|
||||||
|
if topMessageColor.rgb == bottomMessageColor.rgb {
|
||||||
|
messageColors = (topMessageColor, nil)
|
||||||
|
} else {
|
||||||
|
messageColors = (topMessageColor, bottomMessageColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if case let .edit(theme, wallpaper, _, _, _) = strongSelf.mode {
|
} else if case let .edit(theme, wallpaper, _, _, _) = strongSelf.mode {
|
||||||
accentColor = theme.rootController.navigationBar.accentTextColor
|
accentColor = theme.rootController.navigationBar.accentTextColor
|
||||||
|
|
||||||
|
31
submodules/SettingsUI/Sources/Themes/ThemeColorPresets.swift
Normal file
31
submodules/SettingsUI/Sources/Themes/ThemeColorPresets.swift
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import Foundation
|
||||||
|
import Postbox
|
||||||
|
import SyncCore
|
||||||
|
import TelegramUIPreferences
|
||||||
|
|
||||||
|
private func patternWallpaper(slug: String, topColor: Int32, bottomColor: Int32?, intensity: Int32?, rotation: Int32?) -> TelegramWallpaper {
|
||||||
|
return TelegramWallpaper.file(id: 0, accessHash: 0, isCreator: false, isDefault: true, isPattern: true, isDark: false, slug: slug, file: TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], immediateThumbnailData: nil, mimeType: "", size: nil, attributes: []), settings: WallpaperSettings(color: topColor, bottomColor: bottomColor, intensity: intensity ?? 50, rotation: rotation))
|
||||||
|
}
|
||||||
|
|
||||||
|
var dayClassicColorPresets: [PresentationThemeAccentColor] = [
|
||||||
|
PresentationThemeAccentColor(index: 106, baseColor: .preset, accentColor: 0xf55783, bubbleColors: (0xd6f5ff, nil), wallpaper: patternWallpaper(slug: "p-pXcflrmFIBAAAAvXYQk-mCwZU", topColor: 0xfce3ec, bottomColor: nil, intensity: 40, rotation: nil)),
|
||||||
|
PresentationThemeAccentColor(index: 102, baseColor: .preset, accentColor: 0xff5fa9, bubbleColors: (0xfff4d7, nil), wallpaper: patternWallpaper(slug: "51nnTjx8mFIBAAAAaFGJsMIvWkk", topColor: 0xf6b594, bottomColor: 0xebf6cd, intensity: 46, rotation: 45)),
|
||||||
|
PresentationThemeAccentColor(index: 104, baseColor: .preset, accentColor: 0x5a9e29, bubbleColors: (0xdcf8c6, nil), wallpaper: patternWallpaper(slug: "R3j69wKskFIBAAAAoUdXWCKMzCM", topColor: 0xede6dd, bottomColor: nil, intensity: 50, rotation: nil)),
|
||||||
|
PresentationThemeAccentColor(index: 101, baseColor: .preset, accentColor: 0x7e5fe5, bubbleColors: (0xf5e2ff, nil), wallpaper: patternWallpaper(slug: "nQcFYJe1mFIBAAAAcI95wtIK0fk", topColor: 0xfcccf4, bottomColor: 0xae85f0, intensity: 54, rotation: nil)),
|
||||||
|
PresentationThemeAccentColor(index: 103, baseColor: .preset, accentColor: 0x199972, bubbleColors: (0xfffec7, nil), wallpaper: patternWallpaper(slug: "fqv01SQemVIBAAAApND8LDRUhRU", topColor: 0xc1e7cb, bottomColor: nil, intensity: 50, rotation: nil)),
|
||||||
|
PresentationThemeAccentColor(index: 105, baseColor: .preset, accentColor: 0x009eee, bubbleColors: (0x94fff9, 0xccffc7), wallpaper: patternWallpaper(slug: "p-pXcflrmFIBAAAAvXYQk-mCwZU", topColor: 0xffbca6, bottomColor: 0xff63bd, intensity: 57, rotation: 225))
|
||||||
|
]
|
||||||
|
|
||||||
|
var dayColorPresets: [PresentationThemeAccentColor] = [
|
||||||
|
PresentationThemeAccentColor(index: 101, baseColor: .preset, accentColor: 0x007aff, bubbleColors: (0x007aff, 0xff53f4), wallpaper: nil),
|
||||||
|
PresentationThemeAccentColor(index: 102, baseColor: .preset, accentColor: 0x00b09b, bubbleColors: (0xaee946, 0x00b09b), wallpaper: nil),
|
||||||
|
PresentationThemeAccentColor(index: 103, baseColor: .preset, accentColor: 0xd33213, bubbleColors: (0xf9db00, 0xd33213), wallpaper: nil),
|
||||||
|
PresentationThemeAccentColor(index: 104, baseColor: .preset, accentColor: 0xea8ced, bubbleColors: (0xea8ced, 0x00c2ed), wallpaper: nil)
|
||||||
|
]
|
||||||
|
|
||||||
|
var nightColorPresets: [PresentationThemeAccentColor] = [
|
||||||
|
PresentationThemeAccentColor(index: 101, baseColor: .preset, accentColor: 0x007aff, bubbleColors: (0x007aff, 0xff53f4), wallpaper: nil),
|
||||||
|
PresentationThemeAccentColor(index: 102, baseColor: .preset, accentColor: 0x00b09b, bubbleColors: (0xaee946, 0x00b09b), wallpaper: nil),
|
||||||
|
PresentationThemeAccentColor(index: 103, baseColor: .preset, accentColor: 0xd33213, bubbleColors: (0xf9db00, 0xd33213), wallpaper: nil),
|
||||||
|
PresentationThemeAccentColor(index: 104, baseColor: .preset, accentColor: 0xea8ced, bubbleColors: (0xea8ced, 0x00c2ed), wallpaper: nil)
|
||||||
|
]
|
@ -15,6 +15,7 @@ import PresentationDataUtils
|
|||||||
import AccountContext
|
import AccountContext
|
||||||
import SearchBarNode
|
import SearchBarNode
|
||||||
import SearchUI
|
import SearchUI
|
||||||
|
import WallpaperResources
|
||||||
|
|
||||||
struct ThemeGridControllerNodeState: Equatable {
|
struct ThemeGridControllerNodeState: Equatable {
|
||||||
let editing: Bool
|
let editing: Bool
|
||||||
|
@ -21,6 +21,7 @@ public enum ThemePreviewSource {
|
|||||||
case settings(PresentationThemeReference, TelegramWallpaper?)
|
case settings(PresentationThemeReference, TelegramWallpaper?)
|
||||||
case theme(TelegramTheme)
|
case theme(TelegramTheme)
|
||||||
case slug(String, TelegramMediaFile)
|
case slug(String, TelegramMediaFile)
|
||||||
|
case themeSettings(String, TelegramThemeSettings)
|
||||||
case media(AnyMediaReference)
|
case media(AnyMediaReference)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +64,8 @@ public final class ThemePreviewController: ViewController {
|
|||||||
|
|
||||||
var hasInstallsCount = false
|
var hasInstallsCount = false
|
||||||
let themeName: String
|
let themeName: String
|
||||||
if case let .theme(theme) = source {
|
switch source {
|
||||||
|
case let .theme(theme):
|
||||||
themeName = theme.title
|
themeName = theme.title
|
||||||
self.theme.set(.single(theme)
|
self.theme.set(.single(theme)
|
||||||
|> then(
|
|> then(
|
||||||
@ -75,7 +77,7 @@ public final class ThemePreviewController: ViewController {
|
|||||||
|> filter { $0 != nil }
|
|> filter { $0 != nil }
|
||||||
))
|
))
|
||||||
hasInstallsCount = true
|
hasInstallsCount = true
|
||||||
} else if case let .slug(slug, _) = source {
|
case let .slug(slug, _), let .themeSettings(slug, _):
|
||||||
self.theme.set(getTheme(account: context.account, slug: slug)
|
self.theme.set(getTheme(account: context.account, slug: slug)
|
||||||
|> map(Optional.init)
|
|> map(Optional.init)
|
||||||
|> `catch` { _ -> Signal<TelegramTheme?, NoError> in
|
|> `catch` { _ -> Signal<TelegramTheme?, NoError> in
|
||||||
@ -101,18 +103,23 @@ public final class ThemePreviewController: ViewController {
|
|||||||
}
|
}
|
||||||
))
|
))
|
||||||
hasInstallsCount = true
|
hasInstallsCount = true
|
||||||
} else if case let .settings(themeReference, _) = source, case let .cloud(theme) = themeReference {
|
case let .settings(themeReference, _):
|
||||||
|
if case let .cloud(theme) = themeReference {
|
||||||
self.theme.set(getTheme(account: context.account, slug: theme.theme.slug)
|
self.theme.set(getTheme(account: context.account, slug: theme.theme.slug)
|
||||||
|> map(Optional.init)
|
|> map(Optional.init)
|
||||||
|> `catch` { _ -> Signal<TelegramTheme?, NoError> in
|
|> `catch` { _ -> Signal<TelegramTheme?, NoError> in
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
})
|
})
|
||||||
themeName = previewTheme.name.string
|
themeName = theme.theme.title
|
||||||
hasInstallsCount = true
|
hasInstallsCount = true
|
||||||
} else {
|
} else {
|
||||||
self.theme.set(.single(nil))
|
self.theme.set(.single(nil))
|
||||||
themeName = previewTheme.name.string
|
themeName = previewTheme.name.string
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
self.theme.set(.single(nil))
|
||||||
|
themeName = previewTheme.name.string
|
||||||
|
}
|
||||||
|
|
||||||
var isPreview = false
|
var isPreview = false
|
||||||
if case .settings = source {
|
if case .settings = source {
|
||||||
@ -219,7 +226,7 @@ public final class ThemePreviewController: ViewController {
|
|||||||
switch self.source {
|
switch self.source {
|
||||||
case let .settings(reference, _):
|
case let .settings(reference, _):
|
||||||
theme = .single(reference)
|
theme = .single(reference)
|
||||||
case .theme, .slug:
|
case .theme, .slug, .themeSettings:
|
||||||
theme = combineLatest(self.theme.get() |> take(1), wallpaperPromise.get() |> take(1))
|
theme = combineLatest(self.theme.get() |> take(1), wallpaperPromise.get() |> take(1))
|
||||||
|> mapToSignal { theme, wallpaper -> Signal<PresentationThemeReference?, NoError> in
|
|> mapToSignal { theme, wallpaper -> Signal<PresentationThemeReference?, NoError> in
|
||||||
if let theme = theme {
|
if let theme = theme {
|
||||||
@ -440,7 +447,7 @@ public final class ThemePreviewController: ViewController {
|
|||||||
case let .theme(theme):
|
case let .theme(theme):
|
||||||
subject = .url("https://t.me/addtheme/\(theme.slug)")
|
subject = .url("https://t.me/addtheme/\(theme.slug)")
|
||||||
preferredAction = .default
|
preferredAction = .default
|
||||||
case let .slug(slug, _):
|
case let .slug(slug, _), let .themeSettings(slug, _):
|
||||||
subject = .url("https://t.me/addtheme/\(slug)")
|
subject = .url("https://t.me/addtheme/\(slug)")
|
||||||
preferredAction = .default
|
preferredAction = .default
|
||||||
case let .media(media):
|
case let .media(media):
|
||||||
|
@ -73,7 +73,7 @@ private enum ThemeSettingsColorEntry: Comparable, Identifiable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func item(action: @escaping (ThemeSettingsColorOption?, Bool) -> Void, contextAction: ((ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void)?, openColorPicker: @escaping (Bool) -> Void) -> ListViewItem {
|
func item(action: @escaping (ThemeSettingsColorOption?, Bool) -> Void, contextAction: ((ThemeSettingsColorOption?, Bool, ASDisplayNode, ContextGesture?) -> Void)?, openColorPicker: @escaping (Bool) -> Void) -> ListViewItem {
|
||||||
switch self {
|
switch self {
|
||||||
case let .color(_, themeReference, accentColor, selected):
|
case let .color(_, themeReference, accentColor, selected):
|
||||||
return ThemeSettingsAccentColorIconItem(themeReference: themeReference, color: accentColor.flatMap { .accentColor($0) }, selected: selected, action: action, contextAction: contextAction)
|
return ThemeSettingsAccentColorIconItem(themeReference: themeReference, color: accentColor.flatMap { .accentColor($0) }, selected: selected, action: action, contextAction: contextAction)
|
||||||
@ -107,7 +107,7 @@ enum ThemeSettingsColorOption: Equatable {
|
|||||||
case let .accentColor(color):
|
case let .accentColor(color):
|
||||||
return color.baseColor.color
|
return color.baseColor.color
|
||||||
case .theme:
|
case .theme:
|
||||||
return nil
|
return .clear
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,9 +159,9 @@ private class ThemeSettingsAccentColorIconItem: ListViewItem {
|
|||||||
let color: ThemeSettingsColorOption?
|
let color: ThemeSettingsColorOption?
|
||||||
let selected: Bool
|
let selected: Bool
|
||||||
let action: (ThemeSettingsColorOption?, Bool) -> Void
|
let action: (ThemeSettingsColorOption?, Bool) -> Void
|
||||||
let contextAction: ((ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void)?
|
let contextAction: ((ThemeSettingsColorOption?, Bool, ASDisplayNode, ContextGesture?) -> Void)?
|
||||||
|
|
||||||
public init(themeReference: PresentationThemeReference, color: ThemeSettingsColorOption?, selected: Bool, action: @escaping (ThemeSettingsColorOption?, Bool) -> Void, contextAction: ((ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void)?) {
|
public init(themeReference: PresentationThemeReference, color: ThemeSettingsColorOption?, selected: Bool, action: @escaping (ThemeSettingsColorOption?, Bool) -> Void, contextAction: ((ThemeSettingsColorOption?, Bool, ASDisplayNode, ContextGesture?) -> Void)?) {
|
||||||
self.themeReference = themeReference
|
self.themeReference = themeReference
|
||||||
self.color = color
|
self.color = color
|
||||||
self.selected = selected
|
self.selected = selected
|
||||||
@ -307,7 +307,7 @@ private final class ThemeSettingsAccentColorIconItemNode : ListViewItemNode {
|
|||||||
gesture.cancel()
|
gesture.cancel()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
item.contextAction?(item.color, strongSelf.containerNode, gesture)
|
item.contextAction?(item.color, item.selected, strongSelf.containerNode, gesture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,6 +386,16 @@ private final class ThemeSettingsAccentColorIconItemNode : ListViewItemNode {
|
|||||||
topColor = UIColor(rgb: 0xe1ffc7)
|
topColor = UIColor(rgb: 0xe1ffc7)
|
||||||
bottomColor = topColor
|
bottomColor = topColor
|
||||||
}
|
}
|
||||||
|
} else if case .builtin(.nightAccent) = item.themeReference {
|
||||||
|
if let accentColor = item.color?.accentColor {
|
||||||
|
bottomColor = accentColor.withMultiplied(hue: 1.019, saturation: 0.731, brightness: 0.59)
|
||||||
|
topColor = bottomColor!.withMultiplied(hue: 0.966, saturation: 0.61, brightness: 0.98)
|
||||||
|
} else {
|
||||||
|
fillColor = UIColor(rgb: 0x2ea6ff)
|
||||||
|
strokeColor = fillColor
|
||||||
|
topColor = UIColor(rgb: 0x466f95)
|
||||||
|
bottomColor = topColor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.fillNode.image = generateFillImage(color: fillColor ?? .clear)
|
strongSelf.fillNode.image = generateFillImage(color: fillColor ?? .clear)
|
||||||
@ -593,16 +603,18 @@ class ThemeSettingsAccentColorItem: ListViewItem, ItemListItem {
|
|||||||
var sectionId: ItemListSectionId
|
var sectionId: ItemListSectionId
|
||||||
|
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
|
let generalThemeReference: PresentationThemeReference
|
||||||
let themeReference: PresentationThemeReference
|
let themeReference: PresentationThemeReference
|
||||||
let colors: [ThemeSettingsAccentColor]
|
let colors: [ThemeSettingsAccentColor]
|
||||||
let currentColor: ThemeSettingsColorOption?
|
let currentColor: ThemeSettingsColorOption?
|
||||||
let updated: (ThemeSettingsColorOption?) -> Void
|
let updated: (ThemeSettingsColorOption?) -> Void
|
||||||
let contextAction: ((PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void)?
|
let contextAction: ((Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void)?
|
||||||
let openColorPicker: (Bool) -> Void
|
let openColorPicker: (Bool) -> Void
|
||||||
let tag: ItemListItemTag?
|
let tag: ItemListItemTag?
|
||||||
|
|
||||||
init(theme: PresentationTheme, sectionId: ItemListSectionId, themeReference: PresentationThemeReference, colors: [ThemeSettingsAccentColor], currentColor: ThemeSettingsColorOption?, updated: @escaping (ThemeSettingsColorOption?) -> Void, contextAction: ((PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void)?, openColorPicker: @escaping (Bool) -> Void, tag: ItemListItemTag? = nil) {
|
init(theme: PresentationTheme, sectionId: ItemListSectionId, generalThemeReference: PresentationThemeReference, themeReference: PresentationThemeReference, colors: [ThemeSettingsAccentColor], currentColor: ThemeSettingsColorOption?, updated: @escaping (ThemeSettingsColorOption?) -> Void, contextAction: ((Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void)?, openColorPicker: @escaping (Bool) -> Void, tag: ItemListItemTag? = nil) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
|
self.generalThemeReference = generalThemeReference
|
||||||
self.themeReference = themeReference
|
self.themeReference = themeReference
|
||||||
self.colors = colors
|
self.colors = colors
|
||||||
self.currentColor = currentColor
|
self.currentColor = currentColor
|
||||||
@ -654,7 +666,7 @@ private struct ThemeSettingsAccentColorItemNodeTransition {
|
|||||||
let crossfade: Bool
|
let crossfade: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
private func preparedTransition(action: @escaping (ThemeSettingsColorOption?, Bool) -> Void, contextAction: ((ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void)?, openColorPicker: @escaping (Bool) -> Void, from fromEntries: [ThemeSettingsColorEntry], to toEntries: [ThemeSettingsColorEntry], crossfade: Bool) -> ThemeSettingsAccentColorItemNodeTransition {
|
private func preparedTransition(action: @escaping (ThemeSettingsColorOption?, Bool) -> Void, contextAction: ((ThemeSettingsColorOption?, Bool, ASDisplayNode, ContextGesture?) -> Void)?, openColorPicker: @escaping (Bool) -> Void, from fromEntries: [ThemeSettingsColorEntry], to toEntries: [ThemeSettingsColorEntry], crossfade: Bool) -> ThemeSettingsAccentColorItemNodeTransition {
|
||||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||||
|
|
||||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||||
@ -852,7 +864,7 @@ class ThemeSettingsAccentColorItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
switch color {
|
switch color {
|
||||||
case .default:
|
case .default:
|
||||||
let selected = item.currentColor == nil
|
let selected = item.currentColor == nil
|
||||||
entries.append(.color(index, item.themeReference, nil, selected))
|
entries.append(.color(index, item.generalThemeReference, nil, selected))
|
||||||
case let .color(color):
|
case let .color(color):
|
||||||
var selected = false
|
var selected = false
|
||||||
if let currentColor = item.currentColor, case let .accentColor(accentColor) = currentColor {
|
if let currentColor = item.currentColor, case let .accentColor(accentColor) = currentColor {
|
||||||
@ -866,9 +878,9 @@ class ThemeSettingsAccentColorItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
}
|
}
|
||||||
switch accentColor {
|
switch accentColor {
|
||||||
case let .accentColor(color):
|
case let .accentColor(color):
|
||||||
entries.append(.color(index, item.themeReference, color, selected))
|
entries.append(.color(index, item.generalThemeReference, color, selected))
|
||||||
case let .theme(theme):
|
case let .theme(theme):
|
||||||
entries.append(.theme(index, item.themeReference, theme, selected))
|
entries.append(.theme(index, item.generalThemeReference, theme, selected))
|
||||||
}
|
}
|
||||||
case let .preset(color), let .custom(color):
|
case let .preset(color), let .custom(color):
|
||||||
var selected = false
|
var selected = false
|
||||||
@ -881,7 +893,7 @@ class ThemeSettingsAccentColorItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
if let currentColor = item.currentColor {
|
if let currentColor = item.currentColor {
|
||||||
selected = currentColor.index == theme.index
|
selected = currentColor.index == theme.index
|
||||||
}
|
}
|
||||||
entries.append(.theme(index, item.themeReference, theme, selected))
|
entries.append(.theme(index, item.generalThemeReference, theme, selected))
|
||||||
}
|
}
|
||||||
|
|
||||||
index += 1
|
index += 1
|
||||||
@ -908,9 +920,9 @@ class ThemeSettingsAccentColorItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
ensureColorVisible(listNode: strongSelf.listNode, accentColor: color, animated: true)
|
ensureColorVisible(listNode: strongSelf.listNode, accentColor: color, animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let contextAction: ((ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void)? = { [weak item] color, node, gesture in
|
let contextAction: ((ThemeSettingsColorOption?, Bool, ASDisplayNode, ContextGesture?) -> Void)? = { [weak item] color, selected, node, gesture in
|
||||||
if let strongSelf = self, let item = strongSelf.item {
|
if let strongSelf = self, let item = strongSelf.item {
|
||||||
item.contextAction?(item.themeReference, color, node, gesture)
|
item.contextAction?(selected, item.themeReference, color, node, gesture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let openColorPicker: (Bool) -> Void = { [weak self] create in
|
let openColorPicker: (Bool) -> Void = { [weak self] create in
|
||||||
@ -920,7 +932,7 @@ class ThemeSettingsAccentColorItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let previousEntries = strongSelf.entries ?? []
|
let previousEntries = strongSelf.entries ?? []
|
||||||
let crossfade = previousEntries.count != entries.count || (currentItem != nil && currentItem?.themeReference.index != item.themeReference.index)
|
let crossfade = previousEntries.count != entries.count || (currentItem != nil && (currentItem?.generalThemeReference.index != item.generalThemeReference.index))
|
||||||
let transition = preparedTransition(action: action, contextAction: contextAction, openColorPicker: openColorPicker, from: previousEntries, to: entries, crossfade: crossfade)
|
let transition = preparedTransition(action: action, contextAction: contextAction, openColorPicker: openColorPicker, from: previousEntries, to: entries, crossfade: crossfade)
|
||||||
strongSelf.enqueueTransition(transition)
|
strongSelf.enqueueTransition(transition)
|
||||||
|
|
||||||
|
@ -81,9 +81,9 @@ private final class ThemeSettingsControllerArguments {
|
|||||||
let selectAppIcon: (String) -> Void
|
let selectAppIcon: (String) -> Void
|
||||||
let editTheme: (PresentationCloudTheme) -> Void
|
let editTheme: (PresentationCloudTheme) -> Void
|
||||||
let themeContextAction: (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void
|
let themeContextAction: (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void
|
||||||
let colorContextAction: (PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void
|
let colorContextAction: (Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void
|
||||||
|
|
||||||
init(context: AccountContext, selectTheme: @escaping (PresentationThemeReference) -> Void, selectFontSize: @escaping (PresentationFontSize) -> Void, openWallpaperSettings: @escaping () -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor?) -> Void, openAccentColorPicker: @escaping (PresentationThemeReference, Bool) -> Void, openAutoNightTheme: @escaping () -> Void, openTextSize: @escaping () -> Void, toggleLargeEmoji: @escaping (Bool) -> Void, disableAnimations: @escaping (Bool) -> Void, selectAppIcon: @escaping (String) -> Void, editTheme: @escaping (PresentationCloudTheme) -> Void, themeContextAction: @escaping (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void, colorContextAction: @escaping (PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void) {
|
init(context: AccountContext, selectTheme: @escaping (PresentationThemeReference) -> Void, selectFontSize: @escaping (PresentationFontSize) -> Void, openWallpaperSettings: @escaping () -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor?) -> Void, openAccentColorPicker: @escaping (PresentationThemeReference, Bool) -> Void, openAutoNightTheme: @escaping () -> Void, openTextSize: @escaping () -> Void, toggleLargeEmoji: @escaping (Bool) -> Void, disableAnimations: @escaping (Bool) -> Void, selectAppIcon: @escaping (String) -> Void, editTheme: @escaping (PresentationCloudTheme) -> Void, themeContextAction: @escaping (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void, colorContextAction: @escaping (Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.selectTheme = selectTheme
|
self.selectTheme = selectTheme
|
||||||
self.selectFontSize = selectFontSize
|
self.selectFontSize = selectFontSize
|
||||||
@ -133,7 +133,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
|||||||
case fontSize(PresentationTheme, PresentationFontSize)
|
case fontSize(PresentationTheme, PresentationFontSize)
|
||||||
case chatPreview(PresentationTheme, PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, [ChatPreviewMessageItem])
|
case chatPreview(PresentationTheme, PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, [ChatPreviewMessageItem])
|
||||||
case wallpaper(PresentationTheme, String)
|
case wallpaper(PresentationTheme, String)
|
||||||
case accentColor(PresentationTheme, PresentationThemeReference, PresentationThemeCustomColors?, [PresentationThemeReference], ThemeSettingsColorOption?)
|
case accentColor(PresentationTheme, PresentationThemeReference, PresentationThemeReference, PresentationThemeCustomColors?, [PresentationThemeReference], ThemeSettingsColorOption?)
|
||||||
case autoNightTheme(PresentationTheme, String, String)
|
case autoNightTheme(PresentationTheme, String, String)
|
||||||
case textSize(PresentationTheme, String, String)
|
case textSize(PresentationTheme, String, String)
|
||||||
case themeItem(PresentationTheme, PresentationStrings, [PresentationThemeReference], PresentationThemeReference, [Int64: PresentationThemeAccentColor], [Int64: TelegramWallpaper], PresentationThemeAccentColor?)
|
case themeItem(PresentationTheme, PresentationStrings, [PresentationThemeReference], PresentationThemeReference, [Int64: PresentationThemeAccentColor], [Int64: TelegramWallpaper], PresentationThemeAccentColor?)
|
||||||
@ -208,8 +208,8 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .accentColor(lhsTheme, lhsCurrentTheme, lhsCustomColors, lhsThemes, lhsColor):
|
case let .accentColor(lhsTheme, lhsGeneralTheme, lhsCurrentTheme, lhsCustomColors, lhsThemes, lhsColor):
|
||||||
if case let .accentColor(rhsTheme, rhsCurrentTheme, rhsCustomColors, rhsThemes, rhsColor) = rhs, lhsTheme === rhsTheme, lhsCurrentTheme == rhsCurrentTheme, lhsCustomColors == rhsCustomColors, lhsThemes == rhsThemes, lhsColor == rhsColor {
|
if case let .accentColor(rhsTheme, rhsGeneralTheme, rhsCurrentTheme, rhsCustomColors, rhsThemes, rhsColor) = rhs, lhsTheme === rhsTheme, lhsCurrentTheme == rhsCurrentTheme, lhsCustomColors == rhsCustomColors, lhsThemes == rhsThemes, lhsColor == rhsColor {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -308,20 +308,13 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
|||||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: "", sectionId: self.section, style: .blocks, action: {
|
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: "", sectionId: self.section, style: .blocks, action: {
|
||||||
arguments.openWallpaperSettings()
|
arguments.openWallpaperSettings()
|
||||||
})
|
})
|
||||||
case let .accentColor(theme, currentTheme, customColors, themes, color):
|
case let .accentColor(theme, generalThemeReference, currentTheme, customColors, themes, color):
|
||||||
var colorItems: [ThemeSettingsAccentColor] = []
|
var colorItems: [ThemeSettingsAccentColor] = []
|
||||||
|
|
||||||
for theme in themes {
|
for theme in themes {
|
||||||
colorItems.append(.theme(theme))
|
colorItems.append(.theme(theme))
|
||||||
}
|
}
|
||||||
|
|
||||||
let generalThemeReference: PresentationThemeReference
|
|
||||||
if case let .cloud(theme) = currentTheme, let settings = theme.theme.settings {
|
|
||||||
generalThemeReference = .builtin(PresentationBuiltinThemeReference(baseTheme: settings.baseTheme))
|
|
||||||
} else {
|
|
||||||
generalThemeReference = currentTheme
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultColor: PresentationThemeAccentColor? = PresentationThemeAccentColor(baseColor: .blue)
|
var defaultColor: PresentationThemeAccentColor? = PresentationThemeAccentColor(baseColor: .blue)
|
||||||
var colors = PresentationThemeBaseColor.allCases
|
var colors = PresentationThemeBaseColor.allCases
|
||||||
colors = colors.filter { $0 != .custom && $0 != .preset }
|
colors = colors.filter { $0 != .custom && $0 != .preset }
|
||||||
@ -334,28 +327,23 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
|||||||
return TelegramWallpaper.file(id: 0, accessHash: 0, isCreator: false, isDefault: true, isPattern: true, isDark: false, slug: slug, file: TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], immediateThumbnailData: nil, mimeType: "", size: nil, attributes: []), settings: WallpaperSettings(color: topColor, bottomColor: bottomColor, intensity: intensity ?? 50, rotation: rotation))
|
return TelegramWallpaper.file(id: 0, accessHash: 0, isCreator: false, isDefault: true, isPattern: true, isDark: false, slug: slug, file: TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], immediateThumbnailData: nil, mimeType: "", size: nil, attributes: []), settings: WallpaperSettings(color: topColor, bottomColor: bottomColor, intensity: intensity ?? 50, rotation: rotation))
|
||||||
}
|
}
|
||||||
|
|
||||||
colorItems.append(.preset(PresentationThemeAccentColor(index: 104, baseColor: .preset, accentColor: 0x5a9e29, bubbleColors: (0xdcf8c6, nil), wallpaper: patternWallpaper("R3j69wKskFIBAAAAoUdXWCKMzCM", 0xede6dd, nil, 50, nil))))
|
for preset in dayClassicColorPresets {
|
||||||
colorItems.append(.preset(PresentationThemeAccentColor(index: 106, baseColor: .preset, accentColor: 0xf55783, bubbleColors: (0xd6f5ff, nil), wallpaper: patternWallpaper("p-pXcflrmFIBAAAAvXYQk-mCwZU", 0xfce3ec, nil, 40, nil))))
|
colorItems.append(.preset(preset))
|
||||||
colorItems.append(.preset(PresentationThemeAccentColor(index: 101, baseColor: .preset, accentColor: 0x7e5fe5, bubbleColors: (0xf5e2ff, nil), wallpaper: patternWallpaper("nQcFYJe1mFIBAAAAcI95wtIK0fk", 0xfcccf4, 0xae85f0, 54, nil))))
|
}
|
||||||
colorItems.append(.preset(PresentationThemeAccentColor(index: 102, baseColor: .preset, accentColor: 0xff5fa9, bubbleColors: (0xfff4d7, nil), wallpaper: patternWallpaper("51nnTjx8mFIBAAAAaFGJsMIvWkk", 0xf6b594, 0xebf6cd, 46, 45))))
|
|
||||||
colorItems.append(.preset(PresentationThemeAccentColor(index: 103, baseColor: .preset, accentColor: 0x199972, bubbleColors: (0xfffec7, nil), wallpaper: patternWallpaper("fqv01SQemVIBAAAApND8LDRUhRU", 0xc1e7cb, nil, 50, nil))))
|
|
||||||
colorItems.append(.preset(PresentationThemeAccentColor(index: 105, baseColor: .preset, accentColor: 0x009eee, bubbleColors: (0x94fff9, 0xccffc7), wallpaper: patternWallpaper("p-pXcflrmFIBAAAAvXYQk-mCwZU", 0xffbca6, 0xff63bd, 57, 225))))
|
|
||||||
} else if name == .day {
|
} else if name == .day {
|
||||||
colorItems.append(.color(.blue))
|
colorItems.append(.color(.blue))
|
||||||
colors = colors.filter { $0 != .blue }
|
colors = colors.filter { $0 != .blue }
|
||||||
|
|
||||||
colorItems.append(.preset(PresentationThemeAccentColor(index: 101, baseColor: .preset, accentColor: 0x007aff, bubbleColors: (0x007aff, 0xff53f4), wallpaper: nil)))
|
for preset in dayColorPresets {
|
||||||
colorItems.append(.preset(PresentationThemeAccentColor(index: 102, baseColor: .preset, accentColor: 0x00b09b, bubbleColors: (0xaee946, 0x00b09b), wallpaper: nil)))
|
colorItems.append(.preset(preset))
|
||||||
colorItems.append(.preset(PresentationThemeAccentColor(index: 103, baseColor: .preset, accentColor: 0xd33213, bubbleColors: (0xf9db00, 0xd33213), wallpaper: nil)))
|
}
|
||||||
colorItems.append(.preset(PresentationThemeAccentColor(index: 104, baseColor: .preset, accentColor: 0xea8ced, bubbleColors: (0xea8ced, 0x00c2ed), wallpaper: nil)))
|
|
||||||
} else if name == .night {
|
} else if name == .night {
|
||||||
colorItems.append(.color(.blue))
|
colorItems.append(.color(.blue))
|
||||||
colors = colors.filter { $0 != .blue }
|
colors = colors.filter { $0 != .blue }
|
||||||
|
|
||||||
colorItems.append(.preset(PresentationThemeAccentColor(index: 101, baseColor: .preset, accentColor: 0x007aff, bubbleColors: (0x007aff, 0xff53f4), wallpaper: nil)))
|
for preset in nightColorPresets {
|
||||||
colorItems.append(.preset(PresentationThemeAccentColor(index: 102, baseColor: .preset, accentColor: 0x00b09b, bubbleColors: (0xaee946, 0x00b09b), wallpaper: nil)))
|
colorItems.append(.preset(preset))
|
||||||
colorItems.append(.preset(PresentationThemeAccentColor(index: 103, baseColor: .preset, accentColor: 0xd33213, bubbleColors: (0xf9db00, 0xd33213), wallpaper: nil)))
|
}
|
||||||
colorItems.append(.preset(PresentationThemeAccentColor(index: 104, baseColor: .preset, accentColor: 0xea8ced, bubbleColors: (0xea8ced, 0x00c2ed), wallpaper: nil)))
|
|
||||||
}
|
}
|
||||||
if name != .day {
|
if name != .day {
|
||||||
colors = colors.filter { $0 != .black }
|
colors = colors.filter { $0 != .black }
|
||||||
@ -371,14 +359,14 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
|||||||
colorItems.append(contentsOf: colors.map { .color($0) })
|
colorItems.append(contentsOf: colors.map { .color($0) })
|
||||||
|
|
||||||
if let customColors = customColors {
|
if let customColors = customColors {
|
||||||
colorItems.insert(contentsOf: customColors.colors.reversed().map { .custom($0) }, at: 0)
|
// colorItems.insert(contentsOf: customColors.colors.reversed().map { .custom($0) }, at: 0)
|
||||||
} else {
|
} else {
|
||||||
// if let currentColor = currentColor, currentColor.baseColor == .custom {
|
// if let currentColor = currentColor, currentColor.baseColor == .custom {
|
||||||
// colorItems.insert(.custom(currentColor), at: 0)
|
// colorItems.insert(.custom(currentColor), at: 0)
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
return ThemeSettingsAccentColorItem(theme: theme, sectionId: self.section, themeReference: currentTheme, colors: colorItems, currentColor: currentColor, updated: { color in
|
return ThemeSettingsAccentColorItem(theme: theme, sectionId: self.section, generalThemeReference: generalThemeReference, themeReference: currentTheme, colors: colorItems, currentColor: currentColor, updated: { color in
|
||||||
if let color = color {
|
if let color = color {
|
||||||
switch color {
|
switch color {
|
||||||
case let .accentColor(color):
|
case let .accentColor(color):
|
||||||
@ -389,10 +377,10 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
arguments.selectAccentColor(nil)
|
arguments.selectAccentColor(nil)
|
||||||
}
|
}
|
||||||
}, contextAction: { theme, color, node, gesture in
|
}, contextAction: { isCurrent, theme, color, node, gesture in
|
||||||
arguments.colorContextAction(theme, color, node, gesture)
|
arguments.colorContextAction(isCurrent, theme, color, node, gesture)
|
||||||
}, openColorPicker: { create in
|
}, openColorPicker: { create in
|
||||||
arguments.openAccentColorPicker(generalThemeReference, create)
|
arguments.openAccentColorPicker(currentTheme, create)
|
||||||
}, tag: ThemeSettingsEntryTag.accentColor)
|
}, tag: ThemeSettingsEntryTag.accentColor)
|
||||||
case let .autoNightTheme(theme, text, value):
|
case let .autoNightTheme(theme, text, value):
|
||||||
return ItemListDisclosureItem(presentationData: presentationData, icon: nil, title: text, label: value, labelStyle: .text, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
return ItemListDisclosureItem(presentationData: presentationData, icon: nil, title: text, label: value, labelStyle: .text, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||||
@ -479,7 +467,7 @@ private func themeSettingsControllerEntries(presentationData: PresentationData,
|
|||||||
colorOption = .theme(themeReference)
|
colorOption = .theme(themeReference)
|
||||||
}
|
}
|
||||||
|
|
||||||
entries.append(.accentColor(presentationData.theme, themeReference, presentationThemeSettings.themeSpecificCustomColors[themeReference.index], colorThemes, colorOption))
|
entries.append(.accentColor(presentationData.theme, generalThemeReference, themeReference, presentationThemeSettings.themeSpecificCustomColors[generalThemeReference.index], colorThemes, colorOption))
|
||||||
}
|
}
|
||||||
|
|
||||||
entries.append(.wallpaper(presentationData.theme, strings.Settings_ChatBackground))
|
entries.append(.wallpaper(presentationData.theme, strings.Settings_ChatBackground))
|
||||||
@ -615,18 +603,27 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||||||
generalThemeReference = currentTheme
|
generalThemeReference = currentTheme
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let theme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: generalThemeReference, accentColor: accentColor?.color) else {
|
currentTheme = generalThemeReference
|
||||||
|
var updatedTheme = current.theme
|
||||||
|
var updatedAutomaticThemeSwitchSetting = current.automaticThemeSwitchSetting
|
||||||
|
|
||||||
|
if autoNightModeTriggered {
|
||||||
|
var updatedAutomaticThemeSwitchSetting = current.automaticThemeSwitchSetting
|
||||||
|
updatedAutomaticThemeSwitchSetting.theme = generalThemeReference
|
||||||
|
} else {
|
||||||
|
updatedTheme = generalThemeReference
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let theme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: generalThemeReference, accentColor: accentColor?.color, wallpaper: presetWallpaper) else {
|
||||||
return current
|
return current
|
||||||
}
|
}
|
||||||
|
|
||||||
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
||||||
var themeSpecificAccentColors = current.themeSpecificAccentColors
|
var themeSpecificAccentColors = current.themeSpecificAccentColors
|
||||||
themeSpecificAccentColors[generalThemeReference.index] = accentColor
|
themeSpecificAccentColors[generalThemeReference.index] = accentColor?.withUpdatedWallpaper(presetWallpaper)
|
||||||
|
|
||||||
if case let .builtin(theme) = generalThemeReference {
|
if case let .builtin(theme) = generalThemeReference {
|
||||||
if let wallpaper = presetWallpaper, let color = accentColor {
|
if let wallpaper = current.themeSpecificChatWallpapers[coloredThemeIndex(reference: currentTheme, accentColor: accentColor)], wallpaper.isColorOrGradient || wallpaper.isPattern || wallpaper.isBuiltin {
|
||||||
themeSpecificChatWallpapers[coloredThemeIndex(reference: currentTheme, accentColor: color)] = wallpaper
|
|
||||||
} else if let wallpaper = current.themeSpecificChatWallpapers[currentTheme.index], wallpaper.isColorOrGradient || wallpaper.isPattern || wallpaper.isBuiltin {
|
|
||||||
themeSpecificChatWallpapers[currentTheme.index] = nil
|
themeSpecificChatWallpapers[currentTheme.index] = nil
|
||||||
if let accentColor = accentColor {
|
if let accentColor = accentColor {
|
||||||
themeSpecificChatWallpapers[coloredThemeIndex(reference: currentTheme, accentColor: accentColor)] = nil
|
themeSpecificChatWallpapers[coloredThemeIndex(reference: currentTheme, accentColor: accentColor)] = nil
|
||||||
@ -634,7 +631,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return PresentationThemeSettings(theme: current.theme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificCustomColors: current.themeSpecificCustomColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
return PresentationThemeSettings(theme: updatedTheme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificCustomColors: current.themeSpecificCustomColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, automaticThemeSwitchSetting: updatedAutomaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||||
}).start()
|
}).start()
|
||||||
|
|
||||||
presentCrossfadeControllerImpl?(true)
|
presentCrossfadeControllerImpl?(true)
|
||||||
@ -828,7 +825,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||||||
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: themeController, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture)
|
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: themeController, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture)
|
||||||
presentInGlobalOverlayImpl?(contextController, nil)
|
presentInGlobalOverlayImpl?(contextController, nil)
|
||||||
})
|
})
|
||||||
}, colorContextAction: { reference, accentColor, node, gesture in
|
}, colorContextAction: { isCurrent, reference, accentColor, node, gesture in
|
||||||
let _ = (context.sharedContext.accountManager.transaction { transaction -> (ThemeSettingsColorOption?, TelegramWallpaper?) in
|
let _ = (context.sharedContext.accountManager.transaction { transaction -> (ThemeSettingsColorOption?, TelegramWallpaper?) in
|
||||||
let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings) as? PresentationThemeSettings ?? PresentationThemeSettings.defaultSettings
|
let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings) as? PresentationThemeSettings ?? PresentationThemeSettings.defaultSettings
|
||||||
var wallpaper: TelegramWallpaper?
|
var wallpaper: TelegramWallpaper?
|
||||||
@ -849,6 +846,13 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||||||
}
|
}
|
||||||
return (accentColor, wallpaper)
|
return (accentColor, wallpaper)
|
||||||
} |> mapToSignal { accentColor, wallpaper -> Signal<(PresentationTheme?, TelegramWallpaper?), NoError> in
|
} |> mapToSignal { accentColor, wallpaper -> Signal<(PresentationTheme?, TelegramWallpaper?), NoError> in
|
||||||
|
let generalThemeReference: PresentationThemeReference
|
||||||
|
if let accentColor = accentColor, case let .cloud(theme) = reference, let settings = theme.theme.settings {
|
||||||
|
generalThemeReference = .builtin(PresentationBuiltinThemeReference(baseTheme: settings.baseTheme))
|
||||||
|
} else {
|
||||||
|
generalThemeReference = reference
|
||||||
|
}
|
||||||
|
|
||||||
let effectiveWallpaper: TelegramWallpaper
|
let effectiveWallpaper: TelegramWallpaper
|
||||||
if let wallpaper = wallpaper {
|
if let wallpaper = wallpaper {
|
||||||
effectiveWallpaper = wallpaper
|
effectiveWallpaper = wallpaper
|
||||||
@ -857,16 +861,30 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||||||
if let accentColor = accentColor, case let .theme(themeReference) = accentColor {
|
if let accentColor = accentColor, case let .theme(themeReference) = accentColor {
|
||||||
theme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: themeReference)
|
theme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: themeReference)
|
||||||
} else {
|
} else {
|
||||||
theme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: reference, accentColor: accentColor?.accentColor, bubbleColors: accentColor?.customBubbleColors)
|
theme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: generalThemeReference, accentColor: accentColor?.accentColor, bubbleColors: accentColor?.customBubbleColors)
|
||||||
}
|
}
|
||||||
effectiveWallpaper = theme?.chat.defaultWallpaper ?? .builtin(WallpaperSettings())
|
effectiveWallpaper = theme?.chat.defaultWallpaper ?? .builtin(WallpaperSettings())
|
||||||
}
|
}
|
||||||
return chatServiceBackgroundColor(wallpaper: effectiveWallpaper, mediaBox: context.sharedContext.accountManager.mediaBox)
|
|
||||||
|
let wallpaperSignal: Signal<TelegramWallpaper, NoError>
|
||||||
|
if case let .file(file) = effectiveWallpaper, file.id == 0 {
|
||||||
|
wallpaperSignal = cachedWallpaper(account: context.account, slug: file.slug, settings: file.settings)
|
||||||
|
|> map { cachedWallpaper in
|
||||||
|
return cachedWallpaper?.wallpaper ?? effectiveWallpaper
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wallpaperSignal = .single(effectiveWallpaper)
|
||||||
|
}
|
||||||
|
|
||||||
|
return wallpaperSignal
|
||||||
|
|> mapToSignal { wallpaper in
|
||||||
|
return chatServiceBackgroundColor(wallpaper: wallpaper, mediaBox: context.sharedContext.accountManager.mediaBox)
|
||||||
|
}
|
||||||
|> map { serviceBackgroundColor in
|
|> map { serviceBackgroundColor in
|
||||||
if let accentColor = accentColor, case let .theme(themeReference) = accentColor {
|
if let accentColor = accentColor, case let .theme(themeReference) = accentColor {
|
||||||
return (makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: themeReference, serviceBackgroundColor: serviceBackgroundColor), wallpaper)
|
return (makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: themeReference, serviceBackgroundColor: serviceBackgroundColor), wallpaper)
|
||||||
} else {
|
} else {
|
||||||
return (makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: reference, accentColor: accentColor?.accentColor, bubbleColors: accentColor?.customBubbleColors, serviceBackgroundColor: serviceBackgroundColor), wallpaper)
|
return (makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: generalThemeReference, accentColor: accentColor?.accentColor, bubbleColors: accentColor?.customBubbleColors, serviceBackgroundColor: serviceBackgroundColor), wallpaper)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -882,6 +900,99 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||||||
|
|
||||||
if let accentColor = accentColor {
|
if let accentColor = accentColor {
|
||||||
if case let .accentColor(color) = accentColor, color.baseColor != .custom {
|
if case let .accentColor(color) = accentColor, color.baseColor != .custom {
|
||||||
|
} else if case let .theme(theme) = accentColor, case let .cloud(cloudTheme) = theme {
|
||||||
|
if cloudTheme.theme.isCreator {
|
||||||
|
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_EditTheme, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ApplyTheme"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||||
|
let controller = editThemeController(context: context, mode: .edit(cloudTheme), navigateToChat: { peerId in
|
||||||
|
if let navigationController = getNavigationControllerImpl?() {
|
||||||
|
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
c.dismiss(completion: {
|
||||||
|
pushControllerImpl?(controller)
|
||||||
|
})
|
||||||
|
})))
|
||||||
|
} else {
|
||||||
|
items.append(.action(ContextMenuActionItem(text: strings.Theme_Context_ChangeColors, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ApplyTheme"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||||
|
guard let theme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: reference, preview: false) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let resolvedWallpaper: Signal<TelegramWallpaper, NoError>
|
||||||
|
if case let .file(file) = theme.chat.defaultWallpaper, file.id == 0 {
|
||||||
|
resolvedWallpaper = cachedWallpaper(account: context.account, slug: file.slug, settings: file.settings)
|
||||||
|
|> map { cachedWallpaper -> TelegramWallpaper in
|
||||||
|
return cachedWallpaper?.wallpaper ?? theme.chat.defaultWallpaper
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resolvedWallpaper = .single(theme.chat.defaultWallpaper)
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = (resolvedWallpaper
|
||||||
|
|> deliverOnMainQueue).start(next: { wallpaper in
|
||||||
|
let controller = ThemeAccentColorController(context: context, mode: .edit(theme: theme, wallpaper: wallpaper, defaultThemeReference: nil, create: true, completion: { result, settings in
|
||||||
|
let controller = editThemeController(context: context, mode: .create(result, nil), navigateToChat: { peerId in
|
||||||
|
if let navigationController = getNavigationControllerImpl?() {
|
||||||
|
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
updateControllersImpl?({ controllers in
|
||||||
|
var controllers = controllers
|
||||||
|
controllers = controllers.filter { controller in
|
||||||
|
if controller is ThemeAccentColorController {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
controllers.append(controller)
|
||||||
|
return controllers
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
|
||||||
|
c.dismiss(completion: {
|
||||||
|
pushControllerImpl?(controller)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_ShareTheme, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Share"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||||
|
c.dismiss(completion: {
|
||||||
|
let controller = ShareController(context: context, subject: .url("https://t.me/addtheme/\(cloudTheme.theme.slug)"), preferredAction: .default)
|
||||||
|
presentControllerImpl?(controller, nil)
|
||||||
|
})
|
||||||
|
})))
|
||||||
|
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_RemoveTheme, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { c, f in
|
||||||
|
c.dismiss(completion: {
|
||||||
|
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||||
|
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 currentThemeIndex = themes.firstIndex(where: { $0.id == cloudTheme.theme.id }) {
|
||||||
|
let previousThemeIndex = themes.prefix(upTo: currentThemeIndex).reversed().firstIndex(where: { $0.file != nil })
|
||||||
|
let newTheme: PresentationThemeReference
|
||||||
|
if let previousThemeIndex = previousThemeIndex {
|
||||||
|
newTheme = .cloud(PresentationCloudTheme(theme: themes[themes.index(before: previousThemeIndex.base)], resolvedWallpaper: nil))
|
||||||
|
} else {
|
||||||
|
newTheme = .builtin(.nightAccent)
|
||||||
|
}
|
||||||
|
selectThemeImpl?(newTheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = deleteThemeInteractively(account: context.account, accountManager: context.sharedContext.accountManager, theme: cloudTheme.theme).start()
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||||
|
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||||
|
actionSheet?.dismissAnimated()
|
||||||
|
})
|
||||||
|
])])
|
||||||
|
presentControllerImpl?(actionSheet, nil)
|
||||||
|
})
|
||||||
|
})))
|
||||||
} else {
|
} else {
|
||||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_ShareThemeColor, textColor: .primary, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Share"), color: theme.contextMenu.primaryColor)
|
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_ShareThemeColor, textColor: .primary, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Share"), color: theme.contextMenu.primaryColor)
|
||||||
}, action: { c, f in
|
}, action: { c, f in
|
||||||
@ -1118,7 +1229,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||||||
})
|
})
|
||||||
}).start()
|
}).start()
|
||||||
|
|
||||||
presentCrossfadeControllerImpl?(cloudTheme == nil)
|
presentCrossfadeControllerImpl?(cloudTheme == nil || cloudTheme?.settings != nil)
|
||||||
}
|
}
|
||||||
moreImpl = {
|
moreImpl = {
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
@ -602,10 +602,7 @@ class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
}
|
}
|
||||||
let title = themeDisplayName(strings: item.strings, reference: theme)
|
let title = themeDisplayName(strings: item.strings, reference: theme)
|
||||||
let accentColor = item.themeSpecificAccentColors[theme.index]
|
let accentColor = item.themeSpecificAccentColors[theme.index]
|
||||||
var wallpaper: TelegramWallpaper?
|
let wallpaper = accentColor?.wallpaper
|
||||||
if let accentColor = accentColor {
|
|
||||||
wallpaper = item.themeSpecificChatWallpapers[coloredThemeIndex(reference: theme, accentColor: accentColor)]
|
|
||||||
}
|
|
||||||
entries.append(ThemeSettingsThemeEntry(index: index, themeReference: theme, title: title, accentColor: accentColor, selected: item.currentTheme.index == theme.index, theme: item.theme, wallpaper: wallpaper))
|
entries.append(ThemeSettingsThemeEntry(index: index, themeReference: theme, title: title, accentColor: accentColor, selected: item.currentTheme.index == theme.index, theme: item.theme, wallpaper: wallpaper))
|
||||||
index += 1
|
index += 1
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,74 @@
|
|||||||
import Postbox
|
import Postbox
|
||||||
|
|
||||||
|
private enum TelegramMediaWebpageAttributeTypes: Int32 {
|
||||||
|
case unsupported
|
||||||
|
case theme
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TelegramMediaWebpageAttribute: PostboxCoding, Equatable {
|
||||||
|
case unsupported
|
||||||
|
case theme(TelegraMediaWebpageThemeAttribute)
|
||||||
|
|
||||||
|
public init(decoder: PostboxDecoder) {
|
||||||
|
switch decoder.decodeInt32ForKey("r", orElse: 0) {
|
||||||
|
case TelegramMediaWebpageAttributeTypes.theme.rawValue:
|
||||||
|
self = .theme(decoder.decodeObjectForKey("a", decoder: { TelegraMediaWebpageThemeAttribute(decoder: $0) }) as! TelegraMediaWebpageThemeAttribute)
|
||||||
|
default:
|
||||||
|
self = .unsupported
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
|
switch self {
|
||||||
|
case .unsupported:
|
||||||
|
encoder.encodeInt32(TelegramMediaWebpageAttributeTypes.unsupported.rawValue, forKey: "r")
|
||||||
|
case let .theme(attribute):
|
||||||
|
encoder.encodeInt32(TelegramMediaWebpageAttributeTypes.theme.rawValue, forKey: "r")
|
||||||
|
encoder.encodeObject(attribute, forKey: "a")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class TelegraMediaWebpageThemeAttribute: PostboxCoding, Equatable {
|
||||||
|
public static func == (lhs: TelegraMediaWebpageThemeAttribute, rhs: TelegraMediaWebpageThemeAttribute) -> Bool {
|
||||||
|
if lhs.settings != rhs.settings {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.files.count != rhs.files.count {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
for i in 0 ..< lhs.files.count {
|
||||||
|
if !lhs.files[i].isEqual(to: rhs.files[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
public let files: [TelegramMediaFile]
|
||||||
|
public let settings: TelegramThemeSettings?
|
||||||
|
|
||||||
|
public init(files: [TelegramMediaFile], settings: TelegramThemeSettings?) {
|
||||||
|
self.files = files
|
||||||
|
self.settings = settings
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(decoder: PostboxDecoder) {
|
||||||
|
self.files = decoder.decodeObjectArrayForKey("files")
|
||||||
|
self.settings = decoder.decodeObjectForKey("settings", decoder: { TelegramThemeSettings(decoder: $0) }) as? TelegramThemeSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
|
encoder.encodeObjectArray(self.files, forKey: "files")
|
||||||
|
if let settings = self.settings {
|
||||||
|
encoder.encodeObject(settings, forKey: "settings")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "settings")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final class TelegramMediaWebpageLoadedContent: PostboxCoding, Equatable {
|
public final class TelegramMediaWebpageLoadedContent: PostboxCoding, Equatable {
|
||||||
public let url: String
|
public let url: String
|
||||||
public let displayUrl: String
|
public let displayUrl: String
|
||||||
@ -16,10 +85,10 @@ public final class TelegramMediaWebpageLoadedContent: PostboxCoding, Equatable {
|
|||||||
|
|
||||||
public let image: TelegramMediaImage?
|
public let image: TelegramMediaImage?
|
||||||
public let file: TelegramMediaFile?
|
public let file: TelegramMediaFile?
|
||||||
public let files: [TelegramMediaFile]?
|
public let attributes: [TelegramMediaWebpageAttribute]
|
||||||
public let instantPage: InstantPage?
|
public let instantPage: InstantPage?
|
||||||
|
|
||||||
public init(url: String, displayUrl: String, hash: Int32, type: String?, websiteName: String?, title: String?, text: String?, embedUrl: String?, embedType: String?, embedSize: PixelDimensions?, duration: Int?, author: String?, image: TelegramMediaImage?, file: TelegramMediaFile?, files: [TelegramMediaFile]?, instantPage: InstantPage?) {
|
public init(url: String, displayUrl: String, hash: Int32, type: String?, websiteName: String?, title: String?, text: String?, embedUrl: String?, embedType: String?, embedSize: PixelDimensions?, duration: Int?, author: String?, image: TelegramMediaImage?, file: TelegramMediaFile?, attributes: [TelegramMediaWebpageAttribute], instantPage: InstantPage?) {
|
||||||
self.url = url
|
self.url = url
|
||||||
self.displayUrl = displayUrl
|
self.displayUrl = displayUrl
|
||||||
self.hash = hash
|
self.hash = hash
|
||||||
@ -34,7 +103,7 @@ public final class TelegramMediaWebpageLoadedContent: PostboxCoding, Equatable {
|
|||||||
self.author = author
|
self.author = author
|
||||||
self.image = image
|
self.image = image
|
||||||
self.file = file
|
self.file = file
|
||||||
self.files = files
|
self.attributes = attributes
|
||||||
self.instantPage = instantPage
|
self.instantPage = instantPage
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +141,14 @@ public final class TelegramMediaWebpageLoadedContent: PostboxCoding, Equatable {
|
|||||||
self.file = nil
|
self.file = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
self.files = decoder.decodeOptionalObjectArrayWithDecoderForKey("fis")
|
var effectiveAttributes: [TelegramMediaWebpageAttribute] = []
|
||||||
|
if let attributes = decoder.decodeObjectArrayWithDecoderForKey("attr") as [TelegramMediaWebpageAttribute]? {
|
||||||
|
effectiveAttributes.append(contentsOf: attributes)
|
||||||
|
}
|
||||||
|
if let legacyFiles = decoder.decodeOptionalObjectArrayWithDecoderForKey("fis") as [TelegramMediaFile]? {
|
||||||
|
effectiveAttributes.append(.theme(TelegraMediaWebpageThemeAttribute(files: legacyFiles, settings: nil)))
|
||||||
|
}
|
||||||
|
self.attributes = effectiveAttributes
|
||||||
|
|
||||||
if let instantPage = decoder.decodeObjectForKey("ip", decoder: { InstantPage(decoder: $0) }) as? InstantPage {
|
if let instantPage = decoder.decodeObjectForKey("ip", decoder: { InstantPage(decoder: $0) }) as? InstantPage {
|
||||||
self.instantPage = instantPage
|
self.instantPage = instantPage
|
||||||
@ -142,11 +218,9 @@ public final class TelegramMediaWebpageLoadedContent: PostboxCoding, Equatable {
|
|||||||
} else {
|
} else {
|
||||||
encoder.encodeNil(forKey: "fi")
|
encoder.encodeNil(forKey: "fi")
|
||||||
}
|
}
|
||||||
if let files = self.files {
|
|
||||||
encoder.encodeObjectArray(files, forKey: "fis")
|
encoder.encodeObjectArray(self.attributes, forKey: "attr")
|
||||||
} else {
|
|
||||||
encoder.encodeNil(forKey: "fis")
|
|
||||||
}
|
|
||||||
if let instantPage = self.instantPage {
|
if let instantPage = self.instantPage {
|
||||||
encoder.encodeObject(instantPage, forKey: "ip")
|
encoder.encodeObject(instantPage, forKey: "ip")
|
||||||
} else {
|
} else {
|
||||||
@ -187,19 +261,15 @@ public func ==(lhs: TelegramMediaWebpageLoadedContent, rhs: TelegramMediaWebpage
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if let lhsFiles = lhs.files, let rhsFiles = rhs.files {
|
if lhs.attributes.count != rhs.attributes.count {
|
||||||
if lhsFiles.count != rhsFiles.count {
|
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
for i in 0 ..< lhsFiles.count {
|
for i in 0 ..< lhs.attributes.count {
|
||||||
if !lhsFiles[i].isEqual(to: rhsFiles[i]) {
|
if lhs.attributes[i] != rhs.attributes[i] {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (lhs.files == nil) != (rhs.files == nil) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if lhs.instantPage != rhs.instantPage {
|
if lhs.instantPage != rhs.instantPage {
|
||||||
return false
|
return false
|
||||||
|
@ -306,7 +306,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-350980120] = { return Api.WebPage.parse_webPageEmpty($0) }
|
dict[-350980120] = { return Api.WebPage.parse_webPageEmpty($0) }
|
||||||
dict[-981018084] = { return Api.WebPage.parse_webPagePending($0) }
|
dict[-981018084] = { return Api.WebPage.parse_webPagePending($0) }
|
||||||
dict[-2054908813] = { return Api.WebPage.parse_webPageNotModified($0) }
|
dict[-2054908813] = { return Api.WebPage.parse_webPageNotModified($0) }
|
||||||
dict[-94051982] = { return Api.WebPage.parse_webPage($0) }
|
dict[-392411726] = { return Api.WebPage.parse_webPage($0) }
|
||||||
dict[1036876423] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageText($0) }
|
dict[1036876423] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageText($0) }
|
||||||
dict[-190472735] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaGeo($0) }
|
dict[-190472735] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaGeo($0) }
|
||||||
dict[1262639204] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageGame($0) }
|
dict[1262639204] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageGame($0) }
|
||||||
@ -600,6 +600,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-1118798639] = { return Api.InputThemeSettings.parse_inputThemeSettings($0) }
|
dict[-1118798639] = { return Api.InputThemeSettings.parse_inputThemeSettings($0) }
|
||||||
dict[1251549527] = { return Api.InputStickeredMedia.parse_inputStickeredMediaPhoto($0) }
|
dict[1251549527] = { return Api.InputStickeredMedia.parse_inputStickeredMediaPhoto($0) }
|
||||||
dict[70813275] = { return Api.InputStickeredMedia.parse_inputStickeredMediaDocument($0) }
|
dict[70813275] = { return Api.InputStickeredMedia.parse_inputStickeredMediaDocument($0) }
|
||||||
|
dict[1421174295] = { return Api.WebPageAttribute.parse_webPageAttributeTheme($0) }
|
||||||
dict[82699215] = { return Api.messages.FeaturedStickers.parse_featuredStickersNotModified($0) }
|
dict[82699215] = { return Api.messages.FeaturedStickers.parse_featuredStickersNotModified($0) }
|
||||||
dict[-123893531] = { return Api.messages.FeaturedStickers.parse_featuredStickers($0) }
|
dict[-123893531] = { return Api.messages.FeaturedStickers.parse_featuredStickers($0) }
|
||||||
dict[1375940666] = { return Api.auth.LoginTokenInfo.parse_loginTokenInfo($0) }
|
dict[1375940666] = { return Api.auth.LoginTokenInfo.parse_loginTokenInfo($0) }
|
||||||
@ -1258,6 +1259,8 @@ public struct Api {
|
|||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.InputStickeredMedia:
|
case let _1 as Api.InputStickeredMedia:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
|
case let _1 as Api.WebPageAttribute:
|
||||||
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.messages.FeaturedStickers:
|
case let _1 as Api.messages.FeaturedStickers:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.auth.LoginTokenInfo:
|
case let _1 as Api.auth.LoginTokenInfo:
|
||||||
|
@ -9227,7 +9227,7 @@ public extension Api {
|
|||||||
case webPageEmpty(id: Int64)
|
case webPageEmpty(id: Int64)
|
||||||
case webPagePending(id: Int64, date: Int32)
|
case webPagePending(id: Int64, date: Int32)
|
||||||
case webPageNotModified
|
case webPageNotModified
|
||||||
case webPage(flags: Int32, id: Int64, url: String, displayUrl: String, hash: Int32, type: String?, siteName: String?, title: String?, description: String?, photo: Api.Photo?, embedUrl: String?, embedType: String?, embedWidth: Int32?, embedHeight: Int32?, duration: Int32?, author: String?, document: Api.Document?, documents: [Api.Document]?, cachedPage: Api.Page?)
|
case webPage(flags: Int32, id: Int64, url: String, displayUrl: String, hash: Int32, type: String?, siteName: String?, title: String?, description: String?, photo: Api.Photo?, embedUrl: String?, embedType: String?, embedWidth: Int32?, embedHeight: Int32?, duration: Int32?, author: String?, document: Api.Document?, cachedPage: Api.Page?, attributes: [Api.WebPageAttribute]?)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
@ -9250,9 +9250,9 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
case .webPage(let flags, let id, let url, let displayUrl, let hash, let type, let siteName, let title, let description, let photo, let embedUrl, let embedType, let embedWidth, let embedHeight, let duration, let author, let document, let documents, let cachedPage):
|
case .webPage(let flags, let id, let url, let displayUrl, let hash, let type, let siteName, let title, let description, let photo, let embedUrl, let embedType, let embedWidth, let embedHeight, let duration, let author, let document, let cachedPage, let attributes):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-94051982)
|
buffer.appendInt32(-392411726)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeInt64(id, buffer: buffer, boxed: false)
|
serializeInt64(id, buffer: buffer, boxed: false)
|
||||||
@ -9271,12 +9271,12 @@ public extension Api {
|
|||||||
if Int(flags) & Int(1 << 7) != 0 {serializeInt32(duration!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 7) != 0 {serializeInt32(duration!, buffer: buffer, boxed: false)}
|
||||||
if Int(flags) & Int(1 << 8) != 0 {serializeString(author!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 8) != 0 {serializeString(author!, buffer: buffer, boxed: false)}
|
||||||
if Int(flags) & Int(1 << 9) != 0 {document!.serialize(buffer, true)}
|
if Int(flags) & Int(1 << 9) != 0 {document!.serialize(buffer, true)}
|
||||||
if Int(flags) & Int(1 << 11) != 0 {buffer.appendInt32(481674261)
|
if Int(flags) & Int(1 << 10) != 0 {cachedPage!.serialize(buffer, true)}
|
||||||
buffer.appendInt32(Int32(documents!.count))
|
if Int(flags) & Int(1 << 12) != 0 {buffer.appendInt32(481674261)
|
||||||
for item in documents! {
|
buffer.appendInt32(Int32(attributes!.count))
|
||||||
|
for item in attributes! {
|
||||||
item.serialize(buffer, true)
|
item.serialize(buffer, true)
|
||||||
}}
|
}}
|
||||||
if Int(flags) & Int(1 << 10) != 0 {cachedPage!.serialize(buffer, true)}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9289,8 +9289,8 @@ public extension Api {
|
|||||||
return ("webPagePending", [("id", id), ("date", date)])
|
return ("webPagePending", [("id", id), ("date", date)])
|
||||||
case .webPageNotModified:
|
case .webPageNotModified:
|
||||||
return ("webPageNotModified", [])
|
return ("webPageNotModified", [])
|
||||||
case .webPage(let flags, let id, let url, let displayUrl, let hash, let type, let siteName, let title, let description, let photo, let embedUrl, let embedType, let embedWidth, let embedHeight, let duration, let author, let document, let documents, let cachedPage):
|
case .webPage(let flags, let id, let url, let displayUrl, let hash, let type, let siteName, let title, let description, let photo, let embedUrl, let embedType, let embedWidth, let embedHeight, let duration, let author, let document, let cachedPage, let attributes):
|
||||||
return ("webPage", [("flags", flags), ("id", id), ("url", url), ("displayUrl", displayUrl), ("hash", hash), ("type", type), ("siteName", siteName), ("title", title), ("description", description), ("photo", photo), ("embedUrl", embedUrl), ("embedType", embedType), ("embedWidth", embedWidth), ("embedHeight", embedHeight), ("duration", duration), ("author", author), ("document", document), ("documents", documents), ("cachedPage", cachedPage)])
|
return ("webPage", [("flags", flags), ("id", id), ("url", url), ("displayUrl", displayUrl), ("hash", hash), ("type", type), ("siteName", siteName), ("title", title), ("description", description), ("photo", photo), ("embedUrl", embedUrl), ("embedType", embedType), ("embedWidth", embedWidth), ("embedHeight", embedHeight), ("duration", duration), ("author", author), ("document", document), ("cachedPage", cachedPage), ("attributes", attributes)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9361,13 +9361,13 @@ public extension Api {
|
|||||||
if Int(_1!) & Int(1 << 9) != 0 {if let signature = reader.readInt32() {
|
if Int(_1!) & Int(1 << 9) != 0 {if let signature = reader.readInt32() {
|
||||||
_17 = Api.parse(reader, signature: signature) as? Api.Document
|
_17 = Api.parse(reader, signature: signature) as? Api.Document
|
||||||
} }
|
} }
|
||||||
var _18: [Api.Document]?
|
var _18: Api.Page?
|
||||||
if Int(_1!) & Int(1 << 11) != 0 {if let _ = reader.readInt32() {
|
|
||||||
_18 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self)
|
|
||||||
} }
|
|
||||||
var _19: Api.Page?
|
|
||||||
if Int(_1!) & Int(1 << 10) != 0 {if let signature = reader.readInt32() {
|
if Int(_1!) & Int(1 << 10) != 0 {if let signature = reader.readInt32() {
|
||||||
_19 = Api.parse(reader, signature: signature) as? Api.Page
|
_18 = Api.parse(reader, signature: signature) as? Api.Page
|
||||||
|
} }
|
||||||
|
var _19: [Api.WebPageAttribute]?
|
||||||
|
if Int(_1!) & Int(1 << 12) != 0 {if let _ = reader.readInt32() {
|
||||||
|
_19 = Api.parseVector(reader, elementSignature: 0, elementType: Api.WebPageAttribute.self)
|
||||||
} }
|
} }
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
@ -9386,10 +9386,10 @@ public extension Api {
|
|||||||
let _c15 = (Int(_1!) & Int(1 << 7) == 0) || _15 != nil
|
let _c15 = (Int(_1!) & Int(1 << 7) == 0) || _15 != nil
|
||||||
let _c16 = (Int(_1!) & Int(1 << 8) == 0) || _16 != nil
|
let _c16 = (Int(_1!) & Int(1 << 8) == 0) || _16 != nil
|
||||||
let _c17 = (Int(_1!) & Int(1 << 9) == 0) || _17 != nil
|
let _c17 = (Int(_1!) & Int(1 << 9) == 0) || _17 != nil
|
||||||
let _c18 = (Int(_1!) & Int(1 << 11) == 0) || _18 != nil
|
let _c18 = (Int(_1!) & Int(1 << 10) == 0) || _18 != nil
|
||||||
let _c19 = (Int(_1!) & Int(1 << 10) == 0) || _19 != nil
|
let _c19 = (Int(_1!) & Int(1 << 12) == 0) || _19 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 {
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 {
|
||||||
return Api.WebPage.webPage(flags: _1!, id: _2!, url: _3!, displayUrl: _4!, hash: _5!, type: _6, siteName: _7, title: _8, description: _9, photo: _10, embedUrl: _11, embedType: _12, embedWidth: _13, embedHeight: _14, duration: _15, author: _16, document: _17, documents: _18, cachedPage: _19)
|
return Api.WebPage.webPage(flags: _1!, id: _2!, url: _3!, displayUrl: _4!, hash: _5!, type: _6, siteName: _7, title: _8, description: _9, photo: _10, embedUrl: _11, embedType: _12, embedWidth: _13, embedHeight: _14, duration: _15, author: _16, document: _17, cachedPage: _18, attributes: _19)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
@ -17150,6 +17150,56 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public enum WebPageAttribute: TypeConstructorDescription {
|
||||||
|
case webPageAttributeTheme(flags: Int32, documents: [Api.Document]?, settings: Api.ThemeSettings?)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .webPageAttributeTheme(let flags, let documents, let settings):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(1421174295)
|
||||||
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
|
if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(documents!.count))
|
||||||
|
for item in documents! {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}}
|
||||||
|
if Int(flags) & Int(1 << 1) != 0 {settings!.serialize(buffer, true)}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .webPageAttributeTheme(let flags, let documents, let settings):
|
||||||
|
return ("webPageAttributeTheme", [("flags", flags), ("documents", documents), ("settings", settings)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_webPageAttributeTheme(_ reader: BufferReader) -> WebPageAttribute? {
|
||||||
|
var _1: Int32?
|
||||||
|
_1 = reader.readInt32()
|
||||||
|
var _2: [Api.Document]?
|
||||||
|
if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() {
|
||||||
|
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self)
|
||||||
|
} }
|
||||||
|
var _3: Api.ThemeSettings?
|
||||||
|
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
|
||||||
|
_3 = Api.parse(reader, signature: signature) as? Api.ThemeSettings
|
||||||
|
} }
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil
|
||||||
|
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.WebPageAttribute.webPageAttributeTheme(flags: _1!, documents: _2, settings: _3)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public enum PhoneCallDiscardReason: TypeConstructorDescription {
|
public enum PhoneCallDiscardReason: TypeConstructorDescription {
|
||||||
case phoneCallDiscardReasonMissed
|
case phoneCallDiscardReasonMissed
|
||||||
|
@ -5925,13 +5925,13 @@ public extension Api {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func createTheme(flags: Int32, slug: String, title: String, document: Api.InputDocument, settings: Api.InputThemeSettings?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Theme>) {
|
public static func createTheme(flags: Int32, slug: String, title: String, document: Api.InputDocument?, settings: Api.InputThemeSettings?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Theme>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(-1683113716)
|
buffer.appendInt32(-2077048289)
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeString(slug, buffer: buffer, boxed: false)
|
serializeString(slug, buffer: buffer, boxed: false)
|
||||||
serializeString(title, buffer: buffer, boxed: false)
|
serializeString(title, buffer: buffer, boxed: false)
|
||||||
document.serialize(buffer, true)
|
if Int(flags) & Int(1 << 2) != 0 {document!.serialize(buffer, true)}
|
||||||
if Int(flags) & Int(1 << 3) != 0 {settings!.serialize(buffer, true)}
|
if Int(flags) & Int(1 << 3) != 0 {settings!.serialize(buffer, true)}
|
||||||
return (FunctionDescription(name: "account.createTheme", parameters: [("flags", flags), ("slug", slug), ("title", title), ("document", document), ("settings", settings)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Theme? in
|
return (FunctionDescription(name: "account.createTheme", parameters: [("flags", flags), ("slug", slug), ("title", title), ("document", document), ("settings", settings)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Theme? in
|
||||||
let reader = BufferReader(buffer)
|
let reader = BufferReader(buffer)
|
||||||
|
@ -150,6 +150,7 @@ private var declaredEncodables: Void = {
|
|||||||
declareEncodable(SendScheduledMessageImmediatelyAction.self, f: { SendScheduledMessageImmediatelyAction(decoder: $0) })
|
declareEncodable(SendScheduledMessageImmediatelyAction.self, f: { SendScheduledMessageImmediatelyAction(decoder: $0) })
|
||||||
declareEncodable(WalletCollection.self, f: { WalletCollection(decoder: $0) })
|
declareEncodable(WalletCollection.self, f: { WalletCollection(decoder: $0) })
|
||||||
declareEncodable(EmbeddedMediaStickersMessageAttribute.self, f: { EmbeddedMediaStickersMessageAttribute(decoder: $0) })
|
declareEncodable(EmbeddedMediaStickersMessageAttribute.self, f: { EmbeddedMediaStickersMessageAttribute(decoder: $0) })
|
||||||
|
declareEncodable(TelegramMediaWebpageAttribute.self, f: { TelegramMediaWebpageAttribute(decoder: $0) })
|
||||||
|
|
||||||
return
|
return
|
||||||
}()
|
}()
|
||||||
|
@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
|
|||||||
|
|
||||||
public class Serialization: NSObject, MTSerialization {
|
public class Serialization: NSObject, MTSerialization {
|
||||||
public func currentLayer() -> UInt {
|
public func currentLayer() -> UInt {
|
||||||
return 107
|
return 108
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parseMessage(_ data: Data!) -> Any! {
|
public func parseMessage(_ data: Data!) -> Any! {
|
||||||
|
@ -4,13 +4,24 @@ import TelegramApi
|
|||||||
|
|
||||||
import SyncCore
|
import SyncCore
|
||||||
|
|
||||||
|
func telegramMediaWebpageAttributeFromApiWebpageAttribute(_ attribute: Api.WebPageAttribute) -> TelegramMediaWebpageAttribute? {
|
||||||
|
switch attribute {
|
||||||
|
case let .webPageAttributeTheme(flags, documents, settings):
|
||||||
|
var files: [TelegramMediaFile] = []
|
||||||
|
if let documents = documents {
|
||||||
|
files = documents.compactMap { telegramMediaFileFromApiDocument($0) }
|
||||||
|
}
|
||||||
|
return .theme(TelegraMediaWebpageThemeAttribute(files: files, settings: settings.flatMap { TelegramThemeSettings(apiThemeSettings: $0) }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func telegramMediaWebpageFromApiWebpage(_ webpage: Api.WebPage, url: String?) -> TelegramMediaWebpage? {
|
func telegramMediaWebpageFromApiWebpage(_ webpage: Api.WebPage, url: String?) -> TelegramMediaWebpage? {
|
||||||
switch webpage {
|
switch webpage {
|
||||||
case .webPageNotModified:
|
case .webPageNotModified:
|
||||||
return nil
|
return nil
|
||||||
case let .webPagePending(id, date):
|
case let .webPagePending(id, date):
|
||||||
return TelegramMediaWebpage(webpageId: MediaId(namespace: Namespaces.Media.CloudWebpage, id: id), content: .Pending(date, url))
|
return TelegramMediaWebpage(webpageId: MediaId(namespace: Namespaces.Media.CloudWebpage, id: id), content: .Pending(date, url))
|
||||||
case let .webPage(_, id, url, displayUrl, hash, type, siteName, title, description, photo, embedUrl, embedType, embedWidth, embedHeight, duration, author, document, documents, cachedPage):
|
case let .webPage(_, id, url, displayUrl, hash, type, siteName, title, description, photo, embedUrl, embedType, embedWidth, embedHeight, duration, author, document, cachedPage, attributes):
|
||||||
var embedSize: PixelDimensions?
|
var embedSize: PixelDimensions?
|
||||||
if let embedWidth = embedWidth, let embedHeight = embedHeight {
|
if let embedWidth = embedWidth, let embedHeight = embedHeight {
|
||||||
embedSize = PixelDimensions(width: embedWidth, height: embedHeight)
|
embedSize = PixelDimensions(width: embedWidth, height: embedHeight)
|
||||||
@ -27,15 +38,15 @@ func telegramMediaWebpageFromApiWebpage(_ webpage: Api.WebPage, url: String?) ->
|
|||||||
if let document = document {
|
if let document = document {
|
||||||
file = telegramMediaFileFromApiDocument(document)
|
file = telegramMediaFileFromApiDocument(document)
|
||||||
}
|
}
|
||||||
var files: [TelegramMediaFile]?
|
var webpageAttributes: [TelegramMediaWebpageAttribute] = []
|
||||||
if let documents = documents {
|
if let attributes = attributes {
|
||||||
files = documents.compactMap(telegramMediaFileFromApiDocument)
|
webpageAttributes = attributes.compactMap(telegramMediaWebpageAttributeFromApiWebpageAttribute)
|
||||||
}
|
}
|
||||||
var instantPage: InstantPage?
|
var instantPage: InstantPage?
|
||||||
if let cachedPage = cachedPage {
|
if let cachedPage = cachedPage {
|
||||||
instantPage = InstantPage(apiPage: cachedPage)
|
instantPage = InstantPage(apiPage: cachedPage)
|
||||||
}
|
}
|
||||||
return TelegramMediaWebpage(webpageId: MediaId(namespace: Namespaces.Media.CloudWebpage, id: id), content: .Loaded(TelegramMediaWebpageLoadedContent(url: url, displayUrl: displayUrl, hash: hash, type: type, websiteName: siteName, title: title, text: description, embedUrl: embedUrl, embedType: embedType, embedSize: embedSize, duration: webpageDuration, author: author, image: image, file: file, files: files, instantPage: instantPage)))
|
return TelegramMediaWebpage(webpageId: MediaId(namespace: Namespaces.Media.CloudWebpage, id: id), content: .Loaded(TelegramMediaWebpageLoadedContent(url: url, displayUrl: displayUrl, hash: hash, type: type, websiteName: siteName, title: title, text: description, embedUrl: embedUrl, embedType: embedType, embedSize: embedSize, duration: webpageDuration, author: author, image: image, file: file, attributes: webpageAttributes, instantPage: instantPage)))
|
||||||
case .webPageEmpty:
|
case .webPageEmpty:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -279,15 +279,19 @@ public enum CreateThemeResult {
|
|||||||
case progress(Float)
|
case progress(Float)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func createTheme(account: Account, title: String, resource: MediaResource, thumbnailData: Data? = nil, settings: TelegramThemeSettings?) -> Signal<CreateThemeResult, CreateThemeError> {
|
public func createTheme(account: Account, title: String, resource: MediaResource? = nil, thumbnailData: Data? = nil, settings: TelegramThemeSettings?) -> Signal<CreateThemeResult, CreateThemeError> {
|
||||||
var flags: Int32 = 0
|
var flags: Int32 = 0
|
||||||
|
|
||||||
var inputSettings: Api.InputThemeSettings?
|
var inputSettings: Api.InputThemeSettings?
|
||||||
|
if let _ = resource {
|
||||||
|
flags |= 1 << 2
|
||||||
|
}
|
||||||
if let settings = settings {
|
if let settings = settings {
|
||||||
flags |= 1 << 3
|
flags |= 1 << 3
|
||||||
inputSettings = settings.apiInputThemeSettings
|
inputSettings = settings.apiInputThemeSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let resource = resource {
|
||||||
return uploadTheme(account: account, resource: resource, thumbnailData: thumbnailData)
|
return uploadTheme(account: account, resource: resource, thumbnailData: thumbnailData)
|
||||||
|> mapError { _ in return CreateThemeError.generic }
|
|> mapError { _ in return CreateThemeError.generic }
|
||||||
|> mapToSignal { result -> Signal<CreateThemeResult, CreateThemeError> in
|
|> mapToSignal { result -> Signal<CreateThemeResult, CreateThemeError> in
|
||||||
@ -331,6 +335,37 @@ public func createTheme(account: Account, title: String, resource: MediaResource
|
|||||||
return .single(.progress(progress))
|
return .single(.progress(progress))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return account.network.request(Api.functions.account.createTheme(flags: flags, slug: "", title: title, document: .inputDocumentEmpty, settings: inputSettings))
|
||||||
|
|> mapError { error in
|
||||||
|
if error.errorDescription == "THEME_SLUG_INVALID" {
|
||||||
|
return .slugInvalid
|
||||||
|
} else if error.errorDescription == "THEME_SLUG_OCCUPIED" {
|
||||||
|
return .slugOccupied
|
||||||
|
}
|
||||||
|
return .generic
|
||||||
|
}
|
||||||
|
|> 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)
|
||||||
|
}
|
||||||
|
|> castError(CreateThemeError.self)
|
||||||
|
} else {
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updateTheme(account: Account, accountManager: AccountManager, theme: TelegramTheme, title: String?, slug: String?, resource: MediaResource?, thumbnailData: Data? = nil, settings: TelegramThemeSettings?) -> Signal<CreateThemeResult, CreateThemeError> {
|
public func updateTheme(account: Account, accountManager: AccountManager, theme: TelegramTheme, title: String?, slug: String?, resource: MediaResource?, thumbnailData: Data? = nil, settings: TelegramThemeSettings?) -> Signal<CreateThemeResult, CreateThemeError> {
|
||||||
@ -350,6 +385,7 @@ public func updateTheme(account: Account, accountManager: AccountManager, theme:
|
|||||||
var inputSettings: Api.InputThemeSettings?
|
var inputSettings: Api.InputThemeSettings?
|
||||||
if let settings = settings {
|
if let settings = settings {
|
||||||
flags |= 1 << 3
|
flags |= 1 << 3
|
||||||
|
inputSettings = settings.apiInputThemeSettings
|
||||||
}
|
}
|
||||||
let uploadSignal: Signal<UploadThemeResult?, UploadThemeError>
|
let uploadSignal: Signal<UploadThemeResult?, UploadThemeError>
|
||||||
if let resource = resource {
|
if let resource = resource {
|
||||||
@ -379,7 +415,7 @@ public func updateTheme(account: Account, accountManager: AccountManager, theme:
|
|||||||
inputDocument = nil
|
inputDocument = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return account.network.request(Api.functions.account.updateTheme(flags: flags, format: telegramThemeFormat, theme: .inputTheme(id: theme.id, accessHash: theme.accessHash), slug: slug, title: title, document: inputDocument, settings: nil))
|
return account.network.request(Api.functions.account.updateTheme(flags: flags, format: telegramThemeFormat, theme: .inputTheme(id: theme.id, accessHash: theme.accessHash), slug: slug, title: title, document: inputDocument, settings: inputSettings))
|
||||||
|> mapError { error in
|
|> mapError { error in
|
||||||
if error.errorDescription == "THEME_SLUG_INVALID" {
|
if error.errorDescription == "THEME_SLUG_INVALID" {
|
||||||
return .slugInvalid
|
return .slugInvalid
|
||||||
|
@ -129,7 +129,7 @@ public func customizeDefaultDarkPresentationTheme(theme: PresentationTheme, edit
|
|||||||
outgoingSecondaryTextColor = UIColor(rgb: 0xffffff, alpha: 0.5)
|
outgoingSecondaryTextColor = UIColor(rgb: 0xffffff, alpha: 0.5)
|
||||||
outgoingLinkTextColor = UIColor(rgb: 0xffffff)
|
outgoingLinkTextColor = UIColor(rgb: 0xffffff)
|
||||||
outgoingScamColor = UIColor(rgb: 0xffffff)
|
outgoingScamColor = UIColor(rgb: 0xffffff)
|
||||||
outgoingCheckColor = UIColor(rgb: 0xffffff, alpha: 0.5)
|
outgoingCheckColor = UIColor(rgb: 0xffffff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,7 +392,7 @@ public func makeDefaultDarkPresentationTheme(preview: Bool) -> PresentationTheme
|
|||||||
freeform: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x1f1f1f), highlightedFill: UIColor(rgb: 0x2a2a2a), stroke: UIColor(rgb: 0x1f1f1f)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x1f1f1f), highlightedFill: UIColor(rgb: 0x2a2a2a), stroke: UIColor(rgb: 0x1f1f1f))),
|
freeform: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x1f1f1f), highlightedFill: UIColor(rgb: 0x2a2a2a), stroke: UIColor(rgb: 0x1f1f1f)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x1f1f1f), highlightedFill: UIColor(rgb: 0x2a2a2a), stroke: UIColor(rgb: 0x1f1f1f))),
|
||||||
infoPrimaryTextColor: UIColor(rgb: 0xffffff),
|
infoPrimaryTextColor: UIColor(rgb: 0xffffff),
|
||||||
infoLinkTextColor: UIColor(rgb: 0xffffff),
|
infoLinkTextColor: UIColor(rgb: 0xffffff),
|
||||||
outgoingCheckColor: UIColor(rgb: 0xffffff, alpha: 0.5),
|
outgoingCheckColor: UIColor(rgb: 0xffffff),
|
||||||
mediaDateAndStatusFillColor: UIColor(white: 0.0, alpha: 0.5),
|
mediaDateAndStatusFillColor: UIColor(white: 0.0, alpha: 0.5),
|
||||||
mediaDateAndStatusTextColor: UIColor(rgb: 0xffffff),
|
mediaDateAndStatusTextColor: UIColor(rgb: 0xffffff),
|
||||||
shareButtonFillColor: PresentationThemeVariableColor(withWallpaper: UIColor(rgb: 0x000000, alpha: 0.5), withoutWallpaper: UIColor(rgb: 0x000000, alpha: 0.5)),
|
shareButtonFillColor: PresentationThemeVariableColor(withWallpaper: UIColor(rgb: 0x000000, alpha: 0.5), withoutWallpaper: UIColor(rgb: 0x000000, alpha: 0.5)),
|
||||||
|
@ -48,7 +48,13 @@ public func makePresentationTheme(mediaBox: MediaBox, themeReference: Presentati
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case let .cloud(info):
|
case let .cloud(info):
|
||||||
if let file = info.theme.file, let path = mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead), let loadedTheme = makePresentationTheme(data: data, themeReference: themeReference, resolvedWallpaper: info.resolvedWallpaper) {
|
if let settings = info.theme.settings {
|
||||||
|
if let loadedTheme = makePresentationTheme(mediaBox: mediaBox, themeReference: .builtin(PresentationBuiltinThemeReference(baseTheme: settings.baseTheme)), accentColor: accentColor ?? UIColor(rgb: UInt32(bitPattern: settings.accentColor)), backgroundColors: nil, bubbleColors: bubbleColors ?? settings.messageColors.flatMap { (UIColor(rgb: UInt32(bitPattern: $0.top)), UIColor(rgb: UInt32(bitPattern: $0.bottom))) }, wallpaper: wallpaper ?? settings.wallpaper, serviceBackgroundColor: serviceBackgroundColor, preview: preview) {
|
||||||
|
theme = loadedTheme
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} else if let file = info.theme.file, let path = mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead), let loadedTheme = makePresentationTheme(data: data, themeReference: themeReference, resolvedWallpaper: info.resolvedWallpaper) {
|
||||||
theme = customizePresentationTheme(loadedTheme, editing: false, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, wallpaper: wallpaper)
|
theme = customizePresentationTheme(loadedTheme, editing: false, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, wallpaper: wallpaper)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -516,14 +516,14 @@ public func updatedPresentationData(accountManager: AccountManager, applicationI
|
|||||||
|
|
||||||
let contactSettings: ContactSynchronizationSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.contactSynchronizationSettings] as? ContactSynchronizationSettings ?? ContactSynchronizationSettings.defaultSettings
|
let contactSettings: ContactSynchronizationSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.contactSynchronizationSettings] as? ContactSynchronizationSettings ?? ContactSynchronizationSettings.defaultSettings
|
||||||
|
|
||||||
let effectiveColors = themeSettings.themeSpecificAccentColors[themeSettings.theme.index]
|
let currentColors = themeSettings.themeSpecificAccentColors[themeSettings.theme.index]
|
||||||
let themeSpecificWallpaper = (themeSettings.themeSpecificChatWallpapers[coloredThemeIndex(reference: themeSettings.theme, accentColor: effectiveColors)] ?? themeSettings.themeSpecificChatWallpapers[themeSettings.theme.index])
|
let themeSpecificWallpaper = (themeSettings.themeSpecificChatWallpapers[coloredThemeIndex(reference: themeSettings.theme, accentColor: currentColors)] ?? themeSettings.themeSpecificChatWallpapers[themeSettings.theme.index])
|
||||||
|
|
||||||
let currentWallpaper: TelegramWallpaper
|
let currentWallpaper: TelegramWallpaper
|
||||||
if let themeSpecificWallpaper = themeSpecificWallpaper {
|
if let themeSpecificWallpaper = themeSpecificWallpaper {
|
||||||
currentWallpaper = themeSpecificWallpaper
|
currentWallpaper = themeSpecificWallpaper
|
||||||
} else {
|
} else {
|
||||||
let theme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: themeSettings.theme, accentColor: effectiveColors?.color, bubbleColors: effectiveColors?.customBubbleColors) ?? defaultPresentationTheme
|
let theme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: themeSettings.theme, accentColor: currentColors?.color, bubbleColors: currentColors?.customBubbleColors, wallpaper: currentColors?.wallpaper) ?? defaultPresentationTheme
|
||||||
currentWallpaper = theme.chat.defaultWallpaper
|
currentWallpaper = theme.chat.defaultWallpaper
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,12 +537,13 @@ public func updatedPresentationData(accountManager: AccountManager, applicationI
|
|||||||
|> distinctUntilChanged
|
|> distinctUntilChanged
|
||||||
|> map { autoNightModeTriggered in
|
|> map { autoNightModeTriggered in
|
||||||
var effectiveTheme: PresentationThemeReference
|
var effectiveTheme: PresentationThemeReference
|
||||||
var effectiveChatWallpaper: TelegramWallpaper = currentWallpaper
|
var effectiveChatWallpaper = currentWallpaper
|
||||||
|
var effectiveColors = currentColors
|
||||||
|
|
||||||
var switchedToNightModeWallpaper = false
|
var switchedToNightModeWallpaper = false
|
||||||
if autoNightModeTriggered {
|
if autoNightModeTriggered {
|
||||||
let automaticTheme = themeSettings.automaticThemeSwitchSetting.theme
|
let automaticTheme = themeSettings.automaticThemeSwitchSetting.theme
|
||||||
let effectiveColors = themeSettings.themeSpecificAccentColors[automaticTheme.index]
|
effectiveColors = themeSettings.themeSpecificAccentColors[automaticTheme.index]
|
||||||
let themeSpecificWallpaper = (themeSettings.themeSpecificChatWallpapers[coloredThemeIndex(reference: automaticTheme, accentColor: effectiveColors)] ?? themeSettings.themeSpecificChatWallpapers[automaticTheme.index])
|
let themeSpecificWallpaper = (themeSettings.themeSpecificChatWallpapers[coloredThemeIndex(reference: automaticTheme, accentColor: effectiveColors)] ?? themeSettings.themeSpecificChatWallpapers[automaticTheme.index])
|
||||||
|
|
||||||
if let themeSpecificWallpaper = themeSpecificWallpaper {
|
if let themeSpecificWallpaper = themeSpecificWallpaper {
|
||||||
@ -554,8 +555,7 @@ public func updatedPresentationData(accountManager: AccountManager, applicationI
|
|||||||
effectiveTheme = themeSettings.theme
|
effectiveTheme = themeSettings.theme
|
||||||
}
|
}
|
||||||
|
|
||||||
let effectiveColors = themeSettings.themeSpecificAccentColors[effectiveTheme.index]
|
let themeValue = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: effectiveTheme, accentColor: effectiveColors?.color, bubbleColors: effectiveColors?.customBubbleColors, wallpaper: effectiveColors?.wallpaper, serviceBackgroundColor: serviceBackgroundColor) ?? defaultPresentationTheme
|
||||||
let themeValue = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: effectiveTheme, accentColor: effectiveColors?.color, bubbleColors: effectiveColors?.customBubbleColors, serviceBackgroundColor: serviceBackgroundColor) ?? defaultPresentationTheme
|
|
||||||
|
|
||||||
if autoNightModeTriggered && !switchedToNightModeWallpaper {
|
if autoNightModeTriggered && !switchedToNightModeWallpaper {
|
||||||
switch effectiveChatWallpaper {
|
switch effectiveChatWallpaper {
|
||||||
|
@ -322,6 +322,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
|||||||
} else {
|
} else {
|
||||||
unboundSize = CGSize(width: 54.0, height: 54.0)
|
unboundSize = CGSize(width: 54.0, height: 54.0)
|
||||||
}
|
}
|
||||||
|
case .themeSettings:
|
||||||
|
unboundSize = CGSize(width: 160.0, height: 240.0).fitted(CGSize(width: 240.0, height: 240.0))
|
||||||
case .color, .gradient:
|
case .color, .gradient:
|
||||||
unboundSize = CGSize(width: 128.0, height: 128.0)
|
unboundSize = CGSize(width: 128.0, height: 128.0)
|
||||||
}
|
}
|
||||||
@ -439,7 +441,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
|||||||
} else {
|
} else {
|
||||||
emptyColor = message.effectivelyIncoming(context.account.peerId) ? theme.chat.message.incoming.mediaPlaceholderColor : theme.chat.message.outgoing.mediaPlaceholderColor
|
emptyColor = message.effectivelyIncoming(context.account.peerId) ? theme.chat.message.incoming.mediaPlaceholderColor : theme.chat.message.outgoing.mediaPlaceholderColor
|
||||||
}
|
}
|
||||||
if let wallpaper = media as? WallpaperPreviewMedia, case let .file(_, patternColor, patternBottomColor, rotation, _, _) = wallpaper.content {
|
if let wallpaper = media as? WallpaperPreviewMedia {
|
||||||
|
if case let .file(_, patternColor, patternBottomColor, rotation, _, _) = wallpaper.content {
|
||||||
var colors: [UIColor] = []
|
var colors: [UIColor] = []
|
||||||
colors.append(patternColor ?? UIColor(rgb: 0xd6e2ee, alpha: 0.5))
|
colors.append(patternColor ?? UIColor(rgb: 0xd6e2ee, alpha: 0.5))
|
||||||
if let patternBottomColor = patternBottomColor {
|
if let patternBottomColor = patternBottomColor {
|
||||||
@ -447,6 +450,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
|||||||
}
|
}
|
||||||
patternArguments = PatternWallpaperArguments(colors: colors, rotation: rotation)
|
patternArguments = PatternWallpaperArguments(colors: colors, rotation: rotation)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if mediaUpdated || isSendingUpdated || automaticPlaybackUpdated {
|
if mediaUpdated || isSendingUpdated || automaticPlaybackUpdated {
|
||||||
if let image = media as? TelegramMediaImage {
|
if let image = media as? TelegramMediaImage {
|
||||||
@ -580,7 +584,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
|||||||
switch wallpaper.content {
|
switch wallpaper.content {
|
||||||
case let .file(file, _, _, _, isTheme, _):
|
case let .file(file, _, _, _, isTheme, _):
|
||||||
if isTheme {
|
if isTheme {
|
||||||
return themeImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: FileMediaReference.message(message: MessageReference(message), media: file))
|
return themeImage(account: context.account, accountManager: context.sharedContext.accountManager, source: .file(FileMediaReference.message(message: MessageReference(message), media: file)))
|
||||||
} else {
|
} else {
|
||||||
let representations: [ImageRepresentationWithReference] = file.previewRepresentations.map({ ImageRepresentationWithReference(representation: $0, reference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference($0.resource)) })
|
let representations: [ImageRepresentationWithReference] = file.previewRepresentations.map({ ImageRepresentationWithReference(representation: $0, reference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference($0.resource)) })
|
||||||
if file.mimeType == "image/png" {
|
if file.mimeType == "image/png" {
|
||||||
@ -589,6 +593,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
|||||||
return wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: FileMediaReference.message(message: MessageReference(message), media: file), representations: representations, alwaysShowThumbnailFirst: false, thumbnail: true, autoFetchFullSize: true)
|
return wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: FileMediaReference.message(message: MessageReference(message), media: file), representations: representations, alwaysShowThumbnailFirst: false, thumbnail: true, autoFetchFullSize: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case let .themeSettings(settings):
|
||||||
|
return themeImage(account: context.account, accountManager: context.sharedContext.accountManager, source: .settings(settings))
|
||||||
case let .color(color):
|
case let .color(color):
|
||||||
return solidColorImage(color)
|
return solidColorImage(color)
|
||||||
case let .gradient(topColor, bottomColor, rotation):
|
case let .gradient(topColor, bottomColor, rotation):
|
||||||
@ -604,6 +610,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
|||||||
}, cancel: {
|
}, cancel: {
|
||||||
messageMediaFileCancelInteractiveFetch(context: context, messageId: message.id, file: file)
|
messageMediaFileCancelInteractiveFetch(context: context, messageId: message.id, file: file)
|
||||||
})
|
})
|
||||||
|
} else if case .themeSettings = wallpaper.content {
|
||||||
} else {
|
} else {
|
||||||
boundingSize = CGSize(width: boundingSize.width, height: boundingSize.width)
|
boundingSize = CGSize(width: boundingSize.width, height: boundingSize.width)
|
||||||
}
|
}
|
||||||
@ -645,7 +652,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
|||||||
|> map { resourceStatus -> (MediaResourceStatus, MediaResourceStatus?) in
|
|> map { resourceStatus -> (MediaResourceStatus, MediaResourceStatus?) in
|
||||||
return (resourceStatus, nil)
|
return (resourceStatus, nil)
|
||||||
}
|
}
|
||||||
case .color, .gradient:
|
case .themeSettings, .color, .gradient:
|
||||||
updatedStatusSignal = .single((.Local, nil))
|
updatedStatusSignal = .single((.Local, nil))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,21 +310,31 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
} else if type == "telegram_theme" {
|
} else if type == "telegram_theme" {
|
||||||
var file: TelegramMediaFile?
|
var file: TelegramMediaFile?
|
||||||
|
var settings: TelegramThemeSettings?
|
||||||
var isSupported = false
|
var isSupported = false
|
||||||
if let contentFiles = webpage.files {
|
|
||||||
if let filteredFile = contentFiles.filter({ $0.mimeType == themeMimeType }).first {
|
for attribute in webpage.attributes {
|
||||||
|
if case let .theme(attribute) = attribute {
|
||||||
|
if let attributeSettings = attribute.settings {
|
||||||
|
settings = attributeSettings
|
||||||
isSupported = true
|
isSupported = true
|
||||||
|
} else if let filteredFile = attribute.files.filter({ $0.mimeType == themeMimeType }).first {
|
||||||
file = filteredFile
|
file = filteredFile
|
||||||
} else {
|
isSupported = true
|
||||||
file = contentFiles.first
|
|
||||||
}
|
}
|
||||||
} else if let contentFile = webpage.file {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isSupported, let contentFile = webpage.file {
|
||||||
isSupported = true
|
isSupported = true
|
||||||
file = contentFile
|
file = contentFile
|
||||||
}
|
}
|
||||||
if let file = file {
|
if let file = file {
|
||||||
let media = WallpaperPreviewMedia(content: .file(file, nil, nil, nil, true, isSupported))
|
let media = WallpaperPreviewMedia(content: .file(file, nil, nil, nil, true, isSupported))
|
||||||
mediaAndFlags = (media, ChatMessageAttachedContentNodeMediaFlags())
|
mediaAndFlags = (media, ChatMessageAttachedContentNodeMediaFlags())
|
||||||
|
} else if let settings = settings {
|
||||||
|
let media = WallpaperPreviewMedia(content: .themeSettings(settings))
|
||||||
|
mediaAndFlags = (media, ChatMessageAttachedContentNodeMediaFlags())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -812,6 +812,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
break
|
break
|
||||||
case .wallet:
|
case .wallet:
|
||||||
break
|
break
|
||||||
|
case .settings:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
@ -508,17 +508,28 @@ func openChatTheme(context: AccountContext, message: Message, pushController: @e
|
|||||||
let _ = (context.sharedContext.resolveUrl(account: context.account, url: content.url)
|
let _ = (context.sharedContext.resolveUrl(account: context.account, url: content.url)
|
||||||
|> deliverOnMainQueue).start(next: { resolvedUrl in
|
|> deliverOnMainQueue).start(next: { resolvedUrl in
|
||||||
var file: TelegramMediaFile?
|
var file: TelegramMediaFile?
|
||||||
let mimeType = "application/x-tgtheme-ios"
|
var settings: TelegramThemeSettings?
|
||||||
if let contentFiles = content.files, let filteredFile = contentFiles.filter({ $0.mimeType == mimeType }).first {
|
let themeMimeType = "application/x-tgtheme-ios"
|
||||||
|
|
||||||
|
for attribute in content.attributes {
|
||||||
|
if case let .theme(attribute) = attribute {
|
||||||
|
if let attributeSettings = attribute.settings {
|
||||||
|
settings = attributeSettings
|
||||||
|
} else if let filteredFile = attribute.files.filter({ $0.mimeType == themeMimeType }).first {
|
||||||
file = filteredFile
|
file = filteredFile
|
||||||
} else if let contentFile = content.file, contentFile.mimeType == mimeType {
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if file == nil && settings == nil, let contentFile = content.file, contentFile.mimeType == themeMimeType {
|
||||||
file = contentFile
|
file = contentFile
|
||||||
}
|
}
|
||||||
let displayUnsupportedAlert: () -> Void = {
|
let displayUnsupportedAlert: () -> Void = {
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
present(textAlertController(context: context, title: nil, text: presentationData.strings.Theme_Unsupported, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
present(textAlertController(context: context, title: nil, text: presentationData.strings.Theme_Unsupported, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||||
}
|
}
|
||||||
if case let .theme(slug) = resolvedUrl, let file = file {
|
if case let .theme(slug) = resolvedUrl {
|
||||||
|
if let file = file {
|
||||||
if let path = context.sharedContext.accountManager.mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
if let path = context.sharedContext.accountManager.mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
||||||
if let theme = makePresentationTheme(data: data) {
|
if let theme = makePresentationTheme(data: data) {
|
||||||
let controller = ThemePreviewController(context: context, previewTheme: theme, source: .slug(slug, file))
|
let controller = ThemePreviewController(context: context, previewTheme: theme, source: .slug(slug, file))
|
||||||
@ -527,6 +538,14 @@ func openChatTheme(context: AccountContext, message: Message, pushController: @e
|
|||||||
displayUnsupportedAlert()
|
displayUnsupportedAlert()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if let settings = settings {
|
||||||
|
if let theme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: .builtin(PresentationBuiltinThemeReference(baseTheme: settings.baseTheme)), accentColor: UIColor(rgb: UInt32(bitPattern: settings.accentColor)), backgroundColors: nil, bubbleColors: settings.messageColors.flatMap { (UIColor(rgb: UInt32(bitPattern: $0.top)), UIColor(rgb: UInt32(bitPattern: $0.bottom))) }, wallpaper: settings.wallpaper, serviceBackgroundColor: nil, preview: false) {
|
||||||
|
let controller = ThemePreviewController(context: context, previewTheme: theme, source: .themeSettings(slug, settings))
|
||||||
|
pushController(controller)
|
||||||
|
} else {
|
||||||
|
displayUnsupportedAlert()
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
displayUnsupportedAlert()
|
displayUnsupportedAlert()
|
||||||
}
|
}
|
||||||
|
@ -281,12 +281,13 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
|||||||
case let .theme(slug):
|
case let .theme(slug):
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let signal = getTheme(account: context.account, slug: slug)
|
let signal = getTheme(account: context.account, slug: slug)
|
||||||
|> mapToSignal { themeInfo -> Signal<(Data, TelegramTheme), GetThemeError> in
|
|> mapToSignal { themeInfo -> Signal<(Data?, TelegramThemeSettings?, TelegramTheme), GetThemeError> in
|
||||||
return Signal<(Data, TelegramTheme), GetThemeError> { subscriber in
|
return Signal<(Data?, TelegramThemeSettings?, TelegramTheme), GetThemeError> { subscriber in
|
||||||
let disposables = DisposableSet()
|
let disposables = DisposableSet()
|
||||||
let resource = themeInfo.file?.resource
|
if let settings = themeInfo.settings {
|
||||||
|
subscriber.putNext((nil, settings, themeInfo))
|
||||||
if let resource = resource {
|
subscriber.putCompletion()
|
||||||
|
} else if let resource = themeInfo.file?.resource {
|
||||||
disposables.add(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .standalone(resource: resource)).start())
|
disposables.add(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .standalone(resource: resource)).start())
|
||||||
|
|
||||||
let maybeFetched = context.sharedContext.accountManager.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false), attemptSynchronously: false)
|
let maybeFetched = context.sharedContext.accountManager.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false), attemptSynchronously: false)
|
||||||
@ -309,7 +310,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
|||||||
|
|
||||||
disposables.add(maybeFetched.start(next: { data in
|
disposables.add(maybeFetched.start(next: { data in
|
||||||
if let data = data {
|
if let data = data {
|
||||||
subscriber.putNext((data, themeInfo))
|
subscriber.putNext((data, nil, themeInfo))
|
||||||
subscriber.putCompletion()
|
subscriber.putCompletion()
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
@ -348,10 +349,17 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> deliverOnMainQueue).start(next: { dataAndTheme in
|
|> deliverOnMainQueue).start(next: { dataAndTheme in
|
||||||
if let theme = makePresentationTheme(data: dataAndTheme.0) {
|
if let data = dataAndTheme.0 {
|
||||||
let previewController = ThemePreviewController(context: context, previewTheme: theme, source: .theme(dataAndTheme.1))
|
if let theme = makePresentationTheme(data: data) {
|
||||||
|
let previewController = ThemePreviewController(context: context, previewTheme: theme, source: .theme(dataAndTheme.2))
|
||||||
navigationController?.pushViewController(previewController)
|
navigationController?.pushViewController(previewController)
|
||||||
}
|
}
|
||||||
|
} else if let settings = dataAndTheme.1 {
|
||||||
|
if let theme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: .builtin(PresentationBuiltinThemeReference(baseTheme: settings.baseTheme)), accentColor: UIColor(rgb: UInt32(bitPattern: settings.accentColor)), backgroundColors: nil, bubbleColors: settings.messageColors.flatMap { (UIColor(rgb: UInt32(bitPattern: $0.top)), UIColor(rgb: UInt32(bitPattern: $0.bottom))) }, wallpaper: settings.wallpaper) {
|
||||||
|
let previewController = ThemePreviewController(context: context, previewTheme: theme, source: .theme(dataAndTheme.2))
|
||||||
|
navigationController?.pushViewController(previewController)
|
||||||
|
}
|
||||||
|
}
|
||||||
}, error: { error in
|
}, error: { error in
|
||||||
let errorText: String
|
let errorText: String
|
||||||
switch error {
|
switch error {
|
||||||
@ -368,5 +376,51 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
|||||||
context.sharedContext.openWallet(context: context, walletContext: .send(address: address, amount: amount, comment: comment)) { c in
|
context.sharedContext.openWallet(context: context, walletContext: .send(address: address, amount: amount, comment: comment)) { c in
|
||||||
navigationController?.pushViewController(c)
|
navigationController?.pushViewController(c)
|
||||||
}
|
}
|
||||||
|
case let .settings(section):
|
||||||
|
dismissInput()
|
||||||
|
switch section {
|
||||||
|
case .theme:
|
||||||
|
if let navigationController = navigationController {
|
||||||
|
let controller = themeSettingsController(context: context)
|
||||||
|
controller.navigationPresentation = .modal
|
||||||
|
|
||||||
|
var controllers = navigationController.viewControllers
|
||||||
|
controllers = controllers.filter { !($0 is ThemeSettingsController) }
|
||||||
|
controllers.append(controller)
|
||||||
|
|
||||||
|
navigationController.setViewControllers(controllers, animated: true)
|
||||||
|
}
|
||||||
|
case .devices:
|
||||||
|
if let navigationController = navigationController {
|
||||||
|
let activeSessions = deferred { () -> Signal<(ActiveSessionsContext, Int, WebSessionsContext), NoError> in
|
||||||
|
let activeSessionsContext = ActiveSessionsContext(account: context.account)
|
||||||
|
let webSessionsContext = WebSessionsContext(account: context.account)
|
||||||
|
let otherSessionCount = activeSessionsContext.state
|
||||||
|
|> map { state -> Int in
|
||||||
|
return state.sessions.filter({ !$0.isCurrent }).count
|
||||||
|
}
|
||||||
|
|> distinctUntilChanged
|
||||||
|
|
||||||
|
return otherSessionCount
|
||||||
|
|> map { value in
|
||||||
|
return (activeSessionsContext, value, webSessionsContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = (activeSessions
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).start(next: { activeSessionsContext, count, webSessionsContext in
|
||||||
|
let controller = recentSessionsController(context: context, activeSessionsContext: activeSessionsContext, webSessionsContext: webSessionsContext, websitesOnly: false)
|
||||||
|
controller.navigationPresentation = .modal
|
||||||
|
|
||||||
|
var controllers = navigationController.viewControllers
|
||||||
|
controllers = controllers.filter { !($0 is RecentSessionsController) }
|
||||||
|
controllers.append(controller)
|
||||||
|
|
||||||
|
navigationController.setViewControllers(controllers, animated: true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,7 +200,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
|||||||
}
|
}
|
||||||
|
|
||||||
let continueHandling: () -> Void = {
|
let continueHandling: () -> Void = {
|
||||||
let handleRevolvedUrl: (ResolvedUrl) -> Void = { resolved in
|
let handleResolvedUrl: (ResolvedUrl) -> Void = { resolved in
|
||||||
if case let .externalUrl(value) = resolved {
|
if case let .externalUrl(value) = resolved {
|
||||||
context.sharedContext.applicationBindings.openUrl(value)
|
context.sharedContext.applicationBindings.openUrl(value)
|
||||||
} else {
|
} else {
|
||||||
@ -243,11 +243,12 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
|||||||
|
|
||||||
let handleInternalUrl: (String) -> Void = { url in
|
let handleInternalUrl: (String) -> Void = { url in
|
||||||
let _ = (context.sharedContext.resolveUrl(account: context.account, url: url)
|
let _ = (context.sharedContext.resolveUrl(account: context.account, url: url)
|
||||||
|> deliverOnMainQueue).start(next: handleRevolvedUrl)
|
|> deliverOnMainQueue).start(next: handleResolvedUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let scheme = parsedUrl.scheme, (scheme == "tg" || scheme == context.sharedContext.applicationBindings.appSpecificScheme), let query = parsedUrl.query {
|
if let scheme = parsedUrl.scheme, (scheme == "tg" || scheme == context.sharedContext.applicationBindings.appSpecificScheme) {
|
||||||
var convertedUrl: String?
|
var convertedUrl: String?
|
||||||
|
if let query = parsedUrl.query {
|
||||||
if parsedUrl.host == "localpeer" {
|
if parsedUrl.host == "localpeer" {
|
||||||
if let components = URLComponents(string: "/?" + query) {
|
if let components = URLComponents(string: "/?" + query) {
|
||||||
var peerId: PeerId?
|
var peerId: PeerId?
|
||||||
@ -329,7 +330,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if sharePhoneNumber != nil || shareText != nil {
|
if sharePhoneNumber != nil || shareText != nil {
|
||||||
handleRevolvedUrl(.share(url: nil, text: shareText, to: sharePhoneNumber))
|
handleResolvedUrl(.share(url: nil, text: shareText, to: sharePhoneNumber))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -656,6 +657,24 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if parsedUrl.host == "settings" {
|
||||||
|
if let path = parsedUrl.pathComponents.last {
|
||||||
|
var section: ResolvedUrlSettingsSection?
|
||||||
|
switch path {
|
||||||
|
case "theme":
|
||||||
|
section = .theme
|
||||||
|
case "devices":
|
||||||
|
section = .devices
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if let section = section {
|
||||||
|
handleResolvedUrl(.settings(section))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let convertedUrl = convertedUrl {
|
if let convertedUrl = convertedUrl {
|
||||||
handleInternalUrl(convertedUrl)
|
handleInternalUrl(convertedUrl)
|
||||||
|
@ -8,6 +8,7 @@ enum WallpaperPreviewMediaContent: Equatable {
|
|||||||
case file(TelegramMediaFile, UIColor?, UIColor?, Int32?, Bool, Bool)
|
case file(TelegramMediaFile, UIColor?, UIColor?, Int32?, Bool, Bool)
|
||||||
case color(UIColor)
|
case color(UIColor)
|
||||||
case gradient(UIColor, UIColor, Int32?)
|
case gradient(UIColor, UIColor, Int32?)
|
||||||
|
case themeSettings(TelegramThemeSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
final class WallpaperPreviewMedia: Media {
|
final class WallpaperPreviewMedia: Media {
|
||||||
|
@ -117,7 +117,7 @@ final class WebpagePreviewAccessoryPanelNode: AccessoryPanelNode {
|
|||||||
} else {
|
} else {
|
||||||
text = stringForMediaKind(mediaKind, strings: self.strings).0
|
text = stringForMediaKind(mediaKind, strings: self.strings).0
|
||||||
}
|
}
|
||||||
} else if let files = content.files, content.type == "telegram_theme" {
|
} else if content.type == "telegram_theme" {
|
||||||
text = strings.Message_Theme
|
text = strings.Message_Theme
|
||||||
} else if let _ = content.image {
|
} else if let _ = content.image {
|
||||||
text = stringForMediaKind(.image, strings: self.strings).0
|
text = stringForMediaKind(.image, strings: self.strings).0
|
||||||
|
@ -456,6 +456,7 @@ public struct PresentationThemeAccentColor: PostboxCoding, Equatable {
|
|||||||
} else {
|
} else {
|
||||||
self.bubbleColors = nil
|
self.bubbleColors = nil
|
||||||
}
|
}
|
||||||
|
self.wallpaper = decoder.decodeObjectForKey("w", decoder: { TelegramWallpaper(decoder: $0) }) as? TelegramWallpaper
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(_ encoder: PostboxEncoder) {
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
@ -477,6 +478,11 @@ public struct PresentationThemeAccentColor: PostboxCoding, Equatable {
|
|||||||
encoder.encodeNil(forKey: "bt")
|
encoder.encodeNil(forKey: "bt")
|
||||||
encoder.encodeNil(forKey: "bb")
|
encoder.encodeNil(forKey: "bb")
|
||||||
}
|
}
|
||||||
|
if let wallpaper = self.wallpaper {
|
||||||
|
encoder.encodeObject(wallpaper, forKey: "w")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "w")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var color: UIColor {
|
public var color: UIColor {
|
||||||
@ -510,6 +516,10 @@ public struct PresentationThemeAccentColor: PostboxCoding, Equatable {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func withUpdatedWallpaper(_ wallpaper: TelegramWallpaper?) -> PresentationThemeAccentColor {
|
||||||
|
return PresentationThemeAccentColor(index: self.index, baseColor: self.baseColor, accentColor: self.accentColor, bubbleColors: self.bubbleColors, wallpaper: wallpaper)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct PresentationThemeSettings: PreferencesEntry {
|
public struct PresentationThemeSettings: PreferencesEntry {
|
||||||
|
@ -863,15 +863,24 @@ public func drawThemeImage(context c: CGContext, theme: PresentationTheme, wallp
|
|||||||
c.restoreGState()
|
c.restoreGState()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func themeImage(account: Account, accountManager: AccountManager, fileReference: FileMediaReference, synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
public enum ThemeImageSource {
|
||||||
|
case file(FileMediaReference)
|
||||||
|
case settings(TelegramThemeSettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func themeImage(account: Account, accountManager: AccountManager, source: ThemeImageSource, synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||||
|
let theme: Signal<(PresentationTheme?, Data?), NoError>
|
||||||
|
|
||||||
|
switch source {
|
||||||
|
case let .file(fileReference):
|
||||||
let isSupportedTheme = fileReference.media.mimeType == "application/x-tgtheme-ios"
|
let isSupportedTheme = fileReference.media.mimeType == "application/x-tgtheme-ios"
|
||||||
let maybeFetched = accountManager.mediaBox.resourceData(fileReference.media.resource, option: .complete(waitUntilFetchStatus: false), attemptSynchronously: synchronousLoad)
|
let maybeFetched = accountManager.mediaBox.resourceData(fileReference.media.resource, option: .complete(waitUntilFetchStatus: false), attemptSynchronously: synchronousLoad)
|
||||||
let data = maybeFetched
|
theme = maybeFetched
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> mapToSignal { maybeData -> Signal<(Data?, Data?), NoError> in
|
|> mapToSignal { maybeData -> Signal<(PresentationTheme?, Data?), NoError> in
|
||||||
if maybeData.complete && isSupportedTheme {
|
if maybeData.complete && isSupportedTheme {
|
||||||
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
|
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
|
||||||
return .single((loadedData, nil))
|
return .single((loadedData.flatMap { makePresentationTheme(data: $0) }, nil))
|
||||||
} else {
|
} else {
|
||||||
let decodedThumbnailData = fileReference.media.immediateThumbnailData.flatMap(decodeTinyThumbnail)
|
let decodedThumbnailData = fileReference.media.immediateThumbnailData.flatMap(decodeTinyThumbnail)
|
||||||
|
|
||||||
@ -934,13 +943,18 @@ public func themeImage(account: Account, accountManager: AccountManager, fileRef
|
|||||||
|
|
||||||
return thumbnailData |> mapToSignal { thumbnailData in
|
return thumbnailData |> mapToSignal { thumbnailData in
|
||||||
return fullSizeData |> map { fullSizeData in
|
return fullSizeData |> map { fullSizeData in
|
||||||
return (fullSizeData, thumbnailData)
|
return (fullSizeData.flatMap { makePresentationTheme(data: $0) }, thumbnailData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> mapToSignal { (fullSizeData, thumbnailData) -> Signal<(PresentationTheme?, UIImage?, Data?), NoError> in
|
case let .settings(settings):
|
||||||
if let fullSizeData = fullSizeData, let theme = makePresentationTheme(data: fullSizeData) {
|
theme = .single((makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: .builtin(PresentationBuiltinThemeReference(baseTheme: settings.baseTheme)), accentColor: UIColor(rgb: UInt32(bitPattern: settings.accentColor)), backgroundColors: nil, bubbleColors: settings.messageColors.flatMap { (UIColor(rgb: UInt32(bitPattern: $0.top)), UIColor(rgb: UInt32(bitPattern: $0.bottom))) }, wallpaper: settings.wallpaper, serviceBackgroundColor: nil, preview: false), nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = theme
|
||||||
|
|> mapToSignal { (theme, thumbnailData) -> Signal<(PresentationTheme?, UIImage?, Data?), NoError> in
|
||||||
|
if let theme = theme {
|
||||||
if case let .file(file) = theme.chat.defaultWallpaper, file.id == 0 {
|
if case let .file(file) = theme.chat.defaultWallpaper, file.id == 0 {
|
||||||
return cachedWallpaper(account: account, slug: file.slug, settings: file.settings)
|
return cachedWallpaper(account: account, slug: file.slug, settings: file.settings)
|
||||||
|> mapToSignal { wallpaper -> Signal<(PresentationTheme?, UIImage?, Data?), NoError> in
|
|> mapToSignal { wallpaper -> Signal<(PresentationTheme?, UIImage?, Data?), NoError> in
|
||||||
@ -1071,6 +1085,16 @@ public func themeIconImage(account: Account, accountManager: AccountManager, the
|
|||||||
case .dayClassic:
|
case .dayClassic:
|
||||||
incomingColor = UIColor(rgb: 0xffffff)
|
incomingColor = UIColor(rgb: 0xffffff)
|
||||||
if let accentColor = accentColor {
|
if let accentColor = accentColor {
|
||||||
|
if let wallpaper = wallpaper, case let .file(file) = wallpaper {
|
||||||
|
topBackgroundColor = file.settings.color.flatMap { UIColor(rgb: UInt32(bitPattern: $0)) } ?? UIColor(rgb: 0xd6e2ee)
|
||||||
|
bottomBackgroundColor = file.settings.bottomColor.flatMap { UIColor(rgb: UInt32(bitPattern: $0)) }
|
||||||
|
} else {
|
||||||
|
if let bubbleColors = bubbleColors {
|
||||||
|
topBackgroundColor = UIColor(rgb: 0xd6e2ee)
|
||||||
|
} else {
|
||||||
|
topBackgroundColor = accentColor.withMultiplied(hue: 1.019, saturation: 0.867, brightness: 0.965)
|
||||||
|
}
|
||||||
|
}
|
||||||
if let bubbleColors = bubbleColors {
|
if let bubbleColors = bubbleColors {
|
||||||
topBackgroundColor = UIColor(rgb: 0xd6e2ee)
|
topBackgroundColor = UIColor(rgb: 0xd6e2ee)
|
||||||
outgoingColor = bubbleColors
|
outgoingColor = bubbleColors
|
||||||
|
Loading…
x
Reference in New Issue
Block a user