mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 14:20:20 +00:00
no message
This commit is contained in:
241
TelegramUI/InstantPageSettingsNode.swift
Normal file
241
TelegramUI/InstantPageSettingsNode.swift
Normal file
@@ -0,0 +1,241 @@
|
||||
import Foundation
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
|
||||
private func generateArrowImage(color: UIColor) -> UIImage? {
|
||||
let smallRadius: CGFloat = 5.0
|
||||
let largeRadius: CGFloat = 14.0
|
||||
return generateImage(CGSize(width: smallRadius + largeRadius, height: smallRadius + largeRadius + 16.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
if let image = generateTintedImage(image: UIImage(bundleImageName: "Instant View/SettingsArrow"), color: color), let cgImage = image.cgImage {
|
||||
context.setFillColor(color.cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(x: 0.0, y: size.height - image.size.height - 16.0), size: CGSize(width: size.width, height: 16.0)))
|
||||
context.draw(cgImage, in: CGRect(origin: CGPoint(x: size.width - image.size.width, y: size.height - image.size.height), size: image.size))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
final class InstantPageSettingsNode: ASDisplayNode {
|
||||
private var settings: InstantPagePresentationSettings
|
||||
private var theme: InstantPageSettingsItemTheme
|
||||
|
||||
private let applySettings: (InstantPagePresentationSettings) -> Void
|
||||
|
||||
private var sections: [[InstantPageSettingsItemNode]] = []
|
||||
private let sansFamilyNode: InstantPageSettingsFontFamilyNode
|
||||
private let serifFamilyNode: InstantPageSettingsFontFamilyNode
|
||||
private let themeItemNode: InstantPageSettingsThemeItemNode
|
||||
private let autoNightItemNode: InstantPageSettingsSwitchNode
|
||||
|
||||
private let arrowNode: ASImageNode
|
||||
private let itemContainerNode: ASDisplayNode
|
||||
|
||||
init(strings: PresentationStrings, settings: InstantPagePresentationSettings, applySettings: @escaping (InstantPagePresentationSettings) -> Void) {
|
||||
self.settings = settings
|
||||
self.theme = InstantPageSettingsItemTheme.themeFor(settings)
|
||||
|
||||
self.applySettings = applySettings
|
||||
|
||||
self.arrowNode = ASImageNode()
|
||||
self.arrowNode.displayWithoutProcessing = true
|
||||
self.arrowNode.displaysAsynchronously = false
|
||||
self.arrowNode.image = generateArrowImage(color: self.theme.itemBackgroundColor)
|
||||
|
||||
self.itemContainerNode = ASDisplayNode()
|
||||
self.itemContainerNode.layer.masksToBounds = true
|
||||
self.itemContainerNode.layer.cornerRadius = 16.0
|
||||
self.itemContainerNode.backgroundColor = self.theme.listBackgroundColor
|
||||
|
||||
var updateSerifImpl: ((Bool) -> Void)?
|
||||
var updateThemeTypeImpl: ((InstantPageThemeType) -> Void)?
|
||||
var updateAutoNightImpl: ((Bool) -> Void)?
|
||||
|
||||
self.sansFamilyNode = InstantPageSettingsFontFamilyNode(theme: self.theme, title: "San Francisco", family: nil, checked: !settings.forceSerif, tapped: {
|
||||
updateSerifImpl?(false)
|
||||
})
|
||||
self.serifFamilyNode = InstantPageSettingsFontFamilyNode(theme: self.theme, title: "Georgia", family: "Georgia", checked: settings.forceSerif, tapped: {
|
||||
updateSerifImpl?(true)
|
||||
})
|
||||
self.themeItemNode = InstantPageSettingsThemeItemNode(theme: theme, themeType: settings.themeType, update: { value in
|
||||
updateThemeTypeImpl?(value)
|
||||
})
|
||||
self.autoNightItemNode = InstantPageSettingsSwitchNode(theme: theme, title: strings.InstantPage_AutoNightTheme, isOn: settings.autoNightMode, isEnabled: settings.themeType != .dark, toggled: { value in
|
||||
updateAutoNightImpl?(value)
|
||||
})
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.arrowNode)
|
||||
self.addSubnode(self.itemContainerNode)
|
||||
|
||||
self.sections = [
|
||||
[
|
||||
InstantPageSettingsBacklightItemNode(theme: self.theme)
|
||||
],
|
||||
[
|
||||
InstantPageSettingsFontSizeItemNode(theme: self.theme, fontSizeVariant: Int(settings.fontSize.rawValue), updated: { [weak self] value in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateSettings {
|
||||
let size: InstantPagePresentationFontSize = InstantPagePresentationFontSize(rawValue: Int32(value)) ?? .standard
|
||||
return $0.withUpdatedFontSize(size)
|
||||
}
|
||||
}
|
||||
}),
|
||||
self.sansFamilyNode,
|
||||
self.serifFamilyNode
|
||||
],
|
||||
[
|
||||
self.themeItemNode,
|
||||
self.autoNightItemNode
|
||||
]
|
||||
]
|
||||
|
||||
for section in self.sections {
|
||||
for item in section {
|
||||
self.itemContainerNode.addSubnode(item)
|
||||
}
|
||||
}
|
||||
|
||||
updateSerifImpl = { [weak self] value in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateSettings {
|
||||
return $0.withUpdatedForceSerif(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateThemeTypeImpl = { [weak self] value in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateSettings {
|
||||
return $0.withUpdatedThemeType(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateAutoNightImpl = { [weak self] value in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateSettings {
|
||||
return $0.withUpdatedAutoNightMode(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
let fixedWidth: CGFloat = 295.0
|
||||
let sectionSpacing: CGFloat = 4.0
|
||||
let sideInset: CGFloat = 11.0
|
||||
let topInset: CGFloat = layout.insets(options: [.statusBar]).top + 44.0 + 6.0
|
||||
|
||||
var contentHeight: CGFloat = 0.0
|
||||
var itemSizes: [[CGFloat]] = []
|
||||
for sectionIndex in 0 ..< self.sections.count {
|
||||
itemSizes.append([])
|
||||
if sectionIndex != 0 {
|
||||
contentHeight += sectionSpacing
|
||||
}
|
||||
for itemIndex in 0 ..< self.sections[sectionIndex].count {
|
||||
let previousItem: InstantPageSettingsItemNodeStatus
|
||||
var previousItemNode: InstantPageSettingsItemNode?
|
||||
let nextItem: InstantPageSettingsItemNodeStatus
|
||||
var nextItemNode: InstantPageSettingsItemNode?
|
||||
if itemIndex == 0 {
|
||||
if sectionIndex == 0 {
|
||||
previousItem = .none
|
||||
} else {
|
||||
previousItem = .otherSection
|
||||
}
|
||||
} else {
|
||||
previousItem = .sameSection
|
||||
previousItemNode = self.sections[sectionIndex][itemIndex - 1]
|
||||
}
|
||||
if itemIndex == self.sections[sectionIndex].count - 1 {
|
||||
if sectionIndex == self.sections.count - 1 {
|
||||
nextItem = .none
|
||||
} else {
|
||||
nextItem = .otherSection
|
||||
}
|
||||
} else {
|
||||
nextItem = .sameSection
|
||||
nextItemNode = self.sections[sectionIndex][itemIndex + 1]
|
||||
}
|
||||
let itemHeight = self.sections[sectionIndex][itemIndex].updateLayout(width: fixedWidth, previousItem: (previousItem, previousItemNode), nextItem: (nextItem, nextItemNode))
|
||||
itemSizes[sectionIndex].append(itemHeight)
|
||||
contentHeight += itemHeight
|
||||
}
|
||||
}
|
||||
|
||||
if let image = self.arrowNode.image {
|
||||
transition.updateFrame(node: self.arrowNode, frame: CGRect(origin: CGPoint(x: layout.size.width - sideInset - image.size.width, y: topInset - image.size.height + 16.0 + 8.0), size: image.size))
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.itemContainerNode, frame: CGRect(origin: CGPoint(x: layout.size.width - sideInset - fixedWidth, y: topInset), size: CGSize(width: fixedWidth, height: contentHeight)))
|
||||
var nextItemOffset: CGFloat = 0.0
|
||||
for sectionIndex in 0 ..< self.sections.count {
|
||||
if sectionIndex != 0 {
|
||||
nextItemOffset += sectionSpacing
|
||||
}
|
||||
for itemIndex in 0 ..< self.sections[sectionIndex].count {
|
||||
let itemHeight = itemSizes[sectionIndex][itemIndex]
|
||||
transition.updateFrame(node: self.sections[sectionIndex][itemIndex], frame: CGRect(origin: CGPoint(x: 0.0, y: nextItemOffset), size: CGSize(width: fixedWidth, height: itemHeight)))
|
||||
nextItemOffset += itemHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
}
|
||||
|
||||
func animateOut(completion: @escaping () -> Void) {
|
||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
}
|
||||
|
||||
private func updateSettings(_ f: (InstantPagePresentationSettings) -> InstantPagePresentationSettings) {
|
||||
let updated = f(self.settings)
|
||||
if updated != self.settings {
|
||||
self.settings = updated
|
||||
|
||||
self.sansFamilyNode.checked = !self.settings.forceSerif
|
||||
self.serifFamilyNode.checked = self.settings.forceSerif
|
||||
self.themeItemNode.themeType = self.settings.themeType
|
||||
self.autoNightItemNode.isEnabled = self.settings.themeType != .dark
|
||||
|
||||
let theme = InstantPageSettingsItemTheme.themeFor(self.settings)
|
||||
if theme != self.theme {
|
||||
self.theme = theme
|
||||
|
||||
if let snapshotView = self.view.snapshotView(afterScreenUpdates: false) {
|
||||
self.view.addSubview(snapshotView)
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
|
||||
self.arrowNode.image = generateArrowImage(color: self.theme.itemBackgroundColor)
|
||||
self.itemContainerNode.backgroundColor = self.theme.listBackgroundColor
|
||||
for section in self.sections {
|
||||
for item in section {
|
||||
item.updateTheme(self.theme)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
self.applySettings(settings)
|
||||
}
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if self.itemContainerNode.frame.contains(point) {
|
||||
return super.hitTest(point, with: event)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user