diff --git a/Display/AlertControllerNode.swift b/Display/AlertControllerNode.swift index 09a9774c29..eb9ebf16e5 100644 --- a/Display/AlertControllerNode.swift +++ b/Display/AlertControllerNode.swift @@ -3,9 +3,15 @@ import UIKit import AsyncDisplayKit final class AlertControllerNode: ASDisplayNode { - private let dimmingNode: ASDisplayNode + private let centerDimView: UIImageView + private let topDimView: UIView + private let bottomDimView: UIView + private let leftDimView: UIView + private let rightDimView: UIView + private let containerNode: ASDisplayNode private let effectNode: ASDisplayNode + private let backgroundNode: ASDisplayNode private let contentNode: AlertContentNode private let allowInputInset: Bool @@ -15,14 +21,35 @@ final class AlertControllerNode: ASDisplayNode { init(contentNode: AlertContentNode, theme: AlertControllerTheme, allowInputInset: Bool) { self.allowInputInset = allowInputInset - self.dimmingNode = ASDisplayNode() - self.dimmingNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5) + + let dimColor = UIColor(white: 0.0, alpha: 0.5) + + self.centerDimView = UIImageView() + self.centerDimView.image = generateStretchableFilledCircleImage(radius: 16.0, color: nil, backgroundColor: dimColor) + + self.topDimView = UIView() + self.topDimView.backgroundColor = dimColor + self.topDimView.isUserInteractionEnabled = false + + self.bottomDimView = UIView() + self.bottomDimView.backgroundColor = dimColor + self.bottomDimView.isUserInteractionEnabled = false + + self.leftDimView = UIView() + self.leftDimView.backgroundColor = dimColor + self.leftDimView.isUserInteractionEnabled = false + + self.rightDimView = UIView() + self.rightDimView.backgroundColor = dimColor + self.rightDimView.isUserInteractionEnabled = false self.containerNode = ASDisplayNode() - self.containerNode.backgroundColor = theme.backgroundColor self.containerNode.layer.cornerRadius = 14.0 self.containerNode.layer.masksToBounds = true + self.backgroundNode = ASDisplayNode() + self.backgroundNode.backgroundColor = theme.backgroundColor + self.effectNode = ASDisplayNode(viewBlock: { return UIVisualEffectView(effect: UIBlurEffect(style: theme.backgroundType == .light ? .light : .dark)) }) @@ -31,10 +58,14 @@ final class AlertControllerNode: ASDisplayNode { super.init() - self.addSubnode(self.dimmingNode) - - self.addSubnode(self.effectNode) + self.view.addSubview(self.centerDimView) + self.view.addSubview(self.topDimView) + self.view.addSubview(self.bottomDimView) + self.view.addSubview(self.leftDimView) + self.view.addSubview(self.rightDimView) + self.containerNode.addSubnode(self.effectNode) + self.containerNode.addSubnode(self.backgroundNode) self.containerNode.addSubnode(self.contentNode) self.addSubnode(self.containerNode) @@ -48,7 +79,8 @@ final class AlertControllerNode: ASDisplayNode { override func didLoad() { super.didLoad() - self.dimmingNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimmingNodeTapGesture(_:)))) + self.topDimView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimmingNodeTapGesture(_:)))) + self.bottomDimView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimmingNodeTapGesture(_:)))) } func updateTheme(_ theme: AlertControllerTheme) { @@ -60,13 +92,21 @@ final class AlertControllerNode: ASDisplayNode { } func animateIn() { - self.dimmingNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) + self.centerDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) + self.topDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) + self.bottomDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) + self.leftDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) + self.rightDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) self.containerNode.layer.animateSpring(from: 0.8 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, initialVelocity: 0.0, removeOnCompletion: true, additive: false, completion: nil) } func animateOut(completion: @escaping () -> Void) { - self.dimmingNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false) + self.centerDimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false) + self.topDimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false) + self.bottomDimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false) + self.leftDimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false) + self.rightDimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false) self.containerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false) self.containerNode.layer.animateScale(from: 1.0, to: 0.8, duration: 0.4, removeOnCompletion: false, completion: { _ in completion() @@ -76,8 +116,6 @@ final class AlertControllerNode: ASDisplayNode { func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { self.containerLayout = layout - transition.updateFrame(node: self.dimmingNode, frame: CGRect(origin: CGPoint(), size: layout.size)) - var insetOptions: ContainerViewLayoutInsetOptions = [.statusBar] if self.allowInputInset { insetOptions.insert(.input) @@ -91,8 +129,15 @@ final class AlertControllerNode: ASDisplayNode { let containerSize = CGSize(width: contentSize.width, height: contentSize.height) let containerFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - containerSize.width) / 2.0), y: contentAvailableFrame.minY + floor((contentAvailableFrame.size.height - containerSize.height) / 2.0)), size: containerSize) + transition.updateFrame(view: self.centerDimView, frame: containerFrame) + transition.updateFrame(view: self.topDimView, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: containerFrame.minY))) + transition.updateFrame(view: self.bottomDimView, frame: CGRect(origin: CGPoint(x: 0.0, y: containerFrame.maxY), size: CGSize(width: layout.size.width, height: layout.size.height - containerFrame.maxY))) + transition.updateFrame(view: self.leftDimView, frame: CGRect(origin: CGPoint(x: 0.0, y: containerFrame.minY), size: CGSize(width: containerFrame.minX, height: containerFrame.height))) + transition.updateFrame(view: self.rightDimView, frame: CGRect(origin: CGPoint(x: containerFrame.maxX, y: containerFrame.minY), size: CGSize(width: layout.size.width - containerFrame.maxX, height: containerFrame.height))) + transition.updateFrame(node: self.containerNode, frame: containerFrame) - transition.updateFrame(node: self.effectNode, frame: containerFrame) + transition.updateFrame(node: self.effectNode, frame: CGRect(origin: CGPoint(), size: containerFrame.size)) + transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: containerFrame.size)) transition.updateFrame(node: self.contentNode, frame: CGRect(origin: CGPoint(), size: containerFrame.size)) } diff --git a/Display/TextAlertController.swift b/Display/TextAlertController.swift index 59c6d4dac0..7b4d6cc62a 100644 --- a/Display/TextAlertController.swift +++ b/Display/TextAlertController.swift @@ -22,18 +22,20 @@ public struct TextAlertAction { } } -private final class TextAlertContentActionNode: HighlightableButtonNode { - private let backgroundNode: ASDisplayNode - +public final class TextAlertContentActionNode: HighlightableButtonNode { + private var theme: AlertControllerTheme let action: TextAlertAction - init(theme: AlertControllerTheme, action: TextAlertAction) { + private let backgroundNode: ASDisplayNode + + public init(theme: AlertControllerTheme, action: TextAlertAction) { + self.theme = theme + self.action = action + self.backgroundNode = ASDisplayNode() self.backgroundNode.isLayerBacked = true self.backgroundNode.alpha = 0.0 - self.action = action - super.init() self.titleNode.maximumNumberOfLines = 2 @@ -56,16 +58,27 @@ private final class TextAlertContentActionNode: HighlightableButtonNode { self.updateTheme(theme) } - func updateTheme(_ theme: AlertControllerTheme) { + public var actionEnabled: Bool = true { + didSet { + self.isUserInteractionEnabled = self.actionEnabled + self.updateTitle() + } + } + + public func updateTheme(_ theme: AlertControllerTheme) { + self.theme = theme self.backgroundNode.backgroundColor = theme.highlightedItemColor - + self.updateTitle() + } + + private func updateTitle() { var font = Font.regular(17.0) - var color = theme.accentColor + var color: UIColor switch self.action.type { case .defaultAction, .genericAction: - break + color = self.actionEnabled ? self.theme.accentColor : self.theme.disabledColor case .destructiveAction: - color = theme.destructiveColor + color = self.actionEnabled ? self.theme.destructiveColor : self.theme.disabledColor } switch self.action.type { case .defaultAction: @@ -76,7 +89,7 @@ private final class TextAlertContentActionNode: HighlightableButtonNode { self.setAttributedTitle(NSAttributedString(string: self.action.title, font: font, textColor: color, paragraphAlignment: .center), for: []) } - override func didLoad() { + override public func didLoad() { super.didLoad() self.addTarget(self, action: #selector(self.pressed), forControlEvents: .touchUpInside) @@ -86,7 +99,7 @@ private final class TextAlertContentActionNode: HighlightableButtonNode { self.action.action() } - override func layout() { + override public func layout() { super.layout() self.backgroundNode.frame = self.bounds @@ -203,16 +216,17 @@ public final class TextAlertContentNode: AlertContentNode { override public func updateTheme(_ theme: AlertControllerTheme) { self.theme = theme - let textFont: UIFont - if let titleNode = self.titleNode { - titleNode.attributedText = NSAttributedString(string: titleNode.attributedText?.string ?? "", font: Font.medium(17.0), textColor: theme.primaryColor, paragraphAlignment: .center) - textFont = Font.regular(13.0) - } else { - textFont = Font.semibold(17.0) + if let titleNode = self.titleNode, let attributedText = titleNode.attributedText { + let updatedText = NSMutableAttributedString(attributedString: attributedText) + updatedText.addAttribute(NSAttributedStringKey.foregroundColor, value: theme.primaryColor, range: NSRange(location: 0, length: updatedText.length)) + titleNode.attributedText = updatedText } - - self.textNode.attributedText = NSAttributedString(string: self.textNode.attributedText?.string ?? "", font: textFont, textColor: theme.primaryColor, paragraphAlignment: .center) - + if let attributedText = self.textNode.attributedText { + let updatedText = NSMutableAttributedString(attributedString: attributedText) + updatedText.addAttribute(NSAttributedStringKey.foregroundColor, value: theme.primaryColor, range: NSRange(location: 0, length: updatedText.length)) + self.textNode.attributedText = updatedText + } + self.actionNodesSeparator.backgroundColor = theme.separatorColor for actionNode in self.actionNodes { actionNode.updateTheme(theme)