Various improvements

This commit is contained in:
Isaac 2025-09-23 20:49:12 +08:00
parent bf3ec930bc
commit 3684c6ca15
34 changed files with 593 additions and 339 deletions

View File

@ -309,6 +309,8 @@ alternate_icon_folders = [
"PremiumTurbo",
]
composer_icon_folders = ["Telegram"]
[
filegroup(
name = "{}".format(name),
@ -318,6 +320,15 @@ alternate_icon_folders = [
) for name in alternate_icon_folders
]
[
filegroup(
name = "{}_icon".format(name),
srcs = glob([
"Telegram-iOS/{}.icon/**/*".format(name),
]),
) for name in composer_icon_folders
]
filegroup(
name = "LaunchScreen",
srcs = glob([
@ -1699,12 +1710,13 @@ ios_application(
":RequiredDeviceCapabilitiesPlist",
":UrlTypesInfoPlist",
],
app_icons = [ ":{}_icon".format(name) for name in composer_icon_folders ],
alternate_icons = [
":{}".format(name) for name in alternate_icon_folders
],
resources = [
":LaunchScreen",
":DefaultAppIcon",
#":DefaultAppIcon",
],
frameworks = [
":MtProtoKitFramework",

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1024px" height="1024px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Oval</title>
<g id="Oval" stroke="none" fill="none" fill-rule="nonzero">
<circle fill="#000000" cx="512" cy="512" r="410.5"></circle>
</g>
</svg>

After

Width:  |  Height:  |  Size: 364 B

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1024px" height="1024px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Plane</title>
<g id="Plane" stroke="none" fill="none" fill-rule="nonzero">
<path d="M287.315632,507.666819 C406.984718,455.528898 486.782853,421.15639 526.710034,404.549294 C640.710251,357.13266 664.39852,348.895883 679.838202,348.621 C683.234017,348.56408 690.826804,349.405665 695.745092,353.396516 C699.897998,356.766313 701.040629,361.31843 701.587414,364.513367 C702.1342,367.708304 702.815079,374.986453 702.273832,380.673387 C696.09612,445.583141 669.36526,603.101997 655.766116,675.802034 C650.011808,706.564145 638.681397,716.878524 627.712247,717.887922 C603.873746,720.081578 585.77187,702.133777 562.683116,686.998808 C526.553773,663.315568 506.142993,648.572678 471.073211,625.462211 C430.544009,598.754068 456.817404,584.074808 479.914878,560.08479 C485.959597,553.806488 590.992581,458.270869 593.025497,449.604291 C593.279747,448.520391 593.515704,444.480123 591.115452,442.346714 C588.715199,440.213304 585.172634,440.942847 582.61622,441.52306 C578.99258,442.345492 521.275488,480.49435 409.464943,555.969631 C393.082138,567.219329 378.243103,572.700559 364.947836,572.413323 C350.290871,572.096667 322.096751,564.126052 301.137321,557.312967 C275.429726,548.956441 254.997841,544.538286 256.777,530.34632 C257.703696,522.954266 267.883239,515.394432 287.315632,507.666819 Z" id="Path-3" fill="#FFFFFF"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,122 @@
{
"fill" : "system-light",
"groups" : [
{
"blend-mode" : "normal",
"blur-material" : 1,
"layers" : [
{
"blend-mode-specializations" : [
{
"value" : "normal"
},
{
"appearance" : "dark",
"value" : "normal"
}
],
"fill-specializations" : [
{
"appearance" : "dark",
"value" : "automatic"
}
],
"glass" : true,
"image-name" : "Plane.svg",
"name" : "Plane",
"position-specializations" : [
{
"idiom" : "watchOS",
"value" : {
"scale" : 1.35,
"translation-in-points" : [
0,
0
]
}
}
]
},
{
"blend-mode-specializations" : [
{
"value" : "normal"
},
{
"appearance" : "dark",
"value" : "normal"
}
],
"fill-specializations" : [
{
"value" : {
"linear-gradient" : [
"display-p3:0.21569,0.68627,0.89020,1.00000",
"srgb:0.11373,0.57647,0.82353,1.00000"
]
}
},
{
"appearance" : "dark",
"value" : {
"automatic-gradient" : "srgb:0.00000,0.47843,1.00000,1.00000"
}
}
],
"glass" : true,
"hidden-specializations" : [
{
"value" : false
},
{
"idiom" : "watchOS",
"value" : false
}
],
"image-name" : "Oval.svg",
"name" : "Oval",
"position-specializations" : [
{
"idiom" : "watchOS",
"value" : {
"scale" : 2,
"translation-in-points" : [
0,
0
]
}
}
]
}
],
"lighting" : "combined",
"position-specializations" : [
{
"idiom" : "watchOS",
"value" : {
"scale" : 1,
"translation-in-points" : [
0,
0
]
}
}
],
"shadow" : {
"kind" : "layer-color",
"opacity" : 1
},
"specular" : true,
"translucency" : {
"enabled" : false,
"value" : 1
}
}
],
"supported-platforms" : {
"circles" : [
"watchOS"
],
"squares" : "shared"
}
}

View File

@ -15077,3 +15077,14 @@ Error: %8$@";
"Conversation.SuggestedBirthdate.View" = "View";
"PeerInfo.ChangeProfileColor" = "Change Profile Color";
"PUSH_MESSAGE_TODO" = "%1$@|sent you a todo-list %2$@";
"PUSH_CHANNEL_MESSAGE_TODO" = "%1$@|posted a todo-list %2$@";
"PUSH_CHANNEL_MESSAGE_TODO_DONE" = "%1$@|toggled %2$@ tasks";
"PUSH_CHANNEL_MESSAGE_TODO_APPEND" = "%1$@|added %2$@ tasks";
"PUSH_CHAT_MESSAGE_TODO" = "%2$@|%1$@ sent a todo-list %3$@";
"PUSH_CHAT_MESSAGE_TODO_DONE" = "%2$@|%1$@ toggled %3$@ tasks";
"PUSH_CHAT_MESSAGE_TODO_APPEND" = "%2$@|%1$@ added %3$@ tasks";
"PUSH_PINNED_TODO" = "%1$@|pinned a todo-list %2$@";
"PUSH_REACT_TODO" = "%1$@|reacted %2$@ to your todo %3$@";
"PUSH_CHAT_REACT_TODO" = "%2$@|%1$@ reacted %3$@ to your todo %4$@";

View File

@ -700,6 +700,9 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
let hadLayout = self.validLayout != nil
let previousAdditionalSideInsets = self.validLayout?.3
self.validLayout = (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary)
let leftInset = leftInset + 8.0
let rightInset = rightInset + 8.0
var transition = transition
if let previousAdditionalSideInsets = previousAdditionalSideInsets, previousAdditionalSideInsets.right != additionalSideInsets.right {
@ -933,9 +936,13 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
}
private func updateFieldAndButtonsLayout(inputHasText: Bool, panelHeight: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
guard let (width, leftInset, rightInset, additionalSideInsets, _, metrics, _) = self.validLayout else {
guard let (width, leftInsetValue, rightInsetValue, additionalSideInsets, _, metrics, _) = self.validLayout else {
return 0.0
}
let leftInset = leftInsetValue + 8.0
let rightInset = rightInsetValue + 8.0
var textFieldMinHeight: CGFloat = 33.0
if let presentationInterfaceState = self.presentationInterfaceState {
textFieldMinHeight = calclulateTextFieldMinHeight(presentationInterfaceState, metrics: metrics)
@ -1280,6 +1287,9 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
if let (width, leftInset, rightInset, _, maxHeight, metrics, _) = self.validLayout {
let composeButtonsOffset: CGFloat = 0.0
let leftInset = leftInset + 8.0
let rightInset = rightInset + 8.0
let (_, textFieldHeight) = self.calculateTextFieldMetrics(width: width - leftInset - rightInset, maxHeight: maxHeight, metrics: metrics)
let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics)
var textFieldMinHeight: CGFloat = 33.0
@ -1421,6 +1431,9 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
private func updateTextHeight(animated: Bool) -> CGFloat? {
if let (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, _) = self.validLayout {
let leftInset = leftInset + 8.0
let rightInset = rightInset + 8.0
let (_, textFieldHeight) = self.calculateTextFieldMetrics(width: width - leftInset - rightInset - additionalSideInsets.right, maxHeight: maxHeight, metrics: metrics)
let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics)
if !self.bounds.size.height.isEqual(to: panelHeight) {

View File

@ -124,14 +124,16 @@ public enum ChatListItemContent {
public var hideSeparator: Bool
public var hideDate: Bool
public var hidePeerStatus: Bool
public var isInTransparentContainer: Bool
public init(commandPrefix: String?, searchQuery: String?, messageCount: Int?, hideSeparator: Bool, hideDate: Bool, hidePeerStatus: Bool) {
public init(commandPrefix: String?, searchQuery: String?, messageCount: Int?, hideSeparator: Bool, hideDate: Bool, hidePeerStatus: Bool, isInTransparentContainer: Bool = false) {
self.commandPrefix = commandPrefix
self.searchQuery = searchQuery
self.messageCount = messageCount
self.hideSeparator = hideSeparator
self.hideDate = hideDate
self.hidePeerStatus = hidePeerStatus
self.isInTransparentContainer = isInTransparentContainer
}
}
@ -1966,6 +1968,11 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
reallyHighlighted = true
}
}
if case let .peer(peerData) = item.content, let customMessageListData = peerData.customMessageListData {
if customMessageListData.isInTransparentContainer {
reallyHighlighted = false
}
}
}
return reallyHighlighted
}

View File

@ -104,7 +104,34 @@ public extension CALayer {
return animation
} else if timingFunction == kCAMediaTimingFunctionSpring {
if duration == 0.5 {
if #available(iOS 26.0, *) {
let animation = make26SpringAnimationImpl(keyPath, duration)
animation.fromValue = from
animation.toValue = to
animation.isRemovedOnCompletion = removeOnCompletion
animation.fillMode = .forwards
if let completion {
animation.delegate = CALayerAnimationDelegate(animation: animation, completion: completion)
}
let k = Float(UIView.animationDurationFactor())
var speed: Float = 1.0
if k != 0 && k != 1 {
speed = Float(1.0) / k
}
animation.speed = speed * Float(animation.duration / duration)
animation.isAdditive = additive
if !delay.isZero {
animation.beginTime = self.convertTime(CACurrentMediaTime(), from: nil) + delay * UIView.animationDurationFactor()
animation.fillMode = .both
}
adjustFrameRate(animation: animation)
return animation
} else if duration == 0.5 {
let animation = makeSpringAnimation(keyPath)
animation.fromValue = from
animation.toValue = to

View File

@ -900,3 +900,54 @@ public extension CGPoint {
return CGPoint(x: self.x + dx, y: self.y + dy)
}
}
public extension UIView {
func setMonochromaticEffect(tintColor: UIColor?) {
var overrideUserInterfaceStyle: UIUserInterfaceStyle = .unspecified
var red: CGFloat = 0.0
var green: CGFloat = 0.0
var blue: CGFloat = 0.0
var alpha: CGFloat = 1.0
if let tintColor {
if tintColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
if red == 0.0 && green == 0.0 && blue == 0.0 && alpha == 1.0 {
overrideUserInterfaceStyle = .light
}
} else {
if red == 1.0 && green == 1.0 && blue == 1.0 && alpha == 1.0 {
overrideUserInterfaceStyle = .dark
}
}
}
if self.overrideUserInterfaceStyle != overrideUserInterfaceStyle {
self.overrideUserInterfaceStyle = overrideUserInterfaceStyle
setMonochromaticEffectImpl(self, overrideUserInterfaceStyle != .unspecified)
}
}
func setMonochromaticEffectAndAlpha(tintColor: UIColor?, transition: ContainedViewLayoutTransition) {
var overrideUserInterfaceStyle: UIUserInterfaceStyle = .unspecified
var red: CGFloat = 0.0
var green: CGFloat = 0.0
var blue: CGFloat = 0.0
var alpha: CGFloat = 1.0
if let tintColor {
if tintColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
if red == 0.0 && green == 0.0 && blue == 0.0 {
overrideUserInterfaceStyle = .light
}
} else {
if red == 1.0 && green == 1.0 && blue == 1.0 {
overrideUserInterfaceStyle = .dark
}
}
}
if self.overrideUserInterfaceStyle != overrideUserInterfaceStyle {
self.overrideUserInterfaceStyle = overrideUserInterfaceStyle
setMonochromaticEffectImpl(self, overrideUserInterfaceStyle != .unspecified)
}
transition.updateAlpha(layer: self.layer, alpha: alpha)
}
}

View File

@ -604,7 +604,10 @@ public class Window1 {
var duration: Double = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.0
if duration > Double.ulpOfOne {
duration = 0.5
if #available(iOS 26.0, *) {
} else {
duration = 0.5
}
}
let curve: UInt = (notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber)?.uintValue ?? 7

View File

@ -2232,7 +2232,7 @@ final class VideoChatScreenComponent: Component {
color: .white
)),
background: AnyComponent(
GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), tintColor: .init(kind: .custom, color: UIColor(rgb: 0x101014)))
GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), isDark: true, tintColor: .init(kind: .custom, color: UIColor(rgb: 0x101014)))
),
effectAlignment: .center,
minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter),
@ -2254,7 +2254,7 @@ final class VideoChatScreenComponent: Component {
image: closeButtonImage(dark: false)
)),
background: AnyComponent(
GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), tintColor: .init(kind: .custom, color: UIColor(rgb: 0x101014)))
GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), isDark: true, tintColor: .init(kind: .custom, color: UIColor(rgb: 0x101014)))
),
effectAlignment: .center,
minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter),

View File

@ -663,14 +663,14 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati
panelBackgroundColorNoWallpaper: UIColor(rgb: 0x000000),
panelSeparatorColor: UIColor(rgb: 0x545458, alpha: 0.55),
panelControlAccentColor: UIColor(rgb: 0xffffff),
panelControlColor: UIColor(rgb: 0x808080),
panelControlColor: UIColor(rgb: 0xffffff),
panelControlDisabledColor: UIColor(rgb: 0x808080, alpha: 0.5),
panelControlDestructiveColor: UIColor(rgb: 0xff3b30),
inputBackgroundColor: UIColor(rgb: 0x060606),
inputStrokeColor: UIColor(rgb: 0xffffff, alpha: 0.1),
inputPlaceholderColor: UIColor(rgb: 0x7b7b7b),
inputTextColor: UIColor(rgb: 0xffffff),
inputControlColor: UIColor(rgb: 0x7b7b7b),
inputControlColor: UIColor(rgb: 0xffffff),
actionControlFillColor: UIColor(rgb: 0xffffff),
actionControlForegroundColor: UIColor(rgb: 0x000000),
primaryTextColor: UIColor(rgb: 0xffffff),

View File

@ -943,17 +943,17 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
panelBackgroundColorNoWallpaper: UIColor(rgb: 0xffffff),
panelSeparatorColor: UIColor(white: 1.0, alpha: 0.5),
panelControlAccentColor: defaultDayAccentColor,
panelControlColor: UIColor(rgb: 0x858e99),
panelControlColor: UIColor(rgb: 0x000000, alpha: 1.0),
panelControlDisabledColor: UIColor(rgb: 0x727b87, alpha: 0.5),
panelControlDestructiveColor: UIColor(rgb: 0xff3b30),
inputBackgroundColor: UIColor(rgb: 0xffffff),
inputStrokeColor: UIColor(rgb: 0x000000, alpha: 0.1),
inputPlaceholderColor: UIColor(rgb: 0x202020, alpha: 0.4),
inputPlaceholderColor: UIColor(rgb: 0x000000, alpha: 0.4),
inputTextColor: UIColor(rgb: 0x000000),
inputControlColor: UIColor(rgb: 0x202020, alpha: 0.6),
inputControlColor: UIColor(rgb: 0x000000, alpha: 1.0),
actionControlFillColor: defaultDayAccentColor,
actionControlForegroundColor: UIColor(rgb: 0xffffff),
primaryTextColor: UIColor(rgb: 0x000000, alpha: 0.9),
primaryTextColor: UIColor(rgb: 0x000000, alpha: 1.0),
secondaryTextColor: UIColor(rgb: 0x202020, alpha: 0.6),
mediaRecordingDotColor: UIColor(rgb: 0xed2521),
mediaRecordingControl: inputPanelMediaRecordingControl

View File

@ -57,6 +57,10 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
private var cachedMaskBackgroundImage: (CGPoint, UIImage, [CGRect])?
private var absoluteRect: (CGRect, CGSize)?
override public var disablesClipping: Bool {
return true
}
override public var visibility: ListViewItemNodeVisibility {
didSet {
if oldValue != self.visibility {

View File

@ -3442,14 +3442,14 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
contentContainerNodeFrames: contentContainerNodeFrames.map { containerGroupId, containerFrame, currentItemSelection, currentContainerGroupOverlap in
return (containerGroupId, containerFrame.offsetBy(dx: 0.0, dy: layoutInsets.top), currentItemSelection, currentContainerGroupOverlap)
},
mosaicStatusOrigin: mosaicStatusOrigin?.offsetBy(dx: 0.0, dy: layoutInsets.top),
mosaicStatusOrigin: mosaicStatusOrigin,
mosaicStatusSizeAndApply: mosaicStatusSizeAndApply,
unlockButtonPosition: unlockButtonPosition?.offsetBy(dx: 0.0, dy: layoutInsets.top),
unlockButtonPosition: unlockButtonPosition?.offsetBy(dx: 0.0, dy: layoutInsets.top),
unlockButtonSizeAndApply: unlockButtonSizeApply,
mediaInfoOrigin: mediaInfoOrigin?.offsetBy(dx: 0.0, dy: layoutInsets.top),
mediaInfoSizeAndApply: mediaInfoSizeApply,
needsShareButton: needsShareButton,
shareButtonOffset: shareButtonOffset?.offsetBy(dx: 0.0, dy: layoutInsets.top),
shareButtonOffset: shareButtonOffset,
avatarOffset: avatarOffset,
hidesHeaders: hidesHeaders,
disablesComments: disablesComments,

View File

@ -86,6 +86,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
private var currentProgressDisposable: Disposable?
override public var disablesClipping: Bool {
return true
}
override public var visibility: ListViewItemNodeVisibility {
didSet {
let wasVisible = oldValue != .none

View File

@ -449,10 +449,10 @@ public final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded)
var leftInset = leftInset
leftInset += 8.0
leftInset += 16.0
var rightInset = rightInset
rightInset += 8.0
rightInset += 16.0
let panelHeight = defaultHeight(metrics: metrics)

View File

@ -197,6 +197,7 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag
self.expandMediaInputButtonBackgroundView.contentView.addSubview(self.expandMediaInputButtonIcon)
self.expandMediaInputButtonIcon.image = PresentationResourcesChat.chatInputPanelExpandButtonImage(presentationInterfaceState.theme)
self.expandMediaInputButtonIcon.tintColor = theme.chat.inputPanel.inputControlColor
self.expandMediaInputButtonIcon.setMonochromaticEffect(tintColor: theme.chat.inputPanel.inputControlColor)
super.init()
@ -265,6 +266,7 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag
public func updateTheme(theme: PresentationTheme, wallpaper: TelegramWallpaper) {
self.micButton.updateTheme(theme: theme)
self.expandMediaInputButtonIcon.tintColor = theme.chat.inputPanel.inputControlColor
self.expandMediaInputButtonIcon.setMonochromaticEffect(tintColor: theme.chat.inputPanel.inputControlColor)
}
private var absoluteRect: (CGRect, CGSize)?
@ -352,8 +354,8 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag
self.expandMediaInputButtonBackgroundView.update(size: size, cornerRadius: size.height * 0.5, isDark: interfaceState.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: interfaceState.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)), transition: ComponentTransition(transition))
if let image = self.expandMediaInputButtonIcon.image {
let expandIconFrame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) * 0.5), y: floor((size.height - image.size.height) * 0.5)), size: image.size)
transition.updatePosition(layer: self.expandMediaInputButtonIcon.layer, position: expandIconFrame.center)
transition.updateBounds(layer: self.expandMediaInputButtonIcon.layer, bounds: CGRect(origin: CGPoint(), size: expandIconFrame.size))
self.expandMediaInputButtonIcon.center = expandIconFrame.center
self.expandMediaInputButtonIcon.bounds = CGRect(origin: CGPoint(), size: expandIconFrame.size)
transition.updateTransformScale(layer: self.expandMediaInputButtonIcon.layer, scale: CGPoint(x: 1.0, y: isMediaInputExpanded ? 1.0 : -1.0))
}

View File

@ -16,8 +16,7 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie
private var theme: PresentationTheme
private var strings: PresentationStrings
private var width: CGFloat
private let iconImageView: UIImageView
private let tintMaskIconImageView: UIImageView
private let iconImageView: GlassBackgroundView.ContentImageView
private var textView: ImmediateTextView?
private var tintMaskTextView: ImmediateTextView?
private var animationView: ComponentView<Empty>?
@ -34,8 +33,7 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie
self.theme = theme
self.strings = strings
self.iconImageView = UIImageView()
self.tintMaskIconImageView = UIImageView()
self.iconImageView = GlassBackgroundView.ContentImageView()
let (image, text, accessibilityLabel, alpha, _) = AccessoryItemIconButton.imageAndInsets(item: item, theme: theme, strings: strings)
@ -51,12 +49,11 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie
self.iconImageView.isUserInteractionEnabled = false
self.addSubview(self.iconImageView)
self.tintMask.addSubview(self.tintMaskIconImageView)
self.tintMask.addSubview(self.iconImageView.tintMask)
switch item {
case .input, .botInput, .silentPost:
self.iconImageView.isHidden = true
self.tintMaskIconImageView.isHidden = self.iconImageView.isHidden
self.animationView = ComponentView<Empty>()
self.tintMaskAnimationView = UIImageView()
default:
@ -93,10 +90,6 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie
self.iconImageView.tintColor = theme.chat.inputPanel.inputControlColor
self.iconImageView.alpha = alpha
self.tintMaskIconImageView.image = self.iconImageView.image
self.tintMaskIconImageView.tintColor = .black
self.tintMaskIconImageView.alpha = self.iconImageView.alpha
self.accessibilityLabel = accessibilityLabel
self.highligthedChanged = { [weak self] highlighted in
@ -138,10 +131,6 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie
self.iconImageView.tintColor = theme.chat.inputPanel.inputControlColor
self.iconImageView.alpha = alpha
self.tintMaskIconImageView.image = self.iconImageView.image
self.tintMaskIconImageView.tintColor = .black
self.tintMaskIconImageView.alpha = self.iconImageView.alpha
self.accessibilityLabel = accessibilityLabel
}
@ -205,12 +194,13 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie
if let image = self.iconImageView.image {
self.iconImageView.image = updatedImage
self.tintMaskIconImageView.image = updatedImage
let bottomInset: CGFloat = 0.0
let imageFrame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0) - bottomInset), size: image.size)
var imageFrame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0) - bottomInset), size: image.size)
if case .scheduledMessages = item {
imageFrame.origin.y += 1.0
}
self.iconImageView.frame = imageFrame
self.tintMaskIconImageView.frame = imageFrame
if let animationView = self.animationView {
let width = AccessoryItemIconButton.calculateWidth(item: item, image: image, text: "", strings: self.strings)
@ -332,6 +322,7 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie
self.tintMask.addSubview(tintMaskAnimationView)
}
}
view.setMonochromaticEffect(tintColor: self.theme.chat.inputPanel.inputControlColor)
let animationFrameValue = CGRect(origin: CGPoint(x: animationFrame.minX + floor((animationFrame.width - animationSize.width) / 2.0), y: animationFrame.minY + floor((animationFrame.height - animationSize.height) / 2.0)), size: animationSize)
view.frame = animationFrameValue
if let tintMaskAnimationView = self.tintMaskAnimationView {

View File

@ -214,11 +214,9 @@ private func makeTextInputTheme(context: AccountContext, interfaceState: ChatPre
public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, ChatInputTextNodeDelegate {
public let clippingNode: ASDisplayNode
public let textPlaceholderNode: ImmediateTextNodeWithEntities
public let tintMaskTextPlaceholderNode: ImmediateTextNodeWithEntities
public var textLockIconNode: ASImageNode?
public var contextPlaceholderNode: TextNode?
public var tintContextPlaceholderNode: TextNode?
public var slowmodePlaceholderNode: ChatTextInputSlowmodePlaceholderNode?
public let textInputContainerBackgroundView: GlassBackgroundView
public let textInputContainer: ASDisplayNode
@ -521,20 +519,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
self.textPlaceholderNode.contentsScale = UIScreenScale
self.textPlaceholderNode.maximumNumberOfLines = 1
self.textPlaceholderNode.isUserInteractionEnabled = false
//TODO:release add tinted output instead
self.tintMaskTextPlaceholderNode = ImmediateTextNodeWithEntities()
self.tintMaskTextPlaceholderNode.arguments = TextNodeWithEntities.Arguments(
context: context,
cache: context.animationCache,
renderer: context.animationRenderer,
placeholderColor: .clear,
attemptSynchronous: true
)
self.tintMaskTextPlaceholderNode.contentMode = .topLeft
self.tintMaskTextPlaceholderNode.contentsScale = UIScreenScale
self.tintMaskTextPlaceholderNode.maximumNumberOfLines = 1
self.menuButton = HighlightTrackingButtonNode()
self.menuButton.clipsToBounds = true
self.menuButton.cornerRadius = 16.0
@ -566,7 +551,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
self.attachmentButton.isAccessibilityElement = true
self.attachmentButtonBackground = GlassBackgroundView(frame: CGRect())
self.attachmentButtonBackground.isUserInteractionEnabled = false
self.attachmentButton.addSubview(self.attachmentButtonBackground)
self.attachmentButtonIcon = GlassBackgroundView.ContentImageView()
@ -785,7 +769,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
self.clippingNode.addSubnode(self.textInputBackgroundNode)
self.textInputContainerBackgroundView.contentView.addSubview(self.textPlaceholderNode.view)
self.textInputContainerBackgroundView.maskContentView.addSubview(self.tintMaskTextPlaceholderNode.view)
self.menuButton.view.addSubview(self.menuButtonBackgroundView)
self.menuButton.addSubnode(self.menuButtonClippingNode)
@ -1039,6 +1022,8 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
private func calculateTextFieldMetrics(width: CGFloat, maxHeight: CGFloat, metrics: LayoutMetrics) -> (accessoryButtonsWidth: CGFloat, textFieldHeight: CGFloat, isOverflow: Bool) {
let maxHeight = max(maxHeight, 40.0)
var textFieldInsets = self.textFieldInsets(metrics: metrics)
if self.actionButtons.frame.width > 40.0 {
textFieldInsets.right = self.actionButtons.frame.width - 2.0
@ -1076,7 +1061,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
let unboundTextFieldHeight = max(textFieldMinHeight, ceil(measuredHeight))
let maxNumberOfLines = min(12, (Int(fieldMaxHeight - 11.0) - 33) / 22)
let maxNumberOfLines = max(1, min(12, (Int(fieldMaxHeight - 11.0) - 33) / 22))
let updatedMaxHeight = (CGFloat(maxNumberOfLines) * (22.0 + 2.0) + 10.0)
@ -1256,6 +1241,8 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
) -> CGFloat {
let previousAdditionalSideInsets = self.validLayout?.4
self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded)
let placeholderColor: UIColor = interfaceState.theme.chat.inputPanel.inputPlaceholderColor
var transition = transition
var additionalOffset: CGFloat = 0.0
@ -2423,21 +2410,16 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
if interfaceState.slowmodeState == nil || isScheduledMessages, let contextPlaceholder = interfaceState.inputTextPanelState.contextPlaceholder {
let placeholderLayout = TextNode.asyncLayout(self.contextPlaceholderNode)
let tintPlaceholderLayout = TextNode.asyncLayout(self.tintContextPlaceholderNode)
let contextPlaceholder = NSMutableAttributedString(attributedString: contextPlaceholder)
contextPlaceholder.addAttribute(.foregroundColor, value: placeholderColor.withAlphaComponent(1.0), range: NSRange(location: 0, length: contextPlaceholder.length))
let (placeholderSize, placeholderApply) = placeholderLayout(TextNodeLayoutArguments(attributedString: contextPlaceholder, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: width - leftInset - rightInset - textFieldInsets.left - textFieldInsets.right - self.textInputViewInternalInsets.left - self.textInputViewInternalInsets.right - accessoryButtonsWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let tintContextPlaceholder = NSMutableAttributedString(attributedString: contextPlaceholder)
tintContextPlaceholder.addAttribute(.foregroundColor, value: UIColor.black, range: NSRange(location: 0, length: tintContextPlaceholder.length))
let (_, tintPlaceholderApply) = tintPlaceholderLayout(TextNodeLayoutArguments(attributedString: tintContextPlaceholder, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: width - leftInset - rightInset - textFieldInsets.left - textFieldInsets.right - self.textInputViewInternalInsets.left - self.textInputViewInternalInsets.right - accessoryButtonsWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let contextPlaceholderNode = placeholderApply()
let tintContextPlaceholderNode = tintPlaceholderApply()
if let currentContextPlaceholderNode = self.contextPlaceholderNode, currentContextPlaceholderNode !== contextPlaceholderNode {
self.contextPlaceholderNode = nil
currentContextPlaceholderNode.removeFromSupernode()
}
if let currentTintContextPlaceholderNode = self.tintContextPlaceholderNode, currentTintContextPlaceholderNode !== tintContextPlaceholderNode {
self.tintContextPlaceholderNode = nil
currentTintContextPlaceholderNode.removeFromSupernode()
}
if self.contextPlaceholderNode !== contextPlaceholderNode {
contextPlaceholderNode.displaysAsynchronously = false
@ -2445,12 +2427,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
self.contextPlaceholderNode = contextPlaceholderNode
self.textInputContainerBackgroundView.contentView.insertSubview(contextPlaceholderNode.view, aboveSubview: self.textPlaceholderNode.view)
}
if self.tintContextPlaceholderNode !== tintContextPlaceholderNode {
tintContextPlaceholderNode.displaysAsynchronously = false
tintContextPlaceholderNode.isUserInteractionEnabled = false
self.tintContextPlaceholderNode = tintContextPlaceholderNode
self.textInputContainerBackgroundView.maskContentView.insertSubview(tintContextPlaceholderNode.view, aboveSubview: self.tintMaskTextPlaceholderNode.view)
}
let _ = placeholderApply()
@ -2460,21 +2436,14 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
} else {
placeholderTransition = .immediate
}
placeholderTransition.updateFrame(node: contextPlaceholderNode, frame: CGRect(origin: CGPoint(x: self.textInputViewInternalInsets.left, y: hideOffset.y + textFieldInsets.top + self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel), size: placeholderSize.size))
contextPlaceholderNode.alpha = audioRecordingItemsAlpha
placeholderTransition.updateFrame(node: tintContextPlaceholderNode, frame: CGRect(origin: CGPoint(x: self.textInputViewInternalInsets.left, y: hideOffset.y + textFieldInsets.top + self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel), size: placeholderSize.size))
tintContextPlaceholderNode.alpha = audioRecordingItemsAlpha
placeholderTransition.updateFrame(node: contextPlaceholderNode, frame: CGRect(origin: CGPoint(x: self.textInputViewInternalInsets.left, y: hideOffset.y + textFieldInsets.top + self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel + (accessoryPanel != nil ? 52.0 : 0.0)), size: placeholderSize.size))
contextPlaceholderNode.view.setMonochromaticEffect(tintColor: placeholderColor)
contextPlaceholderNode.alpha = audioRecordingItemsAlpha * placeholderColor.alpha
} else {
if let contextPlaceholderNode = self.contextPlaceholderNode {
self.contextPlaceholderNode = nil
contextPlaceholderNode.removeFromSupernode()
self.textPlaceholderNode.alpha = 1.0
self.tintMaskTextPlaceholderNode.alpha = 1.0
}
if let tintContextPlaceholderNode = self.tintContextPlaceholderNode {
self.tintContextPlaceholderNode = nil
tintContextPlaceholderNode.removeFromSupernode()
self.textPlaceholderNode.alpha = 1.0 * placeholderColor.alpha
}
}
@ -2499,11 +2468,9 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
if (interfaceState.slowmodeState != nil && rightSlowModeInset.isZero && !isScheduledMessages && interfaceState.editMessageState == nil) || interfaceState.inputTextPanelState.contextPlaceholder != nil {
self.textPlaceholderNode.isHidden = true
self.tintMaskTextPlaceholderNode.isHidden = true
self.slowmodePlaceholderNode?.isHidden = inputHasText
} else {
self.textPlaceholderNode.isHidden = inputHasText
self.tintMaskTextPlaceholderNode.isHidden = inputHasText
self.slowmodePlaceholderNode?.isHidden = true
}
@ -2539,38 +2506,24 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
let textPlaceholderSize: CGSize
let textPlaceholderMaxWidth: CGFloat = max(1.0, nextButtonTopRight.x - 12.0)
let placeholderColor: UIColor = interfaceState.theme.chat.inputPanel.inputPlaceholderColor
if #available(iOS 26.0, *) {
//placeholderColor = placeholderColor.withProminence(.tertiary)
}
//self.textPlaceholderNode.view.tintColor = .red
if (updatedPlaceholder != nil && self.currentPlaceholder != updatedPlaceholder) || themeUpdated {
let currentPlaceholder = updatedPlaceholder ?? self.currentPlaceholder ?? ""
self.currentPlaceholder = currentPlaceholder
let baseFontSize = max(minInputFontSize, interfaceState.fontSize.baseDisplaySize)
let attributedPlaceholder = NSMutableAttributedString(string: currentPlaceholder, font: Font.regular(baseFontSize), textColor: placeholderColor)
let attributedPlaceholder = NSMutableAttributedString(string: currentPlaceholder, font: Font.regular(baseFontSize), textColor: placeholderColor.withAlphaComponent(1.0))
if placeholderHasStar, let range = attributedPlaceholder.string.range(of: "#") {
attributedPlaceholder.addAttribute(.attachment, value: PresentationResourcesChat.chatPlaceholderStarIcon(interfaceState.theme)!, range: NSRange(range, in: attributedPlaceholder.string))
attributedPlaceholder.addAttribute(.foregroundColor, value: placeholderColor, range: NSRange(range, in: attributedPlaceholder.string))
attributedPlaceholder.addAttribute(.foregroundColor, value: placeholderColor.withAlphaComponent(1.0), range: NSRange(range, in: attributedPlaceholder.string))
attributedPlaceholder.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: attributedPlaceholder.string))
}
let attributedTintMaskPlaceholder = NSMutableAttributedString(string: currentPlaceholder, font: Font.regular(baseFontSize), textColor: UIColor(white: 0.0, alpha: placeholderColor.alpha))
if placeholderHasStar, let range = attributedPlaceholder.string.range(of: "#") {
attributedTintMaskPlaceholder.addAttribute(.attachment, value: PresentationResourcesChat.chatPlaceholderStarIcon(interfaceState.theme)!, range: NSRange(range, in: attributedPlaceholder.string))
attributedTintMaskPlaceholder.addAttribute(.foregroundColor, value: UIColor.black, range: NSRange(range, in: attributedPlaceholder.string))
attributedTintMaskPlaceholder.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: attributedPlaceholder.string))
}
self.textPlaceholderNode.attributedText = attributedPlaceholder
self.tintMaskTextPlaceholderNode.attributedText = attributedTintMaskPlaceholder
self.textPlaceholderNode.view.setMonochromaticEffect(tintColor: placeholderColor)
self.textInputNode?.textView.accessibilityHint = currentPlaceholder
let placeholderSize = self.textPlaceholderNode.updateLayout(CGSize(width: textPlaceholderMaxWidth, height: CGFloat.greatestFiniteMagnitude))
let _ = self.tintMaskTextPlaceholderNode.updateLayout(CGSize(width: textPlaceholderMaxWidth, height: CGFloat.greatestFiniteMagnitude))
if transition.isAnimated, let snapshotLayer = self.textPlaceholderNode.layer.snapshotContentTree() {
self.textPlaceholderNode.supernode?.layer.insertSublayer(snapshotLayer, above: self.textPlaceholderNode.layer)
@ -2580,15 +2533,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
self.textPlaceholderNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.18)
}
let _ = self.tintMaskTextPlaceholderNode.updateLayout(CGSize(width: textPlaceholderMaxWidth, height: CGFloat.greatestFiniteMagnitude))
if transition.isAnimated, let snapshotLayer = self.tintMaskTextPlaceholderNode.layer.snapshotContentTree() {
self.tintMaskTextPlaceholderNode.supernode?.layer.insertSublayer(snapshotLayer, above: self.tintMaskTextPlaceholderNode.layer)
snapshotLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.22, removeOnCompletion: false, completion: { [weak snapshotLayer] _ in
snapshotLayer?.removeFromSuperlayer()
})
self.tintMaskTextPlaceholderNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.18)
}
textPlaceholderSize = placeholderSize
} else {
textPlaceholderSize = self.textPlaceholderNode.bounds.size
@ -2623,13 +2567,11 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
}
transition.updateFrame(node: self.textPlaceholderNode, frame: textPlaceholderFrame)
transition.updateFrame(node: self.tintMaskTextPlaceholderNode, frame: textPlaceholderFrame)
let textPlaceholderAlpha: CGFloat = audioRecordingItemsAlpha
let textPlaceholderAlpha: CGFloat = audioRecordingItemsAlpha * placeholderColor.alpha
transition.updateAlpha(node: self.textPlaceholderNode, alpha: textPlaceholderAlpha)
transition.updateAlpha(node: self.tintMaskTextPlaceholderNode, alpha: textPlaceholderAlpha)
if let removeAccessoryButtons = removeAccessoryButtons {
if let removeAccessoryButtons {
for button in removeAccessoryButtons {
let buttonFrame = CGRect(origin: CGPoint(x: button.frame.origin.x + additionalOffset, y: textInputFrame.maxY - minimalInputHeight), size: button.frame.size)
transition.updateFrame(layer: button.layer, frame: buttonFrame)
@ -2700,7 +2642,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
let attachmentButtonFrame = CGRect(origin: CGPoint(x: attachmentButtonX, y: textInputFrame.maxY - 40.0), size: CGSize(width: 40.0, height: 40.0))
self.attachmentButtonBackground.frame = CGRect(origin: CGPoint(), size: attachmentButtonFrame.size)
self.attachmentButtonBackground.update(size: attachmentButtonFrame.size, cornerRadius: attachmentButtonFrame.height * 0.5, isDark: interfaceState.theme.overallDarkAppearance, tintColor: isEditingMedia ? .init(kind: .custom, color: interfaceState.theme.chat.inputPanel.actionControlFillColor) : .init(kind: .panel, color: interfaceState.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)), transition: ComponentTransition(transition))
self.attachmentButtonBackground.update(size: attachmentButtonFrame.size, cornerRadius: attachmentButtonFrame.height * 0.5, isDark: interfaceState.theme.overallDarkAppearance, tintColor: isEditingMedia ? .init(kind: .custom, color: interfaceState.theme.chat.inputPanel.actionControlFillColor) : .init(kind: .panel, color: interfaceState.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)), isInteractive: true, transition: ComponentTransition(transition))
transition.updateFrame(layer: self.attachmentButton.layer, frame: attachmentButtonFrame)
transition.updateFrame(node: self.attachmentButtonDisabledNode, frame: self.attachmentButton.frame)
@ -3667,11 +3609,9 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
if let interfaceState = self.presentationInterfaceState {
if (interfaceState.slowmodeState != nil && !isScheduledMessages && interfaceState.editMessageState == nil) || interfaceState.inputTextPanelState.contextPlaceholder != nil {
self.textPlaceholderNode.isHidden = true
self.tintMaskTextPlaceholderNode.isHidden = true
self.slowmodePlaceholderNode?.isHidden = inputHasText
} else {
self.textPlaceholderNode.isHidden = inputHasText
self.tintMaskTextPlaceholderNode.isHidden = inputHasText
self.slowmodePlaceholderNode?.isHidden = true
}
}
@ -4721,7 +4661,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
public func frameForAccessoryButton(_ item: ChatTextInputAccessoryItem) -> CGRect? {
for (buttonItem, buttonNode) in self.accessoryItemButtons {
if buttonItem == item {
return buttonNode.frame
return self.view.convert(buttonNode.bounds.insetBy(dx: 0.0, dy: 6.0), from: buttonNode)
}
}
return nil
@ -4744,9 +4684,9 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
public func frameForInputActionButton() -> CGRect? {
if !self.actionButtons.alpha.isZero {
if self.actionButtons.micButton.alpha.isZero {
return self.actionButtons.frame.insetBy(dx: 0.0, dy: 6.0).offsetBy(dx: 4.0, dy: 0.0)
return self.actionButtons.frame.insetBy(dx: 0.0, dy: -4.0).offsetBy(dx: 0.0, dy: 0.0)
} else {
return self.actionButtons.frame.insetBy(dx: 0.0, dy: 6.0).offsetBy(dx: 2.0, dy: 0.0)
return self.actionButtons.frame.insetBy(dx: 0.0, dy: -4.0).offsetBy(dx: 0.0, dy: 0.0)
}
}
return nil
@ -4755,7 +4695,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
public func frameForStickersButton() -> CGRect? {
for (item, button) in self.accessoryItemButtons {
if case let .input(_, inputMode) = item, case .stickers = inputMode {
return button.frame.insetBy(dx: 0.0, dy: 6.0)
return self.view.convert(button.bounds.insetBy(dx: 0.0, dy: 6.0), from: button)
}
}
return nil
@ -4764,7 +4704,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
public func frameForEmojiButton() -> CGRect? {
for (item, button) in self.accessoryItemButtons {
if case let .input(_, inputMode) = item, case .emoji = inputMode {
return button.frame.insetBy(dx: 0.0, dy: 6.0)
return self.view.convert(button.bounds.insetBy(dx: 0.0, dy: 6.0), from: button)
}
}
return nil
@ -4773,7 +4713,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
public func frameForGiftButton() -> CGRect? {
for (item, button) in self.accessoryItemButtons {
if case .gift = item {
return button.frame.insetBy(dx: 0.0, dy: 6.0)
return self.view.convert(button.bounds.insetBy(dx: 0.0, dy: 6.0), from: button)
}
}
return nil

View File

@ -420,11 +420,12 @@ public final class ChatTextInputMediaRecordingButton: TGModernConversationInputM
animationName = "anim_micToVideo"
}
let animationTintColor = self.useDarkTheme ? .white : self.theme.chat.inputPanel.inputControlColor
let _ = self.animationView.update(
transition: .immediate,
component: AnyComponent(LottieComponent(
content: LottieComponent.AppBundleContent(name: animationName),
color: self.useDarkTheme ? .white : self.theme.chat.inputPanel.inputControlColor
color: animationTintColor
)),
environment: {},
containerSize: animationFrame.size
@ -437,6 +438,7 @@ public final class ChatTextInputMediaRecordingButton: TGModernConversationInputM
view.output = self.animationOutput
self.updateShadow()
}
view.setMonochromaticEffect(tintColor: animationTintColor)
view.frame = animationFrame
if previousMode != mode {

View File

@ -65,22 +65,12 @@ final class LockView: UIButton, TGModernConversationInputMicButtonLock {
}
func updateTheme(_ theme: PresentationTheme) {
// [
// "Rectangle.Заливка 1": theme.chat.inputPanel.panelBackgroundColor,
// "Rectangle.Rectangle.Обводка 1": theme.chat.inputPanel.panelControlAccentColor,
// "Rectangle 2.Rectangle.Обводка 1": theme.chat.inputPanel.panelControlAccentColor,
// "Path.Path.Обводка 1": theme.chat.inputPanel.panelControlAccentColor,
// "Path 4.Path 4.Обводка 1": theme.chat.inputPanel.panelControlAccentColor
// ].forEach { key, value in
// idleView.setValueProvider(ColorValueProvider(value.lottieColorValue), keypath: AnimationKeypath(keypath: "\(key).Color"))
// }
//
for keypath in idleView.allKeypaths(predicate: { $0.keys.last == "Color" }) {
idleView.setValueProvider(ColorValueProvider(theme.chat.inputPanel.panelControlAccentColor.lottieColorValue), keypath: AnimationKeypath(keypath: keypath))
idleView.setValueProvider(ColorValueProvider(theme.chat.inputPanel.panelControlColor.lottieColorValue), keypath: AnimationKeypath(keypath: keypath))
}
for keypath in lockingView.allKeypaths(predicate: { $0.keys.last == "Color" }) {
lockingView.setValueProvider(ColorValueProvider(theme.chat.inputPanel.panelControlAccentColor.lottieColorValue), keypath: AnimationKeypath(keypath: keypath))
lockingView.setValueProvider(ColorValueProvider(theme.chat.inputPanel.panelControlColor.lottieColorValue), keypath: AnimationKeypath(keypath: keypath))
}
//
// [

View File

@ -202,6 +202,14 @@ public class GlassBackgroundView: UIView {
}
}
override public var tintColor: UIColor? {
didSet {
if self.tintColor != oldValue {
self.setMonochromaticEffect(tintColor: self.tintColor)
}
}
}
override public init(frame: CGRect) {
self.tintImageView = UIImageView()
@ -252,16 +260,19 @@ public class GlassBackgroundView: UIView {
let cornerRadius: CGFloat
let isDark: Bool
let tintColor: TintColor
let isInteractive: Bool
init(cornerRadius: CGFloat, isDark: Bool, tintColor: TintColor) {
init(cornerRadius: CGFloat, isDark: Bool, tintColor: TintColor, isInteractive: Bool) {
self.cornerRadius = cornerRadius
self.isDark = isDark
self.tintColor = tintColor
self.isInteractive = isInteractive
}
}
private let backgroundNode: NavigationBackgroundNode?
private let nativeView: UIVisualEffectView?
private let nativeContainerView: UIVisualEffectView?
private let foregroundView: UIImageView?
private let shadowView: UIImageView?
@ -283,19 +294,23 @@ public class GlassBackgroundView: UIView {
public override init(frame: CGRect) {
if #available(iOS 26.0, *) {
self.backgroundNode = nil
let glassEffect = UIGlassEffect(style: .clear)
let glassEffect = UIGlassEffect(style: .regular)
glassEffect.isInteractive = false
let nativeView = UIVisualEffectView(effect: glassEffect)
nativeView.layer.cornerCurve = .circular
self.nativeView = nativeView
nativeView.overrideUserInterfaceStyle = .light
nativeView.traitOverrides.userInterfaceStyle = .light
//self.foregroundView = UIImageView()
let glassContainerEffect = UIGlassContainerEffect()
let nativeContainerView = UIVisualEffectView(effect: glassContainerEffect)
self.nativeContainerView = nativeContainerView
nativeContainerView.contentView.addSubview(nativeView)
self.foregroundView = nil
self.shadowView = UIImageView()
self.shadowView = nil
} else {
self.backgroundNode = NavigationBackgroundNode(color: .black, enableBlur: true, customBlurRadius: 5.0)
self.nativeView = nil
self.nativeContainerView = nil
self.foregroundView = UIImageView()
self.shadowView = UIImageView()
}
@ -316,8 +331,8 @@ public class GlassBackgroundView: UIView {
if let shadowView = self.shadowView {
self.addSubview(shadowView)
}
if let nativeView = self.nativeView {
self.addSubview(nativeView)
if let nativeContainerView = self.nativeContainerView {
self.addSubview(nativeContainerView)
}
if let backgroundNode = self.backgroundNode {
self.addSubview(backgroundNode.view)
@ -333,8 +348,17 @@ public class GlassBackgroundView: UIView {
fatalError("init(coder:) has not been implemented")
}
public func update(size: CGSize, cornerRadius: CGFloat, isDark: Bool, tintColor: TintColor, transition: ComponentTransition) {
if let nativeView = self.nativeView {
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
/*if let nativeContainerView = self.nativeContainerView {
if let result = nativeContainerView.hitTest(self.convert(point, to: nativeContainerView), with: event) {
return result
}
}*/
return nil
}
public func update(size: CGSize, cornerRadius: CGFloat, isDark: Bool, tintColor: TintColor, isInteractive: Bool = false, transition: ComponentTransition) {
if let nativeContainerView = self.nativeContainerView, let nativeView = self.nativeView {
let previousFrame = nativeView.frame
if transition.animation.isImmediate {
@ -347,6 +371,8 @@ public class GlassBackgroundView: UIView {
}
nativeView.layer.animateFrame(from: previousFrame, to: CGRect(origin: CGPoint(), size: size), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring)
}
transition.setFrame(view: nativeContainerView, frame: CGRect(origin: CGPoint(), size: size))
}
if let backgroundNode = self.backgroundNode {
backgroundNode.updateColor(color: .clear, forceKeepBlur: tintColor.color.alpha != 1.0, transition: transition.containedViewLayoutTransition)
@ -356,7 +382,7 @@ public class GlassBackgroundView: UIView {
let shadowInset: CGFloat = 32.0
let params = Params(cornerRadius: cornerRadius, isDark: isDark, tintColor: tintColor)
let params = Params(cornerRadius: cornerRadius, isDark: isDark, tintColor: tintColor, isInteractive: isInteractive)
if self.params != params {
self.params = params
@ -378,18 +404,21 @@ public class GlassBackgroundView: UIView {
if let foregroundView = self.foregroundView {
foregroundView.image = GlassBackgroundView.generateLegacyGlassImage(size: CGSize(width: cornerRadius * 2.0, height: cornerRadius * 2.0), inset: shadowInset, isDark: isDark, fillColor: tintColor.color)
} else {
if let nativeView {
if let nativeContainerView = self.nativeContainerView, let nativeView {
if #available(iOS 26.0, *) {
let glassEffect = UIGlassEffect(style: .clear)
let glassEffect = UIGlassEffect(style: .regular)
switch tintColor.kind {
case .panel:
glassEffect.tintColor = tintColor.color.withMultipliedAlpha(1.2)
glassEffect.tintColor = nil
case .custom:
glassEffect.tintColor = tintColor.color
}
glassEffect.isInteractive = false
glassEffect.isInteractive = params.isInteractive
nativeView.effect = glassEffect
let _ = nativeContainerView
//nativeContainerView.overrideUserInterfaceStyle = .light// isDark ? .dark : .light
self.overrideUserInterfaceStyle = isDark ? .dark : .light
}
}
}
@ -407,6 +436,27 @@ public class GlassBackgroundView: UIView {
}
}
public final class GlassBackgroundContainerView: UIView {
private final class ContentView: UIView {
}
private let contentViewImpl: ContentView
public var contentView: UIView {
return self.contentViewImpl
}
public override init(frame: CGRect) {
self.contentViewImpl = ContentView()
super.init(frame: frame)
}
required public init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
public final class VariableBlurView: UIVisualEffectView {
public let maxBlurRadius: CGFloat
@ -536,8 +586,7 @@ public extension GlassBackgroundView {
return result
}
// Your requested closure:
let addShadow: (Bool, CGPoint, CGFloat, CGFloat, UIColor) -> Void = { isOuter, position, blur, spread, shadowColor in
let addShadow: (Bool, CGPoint, CGFloat, CGFloat, UIColor, Bool) -> Void = { isOuter, position, blur, spread, shadowColor, isMultiply in
var blur = blur
blur += abs(spread)
@ -571,132 +620,70 @@ public extension GlassBackgroundView {
context.fillPath()
context.setBlendMode(.normal)
} else {
context.beginTransparencyLayer(auxiliaryInfo: nil)
context.saveGState()
defer {
context.restoreGState()
context.endTransparencyLayer()
if let image = generateImage(size, rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
let spreadRect = CGRect(origin: CGPoint(x: inset, y: inset), size: innerSize).insetBy(dx: -0.25, dy: -0.25)
let spreadPath = UIBezierPath(
roundedRect: spreadRect,
cornerRadius: min(spreadRect.width, spreadRect.height) * 0.5
).cgPath
context.setShadow(offset: CGSize(width: position.x, height: position.y), blur: blur, color: shadowColor.cgColor)
context.setFillColor(UIColor.black.withAlphaComponent(1.0).cgColor)
let enclosingRect = spreadRect.insetBy(dx: -10000.0, dy: -10000.0)
context.addPath(UIBezierPath(rect: enclosingRect).cgPath)
context.addPath(spreadPath)
context.fillPath(using: .evenOdd)
let cleanRect = CGRect(origin: CGPoint(x: inset, y: inset), size: innerSize)
let cleanPath = UIBezierPath(
roundedRect: cleanRect,
cornerRadius: min(cleanRect.width, cleanRect.height) * 0.5
).cgPath
context.setBlendMode(.copy)
context.setFillColor(UIColor.clear.cgColor)
context.addPath(UIBezierPath(rect: enclosingRect).cgPath)
context.addPath(cleanPath)
context.fillPath(using: .evenOdd)
context.setBlendMode(.normal)
}) {
UIGraphicsPushContext(context)
image.draw(in: CGRect(origin: .zero, size: size), blendMode: isMultiply ? .destinationOut : .normal, alpha: 1.0)
UIGraphicsPopContext()
}
let spreadRect = CGRect(origin: CGPoint(x: inset, y: inset), size: innerSize).insetBy(dx: -0.25, dy: -0.25)
let spreadPath = UIBezierPath(
roundedRect: spreadRect,
cornerRadius: min(spreadRect.width, spreadRect.height) * 0.5
).cgPath
context.setShadow(offset: CGSize(width: position.x, height: position.y), blur: blur, color: shadowColor.cgColor)
context.setFillColor(UIColor.black.withAlphaComponent(1.0).cgColor)
let enclosingRect = spreadRect.insetBy(dx: -10000.0, dy: -10000.0)
context.addPath(UIBezierPath(rect: enclosingRect).cgPath)
context.addPath(spreadPath)
context.fillPath(using: .evenOdd)
let cleanRect = CGRect(origin: CGPoint(x: inset, y: inset), size: innerSize)
let cleanPath = UIBezierPath(
roundedRect: cleanRect,
cornerRadius: min(cleanRect.width, cleanRect.height) * 0.5
).cgPath
context.setBlendMode(.copy)
context.setFillColor(UIColor.clear.cgColor)
context.addPath(UIBezierPath(rect: enclosingRect).cgPath)
context.addPath(cleanPath)
context.fillPath(using: .evenOdd)
context.setBlendMode(.normal)
}
}
if isDark {
addShadow(true, CGPoint(), 16.0, 0.0, UIColor(white: 0.0, alpha: 0.12))
addShadow(true, CGPoint(), 8.0, 0.0, UIColor(white: 0.0, alpha: 0.1))
addShadow(true, CGPoint(), 16.0, 0.0, UIColor(white: 0.0, alpha: 0.12), false)
addShadow(true, CGPoint(), 8.0, 0.0, UIColor(white: 0.0, alpha: 0.1), false)
context.setFillColor(fillColor.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset, dy: inset))
addShadow(false, CGPoint(x: 0.0, y: 0.0), 3.0, 0.0, UIColor(white: 1.0, alpha: 0.5))
addShadow(false, CGPoint(x: 3.0, y: -3.0), 2.0, 0.0, UIColor(white: 1.0, alpha: 0.25))
addShadow(false, CGPoint(x: -3.0, y: 3.0), 2.0, 0.0, UIColor(white: 1.0, alpha: 0.25))
addShadow(false, CGPoint(x: 0.0, y: 0.0), 3.0, 0.0, UIColor(white: 1.0, alpha: 0.5), false)
addShadow(false, CGPoint(x: 3.0, y: -3.0), 2.0, 0.0, UIColor(white: 1.0, alpha: 0.25), false)
addShadow(false, CGPoint(x: -3.0, y: 3.0), 2.0, 0.0, UIColor(white: 1.0, alpha: 0.25), false)
} else {
addShadow(true, CGPoint(), 16.0, 0.0, UIColor(white: 0.0, alpha: 0.08))
addShadow(true, CGPoint(), 8.0, 0.0, UIColor(white: 0.0, alpha: 0.08))
addShadow(true, CGPoint(), 32.0, 0.0, UIColor(white: 0.0, alpha: 0.08), false)
addShadow(true, CGPoint(), 16.0, 0.0, UIColor(white: 0.0, alpha: 0.08), false)
context.setFillColor(fillColor.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset, dy: inset))
addShadow(false, CGPoint(x: 3.0, y: -3.0), 0.5, 0.0, fillColor.withMultiplied(hue: 1.0, saturation: 2.0, brightness: 1.0).adjustedPerceivedBrightness(3.0).withMultipliedAlpha(1.0))
addShadow(false, CGPoint(x: -2.0, y: 2.0), 0.5, 0.0, UIColor.black.withMultipliedAlpha(0.15))
}
if "".isEmpty {
return
}
let maxColor = UIColor(white: 1.0, alpha: isDark ? 0.25 : 0.9)
let minColor = UIColor(white: 1.0, alpha: 0.0)
context.setFillColor(fillColor.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
let lineWidth: CGFloat = isDark ? 0.66 : 0.66
context.saveGState()
let darkShadeColor = UIColor(white: isDark ? 1.0 : 0.0, alpha: 0.035)
let lightShadeColor = UIColor(white: isDark ? 0.0 : 1.0, alpha: 0.035)
let innerShadowBlur: CGFloat = 24.0
context.resetClip()
context.addEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: lineWidth * 0.5, dy: lineWidth * 0.5))
context.clip()
context.addRect(CGRect(origin: CGPoint(), size: size).insetBy(dx: -100.0, dy: -100.0))
context.addEllipse(in: CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor.black.cgColor)
context.setShadow(offset: CGSize(width: 10.0, height: -10.0), blur: innerShadowBlur, color: darkShadeColor.cgColor)
context.fillPath(using: .evenOdd)
context.resetClip()
context.addEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: lineWidth * 0.5, dy: lineWidth * 0.5))
context.clip()
context.addRect(CGRect(origin: CGPoint(), size: size).insetBy(dx: -100.0, dy: -100.0))
context.addEllipse(in: CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor.black.cgColor)
context.setShadow(offset: CGSize(width: -10.0, height: 10.0), blur: innerShadowBlur, color: lightShadeColor.cgColor)
context.fillPath(using: .evenOdd)
context.restoreGState()
context.setLineWidth(lineWidth)
context.addRect(CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width * 0.5, height: size.height)))
context.clip()
context.addEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: lineWidth * 0.5, dy: lineWidth * 0.5))
context.replacePathWithStrokedPath()
context.clip()
do {
var locations: [CGFloat] = [0.0, 0.5, 0.5 + 0.2, 1.0 - 0.1, 1.0]
let colors: [CGColor] = [maxColor.cgColor, maxColor.cgColor, minColor.cgColor, minColor.cgColor, maxColor.cgColor]
let highlightColor: UIColor
if fillColor.hsb.s > 0.5 {
highlightColor = fillColor.withMultiplied(hue: 1.0, saturation: 2.0, brightness: 1.0).adjustedPerceivedBrightness(2.0)
let shadowColor = fillColor.withMultiplied(hue: 1.0, saturation: 2.0, brightness: 1.0).adjustedPerceivedBrightness(0.5).withMultipliedAlpha(0.2)
addShadow(false, CGPoint(x: -2.0, y: 2.0), 0.5, 0.0, shadowColor, false)
} else {
highlightColor = UIColor(white: 1.0, alpha: 0.4)
addShadow(false, CGPoint(x: -2.0, y: 2.0), 0.5, 0.0, UIColor.black.withMultipliedAlpha(0.15), true)
addShadow(false, CGPoint(x: -2.0, y: 2.0), 0.6, 0.0, UIColor(white: 0.0, alpha: 0.1), false)
}
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
}
context.resetClip()
context.addRect(CGRect(origin: CGPoint(x: size.width - size.width * 0.5, y: 0.0), size: CGSize(width: size.width * 0.5, height: size.height)))
context.clip()
context.addEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: lineWidth * 0.5, dy: lineWidth * 0.5))
context.replacePathWithStrokedPath()
context.clip()
do {
var locations: [CGFloat] = [0.0, 0.1, 0.5 - 0.2, 0.5, 1.0]
let colors: [CGColor] = [maxColor.cgColor, minColor.cgColor, minColor.cgColor, maxColor.cgColor, maxColor.cgColor]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
addShadow(false, CGPoint(x: 2.0, y: -2.0), 0.5, 0.0, highlightColor, false)
}
})!.stretchableImage(withLeftCapWidth: Int(size.width * 0.5), topCapHeight: Int(size.height * 0.5))
}
@ -784,10 +771,12 @@ public extension GlassBackgroundView {
public final class GlassBackgroundComponent: Component {
private let size: CGSize
private let isDark: Bool
private let tintColor: GlassBackgroundView.TintColor
public init(size: CGSize, tintColor: GlassBackgroundView.TintColor) {
public init(size: CGSize, isDark: Bool, tintColor: GlassBackgroundView.TintColor) {
self.size = size
self.isDark = isDark
self.tintColor = tintColor
}
@ -795,6 +784,9 @@ public final class GlassBackgroundComponent: Component {
if lhs.size != rhs.size {
return false
}
if lhs.isDark != rhs.isDark {
return false
}
if lhs.tintColor != rhs.tintColor {
return false
}
@ -803,7 +795,7 @@ public final class GlassBackgroundComponent: Component {
public final class View: GlassBackgroundView {
func update(component: GlassBackgroundComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.update(size: component.size, cornerRadius: component.size.height / 2.0, isDark: true, tintColor: component.tintColor, transition: transition)
self.update(size: component.size, cornerRadius: component.size.height / 2.0, isDark: component.isDark, tintColor: component.tintColor, transition: transition)
self.frame = CGRect(origin: .zero, size: component.size)
return component.size

View File

@ -315,6 +315,8 @@ public final class TabBarComponent: Component {
self.component = component
self.state = state
self.overrideUserInterfaceStyle = component.theme.overallDarkAppearance ? .dark : .light
if let nativeTabBar = self.nativeTabBar {
if nativeTabBar.items?.count != component.items.count {
nativeTabBar.items = (0 ..< component.items.count).map { i in

View File

@ -191,7 +191,6 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
enum ImageKey: Hashable {
case flip
case flash
case buttonBackground
case flashImage
}
private var cachedImages: [ImageKey: UIImage] = [:]
@ -205,9 +204,6 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
image = UIImage(bundleImageName: "Camera/VideoMessageFlip")!.withRenderingMode(.alwaysTemplate)
case .flash:
image = UIImage(bundleImageName: "Camera/VideoMessageFlash")!.withRenderingMode(.alwaysTemplate)
case .buttonBackground:
let innerSize = CGSize(width: 40.0, height: 40.0)
image = generateFilledCircleImage(diameter: innerSize.width, color: theme.rootController.navigationBar.opaqueBackgroundColor, strokeColor: theme.chat.inputPanel.panelSeparatorColor, strokeWidth: 0.5, backgroundColor: nil)!
case .flashImage:
image = generateImage(CGSize(width: 393.0, height: 852.0), rotatedContext: { size, context in
context.clear(CGRect(origin: .zero, size: size))
@ -590,6 +586,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
let flipButtonBackground = flipButtonBackground.update(
component: GlassBackgroundComponent(
size: CGSize(width: 40.0, height: 40.0),
isDark: environment.theme.overallDarkAppearance,
tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7))
),
availableSize: CGSize(width: 40.0, height: 40.0),
@ -691,6 +688,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
let flashButtonBackground = flashButtonBackground.update(
component: GlassBackgroundComponent(
size: CGSize(width: 40.0, height: 40.0),
isDark: environment.theme.overallDarkAppearance,
tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7))
),
availableSize: CGSize(width: 40.0, height: 40.0),
@ -719,9 +717,10 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
AnyComponentWithIdentity(
id: "background",
component: AnyComponent(
Image(
image: state.image(.buttonBackground, theme: environment.theme),
size: CGSize(width: 40.0, height: 40.0)
GlassBackgroundComponent(
size: CGSize(width: 40.0, height: 40.0),
isDark: environment.theme.overallDarkAppearance,
tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7))
)
)
),
@ -749,7 +748,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
transition: context.transition
)
context.add(viewOnceButton
.position(CGPoint(x: availableSize.width - viewOnceButton.size.width / 2.0 - 2.0 - UIScreenPixel, y: availableSize.height - viewOnceButton.size.height / 2.0 - 8.0 - viewOnceOffset))
.position(CGPoint(x: availableSize.width - viewOnceButton.size.width / 2.0 - 8.0, y: availableSize.height - viewOnceButton.size.height / 2.0 - 8.0 - viewOnceOffset))
.appear(.default(scale: true, alpha: true))
.disappear(.default(scale: true, alpha: true))
)
@ -764,6 +763,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
id: "background",
component: AnyComponent(GlassBackgroundComponent(
size: CGSize(width: 40.0, height: 40.0),
isDark: environment.theme.overallDarkAppearance,
tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7))
))
),
@ -1466,7 +1466,7 @@ public class VideoMessageCameraScreen: ViewController {
var backgroundFrame = CGRect(origin: .zero, size: CGSize(width: layout.size.width, height: controller.inputPanelFrame.0.minY))
let actualBackgroundFrame = CGRect(origin: .zero, size: CGSize(width: layout.size.width, height: layout.size.height))
if backgroundFrame.maxY < layout.size.height - 100.0 && (layout.inputHeight ?? 0.0).isZero && !controller.inputPanelFrame.1 && layout.additionalInsets.bottom.isZero {
backgroundFrame = CGRect(origin: .zero, size: CGSize(width: layout.size.width, height: layout.size.height - layout.intrinsicInsets.bottom - controller.inputPanelFrame.0.height))
backgroundFrame = CGRect(origin: .zero, size: CGSize(width: layout.size.width, height: layout.size.height - layout.intrinsicInsets.bottom - controller.inputPanelFrame.0.height - 8.0))
}
transition.setPosition(view: self.backgroundView, position: actualBackgroundFrame.center)

View File

@ -330,12 +330,6 @@ extension ChatControllerImpl {
self?.canReadHistory.set(true)
}
controller.immediateItemsTransitionAnimation = disableTransitionAnimations
controller.getOverlayViews = { [weak self] in
guard let self else {
return []
}
return [self.chatDisplayNode.navigateButtons.view]
}
self.currentContextController = controller
controller.premiumReactionsSelected = { [weak self, weak controller] in

View File

@ -1311,6 +1311,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
previousInputPanelOrigin.y -= inputPanelNode.bounds.size.height
}
if let secondaryInputPanelNode = self.secondaryInputPanelNode {
previousInputPanelOrigin.y -= 8.0
previousInputPanelOrigin.y -= secondaryInputPanelNode.bounds.size.height
}
self.containerLayoutAndNavigationBarHeight = (layout, navigationBarHeight)
@ -1568,6 +1569,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
inputPanelNodeBaseHeight += inputPanelNode.minimalHeight(interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics)
}
if let secondaryInputPanelNode = self.secondaryInputPanelNode {
inputPanelNodeBaseHeight += 8.0
inputPanelNodeBaseHeight += secondaryInputPanelNode.minimalHeight(interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics)
}
@ -1739,6 +1741,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
}
}
if let secondaryInputPanelSize = secondaryInputPanelSize {
maximumInputNodeHeight -= 8.0
maximumInputNodeHeight -= secondaryInputPanelSize.height
}
if let accessoryPanelSize = accessoryPanelSize {
@ -2128,8 +2131,11 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
if overlayContextPanelNode !== self.overlayContextPanelNode {
dismissedOverlayContextPanelNode = self.overlayContextPanelNode
self.overlayContextPanelNode = overlayContextPanelNode
self.contentContainerNode.contentNode.addSubnode(overlayContextPanelNode)
if let navigationBar = self.navigationBar {
self.contentContainerNode.contentNode.insertSubnode(overlayContextPanelNode, belowSubnode: navigationBar)
} else {
self.contentContainerNode.contentNode.addSubnode(overlayContextPanelNode)
}
immediatelyLayoutOverlayContextPanelAndAnimateAppearance = true
}
} else if let overlayContextPanelNode = self.overlayContextPanelNode {
@ -2147,10 +2153,10 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
var inputPanelHideOffset: CGFloat = 0.0
if let inputNode = self.inputNode, inputNode.hideInput {
if let inputPanelSize = inputPanelSize {
inputPanelHideOffset += -inputPanelSize.height
inputPanelHideOffset += -inputPanelSize.height - 80.0
}
if let accessoryPanelSize = accessoryPanelSize {
inputPanelHideOffset += -accessoryPanelSize.height
inputPanelHideOffset += -accessoryPanelSize.height - 80.0
}
}
@ -2164,11 +2170,11 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
}
if self.secondaryInputPanelNode != nil {
secondaryInputPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - bottomOverflowOffset - inputPanelsHeight - secondaryInputPanelSize!.height), size: CGSize(width: layout.size.width, height: secondaryInputPanelSize!.height))
secondaryInputPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - bottomOverflowOffset - inputPanelsHeight - secondaryInputPanelSize!.height - 8.0), size: CGSize(width: layout.size.width, height: secondaryInputPanelSize!.height))
if self.dismissedAsOverlay {
secondaryInputPanelFrame!.origin.y = layout.size.height
}
inputPanelsHeight += secondaryInputPanelSize!.height
inputPanelsHeight += 8.0 + secondaryInputPanelSize!.height
}
var accessoryPanelFrame: CGRect?

View File

@ -161,6 +161,7 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode {
let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: width - leftInset - rightInset - 8.0 * 2.0, height: panelHeight))
var originX: CGFloat = leftInset + floor((width - leftInset - rightInset - textSize.width) / 2.0)
var totalWidth = textSize.width
if let iconImage {
let iconView: UIImageView
@ -173,7 +174,7 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode {
}
iconView.image = iconImage
let totalWidth = textSize.width + iconImage.size.width + iconSpacing
totalWidth += iconImage.size.width + iconSpacing
iconView.frame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - totalWidth) / 2.0), y: floor((panelHeight - textSize.height) / 2.0) + UIScreenPixel + floorToScreenPixels((textSize.height - iconImage.size.height) / 2.0)), size: iconImage.size)
originX += iconImage.size.width + iconSpacing
@ -190,7 +191,11 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode {
let subtitleFrame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - subtitleSize.width) / 2.0), y: floor((panelHeight + combinedHeight) / 2.0) - subtitleSize.height), size: subtitleSize)
var combinedFrame = textFrame.union(subtitleFrame).insetBy(dx: -12.0, dy: -6.0)
var combinedFrame = textFrame.union(subtitleFrame)
if let iconView {
combinedFrame = combinedFrame.union(iconView.frame)
}
combinedFrame = combinedFrame.insetBy(dx: -12.0, dy: -6.0)
combinedFrame.origin.y += 1.0
self.textNode.frame = textFrame.offsetBy(dx: -combinedFrame.minX, dy: -combinedFrame.minY)

View File

@ -243,7 +243,8 @@ private struct CommandChatInputContextPanelEntry: Comparable, Identifiable {
messageCount: shortcut.totalCount,
hideSeparator: false,
hideDate: true,
hidePeerStatus: true
hidePeerStatus: true,
isInTransparentContainer: true
)
)),
editing: false,

View File

@ -84,7 +84,6 @@ private func preparedTransition(from fromEntries: [HorizontalListContextResultsC
final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputContextPanelNode {
private let listView: ListView
private let separatorNode: ASDisplayNode
private var currentExternalResults: ChatContextResultCollection?
private var currentProcessedResults: ChatContextResultCollection?
private var currentEntries: [HorizontalListContextResultsChatInputContextPanelEntry]?
@ -97,11 +96,6 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
private let batchVideoContext: QueueLocalObject<BatchVideoRenderingContext>
override init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, fontSize: PresentationFontSize, chatPresentationContext: ChatPresentationContext) {
self.separatorNode = ASDisplayNode()
self.separatorNode.isLayerBacked = true
self.separatorNode.backgroundColor = theme.list.itemPlainSeparatorColor
self.separatorNode.isHidden = true
self.listView = ListView()
self.listView.isOpaque = true
self.listView.backgroundColor = theme.list.plainBackgroundColor
@ -121,7 +115,6 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
self.clipsToBounds = true
self.addSubnode(self.listView)
self.addSubnode(self.separatorNode)
self.listView.displayedItemRangeChanged = { [weak self] displayedRange, opaqueTransactionState in
if let strongSelf = self, let state = opaqueTransactionState as? HorizontalListContextResultsOpaqueState {
@ -358,18 +351,10 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
self.listView.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: HorizontalListContextResultsOpaqueState(entryCount: transition.entryCount, hasMore: transition.hasMore), completion: { [weak self] _ in
if let strongSelf = self, firstTime {
let position = strongSelf.listView.position
let separatorPosition = strongSelf.separatorNode.layer.position
strongSelf.listView.isHidden = false
strongSelf.separatorNode.isHidden = false
strongSelf.listView.position = CGPoint(x: position.x, y: position.y + strongSelf.listView.bounds.size.width)
strongSelf.separatorNode.position = CGPoint(x: separatorPosition.x, y: separatorPosition.y + strongSelf.listView.bounds.size.width)
ContainedViewLayoutTransition.animated(duration: 0.3, curve: .spring).animateView {
strongSelf.listView.position = position
strongSelf.separatorNode.position = separatorPosition
}
strongSelf.layer.allowsGroupOpacity = true
strongSelf.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
}
})
}
@ -378,7 +363,6 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) {
let listHeight: CGFloat = 105.0
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: size.height - bottomInset - 8.0 - listHeight), size: CGSize(width: size.width, height: UIScreenPixel)))
self.listView.bounds = CGRect(x: 0.0, y: 0.0, width: listHeight, height: size.width)
//transition.updateFrame(node: self.listView, frame: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
@ -403,18 +387,18 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
if self.theme !== interfaceState.theme {
self.theme = interfaceState.theme
self.separatorNode.backgroundColor = theme.list.itemPlainSeparatorColor
self.listView.backgroundColor = theme.list.plainBackgroundColor
self.listView.backgroundColor = self.theme.list.plainBackgroundColor
}
}
override func animateOut(completion: @escaping () -> Void) {
let position = self.listView.layer.position
/*let position = self.listView.layer.position
self.listView.layer.animatePosition(from: position, to: CGPoint(x: position.x, y: position.y + self.listView.bounds.size.width), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
completion()
})*/
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in
completion()
})
let separatorPosition = self.separatorNode.layer.position
self.separatorNode.layer.animatePosition(from: separatorPosition, to: CGPoint(x: separatorPosition.x, y: separatorPosition.y + listView.bounds.size.width), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

View File

@ -8,8 +8,13 @@ import SwiftSignalKit
import LocalizedPeerData
import ChatPresentationInterfaceState
import ChatInputPanelNode
import ComponentFlow
import MultilineTextComponent
import GlassBackgroundComponent
final class SecretChatHandshakeStatusInputPanelNode: ChatInputPanelNode {
private let titleBackground: GlassBackgroundView
private let title = ComponentView<Empty>()
private let button: HighlightableButtonNode
private var statusDisposable: Disposable?
@ -22,9 +27,12 @@ final class SecretChatHandshakeStatusInputPanelNode: ChatInputPanelNode {
self.button.titleNode.maximumNumberOfLines = 2
self.button.titleNode.truncationMode = .byTruncatingMiddle
self.titleBackground = GlassBackgroundView()
super.init()
self.addSubnode(self.button)
self.button.view.addSubview(self.titleBackground)
self.button.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: [.touchUpInside])
}
@ -46,31 +54,48 @@ final class SecretChatHandshakeStatusInputPanelNode: ChatInputPanelNode {
}
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat {
if self.presentationInterfaceState != interfaceState {
self.presentationInterfaceState = interfaceState
if let renderedPeer = interfaceState.renderedPeer, let peer = renderedPeer.peer as? TelegramSecretChat, let userPeer = renderedPeer.peers[peer.regularPeerId] {
switch peer.embeddedState {
case .handshake:
let text: String
switch peer.role {
case .creator:
text = interfaceState.strings.DialogList_AwaitingEncryption(EnginePeer(userPeer).compactDisplayTitle).string
case .participant:
text = interfaceState.strings.Conversation_EncryptionProcessing
}
self.button.setAttributedTitle(NSAttributedString(string: text, font: Font.regular(15.0), textColor: interfaceState.theme.chat.inputPanel.primaryTextColor, paragraphAlignment: .center), for: [])
case .active, .terminated:
break
self.presentationInterfaceState = interfaceState
var text: String?
if let renderedPeer = interfaceState.renderedPeer, let peer = renderedPeer.peer as? TelegramSecretChat, let userPeer = renderedPeer.peers[peer.regularPeerId] {
switch peer.embeddedState {
case .handshake:
switch peer.role {
case .creator:
text = interfaceState.strings.DialogList_AwaitingEncryption(EnginePeer(userPeer).compactDisplayTitle).string
case .participant:
text = interfaceState.strings.Conversation_EncryptionProcessing
}
case .active, .terminated:
break
}
}
let buttonSize = self.button.measure(CGSize(width: width - 10.0, height: 100.0))
let titleSize = self.title.update(
transition: .immediate,
component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: text ?? " ", font: Font.regular(15.0), textColor: interfaceState.theme.chat.inputPanel.primaryTextColor, paragraphAlignment: .center))
)),
environment: {},
containerSize: CGSize(width: width - 16.0 * 2.0, height: 100.0)
)
let panelHeight = defaultHeight(metrics: metrics)
self.button.frame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - buttonSize.width) / 2.0), y: floor((panelHeight - buttonSize.height) / 2.0)), size: buttonSize)
let backgroundSize = CGSize(width: titleSize.width + 16.0 * 2.0, height: 40.0)
let backgroundFrame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - backgroundSize.width) * 0.5), y: floor((panelHeight - backgroundSize.height) / 2.0)), size: backgroundSize)
transition.updateFrame(node: self.button, frame: backgroundFrame)
transition.updateFrame(view: self.titleBackground, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
self.titleBackground.update(size: backgroundFrame.size, cornerRadius: backgroundFrame.height * 0.5, isDark: interfaceState.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: interfaceState.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)), transition: .immediate)
let titleFrame = CGRect(origin: CGPoint(x: floor((backgroundFrame.width - titleSize.width) * 0.5), y: floor((backgroundFrame.height - titleSize.height) * 0.5)), size: titleSize)
if let titleView = self.title.view {
if titleView.superview == nil {
titleView.setMonochromaticEffect(tintColor: interfaceState.theme.chat.inputPanel.primaryTextColor)
self.titleBackground.contentView.addSubview(titleView)
}
titleView.frame = titleFrame
}
return panelHeight
}

View File

@ -84,17 +84,13 @@ final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItem
private let buttonNode: HighlightTrackingButtonNode
private let titleNode: TextNode
private let topSeparatorNode: ASDisplayNode
private let separatorNode: ASDisplayNode
private var item: VerticalListContextResultsChatInputPanelButtonItem?
init() {
self.buttonNode = HighlightTrackingButtonNode()
self.topSeparatorNode = ASDisplayNode()
self.topSeparatorNode.isLayerBacked = true
self.separatorNode = ASDisplayNode()
self.separatorNode.isLayerBacked = true
@ -102,7 +98,6 @@ final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItem
super.init(layerBacked: false, dynamicBounce: false)
self.addSubnode(self.topSeparatorNode)
self.addSubnode(self.separatorNode)
self.addSubnode(self.titleNode)
@ -145,7 +140,7 @@ final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItem
titleFont = Font.regular(17.0)
}
let titleString = NSAttributedString(string: item.title, font: titleFont, textColor: item.theme.list.itemAccentColor)
let titleString = NSAttributedString(string: item.title, font: titleFont, textColor: item.theme.chat.inputPanel.panelControlColor)
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - 16.0, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
@ -156,7 +151,6 @@ final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItem
strongSelf.item = item
strongSelf.separatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor
strongSelf.topSeparatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor
let titleOffsetY: CGFloat
switch item.style {
@ -172,7 +166,6 @@ final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItem
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: floor((params.width - titleLayout.size.width) / 2.0), y: floor((nodeLayout.contentSize.height - titleLayout.size.height) / 2.0) + titleOffsetY), size: titleLayout.size)
strongSelf.topSeparatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: params.width, height: UIScreenPixel))
strongSelf.separatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: nodeLayout.contentSize.height - UIScreenPixel), size: CGSize(width: params.width, height: UIScreenPixel))
strongSelf.buttonNode.frame = CGRect(origin: CGPoint(), size: nodeLayout.contentSize)

View File

@ -4,6 +4,7 @@
double animationDurationFactorImpl();
CABasicAnimation * _Nonnull makeSpringAnimationImpl(NSString * _Nonnull keyPath);
CABasicAnimation * _Nonnull make26SpringAnimationImpl(NSString * _Nonnull keyPath, double duration);
CABasicAnimation * _Nonnull makeSpringBounceAnimationImpl(NSString * _Nonnull keyPath, CGFloat initialVelocity, CGFloat damping);
CGFloat springAnimationValueAtImpl(CABasicAnimation * _Nonnull animation, CGFloat t);
@ -36,3 +37,5 @@ void setLayerDisableScreenshots(CALayer * _Nonnull layer, bool disableScreenshot
bool getLayerDisableScreenshots(CALayer * _Nonnull layer);
void setLayerContentsMaskMode(CALayer * _Nonnull layer, bool maskMode);
void setMonochromaticEffectImpl(UIView * _Nonnull view, bool isEnabled);

View File

@ -61,6 +61,24 @@ CABasicAnimation * _Nonnull makeSpringAnimationImpl(NSString * _Nonnull keyPath)
return springAnimation;
}
CABasicAnimation * _Nonnull make26SpringAnimationImpl(NSString * _Nonnull keyPath, double duration) {
CASpringAnimation *springAnimation = [CASpringAnimation animationWithKeyPath:keyPath];
springAnimation.mass = 1.0f;
springAnimation.stiffness = 555.027;
springAnimation.damping = 47.118;
springAnimation.duration = duration;
springAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
if (@available(iOS 17.0, *)) {
springAnimation.allowsOverdamping = false;
}
if (@available(iOS 15.0, *)) {
[springAnimation setValue:@(1048619) forKey:@"highFrameRateReason"];
springAnimation.preferredFrameRateRange = CAFrameRateRangeMake(80.0, 120.0, 120.0);
}
return springAnimation;
}
CABasicAnimation * _Nonnull makeSpringBounceAnimationImpl(NSString * _Nonnull keyPath, CGFloat initialVelocity, CGFloat damping) {
CASpringAnimation *springAnimation = [CASpringAnimation animationWithKeyPath:keyPath];
springAnimation.mass = 5.0f;
@ -134,6 +152,20 @@ static void setBoolField(NSObject *object, NSString *name, BOOL value) {
[inv invoke];
}
static void setLongLongField(NSObject *object, NSString *name, long long value) {
SEL selector = NSSelectorFromString(name);
NSMethodSignature *signature = [[object class] instanceMethodSignatureForSelector:selector];
if (signature == nil) {
return;
}
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:signature];
[inv setSelector:selector];
[inv setArgument:&value atIndex:2];
[inv setTarget:object];
[inv invoke];
}
UIBlurEffect *makeCustomZoomBlurEffectImpl(bool isLight) {
if (@available(iOS 13.0, *)) {
if (isLight) {
@ -299,3 +331,27 @@ void setLayerContentsMaskMode(CALayer * _Nonnull layer, bool maskMode) {
[layer setValue:@"RGBA" forKey:key];
}
}
void setMonochromaticEffectImpl(UIView * _Nonnull view, bool isEnabled) {
if (@available(iOS 26.0, *)) {
static NSString *key1 = nil;
static NSString *key2 = nil;
static NSString *key3 = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
key1 = [[@"_" stringByAppendingString:@"setAllows"] stringByAppendingString:@"MonochromaticTreatment:"];
key2 = [[@"_" stringByAppendingString:@"setEnable"] stringByAppendingString:@"MonochromaticTreatment:"];
key3 = [[@"_" stringByAppendingString:@"set"] stringByAppendingString:@"MonochromaticTreatment:"];
});
if (isEnabled) {
setBoolField(view, key1, true);
setBoolField(view, key2, true);
setLongLongField(view, key3, 2);
} else {
setBoolField(view, key1, false);
setBoolField(view, key2, false);
setLongLongField(view, key3, 0);
}
}
}