Name color improvements

This commit is contained in:
Ilya Laktyushin 2023-10-25 12:32:54 +04:00
parent 2511c4a773
commit c444628fbe
17 changed files with 394 additions and 156 deletions

View File

@ -1044,6 +1044,7 @@ public protocol AccountContext: AnyObject {
var isPremium: Bool { get }
var userLimits: EngineConfiguration.UserLimits { get }
var peerNameColors: PeerNameColors { get }
var imageCache: AnyObject? { get }
@ -1200,3 +1201,136 @@ public struct StickersSearchConfiguration {
}
}
}
public class PeerNameColors: Equatable {
public struct Colors: Equatable {
public let main: UIColor
public let secondary: UIColor?
public let tertiary: UIColor?
init(main: UIColor, secondary: UIColor?, tertiary: UIColor?) {
self.main = main
self.secondary = secondary
self.tertiary = tertiary
}
init(main: UIColor) {
self.main = main
self.secondary = nil
self.tertiary = nil
}
init?(colors: [UIColor]) {
guard let first = colors.first else {
return nil
}
self.main = first
if colors.count == 3 {
self.secondary = colors[1]
self.tertiary = colors[2]
} else if colors.count == 2, let second = colors.last {
self.secondary = second
self.tertiary = nil
} else {
self.secondary = nil
self.tertiary = nil
}
}
}
public static var defaultSingleColors: [Int32: Colors] {
return [
0: Colors(main: UIColor(rgb: 0xcc5049)),
1: Colors(main: UIColor(rgb: 0xd67722)),
2: Colors(main: UIColor(rgb: 0x955cdb)),
3: Colors(main: UIColor(rgb: 0x40a920)),
4: Colors(main: UIColor(rgb: 0x309eba)),
5: Colors(main: UIColor(rgb: 0x368ad1)),
6: Colors(main: UIColor(rgb: 0xc7508b))
]
}
public static var defaultValue: PeerNameColors {
return PeerNameColors(
colors: defaultSingleColors,
darkColors: [:],
displayOrder: [5, 3, 1, 0, 2, 4, 6]
)
}
public let colors: [Int32: Colors]
public let darkColors: [Int32: Colors]
public let displayOrder: [Int32]
public func get(_ color: PeerNameColor) -> Colors {
if let colors = self.colors[color.rawValue] {
return colors
} else {
return PeerNameColors.defaultSingleColors[5]!
}
}
fileprivate init(colors: [Int32: Colors], darkColors: [Int32: Colors], displayOrder: [Int32]) {
self.colors = colors
self.darkColors = darkColors
self.displayOrder = displayOrder
}
public static func with(appConfiguration: AppConfiguration) -> PeerNameColors {
if let data = appConfiguration.data {
var colors = PeerNameColors.defaultSingleColors
var darkColors: [Int32: Colors] = [:]
if let peerColors = data["peer_colors"] as? [String: [Double]] {
for (key, values) in peerColors {
if let index = Int32(key) {
let colorsArray = values.map { UIColor(rgb: UInt32($0)) }
if let colorValues = Colors(colors: colorsArray) {
colors[index] = colorValues
}
}
}
}
if let darkPeerColors = data["dark_peer_colors"] as? [String: [Double]] {
for (key, values) in darkPeerColors {
if let index = Int32(key) {
let colorsArray = values.map { UIColor(rgb: UInt32($0)) }
if let colorValues = Colors(colors: colorsArray) {
darkColors[index] = colorValues
}
}
}
}
var displayOrder: [Int32] = []
if let order = data["peer_colors_available"] as? [Double] {
displayOrder = order.map { Int32($0) }
}
if displayOrder.isEmpty {
displayOrder = PeerNameColors.defaultValue.displayOrder
}
return PeerNameColors(
colors: colors,
darkColors: darkColors,
displayOrder: displayOrder
)
} else {
return .defaultValue
}
}
public static func == (lhs: PeerNameColors, rhs: PeerNameColors) -> Bool {
if lhs.colors != rhs.colors {
return false
}
if lhs.darkColors != rhs.darkColors {
return false
}
if lhs.displayOrder != rhs.displayOrder {
return false
}
return true
}
}

View File

@ -369,7 +369,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
}
}
private func themeSettingsControllerEntries(presentationData: PresentationData, presentationThemeSettings: PresentationThemeSettings, mediaSettings: MediaDisplaySettings, themeReference: PresentationThemeReference, availableThemes: [PresentationThemeReference], availableAppIcons: [PresentationAppIcon], currentAppIconName: String?, isPremium: Bool, chatThemes: [PresentationThemeReference], animatedEmojiStickers: [String: [StickerPackItem]], accountPeer: EnginePeer?) -> [ThemeSettingsControllerEntry] {
private func themeSettingsControllerEntries(presentationData: PresentationData, presentationThemeSettings: PresentationThemeSettings, mediaSettings: MediaDisplaySettings, themeReference: PresentationThemeReference, availableThemes: [PresentationThemeReference], availableAppIcons: [PresentationAppIcon], currentAppIconName: String?, isPremium: Bool, chatThemes: [PresentationThemeReference], animatedEmojiStickers: [String: [StickerPackItem]], accountPeer: EnginePeer?, nameColors: PeerNameColors) -> [ThemeSettingsControllerEntry] {
var entries: [ThemeSettingsControllerEntry] = []
let strings = presentationData.strings
@ -382,7 +382,8 @@ private func themeSettingsControllerEntries(presentationData: PresentationData,
entries.append(.wallpaper(presentationData.theme, strings.Settings_ChatBackground))
if let accountPeer {
entries.append(.nameColor(presentationData.theme, strings.Appearance_NameColor, accountPeer.compactDisplayTitle, (accountPeer.nameColor ?? .blue).color))
let colors = nameColors.get(accountPeer.nameColor ?? .blue)
entries.append(.nameColor(presentationData.theme, strings.Appearance_NameColor, accountPeer.compactDisplayTitle, colors.main))
}
entries.append(.autoNight(presentationData.theme, strings.Appearance_NightTheme, presentationThemeSettings.automaticThemeSwitchSetting.force, !presentationData.autoNightModeTriggered || presentationThemeSettings.automaticThemeSwitchSetting.force))
@ -1064,7 +1065,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
chatThemes.insert(.builtin(.dayClassic), at: 0)
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.Appearance_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: themeSettingsControllerEntries(presentationData: presentationData, presentationThemeSettings: settings, mediaSettings: mediaSettings, themeReference: themeReference, availableThemes: availableThemes, availableAppIcons: availableAppIcons, currentAppIconName: currentAppIconName, isPremium: isPremium, chatThemes: chatThemes, animatedEmojiStickers: animatedEmojiStickers, accountPeer: accountPeer), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: themeSettingsControllerEntries(presentationData: presentationData, presentationThemeSettings: settings, mediaSettings: mediaSettings, themeReference: themeReference, availableThemes: availableThemes, availableAppIcons: availableAppIcons, currentAppIconName: currentAppIconName, isPremium: isPremium, chatThemes: chatThemes, animatedEmojiStickers: animatedEmojiStickers, accountPeer: accountPeer, nameColors: context.peerNameColors), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false)
return (controllerState, (listState, arguments))
}

View File

@ -114,7 +114,7 @@ public struct CachedPremiumGiftOption: Equatable, PostboxCoding {
}
}
public enum PeerNameColor: Int32, CaseIterable {
public enum PeerNameColor: Equatable {
case red
case orange
case violet
@ -122,13 +122,49 @@ public enum PeerNameColor: Int32, CaseIterable {
case cyan
case blue
case pink
case redDash
case orangeDash
case violetDash
case greenDash
case cyanDash
case blueDash
case pinkDash
case other(Int32)
public init(rawValue: Int32) {
switch rawValue {
case 0:
self = .red
case 1:
self = .orange
case 2:
self = .violet
case 3:
self = .green
case 4:
self = .cyan
case 5:
self = .blue
case 6:
self = .pink
default:
self = .other(rawValue)
}
}
public var rawValue: Int32 {
switch self {
case .red:
return 0
case .orange:
return 1
case .violet:
return 2
case .green:
return 3
case .cyan:
return 4
case .blue:
return 5
case .pink:
return 6
case let .other(value):
return value
}
}
}
public struct PeerEmojiStatus: Equatable, Codable {

View File

@ -223,27 +223,19 @@ public extension Peer {
if let nameColor = user.nameColor {
return nameColor
} else {
return PeerNameColor(rawValue: Int32(self.id.id._internalGetInt64Value() % 7)) ?? .blue
return PeerNameColor(rawValue: Int32(self.id.id._internalGetInt64Value() % 7))
}
case let channel as TelegramChannel:
if let nameColor = channel.nameColor {
return nameColor
} else {
return PeerNameColor(rawValue: Int32(self.id.id._internalGetInt64Value() % 7)) ?? .blue
return PeerNameColor(rawValue: Int32(self.id.id._internalGetInt64Value() % 7))
}
default:
return nil
}
}
var hasCustomNameColor: Bool {
let defaultNameColor = PeerNameColor(rawValue: Int32(self.id.id._internalGetInt64Value() % 7)) ?? .blue
if self.nameColor != defaultNameColor {
return true
}
return false
}
var backgroundEmojiId: Int64? {
switch self {
case let user as TelegramUser:

View File

@ -1,42 +0,0 @@
import Foundation
import UIKit
import TelegramCore
public extension PeerNameColor {
var color: UIColor {
return self.dashColors.0
}
var dashColors: (UIColor, UIColor?) {
switch self {
case .red:
return (UIColor(rgb: 0xCC5049), nil)
case .orange:
return (UIColor(rgb: 0xD67722), nil)
case .violet:
return (UIColor(rgb: 0x955CDB), nil)
case .green:
return (UIColor(rgb: 0x40A920), nil)
case .cyan:
return (UIColor(rgb: 0x309EBA), nil)
case .blue:
return (UIColor(rgb: 0x368AD1), nil)
case .pink:
return (UIColor(rgb: 0xC7508B), nil)
case .redDash:
return (UIColor(rgb: 0xE15052), UIColor(rgb: 0xF9AE63))
case .orangeDash:
return (UIColor(rgb: 0xE0802B), UIColor(rgb: 0xFAC534))
case .violetDash:
return (UIColor(rgb: 0xA05FF3), UIColor(rgb: 0xF48FFF))
case .greenDash:
return (UIColor(rgb: 0x27A910), UIColor(rgb: 0xA7DC57))
case .cyanDash:
return (UIColor(rgb: 0x27ACCE), UIColor(rgb: 0x82E8D6))
case .blueDash:
return (UIColor(rgb: 0x3391D4), UIColor(rgb: 0x7DD3F0))
case .pinkDash:
return (UIColor(rgb: 0xdd4371), UIColor(rgb: 0xffbe9f))
}
}
}

View File

@ -761,6 +761,7 @@ private final class QuoteBackgroundView: UIView {
size: size,
primaryColor: theme.foreground,
secondaryColor: theme.isDashed ? .clear : nil,
thirdColor: nil,
pattern: nil,
animation: .None
)

View File

@ -179,17 +179,21 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
let messageTheme = incoming ? presentationData.theme.theme.chat.message.incoming : presentationData.theme.theme.chat.message.outgoing
let author = message.author
let nameColors = author?.nameColor.flatMap { context.peerNameColors.get($0) }
let mainColor: UIColor
var secondaryColor: UIColor?
var tertiaryColor: UIColor?
if !incoming {
mainColor = messageTheme.accentTextColor
if let _ = author?.nameColor?.dashColors.1 {
if let _ = nameColors?.secondary {
secondaryColor = .clear
}
} else {
var authorNameColor: UIColor?
authorNameColor = author?.nameColor?.color
secondaryColor = author?.nameColor?.dashColors.1
authorNameColor = nameColors?.main
secondaryColor = nameColors?.secondary
tertiaryColor = nameColors?.tertiary
if let authorNameColor {
mainColor = authorNameColor
@ -846,13 +850,13 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
if let current = self.backgroundView {
backgroundView = current
animation.animator.updateFrame(layer: backgroundView.layer, frame: backgroundFrame, completion: nil)
backgroundView.update(size: backgroundFrame.size, primaryColor: mainColor, secondaryColor: secondaryColor, pattern: nil, animation: animation)
backgroundView.update(size: backgroundFrame.size, primaryColor: mainColor, secondaryColor: secondaryColor, thirdColor: tertiaryColor, pattern: nil, animation: animation)
} else {
backgroundView = MessageInlineBlockBackgroundView()
self.backgroundView = backgroundView
backgroundView.frame = backgroundFrame
self.transformContainer.view.insertSubview(backgroundView, at: 0)
backgroundView.update(size: backgroundFrame.size, primaryColor: mainColor, secondaryColor: secondaryColor, pattern: nil, animation: .None)
backgroundView.update(size: backgroundFrame.size, primaryColor: mainColor, secondaryColor: secondaryColor, thirdColor: tertiaryColor, pattern: nil, animation: .None)
}
} else {
if let backgroundView = self.backgroundView {

View File

@ -1871,31 +1871,40 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
}
if let peer = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel, case .broadcast = peer.info, item.content.firstMessage.adAttribute == nil {
authorNameColor = (peer as Peer).nameColor?.color
let peer = (peer as Peer)
let nameColors = peer.nameColor.flatMap { item.context.peerNameColors.get($0) }
authorNameColor = nameColors?.main
} else if let effectiveAuthor = effectiveAuthor {
let nameColor: UIColor
let nameColor = effectiveAuthor.nameColor ?? .blue
let nameColors = item.context.peerNameColors.get(nameColor)
let color: UIColor
if incoming {
nameColor = (effectiveAuthor.nameColor ?? .blue).color
color = nameColors.main
} else {
nameColor = item.presentationData.theme.theme.chat.message.outgoing.accentTextColor
color = item.presentationData.theme.theme.chat.message.outgoing.accentTextColor
}
authorNameColor = nameColor
authorNameColor = color
}
if initialDisplayHeader && displayAuthorInfo {
if let peer = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel, case .broadcast = peer.info, item.content.firstMessage.adAttribute == nil {
authorNameString = EnginePeer(peer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
authorNameColor = (peer as Peer).nameColor?.color
let peer = (peer as Peer)
let nameColors = peer.nameColor.flatMap { item.context.peerNameColors.get($0) }
authorNameColor = nameColors?.main
} else if let effectiveAuthor = effectiveAuthor {
authorNameString = EnginePeer(effectiveAuthor).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
let nameColor: UIColor
let nameColor = effectiveAuthor.nameColor ?? .blue
let nameColors = item.context.peerNameColors.get(nameColor)
let color: UIColor
if incoming {
nameColor = (effectiveAuthor.nameColor ?? .blue).color
color = nameColors.main
} else {
nameColor = item.presentationData.theme.theme.chat.message.outgoing.accentTextColor
color = item.presentationData.theme.theme.chat.message.outgoing.accentTextColor
}
authorNameColor = nameColor
authorNameColor = color
if case let .peer(peerId) = item.chatLocation, let authorPeerId = item.message.author?.id, authorPeerId == peerId {
} else if effectiveAuthor.isScam {
@ -1903,11 +1912,11 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
} else if effectiveAuthor.isFake {
currentCredibilityIcon = .text(color: incoming ? item.presentationData.theme.theme.chat.message.incoming.scamColor : item.presentationData.theme.theme.chat.message.outgoing.scamColor, string: item.presentationData.strings.Message_FakeAccount.uppercased())
} else if let user = effectiveAuthor as? TelegramUser, let emojiStatus = user.emojiStatus {
currentCredibilityIcon = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 20.0, height: 20.0), placeholderColor: incoming ? item.presentationData.theme.theme.chat.message.incoming.mediaPlaceholderColor : item.presentationData.theme.theme.chat.message.outgoing.mediaPlaceholderColor, themeColor: nameColor.withMultipliedAlpha(0.4), loopMode: .count(2))
currentCredibilityIcon = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 20.0, height: 20.0), placeholderColor: incoming ? item.presentationData.theme.theme.chat.message.incoming.mediaPlaceholderColor : item.presentationData.theme.theme.chat.message.outgoing.mediaPlaceholderColor, themeColor: color.withMultipliedAlpha(0.4), loopMode: .count(2))
} else if effectiveAuthor.isVerified {
currentCredibilityIcon = .verified(fillColor: item.presentationData.theme.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.theme.list.itemCheckColors.foregroundColor, sizeType: .compact)
} else if effectiveAuthor.isPremium {
currentCredibilityIcon = .premium(color: nameColor.withMultipliedAlpha(0.4))
currentCredibilityIcon = .premium(color: color.withMultipliedAlpha(0.4))
}
}
if let rawAuthorNameColor = authorNameColor {

View File

@ -163,11 +163,11 @@ public class ChatMessageForwardInfoNode: ASDisplayNode {
}
} else {
if incoming {
if let color = peer?.nameColor?.color {
titleColor = color
} else {
// if let color = peer?.nameColor?.color {
// titleColor = color
// } else {
titleColor = presentationData.theme.theme.chat.message.incoming.accentTextColor
}
// }
} else {
titleColor = presentationData.theme.theme.chat.message.outgoing.accentTextColor
}

View File

@ -193,14 +193,18 @@ public class ChatMessageReplyInfoNode: ASDisplayNode {
let mainColor: UIColor
let dustColor: UIColor
var secondaryColor: UIColor?
var tertiaryColor: UIColor?
var authorNameColor: UIColor?
var dashSecondaryColor: UIColor?
var dashTertiaryColor: UIColor?
let author = arguments.message?.effectiveAuthor
authorNameColor = author?.nameColor?.color
dashSecondaryColor = author?.nameColor?.dashColors.1
let colors = author?.nameColor.flatMap { arguments.context.peerNameColors.get($0) }
authorNameColor = colors?.main
dashSecondaryColor = colors?.secondary
dashTertiaryColor = colors?.tertiary
switch arguments.type {
case let .bubble(incoming):
@ -209,6 +213,7 @@ public class ChatMessageReplyInfoNode: ASDisplayNode {
if let authorNameColor {
mainColor = authorNameColor
secondaryColor = dashSecondaryColor
tertiaryColor = dashTertiaryColor
} else {
mainColor = arguments.presentationData.theme.theme.chat.message.incoming.accentTextColor
}
@ -754,6 +759,7 @@ public class ChatMessageReplyInfoNode: ASDisplayNode {
size: backgroundFrame.size,
primaryColor: mainColor,
secondaryColor: secondaryColor,
thirdColor: tertiaryColor,
pattern: pattern,
animation: animation
)

View File

@ -393,24 +393,24 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
underlineLinks = false
}
let author = item.message.author
// let author = item.message.author
let mainColor: UIColor
var secondaryColor: UIColor?
let secondaryColor: UIColor? = nil
if !incoming {
mainColor = messageTheme.accentTextColor
if let _ = author?.nameColor?.dashColors.1 {
secondaryColor = .clear
}
// if let _ = author?.nameColor?.dashColors.1 {
// secondaryColor = .clear
// }
} else {
var authorNameColor: UIColor?
authorNameColor = author?.nameColor?.color
secondaryColor = author?.nameColor?.dashColors.1
// let authorNameColor: UIColor?
// authorNameColor = author?.nameColor?.color
// secondaryColor = author?.nameColor?.dashColors.1
if let authorNameColor {
mainColor = authorNameColor
} else {
// if let authorNameColor {
// mainColor = authorNameColor
// } else {
mainColor = messageTheme.accentTextColor
}
// }
}
attributedText = stringWithAppliedEntities(rawText, entities: entities, baseColor: messageTheme.primaryTextColor, linkColor: messageTheme.linkTextColor, baseQuoteTintColor: mainColor, baseQuoteSecondaryTintColor: secondaryColor, baseFont: textFont, linkFont: textFont, boldFont: item.presentationData.messageBoldFont, italicFont: item.presentationData.messageItalicFont, boldItalicFont: item.presentationData.messageBoldItalicFont, fixedFont: item.presentationData.messageFixedFont, blockQuoteFont: item.presentationData.messageBlockQuoteFont, underlineLinks: underlineLinks, message: item.message, adjustQuoteFontSize: true)

View File

@ -92,12 +92,17 @@ private let dashBackgroundTemplateImage: UIImage = {
return generateDashBackgroundTemplateImage()
}()
private func generateDashTemplateImage(isMonochrome: Bool) -> UIImage {
return generateImage(CGSize(width: radius * 2.0, height: 18.0), rotatedContext: { size, context in
private func generateDashTemplateImage(isMonochrome: Bool, isTriple: Bool) -> UIImage {
return generateImage(CGSize(width: radius * 2.0, height: isTriple ? 27.0 : 18.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor.white.cgColor)
let dashOffset: CGFloat = isMonochrome ? -4.0 : 5.0
let dashOffset: CGFloat
if isTriple {
dashOffset = 0.0
} else {
dashOffset = isMonochrome ? -4.0 : 5.0
}
context.translateBy(x: 0.0, y: dashOffset)
@ -109,7 +114,7 @@ private func generateDashTemplateImage(isMonochrome: Bool) -> UIImage {
context.closePath()
context.fillPath()
context.translateBy(x: 0.0, y: 18.0)
context.translateBy(x: 0.0, y: size.height)
}
context.clear(CGRect(origin: CGPoint(x: lineWidth, y: 0.0), size: CGSize(width: size.width - lineWidth, height: size.height)))
@ -117,11 +122,15 @@ private func generateDashTemplateImage(isMonochrome: Bool) -> UIImage {
}
private let dashOpaqueTemplateImage: UIImage = {
return generateDashTemplateImage(isMonochrome: false)
return generateDashTemplateImage(isMonochrome: false, isTriple: false)
}()
private let dashOpaqueTripleTemplateImage: UIImage = {
return generateDashTemplateImage(isMonochrome: false, isTriple: true)
}()
private let dashMonochromeTemplateImage: UIImage = {
return generateDashTemplateImage(isMonochrome: true)
return generateDashTemplateImage(isMonochrome: true, isTriple: false)
}()
private func generateGradient(gradientWidth: CGFloat, baseAlpha: CGFloat) -> UIImage {
@ -175,6 +184,7 @@ private final class PatternContentsTarget: MultiAnimationRenderTarget {
private final class LineView: UIView {
private let backgroundView: UIImageView
private var dashBackgroundView: UIImageView?
private var dashThirdBackgroundView: UIImageView?
private var params: Params?
private var isAnimating: Bool = false
@ -183,12 +193,14 @@ private final class LineView: UIView {
var size: CGSize
var primaryColor: UIColor
var secondaryColor: UIColor?
var thirdColor: UIColor?
var displayProgress: Bool
init(size: CGSize, primaryColor: UIColor, secondaryColor: UIColor?, displayProgress: Bool) {
init(size: CGSize, primaryColor: UIColor, secondaryColor: UIColor?, thirdColor: UIColor?, displayProgress: Bool) {
self.size = size
self.primaryColor = primaryColor
self.secondaryColor = secondaryColor
self.thirdColor = thirdColor
self.displayProgress = displayProgress
}
}
@ -231,6 +243,21 @@ private final class LineView: UIView {
}
dashBackgroundView.layer.add(animation, forKey: "progress")
}
if let dashThirdBackgroundView = self.dashThirdBackgroundView {
if dashThirdBackgroundView.layer.animation(forKey: "progress") == nil {
let animation = dashThirdBackgroundView.layer.makeAnimation(from: 18.0 as NSNumber, to: 0.0 as NSNumber, keyPath: "position.y", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 0.2, delay: 0.0, mediaTimingFunction: nil, removeOnCompletion: true, additive: true)
animation.repeatCount = 1.0
self.isAnimating = true
animation.completion = { [weak self] _ in
guard let self else {
return
}
self.isAnimating = false
self.updateAnimations()
}
dashThirdBackgroundView.layer.add(animation, forKey: "progress")
}
}
} else {
let phaseDuration: Double = 1.0
if self.backgroundView.layer.animation(forKey: "progress") == nil {
@ -271,11 +298,12 @@ private final class LineView: UIView {
self.layer.masksToBounds = params.secondaryColor != nil || self.isAnimating
}
func update(size: CGSize, primaryColor: UIColor, secondaryColor: UIColor?, displayProgress: Bool, animation: ListViewItemUpdateAnimation) {
func update(size: CGSize, primaryColor: UIColor, secondaryColor: UIColor?, thirdColor: UIColor?, displayProgress: Bool, animation: ListViewItemUpdateAnimation) {
let params = Params(
size: size,
primaryColor: primaryColor,
secondaryColor: secondaryColor,
thirdColor: thirdColor,
displayProgress: displayProgress
)
if self.params == params {
@ -305,13 +333,45 @@ private final class LineView: UIView {
dashBackgroundView.frame = dashBackgroundFrame
}
let templateImage: UIImage
if let thirdColor {
let thirdDashBackgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -9.0), size: CGSize(width: radius * 2.0, height: size.height + 18.0))
templateImage = dashOpaqueTripleTemplateImage
let dashThirdBackgroundView: UIImageView
if let current = self.dashThirdBackgroundView {
dashThirdBackgroundView = current
animation.animator.updateFrame(layer: dashThirdBackgroundView.layer, frame: thirdDashBackgroundFrame, completion: nil)
} else {
dashThirdBackgroundView = UIImageView()
self.dashThirdBackgroundView = dashThirdBackgroundView
self.addSubview(dashThirdBackgroundView)
dashThirdBackgroundView.frame = thirdDashBackgroundFrame
}
if secondaryColor.alpha == 0.0 {
dashThirdBackgroundView.image = templateImage
dashThirdBackgroundView.tintColor = thirdColor
} else {
dashThirdBackgroundView.image = templateImage
dashThirdBackgroundView.tintColor = thirdColor
}
} else {
templateImage = dashOpaqueTemplateImage
if let dashThirdBackgroundView = self.dashThirdBackgroundView {
self.dashThirdBackgroundView = nil
dashThirdBackgroundView.removeFromSuperview()
}
}
if secondaryColor.alpha == 0.0 {
self.backgroundView.alpha = 0.2
dashBackgroundView.image = dashMonochromeTemplateImage
dashBackgroundView.tintColor = primaryColor
} else {
self.backgroundView.alpha = 1.0
dashBackgroundView.image = dashOpaqueTemplateImage
dashBackgroundView.image = templateImage
dashBackgroundView.tintColor = secondaryColor
}
} else {
@ -365,6 +425,7 @@ public final class MessageInlineBlockBackgroundView: UIView {
var size: CGSize
var primaryColor: UIColor
var secondaryColor: UIColor?
var thirdColor: UIColor?
var pattern: Pattern?
var displayProgress: Bool
@ -372,12 +433,14 @@ public final class MessageInlineBlockBackgroundView: UIView {
size: CGSize,
primaryColor: UIColor,
secondaryColor: UIColor?,
thirdColor: UIColor?,
pattern: Pattern?,
displayProgress: Bool
) {
self.size = size
self.primaryColor = primaryColor
self.secondaryColor = secondaryColor
self.thirdColor = thirdColor
self.pattern = pattern
self.displayProgress = displayProgress
}
@ -393,6 +456,7 @@ public final class MessageInlineBlockBackgroundView: UIView {
size: params.size,
primaryColor: params.primaryColor,
secondaryColor: params.secondaryColor,
thirdColor: params.thirdColor,
pattern: params.pattern,
animation: .None
)
@ -502,6 +566,7 @@ public final class MessageInlineBlockBackgroundView: UIView {
size: CGSize,
primaryColor: UIColor,
secondaryColor: UIColor?,
thirdColor: UIColor?,
pattern: Pattern?,
animation: ListViewItemUpdateAnimation
) {
@ -509,6 +574,7 @@ public final class MessageInlineBlockBackgroundView: UIView {
size: size,
primaryColor: primaryColor,
secondaryColor: secondaryColor,
thirdColor: thirdColor,
pattern: pattern,
displayProgress: self.displayProgress
)
@ -588,6 +654,7 @@ public final class MessageInlineBlockBackgroundView: UIView {
size: lineFrame.size,
primaryColor: params.primaryColor,
secondaryColor: params.secondaryColor,
thirdColor: params.thirdColor,
displayProgress: params.displayProgress,
animation: animation
)

View File

@ -9,25 +9,26 @@ import TelegramUIPreferences
import MergeLists
import ItemListUI
import PresentationDataUtils
import AccountContext
private enum PeerNameColorEntryId: Hashable {
case color(Int32)
}
private enum PeerNameColorEntry: Comparable, Identifiable {
case color(Int, PeerNameColor, Bool)
case color(Int, PeerNameColor, PeerNameColors.Colors, Bool)
var stableId: PeerNameColorEntryId {
switch self {
case let .color(_, color, _):
case let .color(_, color, _, _):
return .color(color.rawValue)
}
}
static func ==(lhs: PeerNameColorEntry, rhs: PeerNameColorEntry) -> Bool {
switch lhs {
case let .color(lhsIndex, lhsAccentColor, lhsSelected):
if case let .color(rhsIndex, rhsAccentColor, rhsSelected) = rhs, lhsIndex == rhsIndex, lhsAccentColor == rhsAccentColor, lhsSelected == rhsSelected {
case let .color(lhsIndex, lhsColor, lhsAccentColor, lhsSelected):
if case let .color(rhsIndex, rhsColor, rhsAccentColor, rhsSelected) = rhs, lhsIndex == rhsIndex, lhsColor == rhsColor, lhsAccentColor == rhsAccentColor, lhsSelected == rhsSelected {
return true
} else {
return false
@ -37,9 +38,9 @@ private enum PeerNameColorEntry: Comparable, Identifiable {
static func <(lhs: PeerNameColorEntry, rhs: PeerNameColorEntry) -> Bool {
switch lhs {
case let .color(lhsIndex, _, _):
case let .color(lhsIndex, _, _, _):
switch rhs {
case let .color(rhsIndex, _, _):
case let .color(rhsIndex, _, _, _):
return lhsIndex < rhsIndex
}
}
@ -47,20 +48,22 @@ private enum PeerNameColorEntry: Comparable, Identifiable {
func item(action: @escaping (PeerNameColor) -> Void) -> ListViewItem {
switch self {
case let .color(_, color, selected):
return PeerNameColorIconItem(color: color, selected: selected, action: action)
case let .color(_, index, colors, selected):
return PeerNameColorIconItem(index: index, colors: colors, selected: selected, action: action)
}
}
}
private class PeerNameColorIconItem: ListViewItem {
let color: PeerNameColor
let index: PeerNameColor
let colors: PeerNameColors.Colors
let selected: Bool
let action: (PeerNameColor) -> Void
public init(color: PeerNameColor, selected: Bool, action: @escaping (PeerNameColor) -> Void) {
self.color = color
public init(index: PeerNameColor, colors: PeerNameColors.Colors, selected: Bool, action: @escaping (PeerNameColor) -> Void) {
self.index = index
self.colors = colors
self.selected = selected
self.action = action
}
@ -107,22 +110,22 @@ private class PeerNameColorIconItem: ListViewItem {
public var selectable = true
public func selected(listView: ListView) {
self.action(self.color)
self.action(self.index)
}
}
private func generateRingImage(nameColor: PeerNameColor) -> UIImage? {
private func generateRingImage(nameColor: PeerNameColors.Colors) -> UIImage? {
return generateImage(CGSize(width: 40.0, height: 40.0), rotatedContext: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
context.setStrokeColor(nameColor.color.cgColor)
context.setStrokeColor(nameColor.main.cgColor)
context.setLineWidth(2.0)
context.strokeEllipse(in: bounds.insetBy(dx: 1.0, dy: 1.0))
})
}
private func generateFillImage(nameColor: PeerNameColor) -> UIImage? {
private func generateFillImage(nameColor: PeerNameColors.Colors) -> UIImage? {
return generateImage(CGSize(width: 40.0, height: 40.0), rotatedContext: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
@ -131,8 +134,7 @@ private func generateFillImage(nameColor: PeerNameColor) -> UIImage? {
context.addEllipse(in: circleBounds)
context.clip()
let (firstColor, secondColor) = nameColor.dashColors
if let secondColor {
if let secondColor = nameColor.secondary {
context.setFillColor(secondColor.cgColor)
context.fill(circleBounds)
@ -140,10 +142,20 @@ private func generateFillImage(nameColor: PeerNameColor) -> UIImage? {
context.addLine(to: CGPoint(x: size.width, y: 0.0))
context.addLine(to: CGPoint(x: 0.0, y: size.height))
context.closePath()
context.setFillColor(firstColor.cgColor)
context.setFillColor(nameColor.main.cgColor)
context.fillPath()
if let thirdColor = nameColor.tertiary {
context.setFillColor(thirdColor.cgColor)
context.translateBy(x: size.width / 2.0, y: size.height / 2.0)
context.rotate(by: .pi / 4.0)
let path = UIBezierPath(roundedRect: CGRect(origin: CGPoint(x: -9.0, y: -9.0), size: CGSize(width: 18.0, height: 18.0)), cornerRadius: 4.0)
context.addPath(path.cgPath)
context.fillPath()
}
} else {
context.setFillColor(firstColor.cgColor)
context.setFillColor(nameColor.main.cgColor)
context.fill(circleBounds)
}
})
@ -198,7 +210,7 @@ private final class PeerNameColorIconItemNode : ListViewItemNode {
var updatedAccentColor = false
var updatedSelected = false
if currentItem == nil || currentItem?.color != item.color {
if currentItem == nil || currentItem?.colors != item.colors {
updatedAccentColor = true
}
if currentItem?.selected != item.selected {
@ -211,8 +223,8 @@ private final class PeerNameColorIconItemNode : ListViewItemNode {
strongSelf.item = item
if updatedAccentColor {
strongSelf.fillNode.image = generateFillImage(nameColor: item.color)
strongSelf.ringNode.image = generateRingImage(nameColor: item.color)
strongSelf.fillNode.image = generateFillImage(nameColor: item.colors)
strongSelf.ringNode.image = generateRingImage(nameColor: item.colors)
}
let center = CGPoint(x: 30.0, y: 28.0)
@ -256,12 +268,12 @@ final class PeerNameColorItem: ListViewItem, ItemListItem {
var sectionId: ItemListSectionId
let theme: PresentationTheme
let colors: [PeerNameColor]
let colors: PeerNameColors
let currentColor: PeerNameColor
let updated: (PeerNameColor) -> Void
let tag: ItemListItemTag?
init(theme: PresentationTheme, colors: [PeerNameColor], currentColor: PeerNameColor, updated: @escaping (PeerNameColor) -> Void, tag: ItemListItemTag? = nil, sectionId: ItemListSectionId) {
init(theme: PresentationTheme, colors: PeerNameColors, currentColor: PeerNameColor, updated: @escaping (PeerNameColor) -> Void, tag: ItemListItemTag? = nil, sectionId: ItemListSectionId) {
self.theme = theme
self.colors = colors
self.currentColor = currentColor
@ -325,7 +337,7 @@ private func ensureColorVisible(listNode: ListView, color: PeerNameColor, animat
var resultNode: PeerNameColorIconItemNode?
listNode.forEachItemNode { node in
if resultNode == nil, let node = node as? PeerNameColorIconItemNode {
if node.item?.color == color {
if node.item?.index == color {
resultNode = node
}
}
@ -406,7 +418,7 @@ final class PeerNameColorItemNode: ListViewItemNode, ItemListItemNode {
let options = ListViewDeleteAndInsertOptions()
var scrollToItem: ListViewScrollToItem?
if !self.initialized || transition.updatePosition || !self.tapping {
if let index = item.colors.firstIndex(where: { $0 == item.currentColor }) {
if let index = item.colors.displayOrder.firstIndex(where: { $0 == item.currentColor.rawValue }) {
scrollToItem = ListViewScrollToItem(index: index, position: .bottom(-70.0), animated: false, curve: .Default(duration: 0.0), directionHint: .Down)
self.initialized = true
}
@ -501,10 +513,13 @@ final class PeerNameColorItemNode: ListViewItemNode, ItemListItemNode {
var entries: [PeerNameColorEntry] = []
var index: Int = 0
for color in item.colors {
entries.append(.color(index, color, color == item.currentColor))
index += 1
var i: Int = 0
for index in item.colors.displayOrder {
let color = PeerNameColor(rawValue: index)
if let colors = item.colors.colors[index] {
entries.append(.color(i, color, colors, color == item.currentColor))
}
i += 1
}
let action: (PeerNameColor) -> Void = { [weak self] color in

View File

@ -47,7 +47,7 @@ private enum PeerNameColorScreenEntry: ItemListNodeEntry {
case colorHeader(String)
case colorMessage(wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, bubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, items: [PeerNameColorChatPreviewItem.MessageItem])
case colorPicker(colors: [PeerNameColor], currentColor: PeerNameColor)
case colorPicker(colors: PeerNameColors, currentColor: PeerNameColor)
case colorDescription(String)
case backgroundEmojiHeader(String)
case backgroundEmoji(EmojiPagerContentComponent, UIColor)
@ -185,6 +185,7 @@ private struct PeerNameColorScreenState: Equatable {
}
private func peerNameColorScreenEntries(
nameColors: PeerNameColors,
presentationData: PresentationData,
state: PeerNameColorScreenState,
peer: EnginePeer?,
@ -194,11 +195,6 @@ private func peerNameColorScreenEntries(
var entries: [PeerNameColorScreenEntry] = []
if let peer {
var allColors: [PeerNameColor] = [
.blue
]
allColors.append(contentsOf: PeerNameColor.allCases.filter { $0 != .blue})
let nameColor: PeerNameColor
if let updatedNameColor = state.updatedNameColor {
nameColor = updatedNameColor
@ -208,6 +204,8 @@ private func peerNameColorScreenEntries(
nameColor = .blue
}
let colors = nameColors.get(nameColor)
let backgroundEmojiId: Int64?
if let updatedBackgroundEmojiId = state.updatedBackgroundEmojiId {
if updatedBackgroundEmojiId == 0 {
@ -250,14 +248,14 @@ private func peerNameColorScreenEntries(
items: [messageItem]
))
entries.append(.colorPicker(
colors: allColors,
colors: nameColors,
currentColor: nameColor
))
entries.append(.colorDescription(presentationData.strings.NameColor_ChatPreview_Description_Account))
if let emojiContent {
entries.append(.backgroundEmojiHeader(presentationData.strings.NameColor_BackgroundEmoji_Title))
entries.append(.backgroundEmoji(emojiContent, nameColor.color))
entries.append(.backgroundEmoji(emojiContent, colors.main))
}
}
@ -314,6 +312,7 @@ public func PeerNameColorScreen(
peerId = channelId
}
let emojiContent = combineLatest(
statePromise.get(),
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
@ -325,12 +324,13 @@ public func PeerNameColorScreen(
} else {
selectedEmojiId = peer?.backgroundEmojiId
}
let nameColor: UIColor
let nameColor: PeerNameColor
if let updatedNameColor = state.updatedNameColor {
nameColor = updatedNameColor.color
nameColor = updatedNameColor
} else {
nameColor = (peer?.nameColor ?? .blue).color
nameColor = (peer?.nameColor ?? .blue)
}
let color = context.peerNameColors.get(nameColor)
let selectedItems: [EngineMedia.Id]
if let selectedEmojiId, selectedEmojiId != 0 {
@ -351,7 +351,7 @@ public func PeerNameColorScreen(
areCustomEmojiEnabled: true,
chatPeerId: context.account.peerId,
selectedItems: Set(selectedItems),
backgroundIconColor: nameColor
backgroundIconColor: color.main
)
}
@ -547,6 +547,7 @@ public func PeerNameColorScreen(
)
let entries = peerNameColorScreenEntries(
nameColors: context.peerNameColors,
presentationData: presentationData,
state: state,
peer: peer,

View File

@ -244,6 +244,9 @@ public final class AccountContextImpl: AccountContext {
private var userLimitsConfigurationDisposable: Disposable?
public private(set) var userLimits: EngineConfiguration.UserLimits
private var peerNameColorsConfigurationDisposable: Disposable?
public private(set) var peerNameColors: PeerNameColors
public private(set) var isPremium: Bool
public let imageCache: AnyObject?
@ -257,6 +260,7 @@ public final class AccountContextImpl: AccountContext {
self.imageCache = DirectMediaImageCache(account: account)
self.userLimits = EngineConfiguration.UserLimits(UserLimitsConfiguration.defaultValue)
self.peerNameColors = PeerNameColors.defaultValue
self.isPremium = false
self.downloadedMediaStoreManager = DownloadedMediaStoreManagerImpl(postbox: account.postbox, accountManager: sharedContext.accountManager)
@ -336,7 +340,7 @@ public final class AccountContextImpl: AccountContext {
if !temp {
let currentCountriesConfiguration = self.currentCountriesConfiguration
self.countriesConfigurationDisposable = (self.engine.localization.getCountriesList(accountManager: sharedContext.accountManager, langCode: nil)
|> deliverOnMainQueue).start(next: { value in
|> deliverOnMainQueue).start(next: { value in
let _ = currentCountriesConfiguration.swap(CountriesConfiguration(countries: value))
})
}
@ -395,12 +399,20 @@ public final class AccountContextImpl: AccountContext {
return (isPremium, userLimits)
}
}
|> deliverOnMainQueue).start(next: { [weak self] isPremium, userLimits in
guard let strongSelf = self else {
|> deliverOnMainQueue).startStrict(next: { [weak self] isPremium, userLimits in
guard let self = self else {
return
}
strongSelf.isPremium = isPremium
strongSelf.userLimits = userLimits
self.isPremium = isPremium
self.userLimits = userLimits
})
self.peerNameColorsConfigurationDisposable = (self._appConfiguration.get()
|> deliverOnMainQueue).startStrict(next: { [weak self] appConfiguration in
guard let self = self else {
return
}
self.peerNameColors = PeerNameColors.with(appConfiguration: appConfiguration)
})
}
@ -413,6 +425,7 @@ public final class AccountContextImpl: AccountContext {
self.experimentalUISettingsDisposable?.dispose()
self.animatedEmojiStickersDisposable?.dispose()
self.userLimitsConfigurationDisposable?.dispose()
self.peerNameColorsConfigurationDisposable?.dispose()
}
public func storeSecureIdPassword(password: String) {

View File

@ -5090,7 +5090,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let strongSelf = self {
let isPremium = peerView.peers[peerView.peerId]?.isPremium ?? false
var accountPeerColor: ChatPresentationInterfaceState.AccountPeerColor?
if peerView.peers[peerView.peerId]?.nameColor?.dashColors.1 != nil {
if let nameColor = peerView.peers[peerView.peerId]?.nameColor, strongSelf.context.peerNameColors.get(nameColor).secondary != nil {
accountPeerColor = ChatPresentationInterfaceState.AccountPeerColor(isDashed: true)
}
strongSelf.updateChatPresentationInterfaceState(animated: false, interactive: false, { state in

View File

@ -1621,7 +1621,8 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
}
if isCreator || (channel.adminRights?.rights.contains(.canChangeInfo) == true) {
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemNameColor, label: .semitransparentBadge(EnginePeer(channel).compactDisplayTitle, (data.peer?.nameColor ?? .blue).color), text: "Channel Color", icon: UIImage(bundleImageName: "Chat/Info/NameColorIcon"), action: {
let colors = context.peerNameColors.get(data.peer?.nameColor ?? .blue)
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemNameColor, label: .semitransparentBadge(EnginePeer(channel).compactDisplayTitle, colors.main), text: "Channel Color", icon: UIImage(bundleImageName: "Chat/Info/NameColorIcon"), action: {
interaction.editingOpenNameColorSetup()
}))
}