Files
Swiftgram/submodules/TelegramUI/Components/Settings/WallpaperGridScreen/Sources/ThemeGridControllerItem.swift

230 lines
9.0 KiB
Swift

import Foundation
import UIKit
import Display
import TelegramCore
import SwiftSignalKit
import AsyncDisplayKit
import Postbox
import AccountContext
import GridMessageSelectionNode
import SettingsThemeWallpaperNode
import TelegramPresentationData
private var cachedBorderImages: [String: UIImage] = [:]
private func generateBorderImage(theme: PresentationTheme, bordered: Bool, selected: Bool) -> UIImage? {
let key = "\(theme.list.itemBlocksBackgroundColor.hexString)_\(selected ? "s" + theme.list.itemAccentColor.hexString : theme.list.disclosureArrowColor.hexString)"
if let image = cachedBorderImages[key] {
return image
} else {
let image = generateImage(CGSize(width: 20.0, height: 20.0), rotatedContext: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
let lineWidth: CGFloat
if selected {
lineWidth = 2.0
context.setLineWidth(lineWidth)
context.setStrokeColor(theme.list.itemBlocksBackgroundColor.cgColor)
context.strokeEllipse(in: bounds.insetBy(dx: 2.0 + lineWidth / 2.0, dy: 2.0 + lineWidth / 2.0))
var accentColor = theme.list.itemAccentColor
if accentColor.rgb == 0xffffff {
accentColor = UIColor(rgb: 0x999999)
}
context.setStrokeColor(accentColor.cgColor)
} else {
context.setStrokeColor(theme.list.disclosureArrowColor.withAlphaComponent(0.4).cgColor)
lineWidth = 1.0
}
if bordered || selected {
context.setLineWidth(lineWidth)
context.strokeEllipse(in: bounds.insetBy(dx: lineWidth / 2.0, dy: lineWidth / 2.0))
}
})?.stretchableImage(withLeftCapWidth: 10, topCapHeight: 10)
cachedBorderImages[key] = image
return image
}
}
final class ThemeGridControllerItem: GridItem {
let context: AccountContext
let theme: PresentationTheme?
let wallpaper: TelegramWallpaper
let wallpaperId: ThemeGridControllerEntry.StableId
let isEmpty: Bool
let emojiFile: TelegramMediaFile?
let channelMode: Bool
let index: Int
let editable: Bool
let selected: Bool
let interaction: ThemeGridControllerInteraction
let section: GridSection? = nil
init(context: AccountContext, theme: PresentationTheme? = nil, wallpaper: TelegramWallpaper, wallpaperId: ThemeGridControllerEntry.StableId, isEmpty: Bool = false, emojiFile: TelegramMediaFile? = nil, channelMode: Bool = false, index: Int, editable: Bool, selected: Bool, interaction: ThemeGridControllerInteraction) {
self.context = context
self.theme = theme
self.wallpaper = wallpaper
self.wallpaperId = wallpaperId
self.isEmpty = isEmpty
self.emojiFile = emojiFile
self.channelMode = channelMode
self.index = index
self.editable = editable
self.selected = selected
self.interaction = interaction
}
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
let node = ThemeGridControllerItemNode()
node.setup(item: self, synchronousLoad: synchronousLoad)
return node
}
func update(node: GridItemNode) {
guard let node = node as? ThemeGridControllerItemNode else {
assertionFailure()
return
}
node.setup(item: self, synchronousLoad: false)
}
}
final class ThemeGridControllerItemNode: GridItemNode {
private let wallpaperNode: SettingsThemeWallpaperNode
private var selectionNode: GridMessageSelectionNode?
private var selectionBorderNode: ASImageNode?
private var textNode: ImmediateTextNode?
private var item: ThemeGridControllerItem?
override init() {
self.wallpaperNode = SettingsThemeWallpaperNode(displayLoading: false)
super.init()
self.clipsToBounds = true
self.addSubnode(self.wallpaperNode)
}
override func didLoad() {
super.didLoad()
self.view.layer.cornerRadius = 10.0
self.view.isExclusiveTouch = true
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
}
func setup(item: ThemeGridControllerItem, synchronousLoad: Bool) {
self.item = item
self.updateSelectionState(animated: false)
if item.channelMode, item.selected, let theme = item.theme {
let selectionBorderNode: ASImageNode
if let current = self.selectionBorderNode {
selectionBorderNode = current
} else {
selectionBorderNode = ASImageNode()
selectionBorderNode.displaysAsynchronously = false
self.selectionBorderNode = selectionBorderNode
self.addSubnode(selectionBorderNode)
}
selectionBorderNode.image = generateBorderImage(theme: theme, bordered: true, selected: true)
} else {
self.selectionBorderNode?.removeFromSupernode()
}
if item.channelMode, item.isEmpty, let theme = item.theme {
let textNode: ImmediateTextNode
if let current = self.textNode {
textNode = current
} else {
textNode = ImmediateTextNode()
textNode.maximumNumberOfLines = 2
textNode.textAlignment = .center
self.textNode = textNode
self.addSubnode(textNode)
}
let strings = item.context.sharedContext.currentPresentationData.with { $0 }.strings
textNode.attributedText = NSAttributedString(string: strings.Wallpaper_NoWallpaper, font: Font.regular(15.0), textColor: theme.list.itemSecondaryTextColor)
}
self.setNeedsLayout()
}
@objc func tapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state {
if let item = self.item, !item.isEmpty {
item.interaction.openWallpaper(item.wallpaper)
}
}
}
func updateSelectionState(animated: Bool) {
if let item = self.item {
let (editing, selectedIds) = item.interaction.selectionState
if editing && item.editable {
let selected = selectedIds.contains(item.wallpaperId)
if let selectionNode = self.selectionNode {
selectionNode.updateSelected(selected, animated: animated)
selectionNode.frame = CGRect(origin: CGPoint(), size: self.bounds.size)
} else {
let theme = item.context.sharedContext.currentPresentationData.with { $0 }.theme
let selectionNode = GridMessageSelectionNode(theme: theme, toggle: { [weak self] value in
if let strongSelf = self {
strongSelf.item?.interaction.toggleWallpaperSelection(item.wallpaperId, value)
}
})
selectionNode.frame = CGRect(origin: CGPoint(), size: self.bounds.size)
self.addSubnode(selectionNode)
self.selectionNode = selectionNode
selectionNode.updateSelected(selected, animated: false)
if animated {
selectionNode.animateIn()
}
}
}
else {
if let selectionNode = self.selectionNode {
self.selectionNode = nil
if animated {
selectionNode.animateOut { [weak selectionNode] in
selectionNode?.removeFromSupernode()
}
} else {
selectionNode.removeFromSupernode()
}
}
}
}
}
override func layout() {
super.layout()
let bounds = self.bounds
if let item = self.item {
self.wallpaperNode.setWallpaper(context: item.context, theme: item.theme, wallpaper: item.wallpaper, isEmpty: item.isEmpty, emojiFile: item.emojiFile, selected: !item.channelMode && item.selected, size: bounds.size, synchronousLoad: false)
self.selectionNode?.frame = CGRect(origin: CGPoint(), size: bounds.size)
}
self.selectionBorderNode?.frame = CGRect(origin: CGPoint(), size: bounds.size)
if let textNode = self.textNode {
let textSize = textNode.updateLayout(bounds.size)
textNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((bounds.width - textSize.width) / 2.0), y: floorToScreenPixels((bounds.height - textSize.height) / 2.0) - 18.0), size: textSize)
}
}
}