mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 09:20:08 +00:00
Improve theme crossfade animation in apperance section
This commit is contained in:
parent
62ae89d18b
commit
9cc5ede440
@ -1193,8 +1193,13 @@ public class Window1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func forEachViewController(_ f: (ContainableController) -> Bool) {
|
public func forEachViewController(_ f: (ContainableController) -> Bool) {
|
||||||
if let navigationController = self._rootController as? NavigationController, let controller = navigationController.topOverlayController {
|
if let navigationController = self._rootController as? NavigationController {
|
||||||
!f(controller)
|
for case let controller as ContainableController in navigationController.viewControllers {
|
||||||
|
!f(controller)
|
||||||
|
}
|
||||||
|
if let controller = navigationController.topOverlayController {
|
||||||
|
!f(controller)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (controller, _) in self.presentationContext.controllers {
|
for (controller, _) in self.presentationContext.controllers {
|
||||||
if !f(controller) {
|
if !f(controller) {
|
||||||
|
|||||||
@ -230,10 +230,12 @@ private let textFont = Font.regular(11.0)
|
|||||||
private let itemSize = Font.regular(11.0)
|
private let itemSize = Font.regular(11.0)
|
||||||
|
|
||||||
class ThemeSettingsAccentColorItemNode: ListViewItemNode, ItemListItemNode {
|
class ThemeSettingsAccentColorItemNode: ListViewItemNode, ItemListItemNode {
|
||||||
|
private let containerNode: ASDisplayNode
|
||||||
private let backgroundNode: ASDisplayNode
|
private let backgroundNode: ASDisplayNode
|
||||||
private let topStripeNode: ASDisplayNode
|
private let topStripeNode: ASDisplayNode
|
||||||
private let bottomStripeNode: ASDisplayNode
|
private let bottomStripeNode: ASDisplayNode
|
||||||
private let maskNode: ASImageNode
|
private let maskNode: ASImageNode
|
||||||
|
private var snapshotView: UIView?
|
||||||
|
|
||||||
private let scrollNode: ASScrollNode
|
private let scrollNode: ASScrollNode
|
||||||
private var colorNodes: [ThemeSettingsAccentColorNode] = []
|
private var colorNodes: [ThemeSettingsAccentColorNode] = []
|
||||||
@ -247,6 +249,8 @@ class ThemeSettingsAccentColorItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
self.containerNode = ASDisplayNode()
|
||||||
|
|
||||||
self.backgroundNode = ASDisplayNode()
|
self.backgroundNode = ASDisplayNode()
|
||||||
self.backgroundNode.isLayerBacked = true
|
self.backgroundNode.isLayerBacked = true
|
||||||
|
|
||||||
@ -264,6 +268,8 @@ class ThemeSettingsAccentColorItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
|
|
||||||
super.init(layerBacked: false, dynamicBounce: false)
|
super.init(layerBacked: false, dynamicBounce: false)
|
||||||
|
|
||||||
|
self.addSubnode(self.containerNode)
|
||||||
|
|
||||||
self.customNode.setImage(generateCustomSwatchImage(), for: .normal)
|
self.customNode.setImage(generateCustomSwatchImage(), for: .normal)
|
||||||
self.customNode.addTarget(self, action: #selector(customPressed), forControlEvents: .touchUpInside)
|
self.customNode.addTarget(self, action: #selector(customPressed), forControlEvents: .touchUpInside)
|
||||||
|
|
||||||
@ -320,16 +326,16 @@ class ThemeSettingsAccentColorItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
|
strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
|
||||||
|
|
||||||
if strongSelf.backgroundNode.supernode == nil {
|
if strongSelf.backgroundNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0)
|
strongSelf.containerNode.insertSubnode(strongSelf.backgroundNode, at: 0)
|
||||||
}
|
}
|
||||||
if strongSelf.topStripeNode.supernode == nil {
|
if strongSelf.topStripeNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1)
|
strongSelf.containerNode.insertSubnode(strongSelf.topStripeNode, at: 1)
|
||||||
}
|
}
|
||||||
if strongSelf.bottomStripeNode.supernode == nil {
|
if strongSelf.bottomStripeNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
strongSelf.containerNode.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
||||||
}
|
}
|
||||||
if strongSelf.maskNode.supernode == nil {
|
if strongSelf.maskNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.maskNode, at: 3)
|
strongSelf.containerNode.insertSubnode(strongSelf.maskNode, at: 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
let hasCorners = itemListHasRoundedBlockLayout(params)
|
let hasCorners = itemListHasRoundedBlockLayout(params)
|
||||||
@ -355,6 +361,7 @@ class ThemeSettingsAccentColorItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
strongSelf.bottomStripeNode.isHidden = hasCorners
|
strongSelf.bottomStripeNode.isHidden = hasCorners
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strongSelf.containerNode.frame = CGRect(x: 0.0, y: 0.0, width: contentSize.width, height: contentSize.height)
|
||||||
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
||||||
|
|
||||||
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||||
@ -451,5 +458,19 @@ class ThemeSettingsAccentColorItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func prepareCrossfadeTransition() {
|
||||||
|
self.snapshotView?.removeFromSuperview()
|
||||||
|
|
||||||
|
if let snapshotView = self.containerNode.view.snapshotView(afterScreenUpdates: false) {
|
||||||
|
self.view.insertSubview(snapshotView, aboveSubview: self.containerNode.view)
|
||||||
|
self.snapshotView = snapshotView
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func animateCrossfadeTransition() {
|
||||||
|
self.snapshotView?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak self] _ in
|
||||||
|
self?.snapshotView?.removeFromSuperview()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -361,7 +361,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
|||||||
}
|
}
|
||||||
}, contextAction: { theme, node, gesture in
|
}, contextAction: { theme, node, gesture in
|
||||||
arguments.themeContextAction(theme.index == currentTheme.index, theme, node, gesture)
|
arguments.themeContextAction(theme.index == currentTheme.index, theme, node, gesture)
|
||||||
})
|
}, tag: ThemeSettingsEntryTag.theme)
|
||||||
case let .iconHeader(theme, text):
|
case let .iconHeader(theme, text):
|
||||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||||
case let .iconItem(theme, strings, icons, value):
|
case let .iconItem(theme, strings, icons, value):
|
||||||
@ -437,12 +437,20 @@ private func themeSettingsControllerEntries(presentationData: PresentationData,
|
|||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public protocol ThemeSettingsController {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class ThemeSettingsControllerImpl: ItemListController, ThemeSettingsController {
|
||||||
|
}
|
||||||
|
|
||||||
public func themeSettingsController(context: AccountContext, focusOnItemTag: ThemeSettingsEntryTag? = nil) -> ViewController {
|
public func themeSettingsController(context: AccountContext, focusOnItemTag: ThemeSettingsEntryTag? = nil) -> ViewController {
|
||||||
var pushControllerImpl: ((ViewController) -> Void)?
|
var pushControllerImpl: ((ViewController) -> Void)?
|
||||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||||
var updateControllersImpl: ((([UIViewController]) -> [UIViewController]) -> Void)?
|
var updateControllersImpl: ((([UIViewController]) -> [UIViewController]) -> Void)?
|
||||||
var presentInGlobalOverlayImpl: ((ViewController, Any?) -> Void)?
|
var presentInGlobalOverlayImpl: ((ViewController, Any?) -> Void)?
|
||||||
var getNavigationControllerImpl: (() -> NavigationController?)?
|
var getNavigationControllerImpl: (() -> NavigationController?)?
|
||||||
|
var presentCrossfadeControllerImpl: (() -> Void)?
|
||||||
|
|
||||||
var selectThemeImpl: ((PresentationThemeReference) -> Void)?
|
var selectThemeImpl: ((PresentationThemeReference) -> Void)?
|
||||||
var moreImpl: (() -> Void)?
|
var moreImpl: (() -> Void)?
|
||||||
@ -673,6 +681,9 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||||||
presentInGlobalOverlayImpl?(contextController, nil)
|
presentInGlobalOverlayImpl?(contextController, nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let previousThemeReference = Atomic<PresentationThemeReference?>(value: nil)
|
||||||
|
let previousAccentColor = Atomic<PresentationThemeAccentColor?>(value: nil)
|
||||||
|
|
||||||
let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings]), cloudThemes.get(), availableAppIcons, currentAppIconName.get())
|
let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings]), cloudThemes.get(), availableAppIcons, currentAppIconName.get())
|
||||||
|> map { presentationData, sharedData, cloudThemes, availableAppIcons, currentAppIconName -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
|> map { presentationData, sharedData, cloudThemes, availableAppIcons, currentAppIconName -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||||
let settings = (sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings
|
let settings = (sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings
|
||||||
@ -690,7 +701,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||||||
}
|
}
|
||||||
|
|
||||||
let theme = presentationData.theme
|
let theme = presentationData.theme
|
||||||
let accentColor = settings.themeSpecificAccentColors[themeReference.index]?.color
|
let accentColor = settings.themeSpecificAccentColors[themeReference.index]
|
||||||
let wallpaper = presentationData.chatWallpaper
|
let wallpaper = presentationData.chatWallpaper
|
||||||
|
|
||||||
let rightNavigationButton = ItemListNavigationButton(content: .icon(.add), style: .regular, enabled: true, action: {
|
let rightNavigationButton = ItemListNavigationButton(content: .icon(.add), style: .regular, enabled: true, action: {
|
||||||
@ -714,11 +725,17 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||||||
|
|
||||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.Appearance_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.Appearance_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
||||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: themeSettingsControllerEntries(presentationData: presentationData, presentationThemeSettings: settings, theme: theme, themeReference: themeReference, themeSpecificAccentColors: settings.themeSpecificAccentColors, availableThemes: availableThemes, autoNightSettings: settings.automaticThemeSwitchSetting, strings: presentationData.strings, wallpaper: wallpaper, fontSize: fontSize, dateTimeFormat: dateTimeFormat, largeEmoji: largeEmoji, disableAnimations: disableAnimations, availableAppIcons: availableAppIcons, currentAppIconName: currentAppIconName), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false)
|
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: themeSettingsControllerEntries(presentationData: presentationData, presentationThemeSettings: settings, theme: theme, themeReference: themeReference, themeSpecificAccentColors: settings.themeSpecificAccentColors, availableThemes: availableThemes, autoNightSettings: settings.automaticThemeSwitchSetting, strings: presentationData.strings, wallpaper: wallpaper, fontSize: fontSize, dateTimeFormat: dateTimeFormat, largeEmoji: largeEmoji, disableAnimations: disableAnimations, availableAppIcons: availableAppIcons, currentAppIconName: currentAppIconName), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false)
|
||||||
|
|
||||||
|
let previousThemeIndex = previousThemeReference.swap(themeReference)?.index
|
||||||
|
let previousAccentColor = previousAccentColor.swap(accentColor)
|
||||||
|
if previousThemeIndex != nil && (previousThemeIndex != themeReference.index || previousAccentColor != accentColor) {
|
||||||
|
presentCrossfadeControllerImpl?()
|
||||||
|
}
|
||||||
|
|
||||||
return (controllerState, (listState, arguments))
|
return (controllerState, (listState, arguments))
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = ItemListController(context: context, state: signal)
|
let controller = ThemeSettingsControllerImpl(context: context, state: signal)
|
||||||
controller.alwaysSynchronous = true
|
controller.alwaysSynchronous = true
|
||||||
pushControllerImpl = { [weak controller] c in
|
pushControllerImpl = { [weak controller] c in
|
||||||
(controller?.navigationController as? NavigationController)?.pushViewController(c)
|
(controller?.navigationController as? NavigationController)?.pushViewController(c)
|
||||||
@ -737,6 +754,54 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||||||
getNavigationControllerImpl = { [weak controller] in
|
getNavigationControllerImpl = { [weak controller] in
|
||||||
return controller?.navigationController as? NavigationController
|
return controller?.navigationController as? NavigationController
|
||||||
}
|
}
|
||||||
|
presentCrossfadeControllerImpl = { [weak controller] in
|
||||||
|
if let controller = controller, controller.isNodeLoaded {
|
||||||
|
var topOffset: CGFloat?
|
||||||
|
var bottomOffset: CGFloat?
|
||||||
|
var themeItemNode: ThemeSettingsThemeItemNode?
|
||||||
|
var colorItemNode: ThemeSettingsAccentColorItemNode?
|
||||||
|
|
||||||
|
controller.forEachItemNode { node in
|
||||||
|
if let itemNode = node as? ItemListItemNode {
|
||||||
|
if let itemTag = itemNode.tag {
|
||||||
|
if itemTag.isEqual(to: ThemeSettingsEntryTag.theme) {
|
||||||
|
let frame = node.convert(node.bounds, to: controller.displayNode)
|
||||||
|
topOffset = frame.minY
|
||||||
|
bottomOffset = frame.maxY
|
||||||
|
if let itemNode = node as? ThemeSettingsThemeItemNode {
|
||||||
|
themeItemNode = itemNode
|
||||||
|
}
|
||||||
|
} else if itemTag.isEqual(to: ThemeSettingsEntryTag.accentColor) {
|
||||||
|
let frame = node.convert(node.bounds, to: controller.displayNode)
|
||||||
|
bottomOffset = frame.maxY
|
||||||
|
if let itemNode = node as? ThemeSettingsAccentColorItemNode {
|
||||||
|
colorItemNode = itemNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let navigationBar = controller.navigationBar {
|
||||||
|
if let offset = topOffset {
|
||||||
|
topOffset = max(offset, navigationBar.frame.maxY)
|
||||||
|
} else {
|
||||||
|
topOffset = navigationBar.frame.maxY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
themeItemNode?.prepareCrossfadeTransition()
|
||||||
|
colorItemNode?.prepareCrossfadeTransition()
|
||||||
|
|
||||||
|
let crossfadeController = ThemeSettingsCrossfadeController(view: controller.view, topOffset: topOffset, bottomOffset: bottomOffset)
|
||||||
|
crossfadeController.didAppear = { [weak themeItemNode, weak colorItemNode] in
|
||||||
|
themeItemNode?.animateCrossfadeTransition()
|
||||||
|
colorItemNode?.animateCrossfadeTransition()
|
||||||
|
}
|
||||||
|
|
||||||
|
context.sharedContext.presentGlobalController(crossfadeController, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
selectThemeImpl = { theme in
|
selectThemeImpl = { theme in
|
||||||
guard let presentationTheme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: theme) else {
|
guard let presentationTheme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: theme) else {
|
||||||
return
|
return
|
||||||
@ -846,11 +911,37 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class ThemeSettingsCrossfadeController: ViewController {
|
public final class ThemeSettingsCrossfadeController: ViewController {
|
||||||
private let snapshotView: UIView?
|
private var snapshotView: UIView?
|
||||||
|
|
||||||
public init(view: UIView? = nil) {
|
private var topSnapshotView: UIView?
|
||||||
|
private var bottomSnapshotView: UIView?
|
||||||
|
|
||||||
|
fileprivate var didAppear: (() -> Void)?
|
||||||
|
|
||||||
|
public init(view: UIView? = nil, topOffset: CGFloat? = nil, bottomOffset: CGFloat? = nil) {
|
||||||
if let view = view {
|
if let view = view {
|
||||||
self.snapshotView = view.snapshotContentTree()
|
if let view = view.snapshotView(afterScreenUpdates: false) {
|
||||||
|
view.clipsToBounds = true
|
||||||
|
view.contentMode = .top
|
||||||
|
if let topOffset = topOffset {
|
||||||
|
var frame = view.frame
|
||||||
|
frame.size.height = topOffset
|
||||||
|
view.frame = frame
|
||||||
|
}
|
||||||
|
self.topSnapshotView = view
|
||||||
|
}
|
||||||
|
|
||||||
|
if let view = view.snapshotView(afterScreenUpdates: false) {
|
||||||
|
view.clipsToBounds = true
|
||||||
|
view.contentMode = .bottom
|
||||||
|
if let bottomOffset = bottomOffset {
|
||||||
|
var frame = view.frame
|
||||||
|
frame.origin.y = bottomOffset
|
||||||
|
frame.size.height -= bottomOffset
|
||||||
|
view.frame = frame
|
||||||
|
}
|
||||||
|
self.bottomSnapshotView = view
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.snapshotView = UIScreen.main.snapshotView(afterScreenUpdates: false)
|
self.snapshotView = UIScreen.main.snapshotView(afterScreenUpdates: false)
|
||||||
}
|
}
|
||||||
@ -872,6 +963,12 @@ public final class ThemeSettingsCrossfadeController: ViewController {
|
|||||||
if let snapshotView = self.snapshotView {
|
if let snapshotView = self.snapshotView {
|
||||||
self.displayNode.view.addSubview(snapshotView)
|
self.displayNode.view.addSubview(snapshotView)
|
||||||
}
|
}
|
||||||
|
if let topSnapshotView = self.topSnapshotView {
|
||||||
|
self.displayNode.view.addSubview(topSnapshotView)
|
||||||
|
}
|
||||||
|
if let bottomSnapshotView = self.bottomSnapshotView {
|
||||||
|
self.displayNode.view.addSubview(bottomSnapshotView)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func viewDidAppear(_ animated: Bool) {
|
override public func viewDidAppear(_ animated: Bool) {
|
||||||
@ -880,5 +977,7 @@ public final class ThemeSettingsCrossfadeController: ViewController {
|
|||||||
self.displayNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak self] _ in
|
self.displayNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak self] _ in
|
||||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
self.didAppear?()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -182,7 +182,7 @@ private func createThemeImage(theme: PresentationTheme) -> Signal<(TransformImag
|
|||||||
c.draw(icon.cgImage!, in: CGRect(origin: CGPoint(x: floor((drawingRect.width - icon.size.width) / 2.0) - 3.0, y: floor((drawingRect.height - icon.size.height) / 2.0)), size: icon.size))
|
c.draw(icon.cgImage!, in: CGRect(origin: CGPoint(x: floor((drawingRect.width - icon.size.width) / 2.0) - 3.0, y: floor((drawingRect.height - icon.size.height) / 2.0)), size: icon.size))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
addCorners(context, arguments: arguments)
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -412,11 +412,13 @@ private func ensureThemeVisible(listNode: ListView, themeReference: Presentation
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode {
|
class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode {
|
||||||
|
private let containerNode: ASDisplayNode
|
||||||
private let backgroundNode: ASDisplayNode
|
private let backgroundNode: ASDisplayNode
|
||||||
private let topStripeNode: ASDisplayNode
|
private let topStripeNode: ASDisplayNode
|
||||||
private let bottomStripeNode: ASDisplayNode
|
private let bottomStripeNode: ASDisplayNode
|
||||||
private let maskNode: ASImageNode
|
private let maskNode: ASImageNode
|
||||||
|
private var snapshotView: UIView?
|
||||||
|
|
||||||
private let listNode: ListView
|
private let listNode: ListView
|
||||||
private var entries: [ThemeSettingsThemeEntry]?
|
private var entries: [ThemeSettingsThemeEntry]?
|
||||||
private var enqueuedTransitions: [ThemeSettingsThemeItemNodeTransition] = []
|
private var enqueuedTransitions: [ThemeSettingsThemeItemNodeTransition] = []
|
||||||
@ -430,6 +432,8 @@ class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
self.containerNode = ASDisplayNode()
|
||||||
|
|
||||||
self.backgroundNode = ASDisplayNode()
|
self.backgroundNode = ASDisplayNode()
|
||||||
self.backgroundNode.isLayerBacked = true
|
self.backgroundNode.isLayerBacked = true
|
||||||
|
|
||||||
@ -446,6 +450,7 @@ class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
|
|
||||||
super.init(layerBacked: false, dynamicBounce: false)
|
super.init(layerBacked: false, dynamicBounce: false)
|
||||||
|
|
||||||
|
self.addSubnode(self.containerNode)
|
||||||
self.addSubnode(self.listNode)
|
self.addSubnode(self.listNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,16 +517,16 @@ class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
|
strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
|
||||||
|
|
||||||
if strongSelf.backgroundNode.supernode == nil {
|
if strongSelf.backgroundNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0)
|
strongSelf.containerNode.insertSubnode(strongSelf.backgroundNode, at: 0)
|
||||||
}
|
}
|
||||||
if strongSelf.topStripeNode.supernode == nil {
|
if strongSelf.topStripeNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1)
|
strongSelf.containerNode.insertSubnode(strongSelf.topStripeNode, at: 1)
|
||||||
}
|
}
|
||||||
if strongSelf.bottomStripeNode.supernode == nil {
|
if strongSelf.bottomStripeNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
strongSelf.containerNode.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
||||||
}
|
}
|
||||||
if strongSelf.maskNode.supernode == nil {
|
if strongSelf.maskNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.maskNode, at: 3)
|
strongSelf.containerNode.insertSubnode(strongSelf.maskNode, at: 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
let hasCorners = itemListHasRoundedBlockLayout(params)
|
let hasCorners = itemListHasRoundedBlockLayout(params)
|
||||||
@ -547,6 +552,7 @@ class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
strongSelf.bottomStripeNode.isHidden = hasCorners
|
strongSelf.bottomStripeNode.isHidden = hasCorners
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strongSelf.containerNode.frame = CGRect(x: 0.0, y: 0.0, width: contentSize.width, height: contentSize.height)
|
||||||
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
||||||
|
|
||||||
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||||
@ -559,7 +565,7 @@ class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
listInsets.bottom += params.rightInset + 4.0
|
listInsets.bottom += params.rightInset + 4.0
|
||||||
|
|
||||||
strongSelf.listNode.bounds = CGRect(x: 0.0, y: 0.0, width: contentSize.height, height: contentSize.width)
|
strongSelf.listNode.bounds = CGRect(x: 0.0, y: 0.0, width: contentSize.height, height: contentSize.width)
|
||||||
strongSelf.listNode.position = CGPoint(x: contentSize.width / 2.0, y: contentSize.height / 2.0)
|
strongSelf.listNode.position = CGPoint(x: contentSize.width / 2.0, y: contentSize.height / 2.0 + 2.0)
|
||||||
strongSelf.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: CGSize(width: contentSize.height, height: contentSize.width), insets: listInsets, duration: 0.0, curve: .Default(duration: nil)), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
strongSelf.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: CGSize(width: contentSize.height, height: contentSize.width), insets: listInsets, duration: 0.0, curve: .Default(duration: nil)), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||||
|
|
||||||
var entries: [ThemeSettingsThemeEntry] = []
|
var entries: [ThemeSettingsThemeEntry] = []
|
||||||
@ -588,7 +594,7 @@ class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||||
}
|
}
|
||||||
@ -596,4 +602,19 @@ class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func prepareCrossfadeTransition() {
|
||||||
|
self.snapshotView?.removeFromSuperview()
|
||||||
|
|
||||||
|
if let snapshotView = self.containerNode.view.snapshotView(afterScreenUpdates: false) {
|
||||||
|
self.view.insertSubview(snapshotView, aboveSubview: self.containerNode.view)
|
||||||
|
self.snapshotView = snapshotView
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func animateCrossfadeTransition() {
|
||||||
|
self.snapshotView?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak self] _ in
|
||||||
|
self?.snapshotView?.removeFromSuperview()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -86,10 +86,16 @@ extension TelegramWallpaper: Codable {
|
|||||||
bottomColor = Int32(bitPattern: value.rgb)
|
bottomColor = Int32(bitPattern: value.rgb)
|
||||||
}
|
}
|
||||||
} else if component.count <= 3, let value = Int32(component) {
|
} else if component.count <= 3, let value = Int32(component) {
|
||||||
if value >= 0 && value <= 100 {
|
if intensity == nil {
|
||||||
intensity = value
|
if value >= 0 && value <= 100 {
|
||||||
} else {
|
intensity = value
|
||||||
intensity = 50
|
} else {
|
||||||
|
intensity = 50
|
||||||
|
}
|
||||||
|
} else if rotation == nil {
|
||||||
|
if value >= 0 && value < 360 {
|
||||||
|
rotation = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,7 +147,7 @@ extension TelegramWallpaper: Codable {
|
|||||||
if let bottomColor = file.settings.bottomColor {
|
if let bottomColor = file.settings.bottomColor {
|
||||||
components.append(String(format: "%06x", bottomColor))
|
components.append(String(format: "%06x", bottomColor))
|
||||||
}
|
}
|
||||||
if let rotation = file.settings.rotation {
|
if let rotation = file.settings.rotation, rotation != 0 {
|
||||||
components.append("\(rotation)")
|
components.append("\(rotation)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -804,7 +804,7 @@ final class SharedApplicationContext {
|
|||||||
}
|
}
|
||||||
var exists = false
|
var exists = false
|
||||||
strongSelf.mainWindow.forEachViewController { controller in
|
strongSelf.mainWindow.forEachViewController { controller in
|
||||||
if controller is ThemeSettingsCrossfadeController {
|
if controller is ThemeSettingsCrossfadeController || controller is ThemeSettingsController {
|
||||||
exists = true
|
exists = true
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|||||||
@ -500,9 +500,7 @@ public func patternWallpaperImageInternal(thumbnailData: Data?, fullSizeData: Da
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addCorners(context, arguments: arguments)
|
addCorners(context, arguments: arguments)
|
||||||
|
|
||||||
return context
|
return context
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user