Merge commit '7621e2f8dec938cf48181c8b10afc9b01f444e68' into beta

This commit is contained in:
Ilya Laktyushin
2025-12-06 02:17:48 +04:00
commit 8344b97e03
28070 changed files with 7995182 additions and 0 deletions
@@ -0,0 +1,412 @@
import Foundation
import UIKit
public struct PresentationResources {
}
public enum PresentationResourceKey: Int32 {
case rootNavigationIndefiniteActivity
case rootTabContactsIcon
case rootTabContactsSelectedIcon
case rootTabChatsIcon
case rootTabChatsSelectedIcon
case rootTabSettingsIcon
case rootTabSettingsSelectedIcon
case navigationComposeIcon
case navigationCallIcon
case navigationInfoIcon
case navigationShareIcon
case navigationSearchIcon
case navigationCompactSearchIcon
case navigationCompactSearchWhiteIcon
case navigationCompactTagsSearchIcon
case navigationCompactTagsSearchWhiteIcon
case navigationCalendarIcon
case navigationMoreIcon
case navigationMoreCircledIcon
case navigationAddIcon
case navigationPlayerCloseButton
case navigationQrCodeIcon
case navigationLiveLocationIcon
case navigationPlayerRateActiveIcon
case navigationPlayerRateInactiveIcon
case navigationPlayerMaximizedRateActiveIcon
case navigationPlayerMaximizedRateInactiveIcon
case itemListDownArrow
case itemListDisclosureArrow
case disclosureOptionArrowsImage
case itemListDisclosureLocked
case itemListCheckIcon
case itemListSecondaryCheckIcon
case itemListDisabledCheckIcon
case itemListPlusIcon
case itemListRoundPlusIcon
case itemListAccentDeleteIcon
case itemListDeleteIcon
case itemListDeleteIndicatorIcon
case itemListReorderIndicatorIcon
case itemListLinkIcon
case itemListAddPersonIcon
case itemListCreateGroupIcon
case itemListAddExceptionIcon
case itemListAddPhoneIcon
case itemListAddPhotoIcon
case itemListClearInputIcon
case itemListStickerItemUnreadDot
case itemListVerifiedPeerIcon
case itemListCloudFetchIcon
case itemListCloseIconImage
case itemListRemoveIconImage
case itemListMakeVisibleIcon
case itemListMakeInvisibleIcon
case itemListEditThemeIcon
case itemListCornersTop
case itemListCornersBottom
case itemListCornersBoth
case itemListCornersTopGlass
case itemListCornersBottomGlass
case itemListCornersBothGlass
case itemListKnob
case itemListBlockAccentIcon
case itemListBlockDestructiveIcon
case itemListAddDeviceIcon
case itemListResetIcon
case itemListImageIcon
case itemListCloudIcon
case itemListTopicArrowIcon
case itemListAddBoostsIcon
case itemListPremiumIcon
case itemListRoundTopupIcon
case itemListRoundWithdrawIcon
case itemListStatsIcon
case statsReactionsIcon
case statsForwardsIcon
case itemListVoiceCallIcon
case itemListVideoCallIcon
case chatListLockTopUnlockedImage
case chatListLockBottomUnlockedImage
case chatListPending
case chatListClockFrame
case chatListClockMin
case chatListSingleCheck
case chatListDoubleCheck
case chatListBadgeBackgroundActive
case chatListBadgeBackgroundInactive
case chatListBadgeBackgroundMention
case chatListBadgeBackgroundInactiveMention
case chatListBadgeBackgroundPinned
case chatListMutedIcon
case chatListVerifiedIcon
case chatListPremiumIcon
case chatListScamRegularIcon
case chatListScamOutgoingIcon
case chatListScamServiceIcon
case chatListFakeRegularIcon
case chatListFakeOutgoingIcon
case chatListFakeServiceIcon
case chatListSecretIcon
case chatListStatusLockIcon
case chatListTopicArrowIcon
case chatListRecentStatusOnlineIcon
case chatListRecentStatusOnlineHighlightedIcon
case chatListRecentStatusOnlinePinnedIcon
case chatListRecentStatusOnlinePanelIcon
case chatListRecentStatusVoiceChatIcon
case chatListRecentStatusVoiceChatHighlightedIcon
case chatListRecentStatusVoiceChatPinnedIcon
case chatListRecentStatusVoiceChatPanelIcon
case chatListForwardedIcon
case chatListStoryReplyIcon
case chatListGiftIcon
case chatListLocationIcon
case chatListGeneralTopicIcon
case chatListGeneralTopicTemplateIcon
case chatListNewTopicTemplateIcon
case chatListGeneralTopicSmallIcon
case searchAdIcon
case chatTitleLockIcon
case chatTitleMuteIcon
case chatPanelLockIcon
case chatPanelBoostIcon
case chatBubbleVerticalLineIncomingImage
case chatBubbleVerticalLineOutgoingImage
case chatBubbleArrowFreeImage
case chatBubbleArrowIncomingImage
case chatBubbleArrowOutgoingImage
case chatBubbleCheckBubbleFullImage
case chatBubbleBubblePartialImage
case checkBubbleMediaFullImage
case checkBubbleMediaPartialImage
case chatBubbleConsumableContentIncomingIcon
case chatBubbleConsumableContentOutgoingIcon
case chatMediaConsumableContentIcon
case chatBubbleMediaOverlayControlSecret
case chatInstantVideoWithWallpaperBackgroundImage
case chatInstantVideoWithoutWallpaperBackgroundImage
case chatActionPhotoWithWallpaperBackgroundImage
case chatActionPhotoWithoutWallpaperBackgroundImage
case chatUnreadBarBackgroundImage
case chatBubbleFileCloudFetchMediaIcon
case chatBubbleFileCloudFetchIncomingIcon
case chatBubbleFileCloudFetchOutgoingIcon
case chatBubbleFileCloudFetchedIncomingIcon
case chatBubbleFileCloudFetchedOutgoingIcon
case chatBubbleTodoDotIncomingIcon
case chatBubbleTodoDotOutgoingIcon
case chatBubbleTodoCheckIncomingIcon
case chatBubbleTodoCheckOutgoingIcon
case chatServiceMessageTodoCompletedIcon
case chatServiceMessageTodoIncompletedIcon
case chatServiceMessageTodoAppendedIcon
case chatBubbleReplyThumbnailPlayImage
case chatBubbleDeliveryFailedIcon
case chatInfoItemBackgroundImageWithWallpaper
case chatInfoItemBackgroundImageWithoutWallpaper
case chatInputPanelCloseIconImage
case chatInputPanelPinnedListIconImage
case chatInputPanelEncircledCloseIconImage
case chatInputPanelVerticalSeparatorLineImage
case chatInputPanelForwardIconImage
case chatInputPanelReplyIconImage
case chatInputPanelEditIconImage
case chatInputPanelWebpageIconImage
case chatInputMediaPanelAddPackButtonImage
case chatInputMediaPanelAddedPackButtonImage
case chatInputMediaPanelGridSetupImage
case chatInputMediaPanelGridDismissImage
case chatInputButtonPanelButtonHighlightImage
case chatInputButtonPanelButtonShadowImage
case chatInputTextFieldBackgroundImage
case chatInputTextFieldClearImage
case chatInputPanelSendIconImage
case chatInputPanelSendButtonImage
case chatInputPanelApplyIconImage
case chatInputPanelApplyButtonImage
case chatInputPanelScheduleIconImage
case chatInputPanelScheduleButtonImage
case chatInputPanelVoiceButtonImage
case chatInputPanelVideoButtonImage
case chatInputPanelExpandButtonImage
case chatInputPanelVoiceActiveButtonImage
case chatInputPanelVideoActiveButtonImage
case chatInputPanelAttachmentButtonImage
case chatInputPanelEditAttachmentButtonImage
case chatInputPanelMediaRecordingDotImage
case chatInputPanelMediaRecordingCancelArrowImage
case chatInputTextFieldStickersImage
case chatInputTextFieldInputButtonsImage
case chatInputTextFieldKeyboardImage
case chatInputTextFieldCommandsImage
case chatInputTextFieldSilentPostOnImage
case chatInputTextFieldSilentPostOffImage
case chatInputTextFieldTimerImage
case chatInputTextFieldScheduleImage
case chatInputTextFieldGiftImage
case chatInputTextFieldSuggestPostImage
case chatInputSearchPanelUpImage
case chatInputSearchPanelUpDisabledImage
case chatInputSearchPanelDownImage
case chatInputSearchPanelDownDisabledImage
case chatInputSearchPanelCalendarImage
case chatInputSearchPanelMembersImage
case chatHistoryNavigationButtonBackground
case chatHistoryNavigationButtonImage
case chatHistoryNavigationUpButtonImage
case chatHistoryMentionsButtonImage
case chatHistoryReactionsButtonImage
case chatHistoryNavigationButtonBadgeImage
case chatMessageAttachedContentButtonIncoming
case chatMessageAttachedContentHighlightedButtonIncoming
case chatMessageAttachedContentButtonOutgoing
case chatMessageAttachedContentHighlightedButtonOutgoing
case chatMessageAttachedContentButtonIconInstantIncoming
case chatMessageAttachedContentHighlightedButtonIconInstantIncomingWithWallpaper
case chatMessageAttachedContentHighlightedButtonIconInstantIncomingWithoutWallpaper
case chatMessageAttachedContentButtonIconInstantOutgoing
case chatMessageAttachedContentHighlightedButtonIconInstantOutgoingWithWallpaper
case chatMessageAttachedContentHighlightedButtonIconInstantOutgoingWithoutWallpaper
case chatMessageAttachedContentButtonIconLinkIncoming
case chatMessageAttachedContentHighlightedButtonIconLinkIncomingWithWallpaper
case chatMessageAttachedContentHighlightedButtonIconLinkIncomingWithoutWallpaper
case chatMessageAttachedContentButtonIconLinkOutgoing
case chatMessageAttachedContentHighlightedButtonIconLinkOutgoingWithWallpaper
case chatMessageAttachedContentHighlightedButtonIconLinkOutgoingWithoutWallpaper
case chatMessageAttachedContentButtonIconBidIncoming
case chatMessageAttachedContentButtonIconBidOutgoing
case chatCommandPanelArrowImage
case sharedMediaFileDownloadStartIcon
case sharedMediaFileDownloadPauseIcon
case sharedMediaInstantViewIcon
case chatInfoCallButtonImage
case chatInstantMessageInfoBackgroundImage
case chatInstantMessageMuteIconImage
case chatBubbleIncomingCallButtonImage
case chatBubbleOutgoingCallButtonImage
case chatBubbleIncomingVideoCallButtonImage
case chatBubbleOutgoingVideoCallButtonImage
case callListOutgoingIcon
case callListOutgoingVideoIcon
case callListInfoButton
case genericSearchBarLoupeImage
case genericSearchBar
case inAppNotificationBackground
case groupInfoAdminsIcon
case groupInfoPermissionsIcon
case groupInfoMembersIcon
case emptyChatListCheckIcon
case chatFreeCommentButtonIcon
case chatFreeNavigateButtonIcon
case chatFreeShareButtonIcon
case chatFreeCloseButtonIcon
case chatFreeMoreButtonIcon
case chatKeyboardActionButtonMessageIcon
case chatKeyboardActionButtonLinkIcon
case chatKeyboardActionButtonShareIcon
case chatKeyboardActionButtonPhoneIcon
case chatKeyboardActionButtonLocationIcon
case chatKeyboardActionButtonPaymentIcon
case chatKeyboardActionButtonProfileIcon
case chatKeyboardActionButtonAddToChatIcon
case chatKeyboardActionButtonWebAppIcon
case chatGeneralThreadIcon
case chatGeneralThreadIncomingIcon
case chatGeneralThreadOutgoingIcon
case chatGeneralThreadFreeIcon
case uploadToneIcon
case storyViewListLikeIcon
case navigationPostStoryIcon
case navigationSortIcon
case chatReplyBackgroundTemplateIncomingImage
case chatReplyBackgroundTemplateOutgoingDashedImage
case chatReplyServiceBackgroundTemplateImage
case chatBubbleCloseIcon
case chatEmptyStateStarIcon
case chatPlaceholderStarIcon
case chatUserInfoWarningIcon
case avatarPremiumLockBadgeBackground
case avatarPremiumLockBadge
case shareAvatarPremiumLockBadgeBackground
case shareAvatarPremiumLockBadge
case shareAvatarStarsLockBadgeBackground
case shareAvatarStarsLockBadgeInnerBackground
case sharedLinkIcon
case hideIconImage
case peerStatusLockedImage
case expandDownArrowImage
case expandSmallDownArrowImage
case callListCallIcon
case chatFreeNavigateToThreadButtonIcon
case messageButtonsPostReject
case messageButtonsPostApprove
case messageButtonsPostEdit
}
public enum ChatExpiredStoryIndicatorType: Hashable {
case incoming
case outgoing
case free
}
public enum PresentationResourceParameterKey: Hashable {
case chatOutgoingFullCheck(CGFloat)
case chatOutgoingPartialCheck(CGFloat)
case chatMediaFullCheck(CGFloat)
case chatMediaPartialCheck(CGFloat)
case chatFreeFullCheck(CGFloat, Bool)
case chatFreePartialCheck(CGFloat, Bool)
case chatListBadgeBackgroundActive(CGFloat)
case chatListBadgeBackgroundActiveProvisional(CGFloat)
case chatListBadgeBackgroundInactive(CGFloat)
case chatListBadgeBackgroundInactiveProvisional(CGFloat)
case chatListBadgeBackgroundMention(CGFloat)
case badgeBackgroundReactions(CGFloat)
case badgeBackgroundInactiveReactions(CGFloat)
case chatListBadgeBackgroundInactiveMention(CGFloat)
case chatListBadgeBackgroundPinned(CGFloat)
case badgeBackgroundBorder(CGFloat)
case chatBubbleMediaCorner(incoming: Bool, mainRadius: CGFloat, inset: CGFloat)
case chatPrincipalThemeEssentialGraphics(hasWallpaper: Bool, bubbleCorners: PresentationChatBubbleCorners)
case chatPrincipalThemeAdditionalGraphics(isCustomWallpaper: Bool, bubbleCorners: PresentationChatBubbleCorners)
case chatBubbleLamp(incoming: Bool)
case chatPsaInfo(color: UInt32)
case chatMessageCommentsIcon(incoming: Bool)
case chatMessageCommentsArrowIcon(incoming: Bool)
case chatMessageCommentsUnreadDotIcon(incoming: Bool)
case chatMessageRepliesIcon(incoming: Bool)
case chatEntityKeyboardLock(color: UInt32)
case chatInputMediaPanelGridDismissImage(color: UInt32)
case statusAutoremoveIcon(isActive: Bool)
case chatExpiredStoryIndicatorIcon(type: ChatExpiredStoryIndicatorType)
case chatReplyStoryIndicatorIcon(type: ChatExpiredStoryIndicatorType)
}
@@ -0,0 +1,24 @@
import Foundation
import UIKit
import Display
import AppBundle
public struct PresentationResourcesCallList {
public static func outgoingIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.callListOutgoingIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Call List/OutgoingIcon"), color: theme.list.disclosureArrowColor)
})
}
public static func outgoingVideoIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.callListOutgoingVideoIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Call List/OutgoingVideoIcon"), color: theme.list.disclosureArrowColor)
})
}
public static func infoButton(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.callListInfoButton.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Call List/InfoButton"), color: theme.list.itemAccentColor)
})
}
}
@@ -0,0 +1,595 @@
import Foundation
import UIKit
import Display
import AppBundle
import PresentationStrings
private func generateStatusCheckImage(theme: PresentationTheme, single: Bool) -> UIImage? {
return generateImage(CGSize(width: single ? 13.0 : 18.0, height: 13.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.translateBy(x: 1.0, y: 2.0)
context.setStrokeColor(theme.chatList.checkmarkColor.cgColor)
context.setLineWidth(1.32)
context.setLineCap(.round)
context.setLineJoin(.round)
let _ = try? drawSvgPath(context, path: "M0,4.48 L3.59439858,7.93062264 L3.59439858,7.93062264 C3.63384129,7.96848764 3.69651158,7.96720866 3.73437658,7.92776595 C3.7346472,7.92748405 3.73491615,7.92720055 3.73518342,7.92691547 L11.1666667,0 S ")
if !single {
let _ = try? drawSvgPath(context, path: "M7.33333333,8 L14.8333333,0 S ")
}
})
}
private func generateBadgeBackgroundImage(theme: PresentationTheme, diameter: CGFloat, active: Bool, reaction: Bool, provisional: Bool, icon: UIImage? = nil) -> UIImage? {
return generateImage(CGSize(width: diameter, height: diameter), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
if active {
if reaction {
context.setFillColor(theme.chatList.reactionBadgeActiveBackgroundColor.cgColor)
} else if provisional {
context.setFillColor(theme.chatList.unreadBadgeActiveBackgroundColor.withMultipliedAlpha(0.1).cgColor)
} else {
context.setFillColor(theme.chatList.unreadBadgeActiveBackgroundColor.cgColor)
}
} else {
if provisional {
context.setFillColor(theme.chatList.unreadBadgeInactiveBackgroundColor.withMultipliedAlpha(0.2).cgColor)
} else {
context.setFillColor(theme.chatList.unreadBadgeInactiveBackgroundColor.cgColor)
}
}
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
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))
}
})?.stretchableImage(withLeftCapWidth: Int(diameter / 2.0), topCapHeight: Int(diameter / 2.0))
}
private func generateClockFrameImage(color: UIColor) -> UIImage? {
return generateImage(CGSize(width: 11.0, height: 11.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setStrokeColor(color.cgColor)
context.setFillColor(color.cgColor)
let strokeWidth: CGFloat = 1.0
context.setLineWidth(strokeWidth)
context.strokeEllipse(in: CGRect(x: strokeWidth / 2.0, y: strokeWidth / 2.0, width: size.width - strokeWidth, height: size.height - strokeWidth))
context.fill(CGRect(x: (11.0 - strokeWidth) / 2.0, y: strokeWidth * 3.0, width: strokeWidth, height: 11.0 / 2.0 - strokeWidth * 3.0))
})
}
private func generateClockMinImage(color: UIColor) -> UIImage? {
return generateImage(CGSize(width: 11.0, height: 11.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(color.cgColor)
let strokeWidth: CGFloat = 1.0
context.fill(CGRect(x: (11.0 - strokeWidth) / 2.0, y: (11.0 - strokeWidth) / 2.0, width: 11.0 / 2.0 - strokeWidth, height: strokeWidth))
})
}
public enum RecentStatusOnlineIconState {
case regular
case highlighted
case pinned
case panel
}
public enum ScamIconType {
case regular
case outgoing
case service
}
public struct PresentationResourcesChatList {
public static func pendingImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListPending.rawValue, { theme in
return generateImage(CGSize(width: 12.0, height: 14.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.translateBy(x: 0.0, y: 1.0)
context.setStrokeColor(theme.chatList.pendingIndicatorColor.cgColor)
let lineWidth: CGFloat = 0.99
context.setLineWidth(lineWidth)
context.strokeEllipse(in: CGRect(origin: CGPoint(x: lineWidth / 2.0, y: lineWidth / 2.0), size: CGSize(width: 12.0 - lineWidth, height: 12.0 - lineWidth)))
context.setLineCap(.round)
let _ = try? drawSvgPath(context, path: "M6.01830142,3 L6.01830142,6.23251697 L4.5,7.81306587 S ")
})
})
}
public static func singleCheckImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListSingleCheck.rawValue, { theme in
return generateStatusCheckImage(theme: theme, single: true)
})
}
public static func doubleCheckImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListDoubleCheck.rawValue, { theme in
return generateStatusCheckImage(theme: theme, single: false)
})
}
public static func clockFrameImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListClockFrame.rawValue, { theme in
return generateClockFrameImage(color: theme.chatList.pendingIndicatorColor)
})
}
public static func clockMinImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListClockMin.rawValue, { theme in
return generateClockMinImage(color: theme.chatList.pendingIndicatorColor)
})
}
public static func lockTopUnlockedImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListLockTopUnlockedImage.rawValue, { theme in
return generateImage(CGSize(width: 7.0, height: 6.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(theme.rootController.navigationBar.primaryTextColor.cgColor)
context.setStrokeColor(theme.rootController.navigationBar.primaryTextColor.cgColor)
context.setLineWidth(1.5)
context.addPath(UIBezierPath(roundedRect: CGRect(x: 0.75, y: 0.75, width: 5.5, height: 12.0), cornerRadius: 2.5).cgPath)
context.strokePath()
context.setBlendMode(.clear)
context.setFillColor(UIColor.clear.cgColor)
context.fill(CGRect(x: 4.0, y: 5.33, width: 3.0, height: 2.0))
})
})
}
public static func lockBottomUnlockedImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListLockBottomUnlockedImage.rawValue, { theme in
return generateImage(CGSize(width: 10.0, height: 8.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(theme.rootController.navigationBar.primaryTextColor.cgColor)
context.addPath(UIBezierPath(roundedRect: CGRect(x: 0.0, y: 0.0, width: 10.0, height: 8.0), cornerRadius: 1.5).cgPath)
context.fillPath()
})
})
}
public static func recentStatusOnlineIcon(_ theme: PresentationTheme, state: RecentStatusOnlineIconState, voiceChat: Bool = false) -> UIImage? {
let key: PresentationResourceKey
switch state {
case .regular:
key = voiceChat ? PresentationResourceKey.chatListRecentStatusVoiceChatIcon : PresentationResourceKey.chatListRecentStatusOnlineIcon
case .highlighted:
key = voiceChat ? PresentationResourceKey.chatListRecentStatusVoiceChatHighlightedIcon : PresentationResourceKey.chatListRecentStatusOnlineHighlightedIcon
case .pinned:
key = voiceChat ? PresentationResourceKey.chatListRecentStatusVoiceChatPinnedIcon : PresentationResourceKey.chatListRecentStatusOnlinePinnedIcon
case .panel:
key = voiceChat ? PresentationResourceKey.chatListRecentStatusVoiceChatPanelIcon : PresentationResourceKey.chatListRecentStatusOnlinePanelIcon
}
return theme.image(key.rawValue, { theme in
let size: CGFloat = voiceChat ? 22.0 : 14.0
return generateImage(CGSize(width: size, height: size), rotatedContext: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
switch state {
case .regular:
context.setFillColor(theme.chatList.itemBackgroundColor.cgColor)
case .highlighted:
context.setFillColor(theme.chatList.itemHighlightedBackgroundColor.cgColor)
case .pinned:
context.setFillColor(theme.chatList.pinnedItemBackgroundColor.cgColor)
case .panel:
context.setFillColor(theme.actionSheet.itemBackgroundColor.withAlphaComponent(1.0).cgColor)
}
context.fillEllipse(in: bounds)
context.setFillColor(theme.chatList.onlineDotColor.cgColor)
context.fillEllipse(in: bounds.insetBy(dx: 2.0, dy: 2.0))
})
})
}
public static func badgeBackgroundActive(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceParameterKey.chatListBadgeBackgroundActive(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: true, reaction: false, provisional: false)
})
}
public static func badgeBackgroundActiveProvisional(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceParameterKey.chatListBadgeBackgroundActiveProvisional(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: true, reaction: false, provisional: true)
})
}
public static func badgeBackgroundInactive(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceParameterKey.chatListBadgeBackgroundInactive(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: false, reaction: false, provisional: false)
})
}
public static func badgeBackgroundInactiveProvisional(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceParameterKey.chatListBadgeBackgroundInactiveProvisional(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: false, reaction: false, provisional: true)
})
}
public static func badgeBackgroundMention(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceParameterKey.chatListBadgeBackgroundMention(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: true, reaction: false, provisional: false, icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/MentionBadgeIcon"), color: theme.chatList.unreadBadgeActiveTextColor))
})
}
public static func badgeBackgroundInactiveMention(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceParameterKey.chatListBadgeBackgroundInactiveMention(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: false, reaction: false, provisional: false, icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/MentionBadgeIcon"), color: theme.chatList.unreadBadgeInactiveTextColor))
})
}
public static func badgeBackgroundReactions(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceParameterKey.badgeBackgroundReactions(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: true, reaction: true, provisional: false, icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/ReactionsBadgeIcon"), color: theme.chatList.unreadBadgeActiveTextColor))
})
}
public static func badgeBackgroundInactiveReactions(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceParameterKey.badgeBackgroundInactiveReactions(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: false, reaction: false, provisional: false, icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/ReactionsBadgeIcon"), color: theme.chatList.unreadBadgeInactiveTextColor))
})
}
public static func badgeBackgroundPinned(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceParameterKey.chatListBadgeBackgroundPinned(diameter), { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/PeerPinnedIcon"), color: theme.chatList.pinnedBadgeColor)
})
}
public static func badgeBackgroundBorder(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceParameterKey.badgeBackgroundBorder(diameter), { theme in
return generateStretchableFilledCircleImage(diameter: diameter, color: theme.chatList.pinnedItemBackgroundColor.blitOver(theme.chatList.backgroundColor, alpha: 1.0))
})
}
public static func mutedIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListMutedIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/PeerMutedIcon"), color: theme.chatList.muteIconColor)
})
}
public static func forwardedIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListForwardedIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/ForwardedIcon"), color: theme.chatList.muteIconColor)
})
}
public static func storyReplyIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListStoryReplyIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/StoryReplyIcon"), color: theme.chatList.muteIconColor)
})
}
public static func giftIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListGiftIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/GiftIcon"), color: theme.chatList.muteIconColor)
})
}
public static func locationIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListLocationIcon.rawValue, { theme in
if let image = UIImage(bundleImageName: "Chat/Attach Menu/Location") {
return generateImage(CGSize(width: 20.0, height: 20.0), contextGenerator: { size, context in
if let cgImage = image.cgImage {
context.clear(CGRect(origin: CGPoint(), size: size))
context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage)
context.setFillColor(theme.chatList.muteIconColor.cgColor)
context.fill(CGRect(origin: CGPoint(), size: size))
}
})
} else {
return nil
}
})
}
public static func verifiedIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListVerifiedIcon.rawValue, { theme in
if let backgroundImage = UIImage(bundleImageName: "Chat List/PeerVerifiedIconBackground"), let foregroundImage = UIImage(bundleImageName: "Chat List/PeerVerifiedIconForeground") {
return generateImage(backgroundImage.size, contextGenerator: { size, context in
if let backgroundCgImage = backgroundImage.cgImage, let foregroundCgImage = foregroundImage.cgImage {
context.clear(CGRect(origin: CGPoint(), size: size))
context.saveGState()
context.clip(to: CGRect(origin: .zero, size: size), mask: backgroundCgImage)
context.setFillColor(theme.list.itemCheckColors.fillColor.cgColor)
context.fill(CGRect(origin: CGPoint(), size: size))
context.restoreGState()
context.clip(to: CGRect(origin: .zero, size: size), mask: foregroundCgImage)
context.setFillColor(theme.list.itemCheckColors.foregroundColor.cgColor)
context.fill(CGRect(origin: CGPoint(), size: size))
}
}, opaque: false)
} else {
return nil
}
})
}
public static func premiumIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListPremiumIcon.rawValue, { theme in
if let image = UIImage(bundleImageName: "Chat List/PeerPremiumIcon") {
return generateImage(image.size, contextGenerator: { size, context in
if let cgImage = image.cgImage {
context.clear(CGRect(origin: CGPoint(), size: size))
context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage)
context.setFillColor(theme.list.itemCheckColors.fillColor.cgColor)
context.fill(CGRect(origin: CGPoint(), size: size))
}
}, opaque: false)
} else {
return nil
}
})
}
public static func scamIcon(_ theme: PresentationTheme, strings: PresentationStrings, type: ScamIconType) -> UIImage? {
let key: PresentationResourceKey
let color: UIColor
switch type {
case .regular:
key = PresentationResourceKey.chatListScamRegularIcon
color = theme.chat.message.incoming.scamColor
case .outgoing:
key = PresentationResourceKey.chatListScamOutgoingIcon
color = theme.chat.message.outgoing.scamColor
case .service:
key = PresentationResourceKey.chatListScamServiceIcon
color = theme.chat.serviceMessage.components.withDefaultWallpaper.scam
}
return theme.image(key.rawValue, { theme in
let titleString = NSAttributedString(string: strings.Message_ScamAccount.uppercased(), font: Font.bold(10.0), textColor: color, paragraphAlignment: .center)
let stringRect = titleString.boundingRect(with: CGSize(width: 100.0, height: 16.0), options: .usesLineFragmentOrigin, context: nil)
return generateImage(CGSize(width: floor(stringRect.width) + 11.0, height: 16.0), contextGenerator: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
context.setFillColor(color.cgColor)
context.setStrokeColor(color.cgColor)
context.setLineWidth(1.0)
context.addPath(UIBezierPath(roundedRect: bounds.insetBy(dx: 0.5, dy: 0.5), cornerRadius: 2.0).cgPath)
context.strokePath()
let titlePath = CGMutablePath()
titlePath.addRect(bounds.offsetBy(dx: 0.0, dy: -2.0 + UIScreenPixel))
let titleFramesetter = CTFramesetterCreateWithAttributedString(titleString as CFAttributedString)
let titleFrame = CTFramesetterCreateFrame(titleFramesetter, CFRangeMake(0, titleString.length), titlePath, nil)
CTFrameDraw(titleFrame, context)
})
})
}
public static func fakeIcon(_ theme: PresentationTheme, strings: PresentationStrings, type: ScamIconType) -> UIImage? {
let key: PresentationResourceKey
let color: UIColor
switch type {
case .regular:
key = PresentationResourceKey.chatListFakeRegularIcon
color = theme.chat.message.incoming.scamColor
case .outgoing:
key = PresentationResourceKey.chatListFakeOutgoingIcon
color = theme.chat.message.outgoing.scamColor
case .service:
key = PresentationResourceKey.chatListFakeServiceIcon
color = theme.chat.serviceMessage.components.withDefaultWallpaper.scam
}
return theme.image(key.rawValue, { theme in
let titleString = NSAttributedString(string: strings.Message_FakeAccount.uppercased(), font: Font.bold(10.0), textColor: color, paragraphAlignment: .center)
let stringRect = titleString.boundingRect(with: CGSize(width: 100.0, height: 16.0), options: .usesLineFragmentOrigin, context: nil)
return generateImage(CGSize(width: floor(stringRect.width) + 11.0, height: 16.0), contextGenerator: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
context.setFillColor(color.cgColor)
context.setStrokeColor(color.cgColor)
context.setLineWidth(1.0)
context.addPath(UIBezierPath(roundedRect: bounds.insetBy(dx: 0.5, dy: 0.5), cornerRadius: 2.0).cgPath)
context.strokePath()
let titlePath = CGMutablePath()
titlePath.addRect(bounds.offsetBy(dx: 0.0, dy: -2.0 + UIScreenPixel))
let titleFramesetter = CTFramesetterCreateWithAttributedString(titleString as CFAttributedString)
let titleFrame = CTFramesetterCreateFrame(titleFramesetter, CFRangeMake(0, titleString.length), titlePath, nil)
CTFrameDraw(titleFrame, context)
})
})
}
public static func secretIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListSecretIcon.rawValue, { theme in
return generateImage(CGSize(width: 9.0, height: 12.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(theme.chatList.secretIconColor.cgColor)
context.setStrokeColor(theme.chatList.secretIconColor.cgColor)
context.setLineWidth(1.32)
let _ = try? drawSvgPath(context, path: "M4.5,0.66 C3.11560623,0.66 1.99333333,1.78227289 1.99333333,3.16666667 L1.99333333,7.8047619 C1.99333333,9.18915568 3.11560623,10.3114286 4.5,10.3114286 C5.88439377,10.3114286 7.00666667,9.18915568 7.00666667,7.8047619 L7.00666667,3.16666667 C7.00666667,1.78227289 5.88439377,0.66 4.5,0.66 S ")
let _ = try? drawSvgPath(context, path: "M1.32,5.48571429 L7.68,5.48571429 C8.40901587,5.48571429 9,6.07669842 9,6.80571429 L9,10.68 C9,11.4090159 8.40901587,12 7.68,12 L1.32,12 C0.59098413,12 8.92786951e-17,11.4090159 0,10.68 L2.22044605e-16,6.80571429 C1.3276591e-16,6.07669842 0.59098413,5.48571429 1.32,5.48571429 Z ")
})
})
}
public static func statusLockIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListStatusLockIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/StatusLockIcon"), color: theme.chatList.unreadBadgeInactiveBackgroundColor)
})
}
public static func topicArrowIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListTopicArrowIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/TopicArrowIcon"), color: theme.chatList.titleColor)
})
}
public static func generalTopicSmallIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListGeneralTopicSmallIcon.rawValue, { theme in
let image = generateTintedImage(image: UIImage(bundleImageName: "Chat List/GeneralTopicIcon"), color: theme.chatList.unreadBadgeInactiveBackgroundColor)
return generateImage(CGSize(width: 18.0, height: 18.0), contextGenerator: { size, context in
context.clear(CGRect(origin: .zero, size: size))
if let cgImage = image?.cgImage {
context.draw(cgImage, in: CGRect(origin: .zero, size: size))
}
})
})
}
public static func generalTopicIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListGeneralTopicIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/GeneralTopicIcon"), color: theme.chatList.unreadBadgeInactiveBackgroundColor)
})
}
public static func generalTopicTemplateIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListGeneralTopicTemplateIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/GeneralTopicIcon"), color: .white)?.withRenderingMode(.alwaysTemplate)
})
}
public static func newTopicTemplateIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListNewTopicTemplateIcon.rawValue, { theme in
guard let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: .white) else {
return nil
}
let size = CGSize(width: 24.0, height: 24.0)
return generateImage(size, rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
UIGraphicsPushContext(context)
defer {
UIGraphicsPopContext()
}
image.draw(in: CGRect(origin: CGPoint(), size: size))
})?.withRenderingMode(.alwaysTemplate)
})
}
public static func statusAutoremoveIcon(_ theme: PresentationTheme, isActive: Bool) -> UIImage? {
return theme.image(PresentationResourceParameterKey.statusAutoremoveIcon(isActive: isActive), { theme in
return generateTintedImage(image: UIImage(bundleImageName: isActive ? "Chat List/StatusIconAutoremoveOn" : "Chat List/StatusIconAutoremoveOff"), color: isActive ? theme.list.itemAccentColor : theme.list.itemSecondaryTextColor)
})
}
public static func avatarPremiumLockBadgeBackground(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.avatarPremiumLockBadgeBackground.rawValue, { theme in
return generateFilledCircleImage(diameter: 17.0, color: .white)?.withRenderingMode(.alwaysTemplate)
})
}
public static func avatarPremiumLockBadge(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.avatarPremiumLockBadge.rawValue, { theme in
return generateImage(CGSize(width: 16.0, height: 16.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.addPath(CGPath(ellipseIn: CGRect(origin: CGPoint(), size: size), transform: nil))
context.clip()
var locations: [CGFloat] = [0.0, 1.0]
let colors: [CGColor] = [UIColor(rgb: 0x9981FF).cgColor, UIColor(rgb: 0xBA6DE9).cgColor]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: 0.0), options: CGGradientDrawingOptions())
context.resetClip()
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat List/StatusLockIcon"), color: .white), let cgImage = image.cgImage {
let imageSize = image.size.fitted(CGSize(width: 8.0, height: 8.0))
context.draw(cgImage, in: CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) * 0.5), y: floor((size.height - imageSize.height) * 0.5)), size: imageSize))
}
})
})
}
public static func shareAvatarPremiumLockBadgeBackground(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.shareAvatarPremiumLockBadgeBackground.rawValue, { theme in
return generateFilledCircleImage(diameter: 22.0, color: .white)?.withRenderingMode(.alwaysTemplate)
})
}
public static func shareAvatarStarsLockBadgeBackground(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.shareAvatarStarsLockBadgeBackground.rawValue, { theme in
return generateImage(CGSize(width: 20.0, height: 20.0), contextGenerator: { size, context in
context.clear(CGRect(origin: .zero, size: size))
context.setFillColor(UIColor.white.cgColor)
let rect = CGRect(origin: .zero, size: CGSize(width: 20.0, height: 18.0 + UIScreenPixel)).insetBy(dx: 1.0 - UIScreenPixel, dy: 0.0)
context.addPath(UIBezierPath(roundedRect: rect, cornerRadius: rect.height / 2.0).cgPath)
context.fillPath()
})?.withRenderingMode(.alwaysTemplate).stretchableImage(withLeftCapWidth: 10, topCapHeight: 10)
})
}
public static func shareAvatarStarsLockBadgeInnerBackground(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.shareAvatarStarsLockBadgeInnerBackground.rawValue, { theme in
return generateImage(CGSize(width: 20.0, height: 16.0), contextGenerator: { size, context in
context.clear(CGRect(origin: .zero, size: size))
context.setFillColor(UIColor.white.cgColor)
context.addPath(UIBezierPath(roundedRect: CGRect(origin: .zero, size: CGSize(width: 20.0, height: 15.0)), cornerRadius: 7.5).cgPath)
context.fillPath()
})?.withRenderingMode(.alwaysTemplate).stretchableImage(withLeftCapWidth: 10, topCapHeight: 0)
})
}
public static func shareAvatarPremiumLockBadge(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.shareAvatarPremiumLockBadge.rawValue, { theme in
return generateImage(CGSize(width: 20.0, height: 20.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.addPath(CGPath(ellipseIn: CGRect(origin: CGPoint(), size: size), transform: nil))
context.clip()
var locations: [CGFloat] = [0.0, 1.0]
let colors: [CGColor] = [UIColor(rgb: 0x9981FF).cgColor, UIColor(rgb: 0xBA6DE9).cgColor]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: 0.0), options: CGGradientDrawingOptions())
context.resetClip()
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat List/StatusLockIcon"), color: .white), let cgImage = image.cgImage {
let imageSize = image.size.fitted(CGSize(width: 14.0, height: 14.0))
context.draw(cgImage, in: CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) * 0.5), y: floor((size.height - imageSize.height) * 0.5)), size: imageSize))
}
})
})
}
public static func searchAdIcon(_ theme: PresentationTheme, strings: PresentationStrings) -> UIImage? {
return theme.image(PresentationResourceKey.searchAdIcon.rawValue, { theme in
let titleString = NSAttributedString(string: strings.ChatList_Search_Ad, font: Font.regular(11.0), textColor: theme.list.itemAccentColor, paragraphAlignment: .center)
let stringRect = titleString.boundingRect(with: CGSize(width: 200.0, height: 20.0), options: .usesLineFragmentOrigin, context: nil)
return generateImage(CGSize(width: floor(stringRect.width) + 18.0, height: 15.0), rotatedContext: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
context.setFillColor(theme.list.itemAccentColor.withMultipliedAlpha(0.1).cgColor)
context.addPath(UIBezierPath(roundedRect: bounds, cornerRadius: size.height / 2.0).cgPath)
context.fillPath()
context.setFillColor(theme.list.itemAccentColor.cgColor)
let circleSize = CGSize(width: 2.0 - UIScreenPixel, height: 2.0 - UIScreenPixel)
context.fillEllipse(in: CGRect(origin: CGPoint(x: size.width - 8.0, y: 3.0 + UIScreenPixel), size: circleSize))
context.fillEllipse(in: CGRect(origin: CGPoint(x: size.width - 8.0, y: 7.0 - UIScreenPixel), size: circleSize))
context.fillEllipse(in: CGRect(origin: CGPoint(x: size.width - 8.0, y: 10.0), size: circleSize))
let textRect = CGRect(
x: 5.0,
y: (size.height - stringRect.height) / 2.0 - UIScreenPixel,
width: stringRect.width,
height: stringRect.height
)
UIGraphicsPushContext(context)
titleString.draw(in: textRect)
UIGraphicsPopContext()
})
})
}
}
@@ -0,0 +1,490 @@
import Foundation
import UIKit
import Display
import AppBundle
public func generateItemListCheckIcon(color: UIColor) -> UIImage? {
return generateImage(CGSize(width: 12.0, height: 10.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setStrokeColor(color.cgColor)
context.setLineWidth(1.98)
context.setLineCap(.round)
context.setLineJoin(.round)
context.translateBy(x: 1.0, y: 1.0)
let _ = try? drawSvgPath(context, path: "M0.215053763,4.36080467 L3.31621263,7.70466293 L3.31621263,7.70466293 C3.35339229,7.74475231 3.41603123,7.74711109 3.45612061,7.70993143 C3.45920681,7.70706923 3.46210733,7.70401312 3.46480451,7.70078171 L9.89247312,0 S ")
})
}
public func generateItemListPlusIcon(_ color: UIColor) -> UIImage? {
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddIcon"), color: color)
}
public struct PresentationResourcesItemList {
public static func downArrowImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListDownArrow.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Search/DownButton"), color: theme.list.itemAccentColor)
})
}
public static func disclosureArrowImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListDisclosureArrow.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Item List/DisclosureArrow"), color: theme.list.disclosureArrowColor)
})
}
public static func disclosureOptionArrowsImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.disclosureOptionArrowsImage.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Item List/ContextDisclosureArrow"), color: theme.list.disclosureArrowColor)
})
}
public static func disclosureLockedImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListDisclosureLocked.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/SmallLock"), color: theme.list.disclosureArrowColor)
})
}
public static func checkIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListCheckIcon.rawValue, { theme in
return generateItemListCheckIcon(color: theme.list.itemAccentColor)
})
}
public static func secondaryCheckIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListSecondaryCheckIcon.rawValue, { theme in
return generateItemListCheckIcon(color: theme.list.itemSecondaryTextColor)
})
}
public static func disabledCheckIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListDisabledCheckIcon.rawValue, { theme in
return generateItemListCheckIcon(color: theme.list.itemDisabledTextColor)
})
}
public static func plusIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListPlusIcon.rawValue, { theme in
return generateItemListPlusIcon(theme.list.itemAccentColor)
})
}
public static func roundPlusIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListRoundPlusIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddRoundIcon"), color: theme.list.itemAccentColor)
})
}
public static func accentDeleteIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListAccentDeleteIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: theme.list.itemAccentColor)
})
}
public static func deleteIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListDeleteIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: theme.list.itemDestructiveColor)
})
}
public static func stickerUnreadDotImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListStickerItemUnreadDot.rawValue, { theme in
return generateFilledCircleImage(diameter: 6.0, color: theme.list.itemAccentColor)
})
}
public static func verifiedPeerIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListVerifiedPeerIcon.rawValue, { theme in
if let backgroundImage = UIImage(bundleImageName: "Chat List/PeerVerifiedIconBackground"), let foregroundImage = UIImage(bundleImageName: "Chat List/PeerVerifiedIconForeground") {
return generateImage(backgroundImage.size, contextGenerator: { size, context in
if let backgroundCgImage = backgroundImage.cgImage, let foregroundCgImage = foregroundImage.cgImage {
context.clear(CGRect(origin: CGPoint(), size: size))
context.saveGState()
context.clip(to: CGRect(origin: .zero, size: size), mask: backgroundCgImage)
context.setFillColor(theme.chatList.unreadBadgeActiveBackgroundColor.cgColor)
context.fill(CGRect(origin: CGPoint(), size: size))
context.restoreGState()
context.clip(to: CGRect(origin: .zero, size: size), mask: foregroundCgImage)
context.setFillColor(theme.chatList.unreadBadgeActiveTextColor.cgColor)
context.fill(CGRect(origin: CGPoint(), size: size))
}
}, opaque: false)
} else {
return nil
}
})
}
public static func itemListDeleteIndicatorIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListDeleteIndicatorIcon.rawValue, { theme in
guard let image = generateTintedImage(image: UIImage(bundleImageName: "Item List/RemoveItemIcon"), color: theme.list.itemDestructiveColor) else {
return nil
}
return generateImage(image.size, rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(theme.rootController.tabBar.badgeTextColor.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(x: 2, y: 2), size: CGSize(width: size.width - 4.0, height: size.height - 4.0)))
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: size))
})
})
}
public static func itemListReorderIndicatorIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListReorderIndicatorIcon.rawValue, { theme in
return generateImage(CGSize(width: 17.0, height: 14.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(theme.list.itemBlocksSeparatorColor.cgColor)
let lineHeight = 1.0 + UIScreenPixel
context.addPath(CGPath(roundedRect: CGRect(x: 0.0, y: UIScreenPixel, width: 17.0, height: lineHeight), cornerWidth: lineHeight / 2.0, cornerHeight: lineHeight / 2.0, transform: nil))
context.addPath(CGPath(roundedRect: CGRect(x: 0.0, y: UIScreenPixel + 6.0, width: 17.0, height: lineHeight), cornerWidth: lineHeight / 2.0, cornerHeight: lineHeight / 2.0, transform: nil))
context.addPath(CGPath(roundedRect: CGRect(x: 0.0, y: UIScreenPixel + 12.0, width: 17.0, height: lineHeight), cornerWidth: lineHeight / 2.0, cornerHeight: lineHeight / 2.0, transform: nil))
context.fillPath()
})
})
}
public static func linkIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListLinkIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Contact List/LinkActionIcon"), color: theme.list.itemAccentColor)
})
}
public static func addPersonIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListAddPersonIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Contact List/AddMemberIcon"), color: theme.list.itemAccentColor)
})
}
public static func createGroupIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListCreateGroupIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Location/CreateGroupIcon"), color: theme.list.itemAccentColor)
})
}
public static func addChannelIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListAddExceptionIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Item List/AddChannelIcon"), color: theme.list.itemAccentColor)
})
}
public static func voiceCallIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListVoiceCallIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Info/CallButton"), color: theme.list.itemAccentColor)
})
}
public static func videoCallIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListVideoCallIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Info/VideoCallButton"), color: theme.list.itemAccentColor)
})
}
public static func addPhoneIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListAddPhoneIcon.rawValue, { theme in
guard let image = generateTintedImage(image: UIImage(bundleImageName: "Item List/AddItemIcon"), color: theme.list.itemAccentColor) else {
return nil
}
return generateImage(image.size, rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(theme.rootController.tabBar.badgeTextColor.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(x: 2, y: 2), size: CGSize(width: size.width - 4.0, height: size.height - 4.0)))
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: size))
})
})
}
public static func addPhotoIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListAddPhotoIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Settings/SetAvatar"), color: theme.list.itemAccentColor)
})
}
public static func itemListClearInputIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListClearInputIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Clear"), color: theme.list.inputClearButtonColor)
})
}
public static func cloudFetchIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListCloudFetchIcon.rawValue, { theme in
generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/FileCloudFetch"), color: theme.list.itemAccentColor)
})
}
public static func itemListCloseIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListCloseIconImage.rawValue, { theme in
return generateImage(CGSize(width: 12.0, height: 12.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setBlendMode(.copy)
context.setStrokeColor(theme.list.disclosureArrowColor.cgColor)
context.setLineWidth(2.0)
context.setLineCap(.round)
context.move(to: CGPoint(x: 1.0, y: 1.0))
context.addLine(to: CGPoint(x: size.width - 1.0, y: size.height - 1.0))
context.strokePath()
context.move(to: CGPoint(x: size.width - 1.0, y: 1.0))
context.addLine(to: CGPoint(x: 1.0, y: size.height - 1.0))
context.strokePath()
})
})
}
public static func itemListRemoveIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListRemoveIconImage.rawValue, { theme in
return generateImage(CGSize(width: 15.0, height: 15.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setBlendMode(.copy)
context.setStrokeColor(theme.list.disclosureArrowColor.cgColor)
context.setLineWidth(2.0)
context.setLineCap(.round)
context.move(to: CGPoint(x: 1.0, y: 1.0))
context.addLine(to: CGPoint(x: size.width - 1.0, y: size.height - 1.0))
context.strokePath()
context.move(to: CGPoint(x: size.width - 1.0, y: 1.0))
context.addLine(to: CGPoint(x: 1.0, y: size.height - 1.0))
context.strokePath()
})
})
}
public static func makeVisibleIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListMakeVisibleIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Contact List/MakeVisibleIcon"), color: theme.list.itemAccentColor)
})
}
public static func makeInvisibleIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListMakeInvisibleIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Contact List/MakeInvisibleIcon"), color: theme.list.itemDestructiveColor)
})
}
public static func editThemeIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListEditThemeIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Settings/EditTheme"), color: theme.list.itemAccentColor)
})
}
public static func knobImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListKnob.rawValue, { theme in
return generateImage(CGSize(width: 40.0, height: 40.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setShadow(offset: CGSize(width: 0.0, height: -3.0), blur: 12.0, color: UIColor(white: 0.0, alpha: 0.25).cgColor)
context.setFillColor(UIColor.white.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(x: 6.0, y: 6.0), size: CGSize(width: 28.0, height: 28.0)))
})
})
}
public static func blockAccentIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListBlockAccentIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Item List/Block"), color: theme.list.itemAccentColor)
})
}
public static func blockDestructiveIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListBlockDestructiveIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Item List/Block"), color: theme.list.itemDestructiveColor)
})
}
public static func addDeviceIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListAddDeviceIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Settings/QrIcon"), color: theme.list.itemAccentColor)
})
}
public static func resetIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListResetIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Settings/Reset"), color: theme.list.itemAccentColor)
})
}
public static func imageIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListImageIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Attach Menu/Image"), color: theme.list.itemAccentColor)
})
}
public static func cloudIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListCloudIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Attach Menu/Cloud"), color: theme.list.itemAccentColor)
})
}
public static func addBoostsIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListAddBoostsIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Premium/Gift"), color: theme.list.itemAccentColor)
})
}
public static func premiumIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListPremiumIcon.rawValue, { theme in
return generateImage(CGSize(width: 16.0, height: 16.0), contextGenerator: { size, context in
let bounds = CGRect(origin: .zero, size: size)
context.clear(bounds)
let image = UIImage(bundleImageName: "Item List/PremiumIcon")!
context.clip(to: bounds, mask: image.cgImage!)
let colorsArray: [CGColor] = [
UIColor(rgb: 0x6b93ff).cgColor,
UIColor(rgb: 0x6b93ff).cgColor,
UIColor(rgb: 0x8d77ff).cgColor,
UIColor(rgb: 0xb56eec).cgColor,
UIColor(rgb: 0xb56eec).cgColor
]
var locations: [CGFloat] = [0.0, 0.3, 0.5, 0.7, 1.0]
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
})
})
}
public static func cornersImage(_ theme: PresentationTheme, top: Bool, bottom: Bool, glass: Bool = false) -> UIImage? {
if !top && !bottom {
return nil
}
let key: PresentationResourceKey
if top && bottom {
key = glass ? PresentationResourceKey.itemListCornersBothGlass : PresentationResourceKey.itemListCornersBoth
} else if top {
key = glass ? PresentationResourceKey.itemListCornersTopGlass : PresentationResourceKey.itemListCornersTop
} else {
key = glass ? PresentationResourceKey.itemListCornersBottomGlass : PresentationResourceKey.itemListCornersBottom
}
return theme.image(key.rawValue, { theme in
return generateImage(CGSize(width: 56.0, height: 56.0), rotatedContext: { (size, context) in
let bounds = CGRect(origin: CGPoint(), size: size)
context.setFillColor(theme.list.blocksBackgroundColor.cgColor)
context.fill(bounds)
context.setBlendMode(.clear)
var corners: UIRectCorner = []
if top {
corners.insert(.topLeft)
corners.insert(.topRight)
}
if bottom {
corners.insert(.bottomLeft)
corners.insert(.bottomRight)
}
let cornerRadius: CGFloat = glass ? 26.0 : 11.0
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: cornerRadius, height: cornerRadius))
context.addPath(path.cgPath)
context.fillPath()
})?.stretchableImage(withLeftCapWidth: 28, topCapHeight: 28)
})
}
public static func uploadToneIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.uploadToneIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Settings/UploadTone"), color: theme.list.itemAccentColor)
})
}
public static func topicArrowDescriptionIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListTopicArrowIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/TopicArrowIcon"), color: theme.list.itemSecondaryTextColor)
})
}
public static func statsReactionsIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.statsReactionsIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chart/Reactions"), color: theme.list.itemSecondaryTextColor)
})
}
public static func statsForwardsIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.statsForwardsIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chart/Forwards"), color: theme.list.itemSecondaryTextColor)
})
}
public static func sharedLinkIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.sharedLinkIcon.rawValue, { theme in
return generateImage(CGSize(width: 40.0, height: 40.0), rotatedContext: { size, context in
UIGraphicsPushContext(context)
defer {
UIGraphicsPopContext()
}
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(theme.list.itemCheckColors.fillColor.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.list.itemCheckColors.foregroundColor) {
image.draw(at: CGPoint(x: floor((size.width - image.size.width) * 0.5), y: floor((size.height - image.size.height) * 0.5)))
}
})
})
}
public static func hideIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.hideIconImage.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/Archive/IconHide"), color: theme.list.itemAccentColor)
})
}
public static func peerStatusLockedImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.peerStatusLockedImage.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/SmallLock"), color: theme.list.itemSecondaryTextColor)
})
}
public static func expandDownArrowImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.expandDownArrowImage.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Item List/ExpandingItemVerticalRegularArrow"), color: .white)?.withRenderingMode(.alwaysTemplate)
})
}
public static func expandSmallDownArrowImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.expandSmallDownArrowImage.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Item List/ExpandingItemVerticalSmallArrow"), color: .white)?.withRenderingMode(.alwaysTemplate)
})
}
public static func itemListRoundTopupIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListRoundTopupIcon.rawValue, { theme in
return generateImage(CGSize(width: 16.0, height: 18.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.translateBy(x: 0.0, y: 2.0 - UIScreenPixel)
context.setFillColor(theme.list.itemCheckColors.foregroundColor.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.width)))
context.setBlendMode(.clear)
context.addPath(CGPath(roundedRect: CGRect(x: 7.0, y: 3.0, width: 2.0, height: 10.0), cornerWidth: 1.0, cornerHeight: 1.0, transform: nil))
context.addPath(CGPath(roundedRect: CGRect(x: 3.0, y: 7.0, width: 10.0, height: 2.0), cornerWidth: 1.0, cornerHeight: 1.0, transform: nil))
context.fillPath()
})
})
}
public static func itemListRoundWithdrawIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListRoundWithdrawIcon.rawValue, { theme in
return generateImage(CGSize(width: 16.0, height: 18.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.translateBy(x: 0.0, y: 2.0 - UIScreenPixel)
context.setFillColor(theme.list.itemCheckColors.foregroundColor.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.width)))
context.setBlendMode(.clear)
context.addPath(CGPath(roundedRect: CGRect(x: 3.0, y: 7.0, width: 10.0, height: 2.0), cornerWidth: 1.0, cornerHeight: 1.0, transform: nil))
context.fillPath()
})
})
}
public static func itemListStatsIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.itemListStatsIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Premium/Stars/Stats"), color: .white)?.withRenderingMode(.alwaysTemplate)
})
}
}
@@ -0,0 +1,208 @@
import Foundation
import UIKit
import Display
import AppBundle
private func generateShareButtonImage(theme: PresentationTheme) -> UIImage? {
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/NavigationShare"), color: theme.rootController.navigationBar.accentTextColor)
}
public func generateIndefiniteActivityIndicatorImage(color: UIColor, diameter: CGFloat = 22.0, lineWidth: CGFloat = 2.0) -> UIImage? {
return generateImage(CGSize(width: diameter, height: diameter), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setStrokeColor(color.cgColor)
context.setLineWidth(lineWidth)
context.setLineCap(.round)
let cutoutAngle: CGFloat = CGFloat.pi * 30.0 / 180.0
context.addArc(center: CGPoint(x: size.width / 2.0, y: size.height / 2.0), radius: size.width / 2.0 - lineWidth / 2.0, startAngle: 0.0, endAngle: CGFloat.pi * 2.0 - cutoutAngle, clockwise: false)
context.strokePath()
})
}
public func generatePlayerRateIcon(_ color: UIColor) -> UIImage? {
return generateImage(CGSize(width: 19.0, height: 16.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(color.cgColor)
context.setStrokeColor(color.cgColor)
context.setLineWidth(4.0)
context.scaleBy(x: 0.3333, y: 0.3333)
let _ = try? drawSvgPath(context, path: "M15.3637695,32.1972656 L23.7749023,32.1972656 C24.6127972,32.1972656 25.2519509,32.3691389 25.6923828,32.7128906 C26.1328147,33.0566423 26.3530273,33.5239228 26.3530273,34.1147461 C26.3530273,34.6411159 26.1784685,35.0869122 25.8293457,35.4521484 C25.4802229,35.8173846 24.9511754,36 24.2421875,36 L12.3828125,36 C11.5771444,36 10.9487327,35.7771018 10.4975586,35.3312988 C10.0463845,34.8854958 9.82080078,34.3618194 9.82080078,33.7602539 C9.82080078,33.3735332 9.96581886,32.8605989 10.2558594,32.2214355 C10.5458999,31.5822722 10.8627913,31.08008 11.206543,30.7148438 C12.635261,29.2324145 13.9243107,27.9621635 15.0737305,26.9040527 C16.2231503,25.845942 17.0449194,25.1503923 17.5390625,24.8173828 C18.4199263,24.1943328 19.1530732,23.5686067 19.7385254,22.9401855 C20.3239775,22.3117644 20.7697739,21.6672396 21.0759277,21.0065918 C21.3820816,20.345944 21.5351562,19.6987336 21.5351562,19.0649414 C21.5351562,18.377438 21.3713395,17.7624539 21.0437012,17.2199707 C20.7160628,16.6774875 20.2702665,16.2558609 19.7062988,15.9550781 C19.1423312,15.6542954 18.5273471,15.5039062 17.8613281,15.5039062 C16.4540945,15.5039062 15.3476603,16.1215759 14.5419922,17.3569336 C14.4345698,17.5180672 14.2546399,17.9584925 14.0021973,18.6782227 C13.7497546,19.3979528 13.4650895,19.9511699 13.1481934,20.3378906 C12.8312972,20.7246113 12.3667023,20.9179688 11.7543945,20.9179688 C11.2172825,20.9179688 10.7714861,20.7407244 10.4169922,20.3862305 C10.0624982,20.0317365 9.88525391,19.5483429 9.88525391,18.9360352 C9.88525391,18.1948205 10.0517561,17.4213907 10.3847656,16.6157227 C10.7177751,15.8100546 11.2145963,15.0795931 11.8752441,14.4243164 C12.535892,13.7690397 13.3737742,13.2399922 14.388916,12.8371582 C15.4040578,12.4343242 16.5937432,12.2329102 17.9580078,12.2329102 C19.6015707,12.2329102 21.0034122,12.4907201 22.1635742,13.0063477 C22.9155311,13.3500994 23.576169,13.8227509 24.1455078,14.4243164 C24.7148466,15.0258819 25.1579574,15.7214316 25.4748535,16.5109863 C25.7917496,17.3005411 25.9501953,18.1196247 25.9501953,18.9682617 C25.9501953,20.3002996 25.6198764,21.5114692 24.9592285,22.6018066 C24.2985807,23.6921441 23.6245152,24.5461395 22.9370117,25.1638184 C22.2495083,25.7814972 21.0974202,26.75097 19.4807129,28.0722656 C17.8640056,29.3935613 16.7548858,30.4194299 16.1533203,31.1499023 C15.8955065,31.4399429 15.6323256,31.7890605 15.3637695,32.1972656 Z M28.8464425,31.4077148 L34.1315987,23.6894531 L29.6843331,16.8251953 C29.2653857,16.1591764 28.9511799,15.5871606 28.7417062,15.1091309 C28.5322325,14.6311011 28.4274972,14.1718772 28.4274972,13.7314453 C28.4274972,13.2802712 28.6289112,12.8747577 29.0317452,12.5148926 C29.4345793,12.1550275 29.9260294,11.9750977 30.5061105,11.9750977 C31.1721294,11.9750977 31.6904348,12.1711406 32.0610421,12.5632324 C32.4316494,12.9553242 32.9445837,13.6831002 33.5998605,14.746582 L37.1447823,20.4829102 L40.9314034,14.746582 C41.2429284,14.2631812 41.5087949,13.8496111 41.7290109,13.5058594 C41.9492268,13.1621077 42.1613829,12.8774425 42.3654855,12.6518555 C42.569588,12.4262684 42.7978572,12.2570806 43.0502999,12.1442871 C43.3027426,12.0314936 43.5954643,11.9750977 43.9284737,11.9750977 C44.5300392,11.9750977 45.0214894,12.1550275 45.402839,12.5148926 C45.7841885,12.8747577 45.9748605,13.3017553 45.9748605,13.7958984 C45.9748605,14.5156286 45.5612904,15.4931579 44.7341378,16.7285156 L40.0773995,23.6894531 L45.08863,31.4077148 C45.5398041,32.084476 45.8674376,32.6457497 46.0715401,33.0915527 C46.2756427,33.5373557 46.3776925,33.9589824 46.3776925,34.3564453 C46.3776925,34.7324238 46.2863848,35.0761703 46.1037667,35.3876953 C45.9211486,35.6992203 45.6633387,35.9462881 45.3303292,36.1289062 C44.9973197,36.3115244 44.6213469,36.402832 44.2023995,36.402832 C43.7512254,36.402832 43.3698815,36.3088388 43.0583566,36.1208496 C42.7468316,35.9328604 42.4943927,35.6992201 42.3010323,35.4199219 C42.107672,35.1406236 41.7478123,34.5981486 41.2214425,33.7924805 L37.0642159,27.2504883 L32.6491769,33.9858398 C32.3054251,34.5229519 32.0610428,34.8989247 31.9160226,35.1137695 C31.7710023,35.3286144 31.5964435,35.5380849 31.3923409,35.7421875 C31.1882383,35.9462901 30.9465415,36.1074213 30.6672433,36.2255859 C30.387945,36.3437506 30.0603116,36.402832 29.6843331,36.402832 C29.1042521,36.402832 28.623544,36.2255877 28.2421944,35.8710938 C27.8608449,35.5165998 27.670173,35.0009799 27.670173,34.3242188 C27.670173,33.5292929 28.0622589,32.5571347 28.8464425,31.4077148 Z M8,2 C4.6862915,2 2,4.6862915 2,8 L2,40 C2,43.3137085 4.6862915,46 8,46 L48,46 C51.3137085,46 54,43.3137085 54,40 L54,8 C54,4.6862915 51.3137085,2 48,2 L8,2 S")
})
}
public struct PresentationResourcesRootController {
public static func navigationIndefiniteActivityImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.rootNavigationIndefiniteActivity.rawValue, { theme in
generateIndefiniteActivityIndicatorImage(color: theme.rootController.navigationBar.accentTextColor)
})
}
public static func navigationComposeIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationComposeIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/ComposeIcon"), color: theme.rootController.navigationBar.accentTextColor)
})
}
public static func navigationShareIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationShareIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: theme.rootController.navigationBar.accentTextColor)
})
// return theme.image(PresentationResourceKey.navigationShareIcon.rawValue, generateShareButtonImage)
}
public static func navigationCallIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationCallIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Call List/CallIcon"), color: theme.rootController.navigationBar.accentTextColor)
})
}
public static func navigationInfoIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationInfoIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/InfoIcon"), color: theme.rootController.navigationBar.accentTextColor)
})
}
public static func navigationSearchIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationSearchIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/SearchIcon"), color: theme.rootController.navigationBar.accentTextColor)
})
}
public static func navigationCompactSearchIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationCompactSearchIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/SearchIcon"), color: theme.rootController.navigationBar.accentTextColor)
})
}
public static func navigationCompactSearchWhiteIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationCompactSearchWhiteIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/SearchIcon"), color: .white)
})
}
public static func navigationCompactTagsSearchIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationCompactTagsSearchIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/NavigationSearchTagsIcon"), color: theme.rootController.navigationBar.accentTextColor)
})
}
public static func navigationCompactTagsSearchWhiteIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationCompactTagsSearchWhiteIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/NavigationSearchTagsIcon"), color: .white)
})
}
public static func navigationCalendarIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationCalendarIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Search/Calendar"), color: theme.rootController.navigationBar.accentTextColor)
})
}
public static func navigationMoreIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationMoreIcon.rawValue, { theme in
return generateImage(CGSize(width: 30.0, height: 30.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(theme.rootController.navigationBar.accentTextColor.cgColor)
let dotSize: CGFloat = 4.0
context.fillEllipse(in: CGRect(origin: CGPoint(x: 6.0, y: floor((size.height - dotSize) / 2.0)), size: CGSize(width: dotSize, height: dotSize)))
context.fillEllipse(in: CGRect(origin: CGPoint(x: 13.0, y: floor((size.height - dotSize) / 2.0)), size: CGSize(width: dotSize, height: dotSize)))
context.fillEllipse(in: CGRect(origin: CGPoint(x: 20.0, y: floor((size.height - dotSize) / 2.0)), size: CGSize(width: dotSize, height: dotSize)))
})
})
}
public static func navigationMoreCircledIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationMoreCircledIcon.rawValue, { theme in
generateTintedImage(image: UIImage(bundleImageName: "Chat List/NavigationMore"), color: theme.rootController.navigationBar.accentTextColor)
})
}
public static func navigationQrCodeIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationQrCodeIcon.rawValue, { theme in
generateTintedImage(image: UIImage(bundleImageName: "Settings/QrIcon"), color: .white)
})
}
public static func navigationAddIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationAddIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddIcon"), color: theme.rootController.navigationBar.accentTextColor)
})
}
public static func navigationPlayerCloseButton(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationPlayerCloseButton.rawValue, { theme in
return generateImage(CGSize(width: 12.0, height: 12.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setStrokeColor(theme.rootController.navigationBar.controlColor.cgColor)
context.setLineWidth(2.0)
context.setLineCap(.round)
context.move(to: CGPoint(x: 1.0, y: 1.0))
context.addLine(to: CGPoint(x: size.width - 1.0, y: size.height - 1.0))
context.strokePath()
context.move(to: CGPoint(x: size.width - 1.0, y: 1.0))
context.addLine(to: CGPoint(x: 1.0, y: size.height - 1.0))
context.strokePath()
})
})
}
public static func navigationPlayerRateActiveIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationPlayerRateActiveIcon.rawValue, { theme in
return generatePlayerRateIcon(theme.rootController.navigationBar.accentTextColor)
})
}
public static func navigationPlayerRateInactiveIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationPlayerRateInactiveIcon.rawValue, { theme in
return generatePlayerRateIcon(theme.rootController.navigationBar.controlColor)
})
}
public static func navigationPlayerMaximizedRateActiveIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationPlayerMaximizedRateActiveIcon.rawValue, { theme in
return generatePlayerRateIcon(theme.list.itemAccentColor)
})
}
public static func navigationPlayerMaximizedRateInactiveIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationPlayerMaximizedRateInactiveIcon.rawValue, { theme in
return generatePlayerRateIcon(theme.list.itemSecondaryTextColor)
})
}
public static func navigationLiveLocationIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationLiveLocationIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/LiveLocationPanelIcon"), color: theme.rootController.navigationBar.accentTextColor)
})
}
public static func inAppNotificationBackground(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.inAppNotificationBackground.rawValue, { theme in
let inset: CGFloat = 16.0
return generateImage(CGSize(width: 30.0 + inset * 2.0, height: 30.0 + 8.0 * 2.0 + 20.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setShadow(offset: CGSize(width: 0.0, height: -4.0), blur: 40.0, color: UIColor(white: 0.0, alpha: 0.3).cgColor)
context.setFillColor(theme.inAppNotification.fillColor.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(x: inset, y: 8.0 * 2.0), size: CGSize(width: 30.0, height: 30.0)))
})?.stretchableImage(withLeftCapWidth: Int(inset) + 15, topCapHeight: 8 * 2 + 15)
})
}
public static func navigationPostStoryIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationPostStoryIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddStoryIcon"), color: .white)
})
}
public static func navigationSortIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationSortIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SortIcon"), color: .white)
})
}
public static func callListCallIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.callListCallIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Call List/NewCallListIcon"), color: theme.rootController.navigationBar.accentTextColor)
})
}
}
@@ -0,0 +1,196 @@
import Foundation
import UIKit
import Display
import AppBundle
private func drawBorder(context: CGContext, rect: CGRect) {
context.setLineWidth(UIScreenPixel)
context.setStrokeColor(UIColor(rgb: 0xffffff, alpha: 0.25).cgColor)
let path = CGPath(roundedRect: rect.insetBy(dx: UIScreenPixel / 2.0, dy: UIScreenPixel / 2.0), cornerWidth: 6.0, cornerHeight: 6.0, transform: nil)
context.addPath(path)
context.strokePath()
}
private func addRoundedRectPath(context: CGContext, rect: CGRect, radius: CGFloat) {
context.saveGState()
context.translateBy(x: rect.minX, y: rect.minY)
context.scaleBy(x: radius, y: radius)
let fw = rect.width / radius
let fh = rect.height / radius
context.move(to: CGPoint(x: fw, y: fh / 2.0))
context.addArc(tangent1End: CGPoint(x: fw, y: fh), tangent2End: CGPoint(x: fw/2, y: fh), radius: 1.0)
context.addArc(tangent1End: CGPoint(x: 0, y: fh), tangent2End: CGPoint(x: 0, y: fh/2), radius: 1)
context.addArc(tangent1End: CGPoint(x: 0, y: 0), tangent2End: CGPoint(x: fw/2, y: 0), radius: 1)
context.addArc(tangent1End: CGPoint(x: fw, y: 0), tangent2End: CGPoint(x: fw, y: fh/2), radius: 1)
context.closePath()
context.restoreGState()
}
private func renderIcon(name: String, scaleFactor: CGFloat = 1.0, backgroundColors: [UIColor]? = nil) -> UIImage? {
return generateImage(CGSize(width: 29.0, height: 29.0), contextGenerator: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
if let backgroundColors {
addRoundedRectPath(context: context, rect: CGRect(origin: CGPoint(), size: size), radius: 7.0)
context.clip()
var locations: [CGFloat] = [0.0, 1.0]
let colors: [CGColor] = backgroundColors.map(\.cgColor)
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: size.width, y: size.height), end: CGPoint(x: 0.0, y: 0.0), options: CGGradientDrawingOptions())
context.resetClip()
if let image = generateTintedImage(image: UIImage(bundleImageName: name), color: .white), let cgImage = image.cgImage {
let imageSize = CGSize(width: image.size.width * scaleFactor, height: image.size.height * scaleFactor)
context.draw(cgImage, in: CGRect(origin: CGPoint(x: (bounds.width - imageSize.width) * 0.5, y: (bounds.height - imageSize.height) * 0.5), size: imageSize))
}
} else {
if let image = UIImage(bundleImageName: name), let cgImage = image.cgImage {
let imageSize: CGSize
if scaleFactor == 1.0 {
imageSize = size
} else {
imageSize = CGSize(width: image.size.width * scaleFactor, height: image.size.height * scaleFactor)
}
context.draw(cgImage, in: CGRect(origin: CGPoint(x: (bounds.width - imageSize.width) * 0.5, y: (bounds.height - imageSize.height) * 0.5), size: imageSize))
}
}
})
}
public struct PresentationResourcesSettings {
public static let editProfile = renderIcon(name: "Settings/Menu/EditProfile")
public static let proxy = renderIcon(name: "Settings/Menu/Proxy")
public static let savedMessages = renderIcon(name: "Settings/Menu/SavedMessages")
public static let recentCalls = renderIcon(name: "Settings/Menu/RecentCalls")
public static let devices = renderIcon(name: "Settings/Menu/Sessions")
public static let chatFolders = renderIcon(name: "Settings/Menu/ChatListFilters")
public static let stickers = renderIcon(name: "Settings/Menu/Stickers")
public static let notifications = renderIcon(name: "Settings/Menu/Notifications")
public static let security = renderIcon(name: "Settings/Menu/Security")
public static let dataAndStorage = renderIcon(name: "Settings/Menu/DataAndStorage")
public static let appearance = renderIcon(name: "Settings/Menu/Appearance")
public static let language = renderIcon(name: "Settings/Menu/Language")
public static let deleteAccount = renderIcon(name: "Chat/Info/GroupRemovedIcon")
public static let powerSaving = renderIcon(name: "Settings/Menu/PowerSaving")
public static let stories = renderIcon(name: "Premium/Perk/Stories", scaleFactor: 0.97, backgroundColors: [UIColor(rgb: 0x5856D6)])
public static let premiumGift = renderIcon(name: "Settings/Menu/Gift")
public static let business = renderIcon(name: "Settings/Menu/Business", backgroundColors: [UIColor(rgb: 0xA95CE3), UIColor(rgb: 0xF16B80)])
public static let myProfile = renderIcon(name: "Settings/Menu/Profile")
public static let reactions = renderIcon(name: "Settings/Menu/Reactions")
public static let balance = renderIcon(name: "Settings/Menu/Balance", scaleFactor: 0.97, backgroundColors: [UIColor(rgb: 0x34c759)])
public static let affiliateProgram = renderIcon(name: "Settings/Menu/AffiliateProgram")
public static let earnStars = renderIcon(name: "Settings/Menu/EarnStars")
public static let channelMessages = renderIcon(name: "Chat/Info/ChannelMessages", backgroundColors: [UIColor(rgb: 0x5856D6)])
public static let premium = generateImage(CGSize(width: 29.0, height: 29.0), contextGenerator: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
let path = UIBezierPath(roundedRect: bounds, cornerRadius: 7.0)
context.addPath(path.cgPath)
context.clip()
let colorsArray: [CGColor] = [
UIColor(rgb: 0x6b93ff).cgColor,
UIColor(rgb: 0x6b93ff).cgColor,
UIColor(rgb: 0x8d77ff).cgColor,
UIColor(rgb: 0xb56eec).cgColor,
UIColor(rgb: 0xb56eec).cgColor
]
var locations: [CGFloat] = [0.0, 0.15, 0.5, 0.85, 1.0]
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
if let image = generateTintedImage(image: UIImage(bundleImageName: "Premium/ButtonIcon"), color: UIColor(rgb: 0xffffff)), let cgImage = image.cgImage {
context.draw(cgImage, in: CGRect(origin: CGPoint(x: floorToScreenPixels((bounds.width - image.size.width) / 2.0), y: floorToScreenPixels((bounds.height - image.size.height) / 2.0)), size: image.size))
}
drawBorder(context: context, rect: bounds)
})
public static let ton = generateImage(CGSize(width: 29.0, height: 29.0), contextGenerator: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
let path = UIBezierPath(roundedRect: bounds, cornerRadius: 7.0)
context.addPath(path.cgPath)
context.clip()
context.setFillColor(UIColor(rgb: 0x32ade6).cgColor)
context.fill(bounds)
if let image = generateTintedImage(image: UIImage(bundleImageName: "Ads/TonAbout"), color: UIColor(rgb: 0xffffff)), let cgImage = image.cgImage {
context.draw(cgImage, in: CGRect(origin: CGPoint(x: floorToScreenPixels((bounds.width - image.size.width) / 2.0), y: floorToScreenPixels((bounds.height - image.size.height) / 2.0)), size: image.size))
}
drawBorder(context: context, rect: bounds)
})
public static let stars = generateImage(CGSize(width: 29.0, height: 29.0), contextGenerator: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
let path = UIBezierPath(roundedRect: bounds, cornerRadius: 7.0)
context.addPath(path.cgPath)
context.clip()
let colorsArray: [CGColor] = [
UIColor(rgb: 0xfec80f).cgColor,
UIColor(rgb: 0xdd6f12).cgColor
]
var locations: [CGFloat] = [0.0, 1.0]
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions())
if let image = generateTintedImage(image: UIImage(bundleImageName: "Premium/ButtonIcon"), color: UIColor(rgb: 0xffffff)), let cgImage = image.cgImage {
context.draw(cgImage, in: CGRect(origin: CGPoint(x: floorToScreenPixels((bounds.width - image.size.width) / 2.0), y: floorToScreenPixels((bounds.height - image.size.height) / 2.0)), size: image.size))
}
drawBorder(context: context, rect: bounds)
})
public static let bot = generateImage(CGSize(width: 29.0, height: 29.0), contextGenerator: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
let path = UIBezierPath(roundedRect: bounds, cornerRadius: 7.0)
context.addPath(path.cgPath)
context.clip()
context.setFillColor(UIColor(rgb: 0x0088ff).cgColor)
context.fill(bounds)
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat List/Filters/Bot"), color: UIColor(rgb: 0xffffff)), let cgImage = image.cgImage {
context.draw(cgImage, in: CGRect(origin: CGPoint(x: floorToScreenPixels((bounds.width - image.size.width) / 2.0), y: floorToScreenPixels((bounds.height - image.size.height) / 2.0)), size: image.size))
}
drawBorder(context: context, rect: bounds)
})
public static let passport = renderIcon(name: "Settings/Menu/Passport")
public static let watch = renderIcon(name: "Settings/Menu/Watch")
public static let support = renderIcon(name: "Settings/Menu/Support")
public static let faq = renderIcon(name: "Settings/Menu/Faq")
public static let tips = renderIcon(name: "Settings/Menu/Tips")
public static let addAccount = renderIcon(name: "Settings/Menu/AddAccount")
public static let setPasscode = renderIcon(name: "Settings/Menu/SetPasscode")
public static let clearCache = renderIcon(name: "Settings/Menu/ClearCache")
public static let changePhoneNumber = renderIcon(name: "Settings/Menu/ChangePhoneNumber")
public static let deleteAddAccount = renderIcon(name: "Settings/Menu/DeleteAddAccount")
public static let deleteSetTwoStepAuth = renderIcon(name: "Settings/Menu/DeleteTwoStepAuth")
public static let deleteSetPasscode = renderIcon(name: "Settings/Menu/FaceId")
public static let deleteChats = renderIcon(name: "Settings/Menu/DeleteChats")
public static let clearSynced = renderIcon(name: "Settings/Menu/ClearSynced")
public static let websites = renderIcon(name: "Settings/Menu/Websites")
}