Merge commit 'd592c8a0f3713ec888f785c8574f0b8f5391c9b7'

This commit is contained in:
Ali 2021-09-10 20:24:35 +04:00
commit bc0aefc32e
9 changed files with 232 additions and 130 deletions

View File

@ -104,7 +104,8 @@
"PUSH_ALBUM" = "%1$@|sent you an album"; "PUSH_ALBUM" = "%1$@|sent you an album";
"PUSH_MESSAGE_FILES_TEXT_1" = "sent you a file"; "PUSH_MESSAGE_FILES_TEXT_1" = "sent you a file";
"PUSH_MESSAGE_FILES_TEXT_any" = "sent you %d files"; "PUSH_MESSAGE_FILES_TEXT_any" = "sent you %d files";
"PUSH_MESSAGE_THEME" = "%1$@|changed theme to %2$@"; "PUSH_MESSAGE_THEME" = "%1$@|changed chat theme to %2$@";
"PUSH_MESSAGE_NOTHEME" = "%1$@|disabled chat theme";
"PUSH_CHANNEL_MESSAGE_TEXT" = "%1$@|%2$@"; "PUSH_CHANNEL_MESSAGE_TEXT" = "%1$@|%2$@";
"PUSH_CHANNEL_MESSAGE_NOTEXT" = "%1$@|posted a message"; "PUSH_CHANNEL_MESSAGE_NOTEXT" = "%1$@|posted a message";
@ -178,6 +179,7 @@
"PUSH_CHAT_MESSAGE_DOCS_TEXT_1" = "{author} sent a file"; "PUSH_CHAT_MESSAGE_DOCS_TEXT_1" = "{author} sent a file";
"PUSH_CHAT_MESSAGE_DOCS_TEXT_any" = "{author} sent %d files"; "PUSH_CHAT_MESSAGE_DOCS_TEXT_any" = "{author} sent %d files";
"PUSH_CHAT_MESSAGE_THEME" = "%1$@|set theme to %3$@ in the group %2$@"; "PUSH_CHAT_MESSAGE_THEME" = "%1$@|set theme to %3$@ in the group %2$@";
"PUSH_CHAT_MESSAGE_NOTHEME" = "%1$@|disabled theme in the group %2$@";
"PUSH_PINNED_TEXT" = "%1$@|pinned \"%2$@\" "; "PUSH_PINNED_TEXT" = "%1$@|pinned \"%2$@\" ";
"PUSH_PINNED_NOTEXT" = "%1$@|pinned a message"; "PUSH_PINNED_NOTEXT" = "%1$@|pinned a message";

View File

@ -288,8 +288,11 @@ public class ItemListVenueItemNode: ListViewItemNode, ItemListItemNode {
let iconApply = iconLayout(TransformImageArguments(corners: ImageCorners(), imageSize: CGSize(width: iconSize, height: iconSize), boundingSize: CGSize(width: iconSize, height: iconSize), intrinsicInsets: UIEdgeInsets())) let iconApply = iconLayout(TransformImageArguments(corners: ImageCorners(), imageSize: CGSize(width: iconSize, height: iconSize), boundingSize: CGSize(width: iconSize, height: iconSize), intrinsicInsets: UIEdgeInsets()))
iconApply() iconApply()
let placeholderBackgroundColor: UIColor
switch item.style { switch item.style {
case .plain: case .plain:
placeholderBackgroundColor = item.presentationData.theme.list.plainBackgroundColor
if strongSelf.backgroundNode.supernode != nil { if strongSelf.backgroundNode.supernode != nil {
strongSelf.backgroundNode.removeFromSupernode() strongSelf.backgroundNode.removeFromSupernode()
} }
@ -297,7 +300,7 @@ public class ItemListVenueItemNode: ListViewItemNode, ItemListItemNode {
strongSelf.topStripeNode.removeFromSupernode() strongSelf.topStripeNode.removeFromSupernode()
} }
if strongSelf.bottomStripeNode.supernode == nil { if strongSelf.bottomStripeNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0) strongSelf.addSubnode(strongSelf.bottomStripeNode)
} }
if strongSelf.maskNode.supernode != nil { if strongSelf.maskNode.supernode != nil {
strongSelf.maskNode.removeFromSupernode() strongSelf.maskNode.removeFromSupernode()
@ -312,6 +315,7 @@ public class ItemListVenueItemNode: ListViewItemNode, ItemListItemNode {
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: stripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - stripeInset, height: separatorHeight)) strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: stripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - stripeInset, height: separatorHeight))
strongSelf.bottomStripeNode.isHidden = last strongSelf.bottomStripeNode.isHidden = last
case .blocks: case .blocks:
placeholderBackgroundColor = item.presentationData.theme.list.itemBlocksBackgroundColor
if strongSelf.backgroundNode.supernode == nil { if strongSelf.backgroundNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0) strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0)
} }
@ -395,8 +399,8 @@ public class ItemListVenueItemNode: ListViewItemNode, ItemListItemNode {
let subtitleFrame = strongSelf.addressNode.frame let subtitleFrame = strongSelf.addressNode.frame
shapes.append(.roundedRectLine(startPoint: CGPoint(x: subtitleFrame.minX, y: subtitleFrame.minY + floor((subtitleFrame.height - lineDiameter) / 2.0)), width: subtitleLineWidth, diameter: lineDiameter)) shapes.append(.roundedRectLine(startPoint: CGPoint(x: subtitleFrame.minX, y: subtitleFrame.minY + floor((subtitleFrame.height - lineDiameter) / 2.0)), width: subtitleLineWidth, diameter: lineDiameter))
shimmerNode.update(backgroundColor: item.presentationData.theme.list.itemBlocksBackgroundColor, foregroundColor: item.presentationData.theme.list.mediaPlaceholderColor, shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: shapes, size: layout.contentSize) shimmerNode.update(backgroundColor: placeholderBackgroundColor, foregroundColor: item.presentationData.theme.list.mediaPlaceholderColor, shimmeringColor: item.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: shapes, size: layout.contentSize)
} else if let shimmerNode = strongSelf.placeholderNode { } else if let shimmerNode = strongSelf.placeholderNode {
strongSelf.placeholderNode = nil strongSelf.placeholderNode = nil
shimmerNode.removeFromSupernode() shimmerNode.removeFromSupernode()

View File

@ -35,7 +35,7 @@ public let defaultServiceBackgroundColor = UIColor(rgb: 0x000000, alpha: 0.2)
public let defaultPresentationTheme = makeDefaultDayPresentationTheme(serviceBackgroundColor: defaultServiceBackgroundColor, day: false, preview: false) public let defaultPresentationTheme = makeDefaultDayPresentationTheme(serviceBackgroundColor: defaultServiceBackgroundColor, day: false, preview: false)
public let defaultDayAccentColor = UIColor(rgb: 0x007ee5) public let defaultDayAccentColor = UIColor(rgb: 0x007ee5)
public func customizeDefaultDayTheme(theme: PresentationTheme, specialMode: Bool = false, editing: Bool, title: String?, accentColor: UIColor?, outgoingAccentColor: UIColor?, backgroundColors: [UInt32], bubbleColors: [UInt32], animateBubbleColors: Bool?, wallpaper forcedWallpaper: TelegramWallpaper? = nil, serviceBackgroundColor: UIColor?) -> PresentationTheme { public func customizeDefaultDayTheme(theme: PresentationTheme, editing: Bool, title: String?, accentColor: UIColor?, outgoingAccentColor: UIColor?, backgroundColors: [UInt32], bubbleColors: [UInt32], animateBubbleColors: Bool?, wallpaper forcedWallpaper: TelegramWallpaper? = nil, serviceBackgroundColor: UIColor?) -> PresentationTheme {
if (theme.referenceTheme != .day && theme.referenceTheme != .dayClassic) { if (theme.referenceTheme != .day && theme.referenceTheme != .dayClassic) {
return theme return theme
} }
@ -51,85 +51,35 @@ public func customizeDefaultDayTheme(theme: PresentationTheme, specialMode: Bool
var outgoingAccent: UIColor? var outgoingAccent: UIColor?
var suggestedWallpaper: TelegramWallpaper? var suggestedWallpaper: TelegramWallpaper?
var bubbleColors = bubbleColors var bubbleColors = bubbleColors
if specialMode, outgoingAccentColor == nil, bubbleColors.count < 3, let color = bubbleColors.first.flatMap({ UIColor(rgb: $0) }) { if bubbleColors.isEmpty, editing {
let colorHSB = color.hsb if day {
if colorHSB.b > 0.9 { let accentColor = accentColor ?? defaultDayAccentColor
let bubbleColor = color.withMultiplied(hue: 0.9, saturation: 1.3, brightness: 1.0) bubbleColors = [accentColor.withMultiplied(hue: 0.966, saturation: 0.61, brightness: 0.98).rgb, accentColor.rgb]
bubbleColors = [bubbleColor.rgb] outgoingAccent = outgoingAccentColor
} else {
let colorPairs: [(UInt32, UInt32)] = [ if let accentColor = accentColor, !accentColor.alpha.isZero {
(0xe5f9d7, 0x6cd516), let hsb = accentColor.hsb
(0xe7f5ff, 0x43b6f9), bubbleColors = [UIColor(hue: hsb.0, saturation: (hsb.1 > 0.0 && hsb.2 > 0.0) ? 0.14 : 0.0, brightness: 0.79 + hsb.2 * 0.21, alpha: 1.0).rgb]
(0xe3f7f5, 0x4ccbb8), if let outgoingAccentColor = outgoingAccentColor {
(0xfff6cf, 0xe8b816), outgoingAccent = outgoingAccentColor
(0xfffac9, 0xe2c714), } else {
(0xc5a61e, 0xd6b534) if accentColor.lightness > 0.705 {
] outgoingAccent = UIColor(hue: hsb.0, saturation: min(1.0, hsb.1 * 1.1), brightness: min(hsb.2, 0.6), alpha: 1.0)
func generateAccentColor(color: UIColor) -> UIColor {
var nearest: (color: (UInt32, UInt32), distance: Int32)?
for (sample, accentSample) in colorPairs {
let distance = color.distance(to: UIColor(rgb: sample))
if let currentNearest = nearest {
if distance < currentNearest.distance {
nearest = ((sample, accentSample), distance)
}
} else { } else {
nearest = ((sample, accentSample), distance) outgoingAccent = accentColor
} }
} }
if let colors = nearest?.color { suggestedWallpaper = .gradient(TelegramWallpaper.Gradient(id: nil, colors: defaultBuiltinWallpaperGradientColors.map(\.rgb), settings: WallpaperSettings()))
let colorHsb = color.hsb } else {
let similarColorHsb = UIColor(rgb: colors.0).hsb bubbleColors = [UIColor(rgb: 0xe1ffc7).rgb]
let accentColorHsb = UIColor(rgb: colors.1).hsb suggestedWallpaper = .gradient(TelegramWallpaper.Gradient(id: nil, colors: defaultBuiltinWallpaperGradientColors.map(\.rgb), settings: WallpaperSettings()))
outgoingAccent = outgoingAccentColor
let correction = (similarColorHsb.0 > 0.0 ? colorHsb.0 / similarColorHsb.0 : 1.0, similarColorHsb.1 > 0.0 ? colorHsb.1 / similarColorHsb.1 : 1.0, similarColorHsb.2 > 0.0 ? colorHsb.2 / similarColorHsb.2 : 1.0)
let correctedComplementingColor = UIColor(hue: min(1.0, accentColorHsb.0 * correction.0), saturation: min(1.0, accentColorHsb.1 * correction.1), brightness: min(1.0, accentColorHsb.2 * correction.2), alpha: 1.0)
return correctedComplementingColor
} else {
return color
}
} }
outgoingAccent = generateAccentColor(color: color)
} else {
let bubbleColor = color.withMultiplied(hue: 1.014, saturation: 0.12, brightness: 1.29)
bubbleColors = [bubbleColor.rgb]
outgoingAccent = color
} }
} else { } else {
if bubbleColors.isEmpty, editing { outgoingAccent = outgoingAccentColor
if day {
let accentColor = accentColor ?? defaultDayAccentColor
bubbleColors = [accentColor.withMultiplied(hue: 0.966, saturation: 0.61, brightness: 0.98).rgb, accentColor.rgb]
outgoingAccent = outgoingAccentColor
} else {
if let accentColor = accentColor, !accentColor.alpha.isZero {
let hsb = accentColor.hsb
bubbleColors = [UIColor(hue: hsb.0, saturation: (hsb.1 > 0.0 && hsb.2 > 0.0) ? 0.14 : 0.0, brightness: 0.79 + hsb.2 * 0.21, alpha: 1.0).rgb]
if let outgoingAccentColor = outgoingAccentColor {
outgoingAccent = outgoingAccentColor
} else {
if accentColor.lightness > 0.705 {
outgoingAccent = UIColor(hue: hsb.0, saturation: min(1.0, hsb.1 * 1.1), brightness: min(hsb.2, 0.6), alpha: 1.0)
} else {
outgoingAccent = accentColor
}
}
suggestedWallpaper = .gradient(TelegramWallpaper.Gradient(id: nil, colors: defaultBuiltinWallpaperGradientColors.map(\.rgb), settings: WallpaperSettings()))
} else {
bubbleColors = [UIColor(rgb: 0xe1ffc7).rgb]
suggestedWallpaper = .gradient(TelegramWallpaper.Gradient(id: nil, colors: defaultBuiltinWallpaperGradientColors.map(\.rgb), settings: WallpaperSettings()))
outgoingAccent = outgoingAccentColor
}
}
} else {
outgoingAccent = outgoingAccentColor
}
} }
var accentColor = accentColor var accentColor = accentColor

View File

@ -19,13 +19,13 @@ public func makeDefaultPresentationTheme(reference: PresentationBuiltinThemeRefe
return theme return theme
} }
public func customizePresentationTheme(_ theme: PresentationTheme, specialMode: Bool = false, editing: Bool, title: String? = nil, accentColor: UIColor?, outgoingAccentColor: UIColor?, backgroundColors: [UInt32], bubbleColors: [UInt32], animateBubbleColors: Bool?, wallpaper: TelegramWallpaper? = nil, baseColor: PresentationThemeBaseColor? = nil) -> PresentationTheme { public func customizePresentationTheme(_ theme: PresentationTheme, editing: Bool, title: String? = nil, accentColor: UIColor?, outgoingAccentColor: UIColor?, backgroundColors: [UInt32], bubbleColors: [UInt32], animateBubbleColors: Bool?, wallpaper: TelegramWallpaper? = nil, baseColor: PresentationThemeBaseColor? = nil) -> PresentationTheme {
if accentColor == nil && bubbleColors.isEmpty && backgroundColors.isEmpty && wallpaper == nil { if accentColor == nil && bubbleColors.isEmpty && backgroundColors.isEmpty && wallpaper == nil {
return theme return theme
} }
switch theme.referenceTheme { switch theme.referenceTheme {
case .day, .dayClassic: case .day, .dayClassic:
return customizeDefaultDayTheme(theme: theme, specialMode: specialMode, editing: editing, title: title, accentColor: accentColor, outgoingAccentColor: outgoingAccentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, animateBubbleColors: animateBubbleColors ?? false, wallpaper: wallpaper, serviceBackgroundColor: nil) return customizeDefaultDayTheme(theme: theme, editing: editing, title: title, accentColor: accentColor, outgoingAccentColor: outgoingAccentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, animateBubbleColors: animateBubbleColors ?? false, wallpaper: wallpaper, serviceBackgroundColor: nil)
case .night: case .night:
return customizeDefaultDarkPresentationTheme(theme: theme, editing: editing, title: title, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, animateBubbleColors: animateBubbleColors ?? false, wallpaper: wallpaper, baseColor: baseColor) return customizeDefaultDarkPresentationTheme(theme: theme, editing: editing, title: title, accentColor: accentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, animateBubbleColors: animateBubbleColors ?? false, wallpaper: wallpaper, baseColor: baseColor)
case .nightAccent: case .nightAccent:
@ -33,17 +33,25 @@ public func customizePresentationTheme(_ theme: PresentationTheme, specialMode:
} }
} }
public func makePresentationTheme(settings: TelegramThemeSettings, specialMode: Bool = false, title: String? = nil, serviceBackgroundColor: UIColor? = nil) -> PresentationTheme? { public func makePresentationTheme(settings: TelegramThemeSettings, title: String? = nil, serviceBackgroundColor: UIColor? = nil) -> PresentationTheme? {
let defaultTheme = makeDefaultPresentationTheme(reference: PresentationBuiltinThemeReference(baseTheme: settings.baseTheme), extendingThemeReference: nil, serviceBackgroundColor: serviceBackgroundColor, preview: false) let defaultTheme = makeDefaultPresentationTheme(reference: PresentationBuiltinThemeReference(baseTheme: settings.baseTheme), extendingThemeReference: nil, serviceBackgroundColor: serviceBackgroundColor, preview: false)
return customizePresentationTheme(defaultTheme, specialMode: specialMode, editing: true, title: title, accentColor: UIColor(argb: settings.accentColor), outgoingAccentColor: settings.outgoingAccentColor.flatMap { UIColor(argb: $0) }, backgroundColors: [], bubbleColors: settings.messageColors, animateBubbleColors: settings.animateMessageColors, wallpaper: settings.wallpaper) return customizePresentationTheme(defaultTheme, editing: true, title: title, accentColor: UIColor(argb: settings.accentColor), outgoingAccentColor: settings.outgoingAccentColor.flatMap { UIColor(argb: $0) }, backgroundColors: [], bubbleColors: settings.messageColors, animateBubbleColors: settings.animateMessageColors, wallpaper: settings.wallpaper)
} }
public func makePresentationTheme(mediaBox: MediaBox, themeReference: PresentationThemeReference, extendingThemeReference: PresentationThemeReference? = nil, accentColor: UIColor? = nil, outgoingAccentColor: UIColor? = nil, backgroundColors: [UInt32] = [], bubbleColors: [UInt32] = [], animateBubbleColors: Bool? = nil, wallpaper: TelegramWallpaper? = nil, baseColor: PresentationThemeBaseColor? = nil, serviceBackgroundColor: UIColor? = nil, specialMode: Bool = false, preview: Bool = false) -> PresentationTheme? { public func makePresentationTheme(cloudTheme: TelegramTheme) -> PresentationTheme? {
guard let settings = cloudTheme.settings else {
return nil
}
let defaultTheme = makeDefaultPresentationTheme(reference: PresentationBuiltinThemeReference(baseTheme: settings.baseTheme), extendingThemeReference: nil, serviceBackgroundColor: nil, preview: false)
return customizePresentationTheme(defaultTheme, editing: true, accentColor: UIColor(argb: settings.accentColor), outgoingAccentColor: settings.outgoingAccentColor.flatMap { UIColor(argb: $0) }, backgroundColors: [], bubbleColors: settings.messageColors, animateBubbleColors: settings.animateMessageColors, wallpaper: settings.wallpaper)
}
public func makePresentationTheme(mediaBox: MediaBox, themeReference: PresentationThemeReference, extendingThemeReference: PresentationThemeReference? = nil, accentColor: UIColor? = nil, outgoingAccentColor: UIColor? = nil, backgroundColors: [UInt32] = [], bubbleColors: [UInt32] = [], animateBubbleColors: Bool? = nil, wallpaper: TelegramWallpaper? = nil, baseColor: PresentationThemeBaseColor? = nil, serviceBackgroundColor: UIColor? = nil, preview: Bool = false) -> PresentationTheme? {
let theme: PresentationTheme let theme: PresentationTheme
switch themeReference { switch themeReference {
case let .builtin(reference): case let .builtin(reference):
let defaultTheme = makeDefaultPresentationTheme(reference: reference, extendingThemeReference: extendingThemeReference, serviceBackgroundColor: serviceBackgroundColor, preview: preview) let defaultTheme = makeDefaultPresentationTheme(reference: reference, extendingThemeReference: extendingThemeReference, serviceBackgroundColor: serviceBackgroundColor, preview: preview)
theme = customizePresentationTheme(defaultTheme, specialMode: specialMode, editing: true, accentColor: accentColor, outgoingAccentColor: outgoingAccentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, animateBubbleColors: animateBubbleColors, wallpaper: wallpaper, baseColor: baseColor) theme = customizePresentationTheme(defaultTheme, editing: true, accentColor: accentColor, outgoingAccentColor: outgoingAccentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, animateBubbleColors: animateBubbleColors, wallpaper: wallpaper, baseColor: baseColor)
case let .local(info): case let .local(info):
if let path = mediaBox.completedResourcePath(info.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead), let loadedTheme = makePresentationTheme(data: data, themeReference: themeReference, resolvedWallpaper: info.resolvedWallpaper) { if let path = mediaBox.completedResourcePath(info.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, outgoingAccentColor: outgoingAccentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, animateBubbleColors: animateBubbleColors, wallpaper: wallpaper) theme = customizePresentationTheme(loadedTheme, editing: false, accentColor: accentColor, outgoingAccentColor: outgoingAccentColor, backgroundColors: backgroundColors, bubbleColors: bubbleColors, animateBubbleColors: animateBubbleColors, wallpaper: wallpaper)

View File

@ -3926,6 +3926,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
let accountManager = context.sharedContext.accountManager let accountManager = context.sharedContext.accountManager
let currentThemeEmoticon = Atomic<(String?, Bool)?>(value: nil)
self.presentationDataDisposable = combineLatest(queue: Queue.mainQueue(), context.sharedContext.presentationData, themeSettings, context.engine.themes.getChatThemes(accountManager: accountManager, onlyCached: false), themeEmoticon, self.themeEmoticonAndDarkAppearancePreviewPromise.get()).start(next: { [weak self] presentationData, themeSettings, chatThemes, themeEmoticon, themeEmoticonAndDarkAppearance in self.presentationDataDisposable = combineLatest(queue: Queue.mainQueue(), context.sharedContext.presentationData, themeSettings, context.engine.themes.getChatThemes(accountManager: accountManager, onlyCached: false), themeEmoticon, self.themeEmoticonAndDarkAppearancePreviewPromise.get()).start(next: { [weak self] presentationData, themeSettings, chatThemes, themeEmoticon, themeEmoticonAndDarkAppearance in
if let strongSelf = self { if let strongSelf = self {
let (themeEmoticonPreview, darkAppearancePreview) = themeEmoticonAndDarkAppearance let (themeEmoticonPreview, darkAppearancePreview) = themeEmoticonAndDarkAppearance
@ -3944,17 +3945,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
var presentationData = presentationData var presentationData = presentationData
var useDarkAppearance = presentationData.theme.overallDarkAppearance
if let themeEmoticon = themeEmoticon, let theme = chatThemes.first(where: { $0.emoji == themeEmoticon }) { if let themeEmoticon = themeEmoticon, let theme = chatThemes.first(where: { $0.emoji == themeEmoticon }) {
var useDarkAppearance = presentationData.theme.overallDarkAppearance
if let darkAppearancePreview = darkAppearancePreview { if let darkAppearancePreview = darkAppearancePreview {
useDarkAppearance = darkAppearancePreview useDarkAppearance = darkAppearancePreview
} }
let customTheme = useDarkAppearance ? theme.darkTheme : theme.theme let customTheme = useDarkAppearance ? theme.darkTheme : theme.theme
if let settings = customTheme.settings, let theme = makePresentationTheme(settings: settings) { if let settings = customTheme.settings, let theme = makePresentationTheme(settings: settings) {
presentationData = presentationData.withUpdated(theme: theme) presentationData = presentationData.withUpdated(theme: theme).withUpdated(chatWallpaper: theme.chat.defaultWallpaper)
presentationData = presentationData.withUpdated(chatWallpaper: theme.chat.defaultWallpaper)
} }
} else if let darkAppearancePreview = darkAppearancePreview { } else if let darkAppearancePreview = darkAppearancePreview {
useDarkAppearance = darkAppearancePreview
let lightTheme: PresentationTheme let lightTheme: PresentationTheme
let lightWallpaper: TelegramWallpaper let lightWallpaper: TelegramWallpaper
@ -4009,24 +4011,24 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
if darkAppearancePreview { if darkAppearancePreview {
presentationData = presentationData.withUpdated(theme: darkTheme) presentationData = presentationData.withUpdated(theme: darkTheme).withUpdated(chatWallpaper: darkWallpaper)
presentationData = presentationData.withUpdated(chatWallpaper: darkWallpaper)
} else { } else {
presentationData = presentationData.withUpdated(theme: lightTheme) presentationData = presentationData.withUpdated(theme: lightTheme).withUpdated(chatWallpaper: lightWallpaper)
presentationData = presentationData.withUpdated(chatWallpaper: lightWallpaper)
} }
} }
let isFirstTime = !strongSelf.didSetPresentationData let isFirstTime = !strongSelf.didSetPresentationData
strongSelf.presentationData = presentationData strongSelf.presentationData = presentationData
strongSelf.didSetPresentationData = true strongSelf.didSetPresentationData = true
if isFirstTime || previousTheme !== presentationData.theme || previousStrings !== presentationData.strings || presentationData.chatWallpaper != previousChatWallpaper { let previousThemeEmoticon = currentThemeEmoticon.swap((themeEmoticon, useDarkAppearance))
if isFirstTime || previousTheme != presentationData.theme || previousStrings !== presentationData.strings || presentationData.chatWallpaper != previousChatWallpaper {
strongSelf.themeAndStringsUpdated() strongSelf.themeAndStringsUpdated()
controllerInteraction.updatedPresentationData = strongSelf.updatedPresentationData controllerInteraction.updatedPresentationData = strongSelf.updatedPresentationData
strongSelf.presentationDataPromise.set(.single(strongSelf.presentationData)) strongSelf.presentationDataPromise.set(.single(strongSelf.presentationData))
if !isFirstTime && previousTheme !== presentationData.theme { if !isFirstTime && (previousThemeEmoticon?.0 != themeEmoticon || previousThemeEmoticon?.1 != useDarkAppearance) {
strongSelf.presentCrossfadeSnapshot(delay: 0.2) strongSelf.presentCrossfadeSnapshot(delay: 0.2)
} }
} }
@ -5932,7 +5934,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|> deliverOnMainQueue).start(next: { [weak self] searchResult in |> deliverOnMainQueue).start(next: { [weak self] searchResult in
if let strongSelf = self, let (searchResult, searchState, searchLocation) = searchResult { if let strongSelf = self, let (searchResult, searchState, searchLocation) = searchResult {
let controller = ChatSearchResultsController(context: strongSelf.context, location: searchLocation, searchQuery: searchData.query, searchResult: searchResult, searchState: searchState, navigateToMessageIndex: { index in let controller = ChatSearchResultsController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, location: searchLocation, searchQuery: searchData.query, searchResult: searchResult, searchState: searchState, navigateToMessageIndex: { index in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
@ -13365,9 +13367,28 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return updated return updated
}) })
let _ = (self.cachedDataPromise.get() let animatedEmojiStickers = context.engine.stickers.loadedStickerPack(reference: .animatedEmoji, forceActualized: false)
|> take(1) |> map { animatedEmoji -> [String: [StickerPackItem]] in
|> deliverOnMainQueue).start(next: { [weak self] cachedData in var animatedEmojiStickers: [String: [StickerPackItem]] = [:]
switch animatedEmoji {
case let .result(_, items, _):
for case let item as StickerPackItem in items {
if let emoji = item.getStringRepresentationsOfIndexKeys().first {
animatedEmojiStickers[emoji.basicEmoji.0] = [item]
let strippedEmoji = emoji.basicEmoji.0.strippedEmoji
if animatedEmojiStickers[strippedEmoji] == nil {
animatedEmojiStickers[strippedEmoji] = [item]
}
}
}
default:
break
}
return animatedEmojiStickers
}
let _ = (combineLatest(queue: Queue.mainQueue(), self.cachedDataPromise.get(), animatedEmojiStickers)
|> take(1)).start(next: { [weak self] cachedData, animatedEmojiStickers in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
@ -13383,14 +13404,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
selectedEmoticon = nil selectedEmoticon = nil
} }
let controller = ChatThemeScreen(context: context, updatedPresentationData: strongSelf.updatedPresentationData, initiallySelectedEmoticon: selectedEmoticon, previewTheme: { [weak self] emoticon, dark in let controller = ChatThemeScreen(context: context, updatedPresentationData: strongSelf.updatedPresentationData, animatedEmojiStickers: animatedEmojiStickers, initiallySelectedEmoticon: selectedEmoticon, previewTheme: { [weak self] emoticon, dark in
if let strongSelf = self { if let strongSelf = self {
strongSelf.presentCrossfadeSnapshot(delay: 0.2) strongSelf.presentCrossfadeSnapshot(delay: 0.2)
strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon, dark))) strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon, dark)))
} }
}, completion: { [weak self] emoticon in }, completion: { [weak self] emoticon in
strongSelf.presentCrossfadeSnapshot(delay: 0.2) strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon ?? "", nil)))
strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon, nil)))
let _ = context.engine.themes.setChatTheme(peerId: peerId, emoticon: emoticon).start(completed: { [weak self] in let _ = context.engine.themes.setChatTheme(peerId: peerId, emoticon: emoticon).start(completed: { [weak self] in
if let strongSelf = self { if let strongSelf = self {
strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((nil, nil))) strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((nil, nil)))

View File

@ -25,9 +25,9 @@ final class ChatSearchResultsController: ViewController {
private var presentationDataDisposable: Disposable? private var presentationDataDisposable: Disposable?
init(context: AccountContext, location: SearchMessagesLocation, searchQuery: String, searchResult: SearchMessagesResult, searchState: SearchMessagesState, navigateToMessageIndex: @escaping (Int) -> Void, resultsUpdated: @escaping (SearchMessagesResult, SearchMessagesState) -> Void) { init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, location: SearchMessagesLocation, searchQuery: String, searchResult: SearchMessagesResult, searchState: SearchMessagesState, navigateToMessageIndex: @escaping (Int) -> Void, resultsUpdated: @escaping (SearchMessagesResult, SearchMessagesState) -> Void) {
self.context = context self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 } self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
self.location = location self.location = location
self.searchQuery = searchQuery self.searchQuery = searchQuery
self.navigateToMessageIndex = navigateToMessageIndex self.navigateToMessageIndex = navigateToMessageIndex
@ -39,7 +39,7 @@ final class ChatSearchResultsController: ViewController {
self.navigationPresentation = .modal self.navigationPresentation = .modal
self.presentationDataDisposable = (context.sharedContext.presentationData self.presentationDataDisposable = ((updatedPresentationData?.signal ?? context.sharedContext.presentationData)
|> deliverOnMainQueue).start(next: { [weak self] presentationData in |> deliverOnMainQueue).start(next: { [weak self] presentationData in
if let strongSelf = self { if let strongSelf = self {
strongSelf.presentationData = presentationData strongSelf.presentationData = presentationData

View File

@ -14,8 +14,12 @@ import PresentationDataUtils
import AnimationUI import AnimationUI
import MergeLists import MergeLists
import MediaResources import MediaResources
import StickerResources
import WallpaperResources import WallpaperResources
import TooltipUI import TooltipUI
import AnimatedStickerNode
import TelegramAnimatedStickerNode
import ShimmerEffect
private func closeButtonImage(theme: PresentationTheme) -> UIImage? { private func closeButtonImage(theme: PresentationTheme) -> UIImage? {
return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in
@ -41,6 +45,7 @@ private func closeButtonImage(theme: PresentationTheme) -> UIImage? {
private struct ThemeSettingsThemeEntry: Comparable, Identifiable { private struct ThemeSettingsThemeEntry: Comparable, Identifiable {
let index: Int let index: Int
let emoticon: String? let emoticon: String?
let emojiFile: TelegramMediaFile?
let themeReference: PresentationThemeReference? let themeReference: PresentationThemeReference?
var selected: Bool var selected: Bool
let theme: PresentationTheme let theme: PresentationTheme
@ -58,6 +63,7 @@ private struct ThemeSettingsThemeEntry: Comparable, Identifiable {
if lhs.emoticon != rhs.emoticon { if lhs.emoticon != rhs.emoticon {
return false return false
} }
if lhs.themeReference?.index != rhs.themeReference?.index { if lhs.themeReference?.index != rhs.themeReference?.index {
return false return false
} }
@ -81,7 +87,7 @@ private struct ThemeSettingsThemeEntry: Comparable, Identifiable {
} }
func item(context: AccountContext, action: @escaping (String?) -> Void) -> ListViewItem { func item(context: AccountContext, action: @escaping (String?) -> Void) -> ListViewItem {
return ThemeSettingsThemeIconItem(context: context, emoticon: self.emoticon, themeReference: self.themeReference, selected: self.selected, theme: self.theme, strings: self.strings, wallpaper: self.wallpaper, action: action) return ThemeSettingsThemeIconItem(context: context, emoticon: self.emoticon, emojiFile: self.emojiFile, themeReference: self.themeReference, selected: self.selected, theme: self.theme, strings: self.strings, wallpaper: self.wallpaper, action: action)
} }
} }
@ -89,6 +95,7 @@ private struct ThemeSettingsThemeEntry: Comparable, Identifiable {
private class ThemeSettingsThemeIconItem: ListViewItem { private class ThemeSettingsThemeIconItem: ListViewItem {
let context: AccountContext let context: AccountContext
let emoticon: String? let emoticon: String?
let emojiFile: TelegramMediaFile?
let themeReference: PresentationThemeReference? let themeReference: PresentationThemeReference?
let selected: Bool let selected: Bool
let theme: PresentationTheme let theme: PresentationTheme
@ -96,9 +103,10 @@ private class ThemeSettingsThemeIconItem: ListViewItem {
let wallpaper: TelegramWallpaper? let wallpaper: TelegramWallpaper?
let action: (String?) -> Void let action: (String?) -> Void
public init(context: AccountContext, emoticon: String?, themeReference: PresentationThemeReference?, selected: Bool, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper?, action: @escaping (String?) -> Void) { public init(context: AccountContext, emoticon: String?, emojiFile: TelegramMediaFile?, themeReference: PresentationThemeReference?, selected: Bool, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper?, action: @escaping (String?) -> Void) {
self.context = context self.context = context
self.emoticon = emoticon self.emoticon = emoticon
self.emojiFile = emojiFile
self.themeReference = themeReference self.themeReference = themeReference
self.selected = selected self.selected = selected
self.theme = theme self.theme = theme
@ -231,16 +239,37 @@ private func generateBorderImage(theme: PresentationTheme, bordered: Bool, selec
private final class ThemeSettingsThemeItemIconNode : ListViewItemNode { private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
private let containerNode: ASDisplayNode private let containerNode: ASDisplayNode
private let emojiContainerNode: ASDisplayNode
private let imageNode: TransformImageNode private let imageNode: TransformImageNode
private let overlayNode: ASImageNode private let overlayNode: ASImageNode
private let textNode: TextNode private let textNode: TextNode
private let emojiNode: TextNode private let emojiNode: TextNode
private let emojiImageNode: TransformImageNode
private var animatedStickerNode: AnimatedStickerNode?
private var placeholderNode: StickerShimmerEffectNode
var snapshotView: UIView? var snapshotView: UIView?
var item: ThemeSettingsThemeIconItem? var item: ThemeSettingsThemeIconItem?
override var visibility: ListViewItemNodeVisibility {
didSet {
self.visibilityStatus = self.visibility != .none
}
}
private var visibilityStatus: Bool = false {
didSet {
if self.visibilityStatus != oldValue {
self.animatedStickerNode?.visibility = self.visibilityStatus
}
}
}
private let stickerFetchedDisposable = MetaDisposable()
init() { init() {
self.containerNode = ASDisplayNode() self.containerNode = ASDisplayNode()
self.emojiContainerNode = ASDisplayNode()
self.imageNode = TransformImageNode() self.imageNode = TransformImageNode()
self.imageNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 82.0, height: 108.0)) self.imageNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 82.0, height: 108.0))
@ -257,6 +286,10 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
self.emojiNode = TextNode() self.emojiNode = TextNode()
self.emojiNode.isUserInteractionEnabled = false self.emojiNode.isUserInteractionEnabled = false
self.emojiImageNode = TransformImageNode()
self.placeholderNode = StickerShimmerEffectNode()
super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false) super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false)
@ -264,9 +297,47 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
self.containerNode.addSubnode(self.imageNode) self.containerNode.addSubnode(self.imageNode)
self.containerNode.addSubnode(self.overlayNode) self.containerNode.addSubnode(self.overlayNode)
self.containerNode.addSubnode(self.textNode) self.containerNode.addSubnode(self.textNode)
self.containerNode.addSubnode(self.emojiNode)
self.addSubnode(self.emojiContainerNode)
self.emojiContainerNode.addSubnode(self.emojiNode)
self.emojiContainerNode.addSubnode(self.emojiImageNode)
self.emojiContainerNode.addSubnode(self.placeholderNode)
var firstTime = true
self.emojiImageNode.imageUpdated = { [weak self] image in
guard let strongSelf = self else {
return
}
if image != nil {
strongSelf.removePlaceholder(animated: !firstTime)
if firstTime {
strongSelf.emojiImageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
}
firstTime = false
}
} }
deinit {
self.stickerFetchedDisposable.dispose()
}
private func removePlaceholder(animated: Bool) {
if !animated {
self.placeholderNode.removeFromSupernode()
} else {
self.placeholderNode.alpha = 0.0
self.placeholderNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in
self?.placeholderNode.removeFromSupernode()
})
}
}
override func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
let emojiFrame = CGRect(origin: CGPoint(x: 33.0, y: 79.0), size: CGSize(width: 24.0, height: 24.0))
self.placeholderNode.updateAbsoluteRect(CGRect(origin: CGPoint(x: rect.minX + emojiFrame.minX, y: rect.minY + emojiFrame.minY), size: emojiFrame.size), within: containerSize)
}
func asyncLayout() -> (ThemeSettingsThemeIconItem, ListViewItemLayoutParams) -> (ListViewItemNodeLayout, (Bool) -> Void) { func asyncLayout() -> (ThemeSettingsThemeIconItem, ListViewItemLayoutParams) -> (ListViewItemNodeLayout, (Bool) -> Void) {
let makeTextLayout = TextNode.asyncLayout(self.textNode) let makeTextLayout = TextNode.asyncLayout(self.textNode)
let makeEmojiLayout = TextNode.asyncLayout(self.emojiNode) let makeEmojiLayout = TextNode.asyncLayout(self.emojiNode)
@ -275,11 +346,15 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
let currentItem = self.item let currentItem = self.item
return { [weak self] item, params in return { [weak self] item, params in
var updatedEmoticon = false
var updatedThemeReference = false var updatedThemeReference = false
var updatedTheme = false var updatedTheme = false
var updatedWallpaper = false var updatedWallpaper = false
var updatedSelected = false var updatedSelected = false
if currentItem?.emoticon != item.emoticon {
updatedEmoticon = true
}
if currentItem?.themeReference != item.themeReference { if currentItem?.themeReference != item.themeReference {
updatedThemeReference = true updatedThemeReference = true
} }
@ -296,7 +371,13 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
let text = NSAttributedString(string: item.strings.Conversation_Theme_NoTheme, font: Font.semibold(15.0), textColor: item.theme.actionSheet.controlAccentColor) let text = NSAttributedString(string: item.strings.Conversation_Theme_NoTheme, font: Font.semibold(15.0), textColor: item.theme.actionSheet.controlAccentColor)
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: text, backgroundColor: nil, maximumNumberOfLines: 2, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: text, backgroundColor: nil, maximumNumberOfLines: 2, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
let title = NSAttributedString(string: item.emoticon ?? "", font: Font.regular(22.0), textColor: .black) var emoticon = item.emoticon
if emoticon == "🦁" {
emoticon = "🌳"
} else if emoticon == "🔮" {
emoticon = "🎆"
}
let title = NSAttributedString(string: emoticon != nil ? "" : "", font: Font.regular(22.0), textColor: .black)
let (_, emojiApply) = makeEmojiLayout(TextNodeLayoutArguments(attributedString: title, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) let (_, emojiApply) = makeEmojiLayout(TextNodeLayoutArguments(attributedString: title, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
let itemLayout = ListViewItemNodeLayout(contentSize: CGSize(width: 120.0, height: 90.0), insets: UIEdgeInsets()) let itemLayout = ListViewItemNodeLayout(contentSize: CGSize(width: 120.0, height: 90.0), insets: UIEdgeInsets())
@ -324,6 +405,9 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
strongSelf.containerNode.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0) strongSelf.containerNode.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
strongSelf.containerNode.frame = CGRect(origin: CGPoint(x: 15.0, y: -15.0), size: CGSize(width: 90.0, height: 120.0)) strongSelf.containerNode.frame = CGRect(origin: CGPoint(x: 15.0, y: -15.0), size: CGSize(width: 90.0, height: 120.0))
strongSelf.emojiContainerNode.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
strongSelf.emojiContainerNode.frame = CGRect(origin: CGPoint(x: 15.0, y: -15.0), size: CGSize(width: 90.0, height: 120.0))
let _ = textApply() let _ = textApply()
let _ = emojiApply() let _ = emojiApply()
@ -334,14 +418,50 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
strongSelf.overlayNode.frame = strongSelf.imageNode.frame.insetBy(dx: -1.0, dy: -1.0) strongSelf.overlayNode.frame = strongSelf.imageNode.frame.insetBy(dx: -1.0, dy: -1.0)
strongSelf.emojiNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 79.0), size: CGSize(width: 90.0, height: 30.0)) strongSelf.emojiNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 79.0), size: CGSize(width: 90.0, height: 30.0))
let emojiFrame = CGRect(origin: CGPoint(x: 33.0, y: 79.0), size: CGSize(width: 24.0, height: 24.0))
if let file = item.emojiFile, updatedEmoticon {
let imageApply = strongSelf.emojiImageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: emojiFrame.size, boundingSize: emojiFrame.size, intrinsicInsets: UIEdgeInsets()))
imageApply()
strongSelf.emojiImageNode.setSignal(chatMessageStickerPackThumbnail(postbox: item.context.account.postbox, resource: file.resource, animated: true, nilIfEmpty: true))
strongSelf.emojiImageNode.frame = emojiFrame
let animatedStickerNode: AnimatedStickerNode
if let current = strongSelf.animatedStickerNode {
animatedStickerNode = current
} else {
animatedStickerNode = AnimatedStickerNode()
animatedStickerNode.started = { [weak self] in
self?.emojiImageNode.isHidden = true
}
strongSelf.animatedStickerNode = animatedStickerNode
strongSelf.emojiContainerNode.insertSubnode(animatedStickerNode, belowSubnode: strongSelf.placeholderNode)
let pathPrefix = item.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(file.resource.id)
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: item.context.account, resource: file.resource), width: 96, height: 96, mode: .direct(cachePathPrefix: pathPrefix))
}
animatedStickerNode.visibility = strongSelf.visibilityStatus
strongSelf.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: item.context.account.postbox.mediaBox, reference: MediaResourceReference.media(media: .standalone(media: file), resource: file.resource)).start())
let thumbnailDimensions = PixelDimensions(width: 512, height: 512)
strongSelf.placeholderNode.update(backgroundColor: nil, foregroundColor: UIColor(rgb: 0xffffff, alpha: 0.2), shimmeringColor: UIColor(rgb: 0xffffff, alpha: 0.3), data: file.immediateThumbnailData, size: emojiFrame.size, imageSize: thumbnailDimensions.cgSize)
strongSelf.placeholderNode.frame = emojiFrame
}
if let animatedStickerNode = strongSelf.animatedStickerNode {
animatedStickerNode.frame = emojiFrame
animatedStickerNode.updateLayout(size: emojiFrame.size)
}
} }
}) })
} }
} }
func crossfade() { func crossfade() {
if let snapshotView = self.view.snapshotView(afterScreenUpdates: false) { if let snapshotView = self.containerNode.view.snapshotView(afterScreenUpdates: false) {
self.view.addSubview(snapshotView) snapshotView.transform = self.containerNode.view.transform
snapshotView.frame = self.containerNode.view.frame
self.view.insertSubview(snapshotView, aboveSubview: self.containerNode.view)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, delay: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, delay: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview() snapshotView?.removeFromSuperview()
@ -376,6 +496,7 @@ final class ChatThemeScreen: ViewController {
private var animatedIn = false private var animatedIn = false
private let context: AccountContext private let context: AccountContext
private let animatedEmojiStickers: [String: [StickerPackItem]]
private let initiallySelectedEmoticon: String? private let initiallySelectedEmoticon: String?
private let dismissByTapOutside: Bool private let dismissByTapOutside: Bool
private let previewTheme: (String?, Bool?) -> Void private let previewTheme: (String?, Bool?) -> Void
@ -392,9 +513,10 @@ final class ChatThemeScreen: ViewController {
} }
} }
init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>), initiallySelectedEmoticon: String?, dismissByTapOutside: Bool = true, previewTheme: @escaping (String?, Bool?) -> Void, completion: @escaping (String?) -> Void) { init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>), animatedEmojiStickers: [String: [StickerPackItem]], initiallySelectedEmoticon: String?, dismissByTapOutside: Bool = true, previewTheme: @escaping (String?, Bool?) -> Void, completion: @escaping (String?) -> Void) {
self.context = context self.context = context
self.presentationData = updatedPresentationData.initial self.presentationData = updatedPresentationData.initial
self.animatedEmojiStickers = animatedEmojiStickers
self.initiallySelectedEmoticon = initiallySelectedEmoticon self.initiallySelectedEmoticon = initiallySelectedEmoticon
self.dismissByTapOutside = dismissByTapOutside self.dismissByTapOutside = dismissByTapOutside
self.previewTheme = previewTheme self.previewTheme = previewTheme
@ -426,7 +548,7 @@ final class ChatThemeScreen: ViewController {
} }
override public func loadDisplayNode() { override public func loadDisplayNode() {
self.displayNode = ChatThemeScreenNode(context: self.context, presentationData: self.presentationData, initiallySelectedEmoticon: self.initiallySelectedEmoticon, dismissByTapOutside: self.dismissByTapOutside) self.displayNode = ChatThemeScreenNode(context: self.context, presentationData: self.presentationData, animatedEmojiStickers: self.animatedEmojiStickers, initiallySelectedEmoticon: self.initiallySelectedEmoticon, dismissByTapOutside: self.dismissByTapOutside)
self.controllerNode.passthroughHitTestImpl = self.passthroughHitTestImpl self.controllerNode.passthroughHitTestImpl = self.passthroughHitTestImpl
self.controllerNode.previewTheme = { [weak self] emoticon, dark in self.controllerNode.previewTheme = { [weak self] emoticon, dark in
guard let strongSelf = self else { guard let strongSelf = self else {
@ -558,7 +680,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
var dismiss: (() -> Void)? var dismiss: (() -> Void)?
var cancel: (() -> Void)? var cancel: (() -> Void)?
init(context: AccountContext, presentationData: PresentationData, initiallySelectedEmoticon: String?, dismissByTapOutside: Bool) { init(context: AccountContext, presentationData: PresentationData, animatedEmojiStickers: [String: [StickerPackItem]], initiallySelectedEmoticon: String?, dismissByTapOutside: Bool) {
self.context = context self.context = context
self.initiallySelectedEmoticon = initiallySelectedEmoticon self.initiallySelectedEmoticon = initiallySelectedEmoticon
self.selectedEmoticon = initiallySelectedEmoticon self.selectedEmoticon = initiallySelectedEmoticon
@ -662,18 +784,24 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
var entries: [ThemeSettingsThemeEntry] = [] var entries: [ThemeSettingsThemeEntry] = []
if strongSelf.initiallySelectedEmoticon != nil { if strongSelf.initiallySelectedEmoticon != nil {
entries.append(ThemeSettingsThemeEntry(index: 0, emoticon: nil, themeReference: nil, selected: selectedEmoticon == nil, theme: presentationData.theme, strings: presentationData.strings, wallpaper: nil)) entries.append(ThemeSettingsThemeEntry(index: 0, emoticon: nil, emojiFile: nil, themeReference: nil, selected: selectedEmoticon == nil, theme: presentationData.theme, strings: presentationData.strings, wallpaper: nil))
} }
for theme in themes { for theme in themes {
entries.append(ThemeSettingsThemeEntry(index: entries.count, emoticon: theme.emoji, themeReference: .cloud(PresentationCloudTheme(theme: isDarkAppearance ? theme.darkTheme : theme.theme, resolvedWallpaper: nil, creatorAccountId: nil)), selected: selectedEmoticon == theme.emoji, theme: presentationData.theme, strings: presentationData.strings, wallpaper: nil)) var emoticon = theme.emoji
if emoticon == "🦁" {
emoticon = "🌳"
} else if emoticon == "🔮" {
emoticon = "🎆"
}
entries.append(ThemeSettingsThemeEntry(index: entries.count, emoticon: theme.emoji, emojiFile: animatedEmojiStickers[emoticon]?.first?.file, themeReference: .cloud(PresentationCloudTheme(theme: isDarkAppearance ? theme.darkTheme : theme.theme, resolvedWallpaper: nil, creatorAccountId: nil)), selected: selectedEmoticon == theme.emoji, theme: presentationData.theme, strings: presentationData.strings, wallpaper: nil))
} }
let action: (String?) -> Void = { [weak self] emoticon in let action: (String?) -> Void = { [weak self] emoticon in
if let strongSelf = self, strongSelf.selectedEmoticon != emoticon { if let strongSelf = self, strongSelf.selectedEmoticon != emoticon {
strongSelf.animateCrossfade(animateBackground: strongSelf.presentationData.theme.overallDarkAppearance, updateSunIcon: true) strongSelf.animateCrossfade(animateBackground: strongSelf.presentationData.theme.overallDarkAppearance, updateSunIcon: true)
strongSelf.selectedEmoticon = emoticon
strongSelf.previewTheme?(emoticon, strongSelf.isDarkAppearance) strongSelf.previewTheme?(emoticon, strongSelf.isDarkAppearance)
strongSelf.selectedEmoticon = emoticon
let _ = ensureThemeVisible(listNode: strongSelf.listNode, emoticon: emoticon, animated: true) let _ = ensureThemeVisible(listNode: strongSelf.listNode, emoticon: emoticon, animated: true)
strongSelf.doneButton.title = emoticon == nil ? strongSelf.presentationData.strings.Conversation_Theme_Reset : strongSelf.presentationData.strings.Conversation_Theme_Apply strongSelf.doneButton.title = emoticon == nil ? strongSelf.presentationData.strings.Conversation_Theme_Reset : strongSelf.presentationData.strings.Conversation_Theme_Apply

View File

@ -3489,20 +3489,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
let filteredButtons = allHeaderButtons.subtracting(headerButtons) let filteredButtons = allHeaderButtons.subtracting(headerButtons)
var canChangeColors = true var canChangeColors = false
// if let peer = peer as? TelegramUser, self.data?.encryptionKeyFingerprint == nil { if peer is TelegramUser, self.data?.encryptionKeyFingerprint == nil {
// canChangeColors = true canChangeColors = true
// }
if let peer = peer as? TelegramChannel {
if case .broadcast = peer.info {
canChangeColors = false
} else {
canChangeColors = peer.hasPermission(.changeInfo)
}
} else if let peer = peer as? TelegramGroup, case .member = peer.role {
canChangeColors = !peer.hasBannedPermission(.banChangeInfo)
} else if self.data?.encryptionKeyFingerprint != nil {
canChangeColors = false
} }
if canChangeColors { if canChangeColors {
@ -6799,7 +6788,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen {
} }
} }
self.presentationDataDisposable = ((updatedPresentationData?.signal ?? context.sharedContext.presentationData) self.presentationDataDisposable = (presentationDataSignal
|> deliverOnMainQueue).start(next: { [weak self] presentationData in |> deliverOnMainQueue).start(next: { [weak self] presentationData in
if let strongSelf = self { if let strongSelf = self {
let previousTheme = strongSelf.presentationData.theme let previousTheme = strongSelf.presentationData.theme

View File

@ -78,6 +78,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
var displayUndo = true var displayUndo = true
var undoText = presentationData.strings.Undo_Undo var undoText = presentationData.strings.Undo_Undo
var undoTextColor = UIColor(rgb: 0x5ac8fa) var undoTextColor = UIColor(rgb: 0x5ac8fa)
undoTextColor = presentationData.theme.list.itemAccentColor.withMultiplied(hue: 1.0, saturation: 0.64, brightness: 1.08)
if presentationData.theme.overallDarkAppearance { if presentationData.theme.overallDarkAppearance {
self.animationBackgroundColor = presentationData.theme.rootController.tabBar.backgroundColor self.animationBackgroundColor = presentationData.theme.rootController.tabBar.backgroundColor