mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
230 lines
9.0 KiB
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)
|
|
}
|
|
}
|
|
}
|