Improve Dynamic Type in chat list

This commit is contained in:
Ali
2019-12-20 11:29:32 +04:00
parent 8bec45b0d3
commit 7cea54c937
7 changed files with 47 additions and 41 deletions

View File

@@ -33,8 +33,6 @@ private func measureString(_ string: String) -> String {
} }
} }
private let badgeFont = Font.regular(14.0)
final class ChatListBadgeNode: ASDisplayNode { final class ChatListBadgeNode: ASDisplayNode {
private let backgroundNode: ASImageNode private let backgroundNode: ASImageNode
private let textNode: TextNode private let textNode: TextNode
@@ -63,13 +61,13 @@ final class ChatListBadgeNode: ASDisplayNode {
self.addSubnode(self.textNode) self.addSubnode(self.textNode)
} }
func asyncLayout() -> (CGSize, UIImage?, ChatListBadgeContent) -> (CGSize, (Bool, Bool) -> Void) { func asyncLayout() -> (CGSize, CGFloat, UIFont, UIImage?, ChatListBadgeContent) -> (CGSize, (Bool, Bool) -> Void) {
let textLayout = TextNode.asyncLayout(self.textNode) let textLayout = TextNode.asyncLayout(self.textNode)
let measureTextLayout = TextNode.asyncLayout(self.measureTextNode) let measureTextLayout = TextNode.asyncLayout(self.measureTextNode)
let currentContent = self.content let currentContent = self.content
return { [weak self] boundingSize, backgroundImage, content in return { [weak self] boundingSize, imageWidth, badgeFont, backgroundImage, content in
var badgeWidth: CGFloat = 0.0 var badgeWidth: CGFloat = 0.0
var textLayoutAndApply: (TextNodeLayout, () -> TextNode)? var textLayoutAndApply: (TextNodeLayout, () -> TextNode)?
@@ -79,14 +77,14 @@ final class ChatListBadgeNode: ASDisplayNode {
let (measureLayout, _) = measureTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: measureString(text.string), font: badgeFont, textColor: .black), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: boundingSize, alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (measureLayout, _) = measureTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: measureString(text.string), font: badgeFont, textColor: .black), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: boundingSize, alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
badgeWidth = max(20.0, measureLayout.size.width + 10.0) badgeWidth = max(imageWidth, measureLayout.size.width + imageWidth / 2.0)
case .mention, .blank: case .mention, .blank:
badgeWidth = 20.0 badgeWidth = imageWidth
case .none: case .none:
badgeWidth = 0.0 badgeWidth = 0.0
} }
return (CGSize(width: badgeWidth, height: 20.0), { animated, bounce in return (CGSize(width: badgeWidth, height: imageWidth), { animated, bounce in
if let strongSelf = self { if let strongSelf = self {
strongSelf.content = content strongSelf.content = content
@@ -98,7 +96,7 @@ final class ChatListBadgeNode: ASDisplayNode {
return return
} }
let badgeWidth = max(20.0, badgeWidth) let badgeWidth = max(imageWidth, badgeWidth)
let previousBadgeWidth = !strongSelf.backgroundNode.frame.width.isZero ? strongSelf.backgroundNode.frame.width : badgeWidth let previousBadgeWidth = !strongSelf.backgroundNode.frame.width.isZero ? strongSelf.backgroundNode.frame.width : badgeWidth
var animateTextNode = false var animateTextNode = false

View File

@@ -654,7 +654,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
let titleFont = Font.medium(floor(item.presentationData.fontSize.itemListBaseFontSize * 16.0 / 17.0)) let titleFont = Font.medium(floor(item.presentationData.fontSize.itemListBaseFontSize * 16.0 / 17.0))
let textFont = Font.regular(floor(item.presentationData.fontSize.itemListBaseFontSize * 15.0 / 17.0)) let textFont = Font.regular(floor(item.presentationData.fontSize.itemListBaseFontSize * 15.0 / 17.0))
let dateFont = Font.regular(floor(item.presentationData.fontSize.itemListBaseFontSize * 14.0 / 17.0)) let dateFont = Font.regular(floor(item.presentationData.fontSize.itemListBaseFontSize * 14.0 / 17.0))
let badgeFont = Font.regular(14.0) let badgeFont = Font.regular(floor(item.presentationData.fontSize.itemListBaseFontSize * 14.0 / 17.0))
let account = item.context.account let account = item.context.account
var message: Message? var message: Message?
@@ -777,9 +777,11 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
let enableChatListPhotos = item.context.sharedContext.immediateExperimentalUISettings.chatListPhotos let enableChatListPhotos = item.context.sharedContext.immediateExperimentalUISettings.chatListPhotos
let avatarDiameter = floor(item.presentationData.fontSize.baseDisplaySize * 60.0 / 17.0) let avatarDiameter = min(60.0, floor(item.presentationData.fontSize.baseDisplaySize * 60.0 / 17.0))
let avatarLeftInset = 18.0 + avatarDiameter let avatarLeftInset = 18.0 + avatarDiameter
let badgeDiameter = floor(item.presentationData.fontSize.baseDisplaySize * 20.0 / 17.0)
let leftInset: CGFloat = params.leftInset + avatarLeftInset let leftInset: CGFloat = params.leftInset + avatarLeftInset
enum ContentData { enum ContentData {
@@ -995,10 +997,10 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
} else { } else {
let badgeTextColor: UIColor let badgeTextColor: UIColor
if unreadCount.muted { if unreadCount.muted {
currentBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundInactive(item.presentationData.theme) currentBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundInactive(item.presentationData.theme, diameter: badgeDiameter)
badgeTextColor = theme.unreadBadgeInactiveTextColor badgeTextColor = theme.unreadBadgeInactiveTextColor
} else { } else {
currentBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundActive(item.presentationData.theme) currentBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundActive(item.presentationData.theme, diameter: badgeDiameter)
badgeTextColor = theme.unreadBadgeActiveTextColor badgeTextColor = theme.unreadBadgeActiveTextColor
} }
let unreadCountText = compactNumericCountString(Int(unreadCount.count), decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator) let unreadCountText = compactNumericCountString(Int(unreadCount.count), decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator)
@@ -1012,7 +1014,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
if let mutedCount = unreadCount.mutedCount, mutedCount > 0 { if let mutedCount = unreadCount.mutedCount, mutedCount > 0 {
let mutedUnreadCountText = compactNumericCountString(Int(mutedCount), decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator) let mutedUnreadCountText = compactNumericCountString(Int(mutedCount), decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator)
currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundInactive(item.presentationData.theme) currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundInactive(item.presentationData.theme, diameter: badgeDiameter)
mentionBadgeContent = .text(NSAttributedString(string: mutedUnreadCountText, font: badgeFont, textColor: theme.unreadBadgeInactiveTextColor)) mentionBadgeContent = .text(NSAttributedString(string: mutedUnreadCountText, font: badgeFont, textColor: theme.unreadBadgeInactiveTextColor))
} }
} }
@@ -1024,13 +1026,13 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
if !isPeerGroup { if !isPeerGroup {
if totalMentionCount > 0 { if totalMentionCount > 0 {
if Namespaces.PeerGroup.archive == item.peerGroupId { if Namespaces.PeerGroup.archive == item.peerGroupId {
currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundInactiveMention(item.presentationData.theme) currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundInactiveMention(item.presentationData.theme, diameter: badgeDiameter)
} else { } else {
currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundMention(item.presentationData.theme) currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundMention(item.presentationData.theme, diameter: badgeDiameter)
} }
mentionBadgeContent = .mention mentionBadgeContent = .mention
} else if item.index.pinningIndex != nil && !isAd && currentBadgeBackgroundImage == nil { } else if item.index.pinningIndex != nil && !isAd && currentBadgeBackgroundImage == nil {
currentPinnedIconImage = PresentationResourcesChatList.badgeBackgroundPinned(item.presentationData.theme) currentPinnedIconImage = PresentationResourcesChatList.badgeBackgroundPinned(item.presentationData.theme, diameter: badgeDiameter)
} }
} }
@@ -1105,9 +1107,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
let (dateLayout, dateApply) = dateLayout(TextNodeLayoutArguments(attributedString: dateAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: rawContentWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (dateLayout, dateApply) = dateLayout(TextNodeLayoutArguments(attributedString: dateAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: rawContentWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (badgeLayout, badgeApply) = badgeLayout(CGSize(width: rawContentWidth, height: CGFloat.greatestFiniteMagnitude), currentBadgeBackgroundImage, badgeContent) let (badgeLayout, badgeApply) = badgeLayout(CGSize(width: rawContentWidth, height: CGFloat.greatestFiniteMagnitude), badgeDiameter, badgeFont, currentBadgeBackgroundImage, badgeContent)
let (mentionBadgeLayout, mentionBadgeApply) = mentionBadgeLayout(CGSize(width: rawContentWidth, height: CGFloat.greatestFiniteMagnitude), currentMentionBadgeImage, mentionBadgeContent) let (mentionBadgeLayout, mentionBadgeApply) = mentionBadgeLayout(CGSize(width: rawContentWidth, height: CGFloat.greatestFiniteMagnitude), badgeDiameter, badgeFont, currentMentionBadgeImage, mentionBadgeContent)
var badgeSize: CGFloat = 0.0 var badgeSize: CGFloat = 0.0
if !badgeLayout.width.isZero { if !badgeLayout.width.isZero {
@@ -1656,7 +1658,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
transition.updateFrame(node: reorderControlNode, frame: reorderControlFrame) transition.updateFrame(node: reorderControlNode, frame: reorderControlFrame)
} }
let avatarDiameter = floor(item.presentationData.fontSize.baseDisplaySize * 60.0 / 17.0) let avatarDiameter = min(60.0, floor(item.presentationData.fontSize.baseDisplaySize * 60.0 / 17.0))
let avatarLeftInset = 18.0 + avatarDiameter let avatarLeftInset = 18.0 + avatarDiameter
let leftInset: CGFloat = params.leftInset + avatarLeftInset let leftInset: CGFloat = params.leftInset + avatarLeftInset

View File

@@ -591,10 +591,10 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
let badgeTextColor: UIColor let badgeTextColor: UIColor
switch badge.type { switch badge.type {
case .inactive: case .inactive:
currentBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundInactive(item.presentationData.theme) currentBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundInactive(item.presentationData.theme, diameter: 20.0)
badgeTextColor = item.presentationData.theme.chatList.unreadBadgeInactiveTextColor badgeTextColor = item.presentationData.theme.chatList.unreadBadgeInactiveTextColor
case .active: case .active:
currentBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundActive(item.presentationData.theme) currentBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundActive(item.presentationData.theme, diameter: 20.0)
badgeTextColor = item.presentationData.theme.chatList.unreadBadgeActiveTextColor badgeTextColor = item.presentationData.theme.chatList.unreadBadgeActiveTextColor
} }
let badgeAttributedString = NSAttributedString(string: badge.count > 0 ? "\(badge.count)" : " ", font: badgeFont, textColor: badgeTextColor) let badgeAttributedString = NSAttributedString(string: badge.count > 0 ? "\(badge.count)" : " ", font: badgeFont, textColor: badgeTextColor)

View File

@@ -148,10 +148,10 @@ public final class HorizontalPeerItemNode: ListViewItemNode {
let badgeTextColor: UIColor let badgeTextColor: UIColor
let (unreadCount, isMuted) = unreadBadge let (unreadCount, isMuted) = unreadBadge
if isMuted { if isMuted {
currentBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundInactive(item.theme) currentBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundInactive(item.theme, diameter: 20.0)
badgeTextColor = item.theme.chatList.unreadBadgeInactiveTextColor badgeTextColor = item.theme.chatList.unreadBadgeInactiveTextColor
} else { } else {
currentBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundActive(item.theme) currentBadgeBackgroundImage = PresentationResourcesChatList.badgeBackgroundActive(item.theme, diameter: 20.0)
badgeTextColor = item.theme.chatList.unreadBadgeActiveTextColor badgeTextColor = item.theme.chatList.unreadBadgeActiveTextColor
} }
badgeAttributedString = NSAttributedString(string: unreadCount > 0 ? "\(unreadCount)" : " ", font: badgeFont, textColor: badgeTextColor) badgeAttributedString = NSAttributedString(string: unreadCount > 0 ? "\(unreadCount)" : " ", font: badgeFont, textColor: badgeTextColor)

View File

@@ -228,4 +228,10 @@ public enum PresentationResourceParameterKey: Hashable {
case chatMediaPartialCheck(CGFloat) case chatMediaPartialCheck(CGFloat)
case chatFreeFullCheck(CGFloat, Bool) case chatFreeFullCheck(CGFloat, Bool)
case chatFreePartialCheck(CGFloat, Bool) case chatFreePartialCheck(CGFloat, Bool)
case chatListBadgeBackgroundActive(CGFloat)
case chatListBadgeBackgroundInactive(CGFloat)
case chatListBadgeBackgroundMention(CGFloat)
case chatListBadgeBackgroundInactiveMention(CGFloat)
case chatListBadgeBackgroundPinned(CGFloat)
} }

View File

@@ -19,8 +19,8 @@ private func generateStatusCheckImage(theme: PresentationTheme, single: Bool) ->
}) })
} }
private func generateBadgeBackgroundImage(theme: PresentationTheme, active: Bool, icon: UIImage? = nil) -> UIImage? { private func generateBadgeBackgroundImage(theme: PresentationTheme, diameter: CGFloat, active: Bool, icon: UIImage? = nil) -> UIImage? {
return generateImage(CGSize(width: 20.0, height: 20.0), contextGenerator: { size, context in return generateImage(CGSize(width: diameter, height: diameter), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size)) context.clear(CGRect(origin: CGPoint(), size: size))
if active { if active {
context.setFillColor(theme.chatList.unreadBadgeActiveBackgroundColor.cgColor) context.setFillColor(theme.chatList.unreadBadgeActiveBackgroundColor.cgColor)
@@ -31,7 +31,7 @@ private func generateBadgeBackgroundImage(theme: PresentationTheme, active: Bool
if let icon = icon, let cgImage = icon.cgImage { if let icon = icon, let cgImage = icon.cgImage {
context.draw(cgImage, in: CGRect(origin: CGPoint(x: floor((size.width - icon.size.width) / 2.0), y: floor((size.height - icon.size.height) / 2.0)), size: icon.size)) context.draw(cgImage, in: CGRect(origin: CGPoint(x: floor((size.width - icon.size.width) / 2.0), y: floor((size.height - icon.size.height) / 2.0)), size: icon.size))
} }
})?.stretchableImage(withLeftCapWidth: 10, topCapHeight: 10) })?.stretchableImage(withLeftCapWidth: Int(diameter / 2.0), topCapHeight: Int(diameter / 2.0))
} }
private func generateClockFrameImage(color: UIColor) -> UIImage? { private func generateClockFrameImage(color: UIColor) -> UIImage? {
@@ -169,32 +169,32 @@ public struct PresentationResourcesChatList {
}) })
} }
public static func badgeBackgroundActive(_ theme: PresentationTheme) -> UIImage? { public static func badgeBackgroundActive(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceKey.chatListBadgeBackgroundActive.rawValue, { theme in return theme.image(PresentationResourceParameterKey.chatListBadgeBackgroundActive(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, active: true) return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: true)
}) })
} }
public static func badgeBackgroundInactive(_ theme: PresentationTheme) -> UIImage? { public static func badgeBackgroundInactive(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceKey.chatListBadgeBackgroundInactive.rawValue, { theme in return theme.image(PresentationResourceParameterKey.chatListBadgeBackgroundInactive(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, active: false) return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: false)
}) })
} }
public static func badgeBackgroundMention(_ theme: PresentationTheme) -> UIImage? { public static func badgeBackgroundMention(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceKey.chatListBadgeBackgroundMention.rawValue, { theme in return theme.image(PresentationResourceParameterKey.chatListBadgeBackgroundMention(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, active: true, icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/MentionBadgeIcon"), color: theme.chatList.unreadBadgeActiveTextColor)) return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: true, icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/MentionBadgeIcon"), color: theme.chatList.unreadBadgeActiveTextColor))
}) })
} }
public static func badgeBackgroundInactiveMention(_ theme: PresentationTheme) -> UIImage? { public static func badgeBackgroundInactiveMention(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceKey.chatListBadgeBackgroundInactiveMention.rawValue, { theme in return theme.image(PresentationResourceParameterKey.chatListBadgeBackgroundInactiveMention(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, active: false, icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/MentionBadgeIcon"), color: theme.chatList.unreadBadgeInactiveTextColor)) return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: false, icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/MentionBadgeIcon"), color: theme.chatList.unreadBadgeInactiveTextColor))
}) })
} }
public static func badgeBackgroundPinned(_ theme: PresentationTheme) -> UIImage? { public static func badgeBackgroundPinned(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceKey.chatListBadgeBackgroundPinned.rawValue, { theme in return theme.image(PresentationResourceParameterKey.chatListBadgeBackgroundPinned(diameter), { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/PeerPinnedIcon"), color: theme.chatList.pinnedBadgeColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat List/PeerPinnedIcon"), color: theme.chatList.pinnedBadgeColor)
}) })
} }

View File

@@ -175,7 +175,7 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
self.presentationInterfaceState = interfaceState self.presentationInterfaceState = interfaceState
if previousState?.theme !== interfaceState.theme { if previousState?.theme !== interfaceState.theme {
self.badgeBackground.image = PresentationResourcesChatList.badgeBackgroundActive(interfaceState.theme) self.badgeBackground.image = PresentationResourcesChatList.badgeBackgroundActive(interfaceState.theme, diameter: 20.0)
} }
if previousState?.peerDiscussionId != interfaceState.peerDiscussionId { if previousState?.peerDiscussionId != interfaceState.peerDiscussionId {