Various improvements
This commit is contained in:
parent
a14a8ecf00
commit
6558d2e265
26 changed files with 332 additions and 322 deletions
3
.bazelrc
3
.bazelrc
|
|
@ -19,8 +19,7 @@ build --features=swift.enable_vfsoverlays
|
|||
build --strategy=Genrule=standalone
|
||||
build --spawn_strategy=standalone
|
||||
|
||||
build --strategy=SwiftCompile=standalone
|
||||
build --define RULES_SWIFT_BUILD_DUMMY_WORKER=1
|
||||
build --strategy=SwiftCompile=worker
|
||||
|
||||
build:swift_profile --jobs=1
|
||||
build:swift_profile --local_cpu_resources=1
|
||||
|
|
|
|||
|
|
@ -82,13 +82,6 @@ class BazelCommandLine:
|
|||
]
|
||||
|
||||
self.common_debug_args = [
|
||||
# https://github.com/bazelbuild/rules_swift
|
||||
# If enabled, Swift compilation actions will use batch mode by passing
|
||||
# `-enable-batch-mode` to `swiftc`. This is a new compilation mode as of
|
||||
# Swift 4.2 that is intended to speed up non-incremental non-WMO builds by
|
||||
# invoking a smaller number of frontend processes and passing them batches of
|
||||
# source files.
|
||||
'--features=swift.enable_batch_mode',
|
||||
]
|
||||
|
||||
self.common_release_args = [
|
||||
|
|
|
|||
|
|
@ -626,11 +626,11 @@ public class ContactsController: ViewController {
|
|||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Contacts_Sort_ByLastSeen, icon: { theme in return currentSettings.sortOrder == .presence ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil }, action: { _, f in
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Contacts_Sort_ByLastSeen, icon: { theme in return currentSettings.sortOrder == .presence ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage() }, action: { _, f in
|
||||
f(.default)
|
||||
updateSortOrder(.presence)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Contacts_Sort_ByName, icon: { theme in return currentSettings.sortOrder == .natural ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil }, action: { _, f in
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Contacts_Sort_ByName, icon: { theme in return currentSettings.sortOrder == .natural ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage() }, action: { _, f in
|
||||
f(.default)
|
||||
updateSortOrder(.natural)
|
||||
})))
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ public final class ContextMenuActionItem {
|
|||
public let textColor: ContextMenuActionItemTextColor
|
||||
public let textFont: ContextMenuActionItemFont
|
||||
public let textLayout: ContextMenuActionItemTextLayout
|
||||
public let customTextInsets: UIEdgeInsets?
|
||||
public let parseMarkdown: Bool
|
||||
public let badge: ContextMenuActionBadge?
|
||||
public let icon: (PresentationTheme) -> UIImage?
|
||||
|
|
@ -150,6 +151,7 @@ public final class ContextMenuActionItem {
|
|||
enableEntityAnimations: Bool = true,
|
||||
textColor: ContextMenuActionItemTextColor = .primary,
|
||||
textLayout: ContextMenuActionItemTextLayout = .twoLinesMax,
|
||||
customTextInsets: UIEdgeInsets? = nil,
|
||||
textFont: ContextMenuActionItemFont = .regular,
|
||||
parseMarkdown: Bool = false,
|
||||
badge: ContextMenuActionBadge? = nil,
|
||||
|
|
@ -172,6 +174,7 @@ public final class ContextMenuActionItem {
|
|||
enableEntityAnimations: enableEntityAnimations,
|
||||
textColor: textColor,
|
||||
textLayout: textLayout,
|
||||
customTextInsets: customTextInsets,
|
||||
textFont: textFont,
|
||||
parseMarkdown: parseMarkdown,
|
||||
badge: badge,
|
||||
|
|
@ -204,6 +207,7 @@ public final class ContextMenuActionItem {
|
|||
enableEntityAnimations: Bool = true,
|
||||
textColor: ContextMenuActionItemTextColor = .primary,
|
||||
textLayout: ContextMenuActionItemTextLayout = .twoLinesMax,
|
||||
customTextInsets: UIEdgeInsets? = nil,
|
||||
textFont: ContextMenuActionItemFont = .regular,
|
||||
parseMarkdown: Bool = false,
|
||||
badge: ContextMenuActionBadge? = nil,
|
||||
|
|
@ -226,6 +230,7 @@ public final class ContextMenuActionItem {
|
|||
self.textColor = textColor
|
||||
self.textFont = textFont
|
||||
self.textLayout = textLayout
|
||||
self.customTextInsets = customTextInsets
|
||||
self.parseMarkdown = parseMarkdown
|
||||
self.badge = badge
|
||||
self.icon = icon
|
||||
|
|
@ -250,12 +255,17 @@ public protocol ContextMenuCustomNode: ASDisplayNode {
|
|||
func performAction()
|
||||
|
||||
var needsSeparator: Bool { get }
|
||||
var needsPadding: Bool { get }
|
||||
}
|
||||
|
||||
public extension ContextMenuCustomNode {
|
||||
var needsSeparator: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
var needsPadding: Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public protocol ContextMenuCustomItem {
|
||||
|
|
@ -798,6 +808,7 @@ public protocol ContextControllerActionsStackItemNode: ASDisplayNode {
|
|||
transition: ContainedViewLayoutTransition
|
||||
) -> (size: CGSize, apparentHeight: CGFloat)
|
||||
|
||||
func highlightGestureShouldBegin(location: CGPoint) -> Bool
|
||||
func highlightGestureMoved(location: CGPoint)
|
||||
func highlightGestureFinished(performAction: Bool)
|
||||
|
||||
|
|
|
|||
|
|
@ -64,9 +64,9 @@ private final class VoiceChatInfoContextItemNode: ASDisplayNode, ContextMenuCust
|
|||
}
|
||||
|
||||
func updateLayout(constrainedWidth: CGFloat, constrainedHeight: CGFloat) -> (CGSize, (CGSize, ContainedViewLayoutTransition) -> Void) {
|
||||
let sideInset: CGFloat = 16.0
|
||||
let iconSideInset: CGFloat = 12.0
|
||||
let verticalInset: CGFloat = 12.0
|
||||
let sideInset: CGFloat = 18.0
|
||||
let iconSideInset: CGFloat = 20.0
|
||||
let verticalInset: CGFloat = 11.0
|
||||
|
||||
let iconSize = self.iconNode.image.flatMap({ $0.size }) ?? CGSize()
|
||||
|
||||
|
|
@ -80,11 +80,11 @@ private final class VoiceChatInfoContextItemNode: ASDisplayNode, ContextMenuCust
|
|||
|
||||
return (CGSize(width: textSize.width + sideInset + rightTextInset, height: verticalInset * 2.0 + textSize.height), { size, transition in
|
||||
let verticalOrigin = floor((size.height - textSize.height) / 2.0)
|
||||
let textFrame = CGRect(origin: CGPoint(x: sideInset, y: verticalOrigin), size: textSize)
|
||||
let textFrame = CGRect(origin: CGPoint(x: iconSideInset + 40.0, y: verticalOrigin), size: textSize)
|
||||
transition.updateFrameAdditive(node: self.textNode, frame: textFrame)
|
||||
|
||||
if !iconSize.width.isZero {
|
||||
transition.updateFrameAdditive(node: self.iconNode, frame: CGRect(origin: CGPoint(x: size.width - standardIconWidth - iconSideInset + floor((standardIconWidth - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize))
|
||||
transition.updateFrameAdditive(node: self.iconNode, frame: CGRect(origin: CGPoint(x: iconSideInset + floor((standardIconWidth - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize))
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
|
||||
|
|
|
|||
|
|
@ -98,7 +98,6 @@ private final class VoiceChatRecordingContextItemNode: ASDisplayNode, ContextMen
|
|||
private let actionSelected: (ContextMenuActionResult) -> Void
|
||||
|
||||
private let backgroundNode: ASDisplayNode
|
||||
private let highlightedBackgroundNode: ASDisplayNode
|
||||
private let textNode: ImmediateTextNode
|
||||
private let statusNode: ImmediateTextNode
|
||||
private let iconNode: VoiceChatRecordingIconNode
|
||||
|
|
@ -120,10 +119,6 @@ private final class VoiceChatRecordingContextItemNode: ASDisplayNode, ContextMen
|
|||
self.backgroundNode = ASDisplayNode()
|
||||
self.backgroundNode.isAccessibilityElement = false
|
||||
self.backgroundNode.backgroundColor = presentationData.theme.contextMenu.itemBackgroundColor
|
||||
self.highlightedBackgroundNode = ASDisplayNode()
|
||||
self.highlightedBackgroundNode.isAccessibilityElement = false
|
||||
self.highlightedBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor
|
||||
self.highlightedBackgroundNode.alpha = 0.0
|
||||
|
||||
self.textNode = ImmediateTextNode()
|
||||
self.textNode.isAccessibilityElement = false
|
||||
|
|
@ -149,23 +144,11 @@ private final class VoiceChatRecordingContextItemNode: ASDisplayNode, ContextMen
|
|||
super.init()
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.highlightedBackgroundNode)
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.statusNode)
|
||||
self.addSubnode(self.iconNode)
|
||||
self.addSubnode(self.buttonNode)
|
||||
|
||||
self.buttonNode.highligthedChanged = { [weak self] highligted in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if highligted {
|
||||
strongSelf.highlightedBackgroundNode.alpha = 1.0
|
||||
} else {
|
||||
strongSelf.highlightedBackgroundNode.alpha = 0.0
|
||||
strongSelf.highlightedBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
|
||||
}
|
||||
}
|
||||
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
||||
|
|
@ -176,14 +159,8 @@ private final class VoiceChatRecordingContextItemNode: ASDisplayNode, ContextMen
|
|||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.pointerInteraction = PointerInteraction(node: self.buttonNode, style: .hover, willEnter: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.highlightedBackgroundNode.alpha = 0.75
|
||||
}
|
||||
}, willExit: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.highlightedBackgroundNode.alpha = 0.0
|
||||
}
|
||||
self.pointerInteraction = PointerInteraction(node: self.buttonNode, style: .hover, willEnter: {
|
||||
}, willExit: {
|
||||
})
|
||||
|
||||
let timer = SwiftSignalKit.Timer(timeout: 0.5, repeat: true, completion: { [weak self] in
|
||||
|
|
@ -205,15 +182,16 @@ private final class VoiceChatRecordingContextItemNode: ASDisplayNode, ContextMen
|
|||
let subtextFont = Font.regular(self.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0)
|
||||
self.statusNode.attributedText = NSAttributedString(string: stringForDuration(Int32(duration)), font: subtextFont, textColor: presentationData.theme.contextMenu.secondaryColor)
|
||||
|
||||
let sideInset: CGFloat = 16.0
|
||||
let sideInset: CGFloat = 18.0
|
||||
let iconSideInset: CGFloat = 22.0
|
||||
let statusSize = self.statusNode.updateLayout(CGSize(width: size.width - sideInset - 32.0, height: .greatestFiniteMagnitude))
|
||||
transition.updateFrameAdditive(node: self.statusNode, frame: CGRect(origin: CGPoint(x: sideInset, y: self.statusNode.frame.minY), size: statusSize))
|
||||
transition.updateFrameAdditive(node: self.statusNode, frame: CGRect(origin: CGPoint(x: iconSideInset + 38.0, y: self.statusNode.frame.minY), size: statusSize))
|
||||
}
|
||||
|
||||
func updateLayout(constrainedWidth: CGFloat, constrainedHeight: CGFloat) -> (CGSize, (CGSize, ContainedViewLayoutTransition) -> Void) {
|
||||
let sideInset: CGFloat = 16.0
|
||||
let iconSideInset: CGFloat = 12.0
|
||||
let verticalInset: CGFloat = 12.0
|
||||
let sideInset: CGFloat = 18.0
|
||||
let iconSideInset: CGFloat = 22.0
|
||||
let verticalInset: CGFloat = 11.0
|
||||
|
||||
let iconSide = 16.0 + (1.0 + UIScreenPixel) * 2.0
|
||||
let iconSize: CGSize = CGSize(width: iconSide, height: iconSide)
|
||||
|
|
@ -237,23 +215,21 @@ private final class VoiceChatRecordingContextItemNode: ASDisplayNode, ContextMen
|
|||
self.updateTime(transition: .immediate)
|
||||
}
|
||||
let verticalOrigin = floor((size.height - combinedTextHeight) / 2.0)
|
||||
let textFrame = CGRect(origin: CGPoint(x: sideInset, y: verticalOrigin), size: textSize)
|
||||
let textFrame = CGRect(origin: CGPoint(x: iconSideInset + 38.0, y: verticalOrigin), size: textSize)
|
||||
transition.updateFrameAdditive(node: self.textNode, frame: textFrame)
|
||||
transition.updateFrameAdditive(node: self.statusNode, frame: CGRect(origin: CGPoint(x: sideInset, y: verticalOrigin + verticalSpacing + textSize.height), size: textSize))
|
||||
transition.updateFrameAdditive(node: self.statusNode, frame: CGRect(origin: CGPoint(x: iconSideInset + 38.0, y: verticalOrigin + verticalSpacing + textSize.height), size: textSize))
|
||||
|
||||
if !iconSize.width.isZero {
|
||||
transition.updateFrameAdditive(node: self.iconNode, frame: CGRect(origin: CGPoint(x: size.width - standardIconWidth - iconSideInset + floor((standardIconWidth - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize))
|
||||
transition.updateFrameAdditive(node: self.iconNode, frame: CGRect(origin: CGPoint(x: iconSideInset + floor((standardIconWidth - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize))
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
|
||||
transition.updateFrame(node: self.highlightedBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
|
||||
transition.updateFrame(node: self.buttonNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
|
||||
})
|
||||
}
|
||||
|
||||
func updateTheme(presentationData: PresentationData) {
|
||||
self.backgroundNode.backgroundColor = presentationData.theme.contextMenu.itemBackgroundColor
|
||||
self.highlightedBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor
|
||||
|
||||
let textFont = Font.regular(presentationData.listsFontSize.baseDisplaySize)
|
||||
let subtextFont = Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0)
|
||||
|
|
@ -284,10 +260,5 @@ private final class VoiceChatRecordingContextItemNode: ASDisplayNode, ContextMen
|
|||
}
|
||||
|
||||
func setIsHighlighted(_ value: Bool) {
|
||||
if value {
|
||||
self.highlightedBackgroundNode.alpha = 1.0
|
||||
} else {
|
||||
self.highlightedBackgroundNode.alpha = 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ private final class VoiceChatShareScreenContextItemNode: ASDisplayNode, ContextM
|
|||
private let actionSelected: (ContextMenuActionResult) -> Void
|
||||
|
||||
private let backgroundNode: ASDisplayNode
|
||||
private let highlightedBackgroundNode: ASDisplayNode
|
||||
private let textNode: ImmediateTextNode
|
||||
private let iconNode: ASImageNode
|
||||
|
||||
|
|
@ -59,10 +58,6 @@ private final class VoiceChatShareScreenContextItemNode: ASDisplayNode, ContextM
|
|||
self.backgroundNode = ASDisplayNode()
|
||||
self.backgroundNode.isAccessibilityElement = false
|
||||
self.backgroundNode.backgroundColor = presentationData.theme.contextMenu.itemBackgroundColor
|
||||
self.highlightedBackgroundNode = ASDisplayNode()
|
||||
self.highlightedBackgroundNode.isAccessibilityElement = false
|
||||
self.highlightedBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor
|
||||
self.highlightedBackgroundNode.alpha = 0.0
|
||||
|
||||
self.textNode = ImmediateTextNode()
|
||||
self.textNode.isAccessibilityElement = false
|
||||
|
|
@ -89,7 +84,6 @@ private final class VoiceChatShareScreenContextItemNode: ASDisplayNode, ContextM
|
|||
super.init()
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.highlightedBackgroundNode)
|
||||
if let broadcastPickerView = self.broadcastPickerView {
|
||||
self.view.addSubview(broadcastPickerView)
|
||||
}
|
||||
|
|
@ -118,9 +112,9 @@ private final class VoiceChatShareScreenContextItemNode: ASDisplayNode, ContextM
|
|||
|
||||
private var validLayout: CGSize?
|
||||
func updateLayout(constrainedWidth: CGFloat, constrainedHeight: CGFloat) -> (CGSize, (CGSize, ContainedViewLayoutTransition) -> Void) {
|
||||
let sideInset: CGFloat = 16.0
|
||||
let iconSideInset: CGFloat = 12.0
|
||||
let verticalInset: CGFloat = 12.0
|
||||
let sideInset: CGFloat = 18.0
|
||||
let iconSideInset: CGFloat = 20.0
|
||||
let verticalInset: CGFloat = 11.0
|
||||
|
||||
let iconSize = self.iconNode.image.flatMap({ $0.size }) ?? CGSize()
|
||||
|
||||
|
|
@ -139,15 +133,14 @@ private final class VoiceChatShareScreenContextItemNode: ASDisplayNode, ContextM
|
|||
self.validLayout = size
|
||||
|
||||
let verticalOrigin = floor((size.height - combinedTextHeight) / 2.0)
|
||||
let textFrame = CGRect(origin: CGPoint(x: sideInset, y: verticalOrigin), size: textSize)
|
||||
let textFrame = CGRect(origin: CGPoint(x: iconSideInset + 40.0, y: verticalOrigin), size: textSize)
|
||||
transition.updateFrameAdditive(node: self.textNode, frame: textFrame)
|
||||
|
||||
if !iconSize.width.isZero {
|
||||
transition.updateFrameAdditive(node: self.iconNode, frame: CGRect(origin: CGPoint(x: size.width - standardIconWidth - iconSideInset + floor((standardIconWidth - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize))
|
||||
transition.updateFrameAdditive(node: self.iconNode, frame: CGRect(origin: CGPoint(x: iconSideInset + floor((standardIconWidth - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize))
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
|
||||
transition.updateFrame(node: self.highlightedBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
|
||||
|
||||
if let broadcastPickerView = self.broadcastPickerView {
|
||||
broadcastPickerView.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height))
|
||||
|
|
@ -157,7 +150,6 @@ private final class VoiceChatShareScreenContextItemNode: ASDisplayNode, ContextM
|
|||
|
||||
func updateTheme(presentationData: PresentationData) {
|
||||
self.backgroundNode.backgroundColor = presentationData.theme.contextMenu.itemBackgroundColor
|
||||
self.highlightedBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor
|
||||
|
||||
let textFont = Font.regular(presentationData.listsFontSize.baseDisplaySize)
|
||||
|
||||
|
|
@ -186,10 +178,5 @@ private final class VoiceChatShareScreenContextItemNode: ASDisplayNode, ContextM
|
|||
}
|
||||
|
||||
func setIsHighlighted(_ value: Bool) {
|
||||
if value {
|
||||
self.highlightedBackgroundNode.alpha = 1.0
|
||||
} else {
|
||||
self.highlightedBackgroundNode.alpha = 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ private final class VoiceChatVolumeContextItemNode: ASDisplayNode, ContextMenuCu
|
|||
}
|
||||
}
|
||||
|
||||
let needsPadding: Bool = false
|
||||
|
||||
private let valueChanged: (CGFloat, Bool) -> Void
|
||||
|
||||
private let hapticFeedback = HapticFeedback()
|
||||
|
|
@ -134,7 +136,7 @@ private final class VoiceChatVolumeContextItemNode: ASDisplayNode, ContextMenuCu
|
|||
textSize.width = valueWidth
|
||||
|
||||
return (CGSize(width: height * 3.0, height: height), { size, transition in
|
||||
let leftInset: CGFloat = 17.0
|
||||
let leftInset: CGFloat = 25.0
|
||||
|
||||
let textFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((size.height - textSize.height) / 2.0)), size: textSize)
|
||||
transition.updateFrameAdditive(node: self.backgroundTextNode, frame: textFrame)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ private final class ChatSendAsPeerTitleContextItemNode: ASDisplayNode, ContextMe
|
|||
private let backgroundNode: ASDisplayNode
|
||||
private let textNode: ImmediateTextNode
|
||||
|
||||
let needsPadding: Bool = false
|
||||
|
||||
init(presentationData: PresentationData, item: ChatSendAsPeerTitleContextItem, getController: @escaping () -> ContextControllerProtocol?, actionSelected: @escaping (ContextMenuActionResult) -> Void) {
|
||||
self.item = item
|
||||
self.presentationData = presentationData
|
||||
|
|
@ -55,10 +57,10 @@ private final class ChatSendAsPeerTitleContextItemNode: ASDisplayNode, ContextMe
|
|||
}
|
||||
|
||||
func updateLayout(constrainedWidth: CGFloat, constrainedHeight: CGFloat) -> (CGSize, (CGSize, ContainedViewLayoutTransition) -> Void) {
|
||||
let sideInset: CGFloat = 16.0
|
||||
let sideInset: CGFloat = 18.0
|
||||
|
||||
let textSize = self.textNode.updateLayout(CGSize(width: constrainedWidth - sideInset - sideInset, height: .greatestFiniteMagnitude))
|
||||
let height: CGFloat = 28.0
|
||||
let height: CGFloat = 28.0 + 10.0
|
||||
|
||||
return (CGSize(width: textSize.width + sideInset + sideInset, height: height), { size, transition in
|
||||
let verticalOrigin = floor((size.height - textSize.height) / 2.0)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ import TextFormat
|
|||
import TextNodeWithEntities
|
||||
import SwiftSignalKit
|
||||
import ContextUI
|
||||
import GlassBackgroundComponent
|
||||
import ComponentFlow
|
||||
import ComponentDisplayAdapters
|
||||
|
||||
private final class ContextActionsSelectionGestureRecognizer: UIPanGestureRecognizer {
|
||||
var updateLocation: ((CGPoint, Bool) -> Void)?
|
||||
|
|
@ -325,10 +328,7 @@ private final class InnerActionsContainerNode: ASDisplayNode {
|
|||
|
||||
final class InnerTextSelectionTipContainerNode: ASDisplayNode {
|
||||
private let presentationData: PresentationData
|
||||
let shadowNode: ASImageNode
|
||||
private let backgroundNode: ASDisplayNode
|
||||
private var effectView: UIVisualEffectView?
|
||||
private let highlightBackgroundNode: ASDisplayNode
|
||||
private var background: (container: GlassBackgroundContainerView, background: GlassBackgroundView)?
|
||||
private let buttonNode: HighlightTrackingButtonNode
|
||||
private let textNode: TextNodeWithEntities
|
||||
private var textSelectionNode: TextSelectionNode?
|
||||
|
|
@ -347,22 +347,15 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
|
|||
private var action: (() -> Void)?
|
||||
var requestDismiss: (@escaping () -> Void) -> Void = { _ in }
|
||||
|
||||
init(presentationData: PresentationData, tip: ContextController.Tip) {
|
||||
init(presentationData: PresentationData, tip: ContextController.Tip, isInline: Bool) {
|
||||
self.tip = tip
|
||||
self.presentationData = presentationData
|
||||
|
||||
self.shadowNode = ASImageNode()
|
||||
self.shadowNode.displaysAsynchronously = false
|
||||
self.shadowNode.displayWithoutProcessing = true
|
||||
self.shadowNode.image = UIImage(bundleImageName: "Components/Context Menu/Shadow")?.stretchableImage(withLeftCapWidth: 60, topCapHeight: 60)
|
||||
self.shadowNode.contentMode = .scaleToFill
|
||||
self.shadowNode.isHidden = true
|
||||
|
||||
self.backgroundNode = ASDisplayNode()
|
||||
|
||||
self.highlightBackgroundNode = ASDisplayNode()
|
||||
self.highlightBackgroundNode.isAccessibilityElement = false
|
||||
self.highlightBackgroundNode.alpha = 0.0
|
||||
if !isInline {
|
||||
self.background = (GlassBackgroundContainerView(), GlassBackgroundView())
|
||||
} else {
|
||||
self.background = nil
|
||||
}
|
||||
|
||||
self.buttonNode = HighlightTrackingButtonNode()
|
||||
|
||||
|
|
@ -448,13 +441,6 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
|
|||
|
||||
super.init()
|
||||
|
||||
self.backgroundNode.backgroundColor = presentationData.theme.contextMenu.backgroundColor
|
||||
self.backgroundNode.clipsToBounds = true
|
||||
self.backgroundNode.cornerRadius = 14.0
|
||||
|
||||
self.highlightBackgroundNode.clipsToBounds = true
|
||||
self.highlightBackgroundNode.cornerRadius = 14.0
|
||||
|
||||
let textSelectionNode = TextSelectionNode(theme: TextSelectionTheme(selection: presentationData.theme.contextMenu.primaryColor.withAlphaComponent(0.15), knob: presentationData.theme.contextMenu.primaryColor, knobDiameter: 8.0, isDark: presentationData.theme.overallDarkAppearance), strings: presentationData.strings, textNode: self.textNode.textNode, updateIsActive: { _ in
|
||||
}, present: { _, _ in
|
||||
}, rootNode: { [weak self] in
|
||||
|
|
@ -463,17 +449,24 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
|
|||
})
|
||||
self.textSelectionNode = textSelectionNode
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.highlightBackgroundNode)
|
||||
self.addSubnode(self.textNode.textNode)
|
||||
self.addSubnode(self.iconNode)
|
||||
self.addSubnode(self.placeholderNode)
|
||||
let parentView: UIView
|
||||
if let background = self.background {
|
||||
self.view.addSubview(background.container)
|
||||
background.container.contentView.addSubview(background.background)
|
||||
parentView = background.background.contentView
|
||||
} else {
|
||||
parentView = self.view
|
||||
}
|
||||
|
||||
self.textSelectionNode.flatMap(self.addSubnode)
|
||||
parentView.addSubview(self.textNode.textNode.view)
|
||||
parentView.addSubview(self.iconNode.view)
|
||||
parentView.addSubview(self.placeholderNode.view)
|
||||
|
||||
self.addSubnode(textSelectionNode.highlightAreaNode)
|
||||
self.textSelectionNode.flatMap { parentView.addSubview($0.view) }
|
||||
|
||||
self.addSubnode(self.buttonNode)
|
||||
parentView.addSubview(textSelectionNode.highlightAreaNode.view)
|
||||
|
||||
parentView.addSubview(self.buttonNode.view)
|
||||
|
||||
self.buttonNode.highligthedChanged = { [weak self] highlighted in
|
||||
guard let strongSelf = self else {
|
||||
|
|
@ -512,7 +505,11 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
|
|||
]
|
||||
|
||||
for node in nodes {
|
||||
other.addSubnode(node)
|
||||
if let background = other.background {
|
||||
background.background.contentView.addSubview(node.view)
|
||||
} else {
|
||||
other.view.addSubview(node.view)
|
||||
}
|
||||
node.layer.animateAlpha(from: node.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak node] _ in
|
||||
node?.removeFromSupernode()
|
||||
})
|
||||
|
|
@ -531,44 +528,13 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
|
|||
}
|
||||
|
||||
func updateLayout(widthClass: ContainerViewLayoutSizeClass, presentation: ContextControllerActionsStackNode.Presentation, width: CGFloat, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||
var needsBlur = false
|
||||
if case .regular = widthClass {
|
||||
needsBlur = true
|
||||
} else if case .inline = presentation {
|
||||
needsBlur = true
|
||||
}
|
||||
|
||||
if !needsBlur {
|
||||
if let effectView = self.effectView {
|
||||
self.effectView = nil
|
||||
effectView.removeFromSuperview()
|
||||
}
|
||||
} else {
|
||||
if self.effectView == nil {
|
||||
let effectView: UIVisualEffectView
|
||||
if #available(iOS 13.0, *) {
|
||||
if self.presentationData.theme.overallDarkAppearance {
|
||||
effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterialDark))
|
||||
} else {
|
||||
effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterialLight))
|
||||
}
|
||||
} else {
|
||||
effectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
|
||||
}
|
||||
effectView.clipsToBounds = true
|
||||
effectView.layer.cornerRadius = self.backgroundNode.cornerRadius
|
||||
self.effectView = effectView
|
||||
self.view.insertSubview(effectView, at: 0)
|
||||
}
|
||||
}
|
||||
|
||||
let verticalInset: CGFloat = 10.0
|
||||
let horizontalInset: CGFloat = 16.0
|
||||
let verticalInset: CGFloat = 16.0
|
||||
let horizontalInset: CGFloat = 18.0
|
||||
let standardIconWidth: CGFloat = 32.0
|
||||
let iconSideInset: CGFloat = 12.0
|
||||
let iconSideInset: CGFloat = 20.0
|
||||
|
||||
let textFont = Font.regular(floor(presentationData.listsFontSize.baseDisplaySize * 14.0 / 17.0))
|
||||
let boldTextFont = Font.bold(floor(presentationData.listsFontSize.baseDisplaySize * 14.0 / 17.0))
|
||||
let textFont = Font.regular(floor(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0))
|
||||
let boldTextFont = Font.bold(floor(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0))
|
||||
let textColor = self.presentationData.theme.contextMenu.primaryColor
|
||||
let linkColor = self.presentationData.theme.overallDarkAppearance ? UIColor(rgb: 0x64d2ff) : self.presentationData.theme.contextMenu.badgeFillColor
|
||||
|
||||
|
|
@ -626,7 +592,7 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
|
|||
transition.updateFrame(node: self.placeholderNode, frame: CGRect(origin: CGPoint(x: horizontalInset, y: floorToScreenPixels((size.height - lineHeight) / 2.0)), size: CGSize(width: width - horizontalInset * 2.0, height: lineHeight)))
|
||||
transition.updateAlpha(node: self.placeholderNode, alpha: textFrame.height.isZero ? 1.0 : 0.0)
|
||||
|
||||
let iconFrame = CGRect(origin: CGPoint(x: size.width - standardIconWidth - iconSideInset + floor((standardIconWidth - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)
|
||||
let iconFrame = CGRect(origin: CGPoint(x: iconSideInset + floor((standardIconWidth - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize)
|
||||
transition.updateFrame(node: self.iconNode, frame: iconFrame)
|
||||
|
||||
if let textSelectionNode = self.textSelectionNode {
|
||||
|
|
@ -634,30 +600,24 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
|
|||
textSelectionNode.highlightAreaNode.frame = textFrame
|
||||
}
|
||||
|
||||
switch presentation {
|
||||
case .modal:
|
||||
self.shadowNode.isHidden = true
|
||||
case .inline, .additional:
|
||||
self.shadowNode.isHidden = false
|
||||
}
|
||||
|
||||
if let effectView = self.effectView {
|
||||
transition.updateFrame(view: effectView, frame: CGRect(origin: CGPoint(), size: size))
|
||||
}
|
||||
|
||||
self.highlightBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor
|
||||
|
||||
return size
|
||||
}
|
||||
|
||||
func setActualSize(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
self.highlightBackgroundNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
let transition = ComponentTransition(transition)
|
||||
|
||||
if let background = self.background {
|
||||
background.container.update(size: size, isDark: self.presentationData.theme.overallDarkAppearance, transition: transition)
|
||||
transition.setFrame(view: background.container, frame: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
background.background.update(size: size, cornerRadius: min(30.0, size.height * 0.5), isDark: self.presentationData.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: UIColor(white: self.presentationData.theme.overallDarkAppearance ? 0.0 : 1.0, alpha: 0.6)), transition: transition)
|
||||
transition.setFrame(view: background.background, frame: CGRect(origin: CGPoint(), size: size))
|
||||
}
|
||||
|
||||
self.buttonNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
}
|
||||
|
||||
func updateTheme(presentationData: PresentationData) {
|
||||
self.backgroundColor = presentationData.theme.contextMenu.backgroundColor
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
|
|
@ -673,17 +633,6 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
|
|||
}
|
||||
|
||||
func updateHighlight(animated: Bool) {
|
||||
if self.isButtonHighlighted || self.isHighlighted {
|
||||
self.highlightBackgroundNode.alpha = 1.0
|
||||
} else {
|
||||
if animated {
|
||||
let previousAlpha = self.highlightBackgroundNode.alpha
|
||||
self.highlightBackgroundNode.alpha = 0.0
|
||||
self.highlightBackgroundNode.layer.animateAlpha(from: previousAlpha, to: 0.0, duration: 0.2)
|
||||
} else {
|
||||
self.highlightBackgroundNode.alpha = 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var isButtonHighlighted = false
|
||||
|
|
@ -796,8 +745,6 @@ final class ContextActionsContainerNode: ASDisplayNode {
|
|||
|
||||
super.init()
|
||||
|
||||
//self.addSubnode(self.shadowNode)
|
||||
//self.additionalShadowNode.flatMap(self.addSubnode)
|
||||
self.additionalActionsNode.flatMap(self.scrollNode.addSubnode)
|
||||
self.scrollNode.addSubnode(self.actionsNode)
|
||||
self.addSubnode(self.scrollNode)
|
||||
|
|
@ -857,7 +804,7 @@ final class ContextActionsContainerNode: ASDisplayNode {
|
|||
textSelectionTipNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
let textSelectionTipNode = InnerTextSelectionTipContainerNode(presentationData: self.presentationData, tip: tip)
|
||||
let textSelectionTipNode = InnerTextSelectionTipContainerNode(presentationData: self.presentationData, tip: tip, isInline: false)
|
||||
let getController = self.getController
|
||||
textSelectionTipNode.requestDismiss = { completion in
|
||||
getController()?.dismiss(completion: completion)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ public protocol ContextControllerActionsListItemNode: ASDisplayNode {
|
|||
func canBeHighlighted() -> Bool
|
||||
func updateIsHighlighted(isHighlighted: Bool)
|
||||
func performAction()
|
||||
|
||||
var needsPadding: Bool { get }
|
||||
}
|
||||
|
||||
public final class ContextControllerActionsListActionItemNode: HighlightTrackingButtonNode, ContextControllerActionsListItemNode {
|
||||
|
|
@ -49,6 +51,8 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
|||
|
||||
private var iconDisposable: Disposable?
|
||||
|
||||
public let needsPadding: Bool = true
|
||||
|
||||
public init(
|
||||
context: AccountContext?,
|
||||
getController: @escaping () -> ContextControllerProtocol?,
|
||||
|
|
@ -205,10 +209,10 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
|||
let sideInset: CGFloat = 18.0
|
||||
let verticalInset: CGFloat = 11.0
|
||||
let titleSubtitleSpacing: CGFloat = 1.0
|
||||
let iconSideInset: CGFloat = 18.0 + 6.0
|
||||
let iconSideInset: CGFloat = 20.0
|
||||
let standardIconWidth: CGFloat = 32.0
|
||||
let iconSpacing: CGFloat = 8.0
|
||||
|
||||
|
||||
var forcedHeight: CGFloat?
|
||||
var titleVerticalOffset: CGFloat?
|
||||
let titleFont: UIFont
|
||||
|
|
@ -490,6 +494,10 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
|||
maxTextWidth -= sideInset
|
||||
}
|
||||
|
||||
if let additionalIconSize {
|
||||
maxTextWidth -= additionalIconSize.width
|
||||
}
|
||||
|
||||
if let badgeSize = badgeSize {
|
||||
maxTextWidth -= badgeSize.width
|
||||
maxTextWidth -= 8.0
|
||||
|
|
@ -510,8 +518,8 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
|||
} else {
|
||||
minSize.width += sideInset
|
||||
}
|
||||
if self.item.additionalLeftIcon != nil {
|
||||
minSize.width += 24.0
|
||||
if let additionalIconSize {
|
||||
minSize.width += additionalIconSize.width
|
||||
minSize.width += iconSideInset
|
||||
minSize.width += iconSpacing
|
||||
}
|
||||
|
|
@ -528,13 +536,15 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
|||
|
||||
return (minSize: minSize, apply: { size, transition in
|
||||
var titleFrame = CGRect(origin: CGPoint(x: sideInset, y: verticalInset), size: titleSize)
|
||||
if let customTextInsets = self.item.customTextInsets {
|
||||
titleFrame.origin.x = customTextInsets.left
|
||||
}
|
||||
if let titleVerticalOffset {
|
||||
titleFrame = titleFrame.offsetBy(dx: 0.0, dy: titleVerticalOffset)
|
||||
}
|
||||
var subtitleFrame = CGRect(origin: CGPoint(x: titleFrame.minX, y: titleFrame.maxY + titleSubtitleSpacing), size: subtitleSize)
|
||||
if self.item.additionalLeftIcon != nil {
|
||||
} else if iconSize != nil {
|
||||
titleFrame.origin.x = iconSideInset + 36.0
|
||||
if iconSize != nil {
|
||||
titleFrame.origin.x = iconSideInset + 40.0
|
||||
subtitleFrame.origin.x = titleFrame.minX
|
||||
}
|
||||
|
||||
|
|
@ -548,7 +558,7 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
|||
if let iconSize {
|
||||
let iconFrame = CGRect(
|
||||
origin: CGPoint(
|
||||
x: iconSideInset,
|
||||
x: iconSideInset + floor((standardIconWidth - iconSize.width) * 0.5),
|
||||
y: floor((size.height - iconSize.height) / 2.0)
|
||||
),
|
||||
size: iconSize
|
||||
|
|
@ -577,7 +587,7 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
|||
if let additionalIconSize {
|
||||
let iconFrame = CGRect(
|
||||
origin: CGPoint(
|
||||
x: 10.0,
|
||||
x: size.width - iconSideInset - additionalIconSize.width,
|
||||
y: floor((size.height - additionalIconSize.height) / 2.0)
|
||||
),
|
||||
size: additionalIconSize
|
||||
|
|
@ -591,6 +601,8 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
|||
private final class ContextControllerActionsListSeparatorItemNode: ASDisplayNode, ContextControllerActionsListItemNode {
|
||||
private let separatorView: UIImageView
|
||||
|
||||
let needsPadding: Bool = false
|
||||
|
||||
func canBeHighlighted() -> Bool {
|
||||
return false
|
||||
}
|
||||
|
|
@ -644,6 +656,14 @@ private final class ContextControllerActionsListCustomItemNode: ASDisplayNode, C
|
|||
}
|
||||
}
|
||||
|
||||
var needsPadding: Bool {
|
||||
if let itemNode = self.itemNode {
|
||||
return itemNode.needsPadding
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private let getController: () -> ContextControllerProtocol?
|
||||
private let item: ContextMenuCustomItem
|
||||
private let requestDismiss: (ContextMenuActionResult) -> Void
|
||||
|
|
@ -733,6 +753,10 @@ public final class ContextControllerActionsListStackItem: ContextControllerActio
|
|||
private var items: [ContextMenuItem]
|
||||
private var itemNodes: [Item]
|
||||
|
||||
private var tip: ContextController.Tip?
|
||||
private var tipDisposable: Disposable?
|
||||
private var tipNode: InnerTextSelectionTipContainerNode?
|
||||
|
||||
private var hapticFeedback: HapticFeedback?
|
||||
|
||||
private let highlightedItemBackgroundView: UIView
|
||||
|
|
@ -750,13 +774,16 @@ public final class ContextControllerActionsListStackItem: ContextControllerActio
|
|||
getController: @escaping () -> ContextControllerProtocol?,
|
||||
requestDismiss: @escaping (ContextMenuActionResult) -> Void,
|
||||
requestUpdate: @escaping (ContainedViewLayoutTransition) -> Void,
|
||||
items: [ContextMenuItem]
|
||||
items: [ContextMenuItem],
|
||||
tip: ContextController.Tip?,
|
||||
tipSignal: Signal<ContextController.Tip?, NoError>?
|
||||
) {
|
||||
self.context = context
|
||||
self.requestUpdate = requestUpdate
|
||||
self.getController = getController
|
||||
self.requestDismiss = requestDismiss
|
||||
self.items = items
|
||||
self.tip = tip
|
||||
|
||||
var requestUpdateAction: ((AnyHashable, ContextMenuActionItem) -> Void)?
|
||||
self.itemNodes = items.map { item -> Item in
|
||||
|
|
@ -807,6 +834,10 @@ public final class ContextControllerActionsListStackItem: ContextControllerActio
|
|||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.tipDisposable?.dispose()
|
||||
}
|
||||
|
||||
func updateItems(items: [ContextMenuItem]) {
|
||||
self.items = items
|
||||
for i in 0 ..< items.count {
|
||||
|
|
@ -890,21 +921,35 @@ public final class ContextControllerActionsListStackItem: ContextControllerActio
|
|||
let verticalInset: CGFloat = 10.0
|
||||
|
||||
var itemNodeLayouts: [(minSize: CGSize, apply: (_ size: CGSize, _ transition: ContainedViewLayoutTransition) -> Void)] = []
|
||||
var combinedSize = CGSize(width: 0.0, height: verticalInset)
|
||||
for item in self.itemNodes {
|
||||
var combinedSize = CGSize(width: 0.0, height: 0.0)
|
||||
for i in 0 ..< self.itemNodes.count {
|
||||
let item = self.itemNodes[i]
|
||||
|
||||
let itemNodeLayout = item.node.update(
|
||||
presentationData: presentationData,
|
||||
constrainedSize: CGSize(width: standardMaxWidth, height: constrainedSize.height)
|
||||
)
|
||||
|
||||
if item.node.needsPadding {
|
||||
if i == 0 {
|
||||
combinedSize.height += verticalInset
|
||||
}
|
||||
}
|
||||
|
||||
itemNodeLayouts.append(itemNodeLayout)
|
||||
combinedSize.width = max(combinedSize.width, itemNodeLayout.minSize.width)
|
||||
combinedSize.height += itemNodeLayout.minSize.height
|
||||
|
||||
if item.node.needsPadding {
|
||||
if i == self.itemNodes.count - 1 {
|
||||
combinedSize.height += verticalInset
|
||||
}
|
||||
}
|
||||
}
|
||||
combinedSize.height += verticalInset
|
||||
self.invalidatedItemNodes = false
|
||||
combinedSize.width = max(combinedSize.width, standardMinWidth)
|
||||
|
||||
var nextItemOrigin = CGPoint(x: 0.0, y: verticalInset)
|
||||
var nextItemOrigin = CGPoint(x: 0.0, y: 0.0)
|
||||
for i in 0 ..< self.itemNodes.count {
|
||||
let item = self.itemNodes[i]
|
||||
let itemNodeLayout = itemNodeLayouts[i]
|
||||
|
|
@ -914,6 +959,12 @@ public final class ContextControllerActionsListStackItem: ContextControllerActio
|
|||
itemTransition = .immediate
|
||||
}
|
||||
|
||||
if item.node.needsPadding {
|
||||
if i == 0 {
|
||||
nextItemOrigin.y += verticalInset
|
||||
}
|
||||
}
|
||||
|
||||
let itemSize = CGSize(width: combinedSize.width, height: itemNodeLayout.minSize.height)
|
||||
let itemFrame = CGRect(origin: nextItemOrigin, size: itemSize)
|
||||
itemTransition.updateFrame(node: item.node, frame: itemFrame, beginWithCurrentState: true)
|
||||
|
|
@ -926,6 +977,27 @@ public final class ContextControllerActionsListStackItem: ContextControllerActio
|
|||
}
|
||||
}
|
||||
|
||||
if let tip = self.tip, !"".isEmpty {
|
||||
let tipNode: InnerTextSelectionTipContainerNode
|
||||
var tipTransition = transition
|
||||
if let current = self.tipNode {
|
||||
tipNode = current
|
||||
} else {
|
||||
tipTransition = .immediate
|
||||
tipNode = InnerTextSelectionTipContainerNode(presentationData: presentationData, tip: tip, isInline: true)
|
||||
self.addSubnode(tipNode)
|
||||
self.tipNode = tipNode
|
||||
}
|
||||
let tipSize = tipNode.updateLayout(widthClass: .compact, presentation: .inline, width: combinedSize.width, transition: tipTransition)
|
||||
let tipFrame = CGRect(origin: nextItemOrigin, size: tipSize)
|
||||
tipTransition.updateFrame(node: tipNode, frame: tipFrame)
|
||||
nextItemOrigin.y += tipSize.height
|
||||
combinedSize.height += tipSize.height
|
||||
} else if let tipNode = self.tipNode {
|
||||
tipNode.removeFromSupernode()
|
||||
self.tipNode = nil
|
||||
}
|
||||
|
||||
if let highlightedItemFrame {
|
||||
self.highlightedItemBackgroundView.backgroundColor = presentationData.theme.overallDarkAppearance ? UIColor.white : UIColor.black
|
||||
self.highlightedItemBackgroundView.setMonochromaticEffect(tintColor: self.highlightedItemBackgroundView.backgroundColor)
|
||||
|
|
@ -955,6 +1027,18 @@ public final class ContextControllerActionsListStackItem: ContextControllerActio
|
|||
return (combinedSize, combinedSize.height)
|
||||
}
|
||||
|
||||
func highlightGestureShouldBegin(location: CGPoint) -> Bool {
|
||||
for itemNode in self.itemNodes {
|
||||
if itemNode.node.frame.contains(location) {
|
||||
if !itemNode.node.canBeHighlighted() {
|
||||
return false
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func highlightGestureMoved(location: CGPoint) {
|
||||
var highlightedItemNode: Item?
|
||||
for itemNode in self.itemNodes {
|
||||
|
|
@ -1058,7 +1142,9 @@ public final class ContextControllerActionsListStackItem: ContextControllerActio
|
|||
getController: getController,
|
||||
requestDismiss: requestDismiss,
|
||||
requestUpdate: requestUpdate,
|
||||
items: self.items
|
||||
items: self.items,
|
||||
tip: self.tip,
|
||||
tipSignal: self.tipSignal
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1110,6 +1196,10 @@ final class ContextControllerActionsCustomStackItem: ContextControllerActionsSta
|
|||
return (contentLayout.cleanSize, contentLayout.apparentHeight)
|
||||
}
|
||||
|
||||
func highlightGestureShouldBegin(location: CGPoint) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func highlightGestureMoved(location: CGPoint) {
|
||||
}
|
||||
|
||||
|
|
@ -1195,7 +1285,7 @@ func makeContextControllerActionsStackItem(items: ContextController.Items) -> [C
|
|||
}
|
||||
|
||||
private final class ItemSelectionRecognizer: UIGestureRecognizer {
|
||||
var shouldBegin: (() -> Bool)?
|
||||
var shouldBegin: ((CGPoint) -> Bool)?
|
||||
|
||||
private var initialLocation: CGPoint?
|
||||
private var currentLocation: CGPoint?
|
||||
|
|
@ -1216,7 +1306,7 @@ private final class ItemSelectionRecognizer: UIGestureRecognizer {
|
|||
public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||
super.touchesBegan(touches, with: event)
|
||||
|
||||
if let shouldBegin = self.shouldBegin, !shouldBegin() {
|
||||
if let location = touches.first?.location(in: self.view), let shouldBegin = self.shouldBegin, !shouldBegin(location) {
|
||||
self.state = .failed
|
||||
return
|
||||
}
|
||||
|
|
@ -1283,7 +1373,6 @@ public final class ContextControllerActionsStackNodeImpl: ASDisplayNode, Context
|
|||
|
||||
self.contentContainer = UIView()
|
||||
self.contentContainer.clipsToBounds = true
|
||||
self.contentContainer.layer.cornerRadius = 30.0
|
||||
self.backgroundView.contentView.addSubview(self.contentContainer)
|
||||
|
||||
super.init()
|
||||
|
|
@ -1416,12 +1505,14 @@ public final class ContextControllerActionsStackNodeImpl: ASDisplayNode, Context
|
|||
})
|
||||
}
|
||||
|
||||
transition.setCornerRadius(layer: self.contentContainer.layer, cornerRadius: min(30.0, size.height * 0.5))
|
||||
|
||||
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(), size: size))
|
||||
self.backgroundView.update(size: size, cornerRadius: 30.0, isDark: presentationData.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: UIColor(white: presentationData.theme.overallDarkAppearance ? 0.0 : 1.0, alpha: 0.6)), isInteractive: true, transition: transition)
|
||||
self.backgroundView.update(size: size, cornerRadius: min(30.0, size.height * 0.5), isDark: presentationData.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: UIColor(white: presentationData.theme.overallDarkAppearance ? 0.0 : 1.0, alpha: 0.6)), isInteractive: true, transition: transition)
|
||||
|
||||
if let sourceExtractableContainer = self.sourceExtractableContainer {
|
||||
transition.setFrame(view: sourceExtractableContainer.extractableContentView, frame: CGRect(origin: CGPoint(), size: size))
|
||||
sourceExtractableContainer.updateState(state: .extracted(size: size, cornerRadius: 30.0, state: .animatedIn), transition: transition.containedViewLayoutTransition)
|
||||
sourceExtractableContainer.updateState(state: .extracted(size: size, cornerRadius: min(30.0, size.height * 0.5), state: .animatedIn), transition: transition.containedViewLayoutTransition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1540,7 +1631,7 @@ public final class ContextControllerActionsStackNodeImpl: ASDisplayNode, Context
|
|||
} else {
|
||||
let previousTipNode = self.tipNode
|
||||
updatedTransition = .immediate
|
||||
let tipNode = InnerTextSelectionTipContainerNode(presentationData: presentationData, tip: tip)
|
||||
let tipNode = InnerTextSelectionTipContainerNode(presentationData: presentationData, tip: tip, isInline: false)
|
||||
tipNode.requestDismiss = { [weak self] completion in
|
||||
self?.getController()?.dismiss(completion: completion)
|
||||
}
|
||||
|
|
@ -1572,6 +1663,10 @@ public final class ContextControllerActionsStackNodeImpl: ASDisplayNode, Context
|
|||
transition.updateAlpha(node: self.dimNode, alpha: 1.0 - transitionFraction, beginWithCurrentState: true)
|
||||
}
|
||||
|
||||
func highlightGestureShouldBegin(at location: CGPoint) -> Bool {
|
||||
return self.node.highlightGestureShouldBegin(location: self.view.convert(location, to: self.node.view))
|
||||
}
|
||||
|
||||
func highlightGestureMoved(location: CGPoint) {
|
||||
if let tipNode = self.tipNode {
|
||||
let tipLocation = self.view.convert(location, to: tipNode.view)
|
||||
|
|
@ -1655,7 +1750,7 @@ public final class ContextControllerActionsStackNodeImpl: ASDisplayNode, Context
|
|||
}
|
||||
|
||||
let selectionPanGesture = ItemSelectionRecognizer(target: self, action: #selector(self.panGesture(_:)))
|
||||
selectionPanGesture.shouldBegin = { [weak self] in
|
||||
selectionPanGesture.shouldBegin = { [weak self] point in
|
||||
guard let self, let topItemContainer = self.itemContainers.last else {
|
||||
return false
|
||||
}
|
||||
|
|
@ -1663,6 +1758,9 @@ public final class ContextControllerActionsStackNodeImpl: ASDisplayNode, Context
|
|||
if topItemContainer.item is ContextControllerActionsCustomStackItem {
|
||||
return false
|
||||
}
|
||||
if !topItemContainer.highlightGestureShouldBegin(at: self.view.convert(point, to: topItemContainer.view)) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
@ -1959,32 +2057,25 @@ public final class ContextControllerActionsStackNodeImpl: ASDisplayNode, Context
|
|||
let tipTransition = transition
|
||||
var animateTipIn = false
|
||||
if tip.tipNode.supernode == nil {
|
||||
self.insertSubnode(tip.tipNode.shadowNode, at: 0)
|
||||
self.addSubnode(tip.tipNode)
|
||||
animateTipIn = transition.isAnimated
|
||||
let tipFrame = CGRect(origin: CGPoint(x: previousNavigationContainerFrame.minX, y: previousNavigationContainerFrame.maxY + tipSpacing), size: CGSize(width: itemLayouts[i].size.width, height: tip.tipHeight))
|
||||
tip.tipNode.frame = tipFrame
|
||||
tip.tipNode.setActualSize(size: tipFrame.size, transition: .immediate)
|
||||
transition.updateFrame(node: tip.tipNode.shadowNode, frame: tipFrame.insetBy(dx: -30.0, dy: -30.0))
|
||||
}
|
||||
|
||||
let tipAlpha: CGFloat = itemLayouts[i].alphaTransitionFraction
|
||||
|
||||
let tipFrame = CGRect(origin: CGPoint(x: navigationContainerFrame.minX, y: navigationContainerFrame.maxY + tipSpacing), size: CGSize(width: itemLayouts[i].size.width, height: tip.tipHeight))
|
||||
tipTransition.updateFrame(node: tip.tipNode, frame: tipFrame, beginWithCurrentState: true)
|
||||
transition.updateFrame(node: tip.tipNode.shadowNode, frame: tipFrame.insetBy(dx: -30.0, dy: -30.0))
|
||||
|
||||
tip.tipNode.setActualSize(size: tip.tipNode.bounds.size, transition: tipTransition)
|
||||
|
||||
if animateTipIn {
|
||||
tip.tipNode.alpha = tipAlpha
|
||||
tip.tipNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
|
||||
tip.tipNode.shadowNode.alpha = tipAlpha
|
||||
tip.tipNode.shadowNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
tip.tipNode.alpha = 0.0
|
||||
ComponentTransition.easeInOut(duration: 0.2).setAlpha(view: tip.tipNode.view, alpha: 1.0)
|
||||
} else {
|
||||
tipTransition.updateAlpha(node: tip.tipNode, alpha: tipAlpha, beginWithCurrentState: true)
|
||||
tipTransition.updateAlpha(node: tip.tipNode.shadowNode, alpha: tipAlpha, beginWithCurrentState: true)
|
||||
ComponentTransition(tipTransition).setAlpha(view: tip.tipNode.view, alpha: tipAlpha)
|
||||
}
|
||||
|
||||
if i == self.itemContainers.count - 1 {
|
||||
|
|
@ -2006,15 +2097,10 @@ public final class ContextControllerActionsStackNodeImpl: ASDisplayNode, Context
|
|||
if let tipNode = itemContainer.tipNode {
|
||||
let tipFrame = CGRect(origin: CGPoint(x: navigationContainerFrame.minX, y: navigationContainerFrame.maxY + tipSpacing), size: tipNode.frame.size)
|
||||
transition.updateFrame(node: tipNode, frame: tipFrame, beginWithCurrentState: true)
|
||||
transition.updateFrame(node: tipNode.shadowNode, frame: tipFrame.insetBy(dx: -30.0, dy: -30.0))
|
||||
|
||||
transition.updateAlpha(node: tipNode, alpha: 0.0, completion: { [weak tipNode] _ in
|
||||
ComponentTransition(transition).setAlpha(view: tipNode.view, alpha: 0.0, completion: { [weak tipNode] _ in
|
||||
tipNode?.removeFromSupernode()
|
||||
})
|
||||
let shadowNode = tipNode.shadowNode
|
||||
transition.updateAlpha(node: shadowNode, alpha: 0.0, completion: { [weak shadowNode] _ in
|
||||
shadowNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
}
|
||||
self.dismissingItemContainers.removeAll()
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@ public class EdgeEffectView: UIView {
|
|||
}
|
||||
|
||||
if blur {
|
||||
let blurHeight: CGFloat = max(edgeSize, bounds.height - 14.0)
|
||||
let blurFrame = CGRect(origin: CGPoint(x: 0.0, y: edge == .bottom ? (bounds.height - blurHeight) : 0.0), size: CGSize(width: bounds.width, height: blurHeight))
|
||||
|
||||
let blurView: VariableBlurView
|
||||
if let current = self.blurView {
|
||||
blurView = current
|
||||
|
|
@ -59,14 +62,15 @@ public class EdgeEffectView: UIView {
|
|||
self.insertSubview(blurView, at: 0)
|
||||
self.blurView = blurView
|
||||
}
|
||||
|
||||
blurView.update(
|
||||
size: bounds.size,
|
||||
constantHeight: edgeSize,
|
||||
size: blurFrame.size,
|
||||
constantHeight: max(1.0, edgeSize - 4.0),
|
||||
isInverted: edge == .bottom,
|
||||
gradient: EdgeEffectView.generateEdgeGradientData(baseHeight: edgeSize),
|
||||
gradient: EdgeEffectView.generateEdgeGradientData(baseHeight: max(1.0, edgeSize - 4.0)),
|
||||
transition: transition.containedViewLayoutTransition
|
||||
)
|
||||
transition.setFrame(view: blurView, frame: bounds)
|
||||
transition.setFrame(view: blurView, frame: blurFrame)
|
||||
blurView.transform = self.contentMaskView.transform
|
||||
} else if let blurView = self.blurView {
|
||||
self.blurView = nil
|
||||
|
|
|
|||
|
|
@ -159,12 +159,12 @@ public final class GiftLoadingShimmerView: UIView {
|
|||
let filterWidth = (size.width - sideInset * 2.0 - filterSpacing * 3.0) / 4.0
|
||||
for i in 0 ..< 4 {
|
||||
let rect = CGRect(origin: CGPoint(x: sideInset + (filterWidth + filterSpacing) * CGFloat(i), y: 0.0),
|
||||
size: CGSize(width: filterWidth, height: 28.0))
|
||||
context.addPath(CGPath(roundedRect: rect, cornerWidth: 14.0, cornerHeight: 14.0, transform: nil))
|
||||
size: CGSize(width: filterWidth, height: 36.0))
|
||||
context.addPath(CGPath(roundedRect: rect, cornerWidth: 36.0 * 0.5, cornerHeight: 36.0 * 0.5, transform: nil))
|
||||
}
|
||||
}
|
||||
|
||||
var currentY: CGFloat = 52.0 + 7.0
|
||||
var currentY: CGFloat = 52.0 + 16.0
|
||||
var rowIndex: Int = 0
|
||||
|
||||
let optionSpacing: CGFloat = 10.0
|
||||
|
|
@ -178,7 +178,7 @@ public final class GiftLoadingShimmerView: UIView {
|
|||
for i in 0 ..< 3 {
|
||||
let itemOrigin = CGPoint(
|
||||
x: sideInset + CGFloat(i) * (itemSize.width + optionSpacing),
|
||||
y: 39.0 + 9.0 + CGFloat(rowIndex) * (itemSize.height + optionSpacing)
|
||||
y: 39.0 + 13.0 + CGFloat(rowIndex) * (itemSize.height + optionSpacing)
|
||||
)
|
||||
context.addPath(CGPath(roundedRect: CGRect(origin: itemOrigin, size: itemSize),
|
||||
cornerWidth: 10.0, cornerHeight: 10.0, transform: nil))
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ private func actionForAttribute(attribute: StarGift.UniqueGift.Attribute, presen
|
|||
)
|
||||
title += count
|
||||
}
|
||||
|
||||
|
||||
let words = title.components(separatedBy: .whitespacesAndNewlines).filter { !$0.isEmpty }
|
||||
var wordStartIndices: [String.Index] = []
|
||||
|
|
@ -118,7 +117,9 @@ private func actionForAttribute(attribute: StarGift.UniqueGift.Attribute, presen
|
|||
}
|
||||
}
|
||||
|
||||
return ContextMenuActionItem(text: title, entities: entities, entityFiles: entityFiles, enableEntityAnimations: false, parseMarkdown: true, icon: { theme in
|
||||
return ContextMenuActionItem(text: title, entities: entities, entityFiles: entityFiles, enableEntityAnimations: false, customTextInsets: UIEdgeInsets(top: 0.0, left: 18.0 + 5.0, bottom: 0.0, right: 0.0), parseMarkdown: true, icon: { _ in
|
||||
return nil
|
||||
}, additionalLeftIcon: { theme in
|
||||
return isSelected ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
}, action: { _, f in
|
||||
getController()?.dismiss(result: .dismissWithoutContent, completion: nil)
|
||||
|
|
@ -134,7 +135,7 @@ private func actionForAttribute(attribute: StarGift.UniqueGift.Attribute, presen
|
|||
let isSelected = selectedAttributes.isEmpty || selectedAttributes.contains(attributeId)
|
||||
|
||||
var entities: [MessageTextEntity] = []
|
||||
var title = " \(name)"
|
||||
var title = "\(name)"
|
||||
var count = ""
|
||||
if let counter = item.attributeCount[attributeId] {
|
||||
count = " \(presentationStringsFormattedNumber(counter, presentationData.dateTimeFormat.groupingSeparator))"
|
||||
|
|
@ -177,10 +178,10 @@ private func actionForAttribute(attribute: StarGift.UniqueGift.Attribute, presen
|
|||
}
|
||||
}
|
||||
|
||||
return ContextMenuActionItem(text: title, entities: entities, icon: { theme in
|
||||
return isSelected ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
}, additionalLeftIcon: { _ in
|
||||
return ContextMenuActionItem(text: title, entities: entities, icon: { _ in
|
||||
return generateGradientFilledCircleImage(diameter: 24.0, colors: [UIColor(rgb: UInt32(bitPattern: innerColor)).cgColor, UIColor(rgb: UInt32(bitPattern: outerColor)).cgColor])
|
||||
}, additionalLeftIcon: { theme in
|
||||
return isSelected ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
}, action: { _, f in
|
||||
getController()?.dismiss(result: .dismissWithoutContent, completion: nil)
|
||||
|
||||
|
|
@ -212,6 +213,8 @@ private final class GiftAttributeListContextItemNode: ASDisplayNode, ContextMenu
|
|||
private var totalContentHeight: CGFloat = 0
|
||||
private var itemFrames: [AnyHashable: CGRect] = [:]
|
||||
|
||||
let needsPadding: Bool = false
|
||||
|
||||
init(presentationData: PresentationData, item: GiftAttributeListContextItem, getController: @escaping () -> ContextControllerProtocol?, actionSelected: @escaping (ContextMenuActionResult) -> Void) {
|
||||
self.item = item
|
||||
self.presentationData = presentationData.withUpdate(listsFontSize: .regular)
|
||||
|
|
@ -286,19 +289,12 @@ private final class GiftAttributeListContextItemNode: ASDisplayNode, ContextMenu
|
|||
yOffset += UIScreenPixel
|
||||
}
|
||||
|
||||
for (index, attribute) in effectiveAttributes.enumerated() {
|
||||
for (_, attribute) in effectiveAttributes.enumerated() {
|
||||
let attributeId = self.getAttributeId(from: attribute)
|
||||
let height = self.itemHeights[attributeId] ?? defaultHeight
|
||||
let frame = CGRect(x: 0, y: yOffset, width: constrainedWidth, height: height)
|
||||
items.append((attributeId, .attribute(attribute), frame))
|
||||
yOffset += height
|
||||
|
||||
if index < effectiveAttributes.count - 1 {
|
||||
let separatorId = AnyHashable("separator_\(attributeId)")
|
||||
let separatorFrame = CGRect(x: 0, y: yOffset, width: constrainedWidth, height: UIScreenPixel)
|
||||
items.append((separatorId, .separator, separatorFrame))
|
||||
yOffset += UIScreenPixel
|
||||
}
|
||||
}
|
||||
|
||||
if !self.searchQuery.isEmpty && effectiveAttributes.isEmpty {
|
||||
|
|
@ -467,7 +463,7 @@ private final class GiftAttributeListContextItemNode: ASDisplayNode, ContextMenu
|
|||
}
|
||||
|
||||
func updateLayout(constrainedWidth: CGFloat, constrainedHeight: CGFloat) -> (CGSize, (CGSize, ContainedViewLayoutTransition) -> Void) {
|
||||
let minActionsWidth: CGFloat = 250.0
|
||||
let minActionsWidth: CGFloat = 270.0
|
||||
let maxActionsWidth: CGFloat = 300.0
|
||||
let constrainedWidth = min(constrainedWidth, maxActionsWidth)
|
||||
let maxWidth = max(constrainedWidth, minActionsWidth)
|
||||
|
|
@ -503,7 +499,7 @@ private final class GiftAttributeListContextItemNode: ASDisplayNode, ContextMenu
|
|||
}
|
||||
|
||||
func canBeHighlighted() -> Bool {
|
||||
return self.isActionEnabled
|
||||
return false
|
||||
}
|
||||
|
||||
func updateIsHighlighted(isHighlighted: Bool) {
|
||||
|
|
|
|||
|
|
@ -133,9 +133,9 @@ final class GiftStoreScreenComponent: Component {
|
|||
|
||||
self.scrollView.delegate = self
|
||||
self.addSubview(self.scrollView)
|
||||
self.addSubview(self.loadingView)
|
||||
|
||||
self.addSubview(self.edgeEffectView)
|
||||
self.addSubview(self.loadingView)
|
||||
|
||||
self.scrollView.layer.addSublayer(self.topOverscrollLayer)
|
||||
}
|
||||
|
|
@ -415,7 +415,7 @@ final class GiftStoreScreenComponent: Component {
|
|||
if view.superview == nil {
|
||||
view.alpha = 0.0
|
||||
fadeTransition.setAlpha(view: view, alpha: 1.0)
|
||||
self.insertSubview(view, belowSubview: self.loadingView)
|
||||
self.insertSubview(view, aboveSubview: self.scrollView)
|
||||
view.playOnce()
|
||||
}
|
||||
view.bounds = CGRect(origin: .zero, size: emptyResultsAnimationFrame.size)
|
||||
|
|
@ -425,7 +425,7 @@ final class GiftStoreScreenComponent: Component {
|
|||
if view.superview == nil {
|
||||
view.alpha = 0.0
|
||||
fadeTransition.setAlpha(view: view, alpha: 1.0)
|
||||
self.insertSubview(view, belowSubview: self.loadingView)
|
||||
self.insertSubview(view, aboveSubview: self.scrollView)
|
||||
}
|
||||
view.bounds = CGRect(origin: .zero, size: emptyResultsTitleFrame.size)
|
||||
ComponentTransition.immediate.setPosition(view: view, position: emptyResultsTitleFrame.center)
|
||||
|
|
@ -1203,7 +1203,7 @@ final class GiftStoreScreenComponent: Component {
|
|||
} else {
|
||||
loadingTransition.setAlpha(view: self.loadingView, alpha: 0.0)
|
||||
}
|
||||
transition.setFrame(view: self.loadingView, frame: CGRect(origin: CGPoint(x: 0.0, y: environment.navigationHeight), size: availableSize))
|
||||
transition.setFrame(view: self.loadingView, frame: CGRect(origin: CGPoint(x: 0.0, y: environment.navigationHeight + 10.0), size: availableSize))
|
||||
|
||||
return availableSize
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ private final class SearchContextItemNode: ASDisplayNode, ContextMenuCustomNode,
|
|||
environment: {},
|
||||
containerSize: size
|
||||
)
|
||||
let iconFrame = CGRect(origin: CGPoint(x: 17.0, y: floorToScreenPixels((size.height - iconSize.height) / 2.0)), size: iconSize)
|
||||
let iconFrame = CGRect(origin: CGPoint(x: 23.0, y: floorToScreenPixels((size.height - iconSize.height) / 2.0)), size: iconSize)
|
||||
if let iconView = self.icon.view {
|
||||
if iconView.superview == nil {
|
||||
self.view.addSubview(iconView)
|
||||
|
|
@ -88,7 +88,7 @@ private final class SearchContextItemNode: ASDisplayNode, ContextMenuCustomNode,
|
|||
transition.setFrame(view: iconView, frame: iconFrame)
|
||||
}
|
||||
|
||||
let inputInset: CGFloat = 42.0
|
||||
let inputInset: CGFloat = 46.0
|
||||
|
||||
self.inputField.parentState = self.state
|
||||
let inputFieldSize = self.inputField.update(
|
||||
|
|
|
|||
|
|
@ -305,6 +305,8 @@ public final class HorizontalTabsComponent: Component {
|
|||
private var tabSwitchFraction: CGFloat = 0.0
|
||||
private var isDraggingTabs: Bool = false
|
||||
private var temporaryLiftTimer: Foundation.Timer?
|
||||
private var didTapOnAnItem: Bool = false
|
||||
private var didTapOnAnItemTimer: Foundation.Timer?
|
||||
|
||||
private var tapRecognizer: UITapGestureRecognizer?
|
||||
|
||||
|
|
@ -531,6 +533,14 @@ public final class HorizontalTabsComponent: Component {
|
|||
for (id, itemView) in self.itemViews {
|
||||
if self.scrollView.convert(itemView.selectionFrame, to: self).contains(point) {
|
||||
if let tab = component.tabs.first(where: { $0.id == id }) {
|
||||
self.didTapOnAnItem = true
|
||||
self.didTapOnAnItemTimer?.invalidate()
|
||||
self.didTapOnAnItemTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false, block: { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.didTapOnAnItem = false
|
||||
})
|
||||
tab.action()
|
||||
}
|
||||
}
|
||||
|
|
@ -609,7 +619,7 @@ public final class HorizontalTabsComponent: Component {
|
|||
self.temporaryLiftTimer?.invalidate()
|
||||
self.temporaryLiftTimer = nil
|
||||
|
||||
if !transition.animation.isImmediate {
|
||||
if !transition.animation.isImmediate && self.didTapOnAnItem {
|
||||
self.temporaryLiftTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 0.3, repeats: false, block: { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
|
|
@ -627,6 +637,12 @@ public final class HorizontalTabsComponent: Component {
|
|||
self.component = component
|
||||
self.state = state
|
||||
|
||||
self.didTapOnAnItem = false
|
||||
if let didTapOnAnItemTimer = self.didTapOnAnItemTimer {
|
||||
self.didTapOnAnItemTimer = nil
|
||||
didTapOnAnItemTimer.invalidate()
|
||||
}
|
||||
|
||||
self.reorderingGesture?.isEnabled = component.isEditing
|
||||
|
||||
let sizeHeight: CGFloat = availableSize.height
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
if let backgroundContainer = self.backgroundContainer {
|
||||
backgroundContainer.contentView.addSubview(titleView)
|
||||
} else {
|
||||
self.buttonsContainerNode.view.addSubview(titleView)
|
||||
self.buttonsContainerNode.view.insertSubview(titleView, at: 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -814,10 +814,13 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
edgeEffectView.isHidden = true
|
||||
} else {
|
||||
edgeEffectView.isHidden = false
|
||||
let edgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: -20.0), size: CGSize(width: size.width, height: size.height + additionalBackgroundHeight + 20.0 + 20.0))
|
||||
|
||||
let edgeEffectHeight: CGFloat = size.height + additionalBackgroundHeight + 24.0
|
||||
|
||||
let edgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: -20.0), size: CGSize(width: size.width, height: 20.0 + edgeEffectHeight))
|
||||
transition.updatePosition(layer: edgeEffectView.layer, position: edgeEffectFrame.center)
|
||||
transition.updateBounds(layer: edgeEffectView.layer, bounds: CGRect(origin: CGPoint(), size: edgeEffectFrame.size))
|
||||
edgeEffectView.update(content: self.presentationData.theme.edgeEffectColor ?? .white, blur: true, rect: CGRect(origin: CGPoint(), size: edgeEffectFrame.size), edge: .top, edgeSize: 50.0, transition: ComponentTransition(transition))
|
||||
edgeEffectView.update(content: self.presentationData.theme.edgeEffectColor ?? .white, blur: true, rect: CGRect(origin: CGPoint(), size: edgeEffectFrame.size), edge: .top, edgeSize: min(64.0, edgeEffectHeight), transition: ComponentTransition(transition))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -228,6 +228,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||
let edgeEffectView: EdgeEffectView
|
||||
|
||||
let headerNode: PeerInfoHeaderNode
|
||||
var underHeaderContentsAlpha: CGFloat = 1.0
|
||||
var regularSections: [AnyHashable: PeerInfoScreenItemSectionContainerNode] = [:]
|
||||
var editingSections: [AnyHashable: PeerInfoScreenItemSectionContainerNode] = [:]
|
||||
let paneContainerNode: PeerInfoPaneContainerNode
|
||||
|
|
@ -2059,6 +2060,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.underHeaderContentsAlpha = alpha
|
||||
if !self.state.isEditing {
|
||||
for (_, section) in self.regularSections {
|
||||
transition.updateAlpha(node: section, alpha: alpha)
|
||||
|
|
@ -5293,7 +5295,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||
|
||||
if wasAdded && transition.isAnimated && (self.isSettings || self.isMyProfile) && !self.state.isEditing {
|
||||
sectionNode.alpha = 0.0
|
||||
transition.updateAlpha(node: sectionNode, alpha: 1.0, delay: 0.1)
|
||||
transition.updateAlpha(node: sectionNode, alpha: self.underHeaderContentsAlpha, delay: 0.1)
|
||||
}
|
||||
|
||||
let sectionWidth = layout.size.width - insets.left - insets.right
|
||||
|
|
@ -5312,7 +5314,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||
|
||||
if wasAdded && transition.isAnimated && (self.isSettings || self.isMyProfile) && !self.state.isEditing {
|
||||
} else {
|
||||
transition.updateAlpha(node: sectionNode, alpha: self.state.isEditing ? 0.0 : 1.0)
|
||||
transition.updateAlpha(node: sectionNode, alpha: self.state.isEditing ? 0.0 : self.underHeaderContentsAlpha)
|
||||
}
|
||||
if !sectionHeight.isZero && !self.state.isEditing {
|
||||
contentHeight += sectionHeight
|
||||
|
|
|
|||
|
|
@ -360,7 +360,7 @@ extension PeerInfoScreenNode {
|
|||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ShowPhotos, icon: { theme in
|
||||
if !showPhotos {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak pane] _, a in
|
||||
|
|
@ -384,7 +384,7 @@ extension PeerInfoScreenNode {
|
|||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ShowVideos, icon: { theme in
|
||||
if !showVideos {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak pane] _, a in
|
||||
|
|
|
|||
|
|
@ -113,7 +113,6 @@ private final class AccountPeerContextItemNode: ASDisplayNode, ContextMenuCustom
|
|||
private let getController: () -> ContextControllerProtocol?
|
||||
private let actionSelected: (ContextMenuActionResult) -> Void
|
||||
|
||||
private let highlightedBackgroundNode: ASDisplayNode
|
||||
private let buttonNode: HighlightTrackingButtonNode
|
||||
private let textNode: ImmediateTextNode
|
||||
private let avatarNode: AvatarNode
|
||||
|
|
@ -127,11 +126,6 @@ private final class AccountPeerContextItemNode: ASDisplayNode, ContextMenuCustom
|
|||
|
||||
let textFont = Font.regular(presentationData.listsFontSize.baseDisplaySize * 17.0 / 17.0)
|
||||
|
||||
self.highlightedBackgroundNode = ASDisplayNode()
|
||||
self.highlightedBackgroundNode.isAccessibilityElement = false
|
||||
self.highlightedBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor
|
||||
self.highlightedBackgroundNode.alpha = 0.0
|
||||
|
||||
self.textNode = ImmediateTextNode()
|
||||
self.textNode.isAccessibilityElement = false
|
||||
self.textNode.isUserInteractionEnabled = false
|
||||
|
|
@ -150,29 +144,17 @@ private final class AccountPeerContextItemNode: ASDisplayNode, ContextMenuCustom
|
|||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.highlightedBackgroundNode)
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.avatarNode)
|
||||
self.addSubnode(self.buttonNode)
|
||||
|
||||
self.buttonNode.highligthedChanged = { [weak self] highligted in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if highligted {
|
||||
strongSelf.highlightedBackgroundNode.alpha = 1.0
|
||||
} else {
|
||||
strongSelf.highlightedBackgroundNode.alpha = 0.0
|
||||
strongSelf.highlightedBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
|
||||
}
|
||||
}
|
||||
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
||||
func updateLayout(constrainedWidth: CGFloat, constrainedHeight: CGFloat) -> (CGSize, (CGSize, ContainedViewLayoutTransition) -> Void) {
|
||||
let sideInset: CGFloat = 16.0
|
||||
let iconSideInset: CGFloat = 12.0
|
||||
let verticalInset: CGFloat = 12.0
|
||||
let sideInset: CGFloat = 18.0
|
||||
let iconSideInset: CGFloat = 20.0
|
||||
let verticalInset: CGFloat = 11.0
|
||||
|
||||
let iconSize = CGSize(width: 28.0, height: 28.0)
|
||||
|
||||
|
|
@ -192,7 +174,7 @@ private final class AccountPeerContextItemNode: ASDisplayNode, ContextMenuCustom
|
|||
|
||||
return (CGSize(width: textSize.width + sideInset + rightTextInset, height: verticalInset * 2.0 + textSize.height), { size, transition in
|
||||
let verticalOrigin = floor((size.height - textSize.height) / 2.0)
|
||||
let textFrame = CGRect(origin: CGPoint(x: sideInset, y: verticalOrigin), size: textSize)
|
||||
let textFrame = CGRect(origin: CGPoint(x: iconSideInset + 40.0, y: verticalOrigin), size: textSize)
|
||||
transition.updateFrameAdditive(node: self.textNode, frame: textFrame)
|
||||
|
||||
var iconContent: EmojiStatusComponent.Content?
|
||||
|
|
@ -229,16 +211,13 @@ private final class AccountPeerContextItemNode: ASDisplayNode, ContextMenuCustom
|
|||
}
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.avatarNode, frame: CGRect(origin: CGPoint(x: size.width - standardIconWidth - iconSideInset + floor((standardIconWidth - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize))
|
||||
transition.updateFrame(node: self.avatarNode, frame: CGRect(origin: CGPoint(x: iconSideInset + floor((standardIconWidth - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize))
|
||||
|
||||
transition.updateFrame(node: self.highlightedBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
|
||||
transition.updateFrame(node: self.buttonNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
|
||||
})
|
||||
}
|
||||
|
||||
func updateTheme(presentationData: PresentationData) {
|
||||
self.highlightedBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor
|
||||
|
||||
if let attributedText = self.textNode.attributedText {
|
||||
let updatedAttributedText = NSMutableAttributedString(attributedString: attributedText)
|
||||
updatedAttributedText.addAttribute(.foregroundColor, value: presentationData.theme.contextMenu.primaryColor.cgColor, range: NSRange(location: 0, length: updatedAttributedText.length))
|
||||
|
|
@ -255,11 +234,6 @@ private final class AccountPeerContextItemNode: ASDisplayNode, ContextMenuCustom
|
|||
}
|
||||
|
||||
func setIsHighlighted(_ value: Bool) {
|
||||
if value {
|
||||
self.highlightedBackgroundNode.alpha = 1.0
|
||||
} else {
|
||||
self.highlightedBackgroundNode.alpha = 0.0
|
||||
}
|
||||
}
|
||||
|
||||
func updateIsHighlighted(isHighlighted: Bool) {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@ private final class SectionTitleContextItemNode: ASDisplayNode, ContextMenuCusto
|
|||
return false
|
||||
}
|
||||
|
||||
var needsPadding: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
init(presentationData: PresentationData, item: SectionTitleContextItem, getController: @escaping () -> ContextControllerProtocol?, actionSelected: @escaping (ContextMenuActionResult) -> Void) {
|
||||
self.item = item
|
||||
self.presentationData = presentationData
|
||||
|
|
@ -56,17 +60,17 @@ private final class SectionTitleContextItemNode: ASDisplayNode, ContextMenuCusto
|
|||
}
|
||||
|
||||
func updateLayout(constrainedWidth: CGFloat, constrainedHeight: CGFloat) -> (CGSize, (CGSize, ContainedViewLayoutTransition) -> Void) {
|
||||
let sideInset: CGFloat = 16.0
|
||||
let sideInset: CGFloat = 18.0 + 4.0
|
||||
|
||||
let textSize = self.textNode.updateLayout(CGSize(width: constrainedWidth - sideInset - sideInset, height: .greatestFiniteMagnitude))
|
||||
let height: CGFloat = 28.0
|
||||
let height: CGFloat = 10.0 + 28.0
|
||||
|
||||
return (CGSize(width: textSize.width + sideInset + sideInset, height: height), { size, transition in
|
||||
let verticalOrigin = floor((size.height - textSize.height) / 2.0)
|
||||
let verticalOrigin = floor((size.height - 10.0 - textSize.height) / 2.0)
|
||||
let textFrame = CGRect(origin: CGPoint(x: sideInset, y: verticalOrigin), size: textSize)
|
||||
transition.updateFrameAdditive(node: self.textNode, frame: textFrame)
|
||||
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height - 10.0)))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,12 +47,17 @@ private final class SliderContextItemNode: ASDisplayNode, ContextMenuCustomNode,
|
|||
let title: String?
|
||||
let minValue: CGFloat
|
||||
let maxValue: CGFloat
|
||||
var suppressAnimation = false
|
||||
var value: CGFloat = 1.0 {
|
||||
didSet {
|
||||
self.updateValue(transition: .animated(duration: 0.2, curve: .spring))
|
||||
self.updateValue(transition: self.suppressAnimation ? .immediate :.animated(duration: 0.2, curve: .spring))
|
||||
}
|
||||
}
|
||||
|
||||
public var needsPadding: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
private let valueChanged: (CGFloat, Bool) -> Void
|
||||
|
||||
private let hapticFeedback = HapticFeedback()
|
||||
|
|
@ -167,11 +172,21 @@ private final class SliderContextItemNode: ASDisplayNode, ContextMenuCustomNode,
|
|||
}
|
||||
|
||||
private func updateValue(transition: ContainedViewLayoutTransition = .immediate) {
|
||||
let width = self.frame.width
|
||||
let sideInset: CGFloat = 10.0
|
||||
let width = self.frame.width - sideInset * 2.0
|
||||
|
||||
let range = self.maxValue - self.minValue
|
||||
let value = (self.value - self.minValue) / range
|
||||
transition.updateFrameAdditive(node: self.foregroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: value * width, height: self.frame.height)))
|
||||
var foregroundFrame = CGRect(origin: CGPoint(x: sideInset, y: 0.0), size: CGSize(width: value * width, height: self.frame.height))
|
||||
var foregroundOffset: CGFloat = 0.0
|
||||
if foregroundFrame.width < 40.0 {
|
||||
foregroundOffset = (40.0 - foregroundFrame.width) * 0.5
|
||||
foregroundFrame = foregroundFrame.insetBy(dx: 0.0, dy: foregroundOffset)
|
||||
}
|
||||
transition.updateFrameAdditive(node: self.foregroundNode, frame: foregroundFrame)
|
||||
transition.updateSublayerTransformOffset(layer: self.foregroundNode.layer, offset: CGPoint(x: 0.0, y: -foregroundOffset))
|
||||
|
||||
transition.updateCornerRadius(node: self.foregroundNode, cornerRadius: min(20.0, foregroundFrame.width * 0.5))
|
||||
|
||||
let stringValue = String(format: "%.1fx", self.value)
|
||||
|
||||
|
|
@ -221,9 +236,10 @@ private final class SliderContextItemNode: ASDisplayNode, ContextMenuCustomNode,
|
|||
let _ = self.foregroundTitleNode.updateLayout(CGSize(width: 120.0, height: 100.0))
|
||||
|
||||
return (CGSize(width: height * 3.0, height: height), { size, transition in
|
||||
let leftInset: CGFloat = 17.0
|
||||
let leftInset: CGFloat = 10.0
|
||||
let sideInset: CGFloat = 10.0
|
||||
|
||||
self.vibrancyEffectView?.frame = CGRect(origin: .zero, size: size)
|
||||
self.vibrancyEffectView?.frame = CGRect(origin: CGPoint(x: sideInset, y: 0.0), size: CGSize(width: size.width - sideInset * 2.0, height: size.height))
|
||||
|
||||
let backgroundTextWidth = self.backgroundTextNode.updateLayout(size: CGSize(width: 70.0, height: .greatestFiniteMagnitude), animated: true).width
|
||||
|
||||
|
|
@ -235,18 +251,18 @@ private final class SliderContextItemNode: ASDisplayNode, ContextMenuCustomNode,
|
|||
titleFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((height - backgroundTitleSize.height) / 2.0)), size: backgroundTitleSize)
|
||||
|
||||
if self.title != nil {
|
||||
textFrame = CGRect(origin: CGPoint(x: size.width - leftInset - backgroundTextWidth, y: floor((height - backgroundTextSize.height) / 2.0)), size: backgroundTextSize)
|
||||
textFrame = CGRect(origin: CGPoint(x: size.width - sideInset - leftInset - backgroundTextWidth, y: floor((height - backgroundTextSize.height) / 2.0)), size: backgroundTextSize)
|
||||
} else {
|
||||
textFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((height - backgroundTextSize.height) / 2.0)), size: backgroundTextSize)
|
||||
textFrame = CGRect(origin: CGPoint(x: leftInset + sideInset, y: floor((height - backgroundTextSize.height) / 2.0)), size: backgroundTextSize)
|
||||
}
|
||||
|
||||
transition.updateFrameAdditive(node: self.dimBackgroundTitleNode, frame: titleFrame)
|
||||
transition.updateFrameAdditive(node: self.backgroundTitleNode, frame: titleFrame)
|
||||
transition.updateFrameAdditive(node: self.backgroundTitleNode, frame: titleFrame.offsetBy(dx: sideInset, dy: 0.0))
|
||||
transition.updateFrameAdditive(node: self.foregroundTitleNode, frame: titleFrame)
|
||||
|
||||
transition.updateFrameAdditive(node: self.dimBackgroundTextNode, frame: textFrame)
|
||||
transition.updateFrameAdditive(node: self.backgroundTextNode, frame: textFrame)
|
||||
transition.updateFrameAdditive(node: self.foregroundTextNode, frame: textFrame)
|
||||
transition.updateFrameAdditive(node: self.foregroundTextNode, frame: textFrame.offsetBy(dx: -sideInset, dy: 0.0))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -260,7 +276,9 @@ private final class SliderContextItemNode: ASDisplayNode, ContextMenuCustomNode,
|
|||
|
||||
let translation: CGFloat = gestureRecognizer.translation(in: gestureRecognizer.view).x
|
||||
let delta = translation / self.bounds.width * range
|
||||
self.suppressAnimation = true
|
||||
self.value = max(self.minValue, min(self.maxValue, self.value + delta))
|
||||
self.suppressAnimation = false
|
||||
gestureRecognizer.setTranslation(CGPoint(), in: gestureRecognizer.view)
|
||||
|
||||
if self.value == 2.0 && previousValue != 2.0 {
|
||||
|
|
|
|||
|
|
@ -2242,14 +2242,17 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
edgeEffectAlpha = self.chatPresentationInterfaceState.chatWallpaper.singleColor != nil ? 0.85 : 0.75
|
||||
}
|
||||
|
||||
|
||||
var bottomBackgroundEdgeEffectNode: WallpaperEdgeEffectNode?
|
||||
if let current = self.bottomBackgroundEdgeEffectNode {
|
||||
bottomBackgroundEdgeEffectNode = current
|
||||
} else {
|
||||
if let value = self.backgroundNode.makeEdgeEffectNode() {
|
||||
bottomBackgroundEdgeEffectNode = value
|
||||
self.bottomBackgroundEdgeEffectNode = value
|
||||
self.historyNodeContainer.view.superview?.insertSubview(value.view, aboveSubview: self.historyNodeContainer.view)
|
||||
if self.historyNode.rotated {
|
||||
if let current = self.bottomBackgroundEdgeEffectNode {
|
||||
bottomBackgroundEdgeEffectNode = current
|
||||
} else {
|
||||
if let value = self.backgroundNode.makeEdgeEffectNode() {
|
||||
bottomBackgroundEdgeEffectNode = value
|
||||
self.bottomBackgroundEdgeEffectNode = value
|
||||
self.historyNodeContainer.view.superview?.insertSubview(value.view, aboveSubview: self.historyNodeContainer.view)
|
||||
}
|
||||
}
|
||||
}
|
||||
if let bottomBackgroundEdgeEffectNode {
|
||||
|
|
@ -2451,13 +2454,15 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
})
|
||||
|
||||
var topBackgroundEdgeEffectNode: WallpaperEdgeEffectNode?
|
||||
if let current = self.topBackgroundEdgeEffectNode {
|
||||
topBackgroundEdgeEffectNode = current
|
||||
} else {
|
||||
if let value = self.backgroundNode.makeEdgeEffectNode() {
|
||||
topBackgroundEdgeEffectNode = value
|
||||
self.topBackgroundEdgeEffectNode = value
|
||||
self.historyNodeContainer.view.superview?.insertSubview(value.view, aboveSubview: self.historyNodeContainer.view)
|
||||
if self.historyNode.rotated {
|
||||
if let current = self.topBackgroundEdgeEffectNode {
|
||||
topBackgroundEdgeEffectNode = current
|
||||
} else {
|
||||
if let value = self.backgroundNode.makeEdgeEffectNode() {
|
||||
topBackgroundEdgeEffectNode = value
|
||||
self.topBackgroundEdgeEffectNode = value
|
||||
self.historyNodeContainer.view.superview?.insertSubview(value.view, aboveSubview: self.historyNodeContainer.view)
|
||||
}
|
||||
}
|
||||
}
|
||||
if let topBackgroundEdgeEffectNode {
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ class ChatHistoryNavigationButtonNode: ContextControllerSourceNode {
|
|||
}
|
||||
|
||||
self.badgeBackgroundView = GlassBackgroundView()
|
||||
self.badgeBackgroundView.isUserInteractionEnabled = false
|
||||
self.badgeBackgroundView.alpha = 0.0
|
||||
|
||||
self.badgeTextNode = ImmediateAnimatedCountLabelNode()
|
||||
|
|
|
|||
|
|
@ -178,10 +178,8 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||
self.title = self.titleProducer(self.presentationData.strings)
|
||||
|
||||
if glass {
|
||||
|
||||
} else {
|
||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
|
||||
}
|
||||
|
||||
if self.multipleSelection == .always {
|
||||
|
|
@ -413,15 +411,6 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
if let presentationArguments = self.presentationArguments as? ViewControllerPresentationArguments {
|
||||
switch presentationArguments.presentationAnimation {
|
||||
case .modalSheet:
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(cancelPressed))
|
||||
case .none:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
self.contactsNode.contactListNode.enableUpdates = true
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue