mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-06 14:25:04 +00:00
Various improvements
This commit is contained in:
parent
bf3ec930bc
commit
3684c6ca15
@ -309,6 +309,8 @@ alternate_icon_folders = [
|
|||||||
"PremiumTurbo",
|
"PremiumTurbo",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
composer_icon_folders = ["Telegram"]
|
||||||
|
|
||||||
[
|
[
|
||||||
filegroup(
|
filegroup(
|
||||||
name = "{}".format(name),
|
name = "{}".format(name),
|
||||||
@ -318,6 +320,15 @@ alternate_icon_folders = [
|
|||||||
) for name in 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(
|
filegroup(
|
||||||
name = "LaunchScreen",
|
name = "LaunchScreen",
|
||||||
srcs = glob([
|
srcs = glob([
|
||||||
@ -1699,12 +1710,13 @@ ios_application(
|
|||||||
":RequiredDeviceCapabilitiesPlist",
|
":RequiredDeviceCapabilitiesPlist",
|
||||||
":UrlTypesInfoPlist",
|
":UrlTypesInfoPlist",
|
||||||
],
|
],
|
||||||
|
app_icons = [ ":{}_icon".format(name) for name in composer_icon_folders ],
|
||||||
alternate_icons = [
|
alternate_icons = [
|
||||||
":{}".format(name) for name in alternate_icon_folders
|
":{}".format(name) for name in alternate_icon_folders
|
||||||
],
|
],
|
||||||
resources = [
|
resources = [
|
||||||
":LaunchScreen",
|
":LaunchScreen",
|
||||||
":DefaultAppIcon",
|
#":DefaultAppIcon",
|
||||||
],
|
],
|
||||||
frameworks = [
|
frameworks = [
|
||||||
":MtProtoKitFramework",
|
":MtProtoKitFramework",
|
||||||
|
|||||||
7
Telegram/Telegram-iOS/Telegram.icon/Assets/Oval.svg
Normal file
7
Telegram/Telegram-iOS/Telegram.icon/Assets/Oval.svg
Normal 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 |
7
Telegram/Telegram-iOS/Telegram.icon/Assets/Plane.svg
Normal file
7
Telegram/Telegram-iOS/Telegram.icon/Assets/Plane.svg
Normal 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 |
122
Telegram/Telegram-iOS/Telegram.icon/icon.json
Normal file
122
Telegram/Telegram-iOS/Telegram.icon/icon.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15077,3 +15077,14 @@ Error: %8$@";
|
|||||||
"Conversation.SuggestedBirthdate.View" = "View";
|
"Conversation.SuggestedBirthdate.View" = "View";
|
||||||
|
|
||||||
"PeerInfo.ChangeProfileColor" = "Change Profile Color";
|
"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$@";
|
||||||
|
|||||||
@ -700,6 +700,9 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
|
|||||||
let hadLayout = self.validLayout != nil
|
let hadLayout = self.validLayout != nil
|
||||||
let previousAdditionalSideInsets = self.validLayout?.3
|
let previousAdditionalSideInsets = self.validLayout?.3
|
||||||
self.validLayout = (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary)
|
self.validLayout = (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary)
|
||||||
|
|
||||||
|
let leftInset = leftInset + 8.0
|
||||||
|
let rightInset = rightInset + 8.0
|
||||||
|
|
||||||
var transition = transition
|
var transition = transition
|
||||||
if let previousAdditionalSideInsets = previousAdditionalSideInsets, previousAdditionalSideInsets.right != additionalSideInsets.right {
|
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 {
|
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
|
return 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let leftInset = leftInsetValue + 8.0
|
||||||
|
let rightInset = rightInsetValue + 8.0
|
||||||
|
|
||||||
var textFieldMinHeight: CGFloat = 33.0
|
var textFieldMinHeight: CGFloat = 33.0
|
||||||
if let presentationInterfaceState = self.presentationInterfaceState {
|
if let presentationInterfaceState = self.presentationInterfaceState {
|
||||||
textFieldMinHeight = calclulateTextFieldMinHeight(presentationInterfaceState, metrics: metrics)
|
textFieldMinHeight = calclulateTextFieldMinHeight(presentationInterfaceState, metrics: metrics)
|
||||||
@ -1280,6 +1287,9 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
|
|||||||
if let (width, leftInset, rightInset, _, maxHeight, metrics, _) = self.validLayout {
|
if let (width, leftInset, rightInset, _, maxHeight, metrics, _) = self.validLayout {
|
||||||
let composeButtonsOffset: CGFloat = 0.0
|
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 (_, textFieldHeight) = self.calculateTextFieldMetrics(width: width - leftInset - rightInset, maxHeight: maxHeight, metrics: metrics)
|
||||||
let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics)
|
let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics)
|
||||||
var textFieldMinHeight: CGFloat = 33.0
|
var textFieldMinHeight: CGFloat = 33.0
|
||||||
@ -1421,6 +1431,9 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
|
|||||||
|
|
||||||
private func updateTextHeight(animated: Bool) -> CGFloat? {
|
private func updateTextHeight(animated: Bool) -> CGFloat? {
|
||||||
if let (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, _) = self.validLayout {
|
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 (_, textFieldHeight) = self.calculateTextFieldMetrics(width: width - leftInset - rightInset - additionalSideInsets.right, maxHeight: maxHeight, metrics: metrics)
|
||||||
let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics)
|
let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics)
|
||||||
if !self.bounds.size.height.isEqual(to: panelHeight) {
|
if !self.bounds.size.height.isEqual(to: panelHeight) {
|
||||||
|
|||||||
@ -124,14 +124,16 @@ public enum ChatListItemContent {
|
|||||||
public var hideSeparator: Bool
|
public var hideSeparator: Bool
|
||||||
public var hideDate: Bool
|
public var hideDate: Bool
|
||||||
public var hidePeerStatus: 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.commandPrefix = commandPrefix
|
||||||
self.searchQuery = searchQuery
|
self.searchQuery = searchQuery
|
||||||
self.messageCount = messageCount
|
self.messageCount = messageCount
|
||||||
self.hideSeparator = hideSeparator
|
self.hideSeparator = hideSeparator
|
||||||
self.hideDate = hideDate
|
self.hideDate = hideDate
|
||||||
self.hidePeerStatus = hidePeerStatus
|
self.hidePeerStatus = hidePeerStatus
|
||||||
|
self.isInTransparentContainer = isInTransparentContainer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1966,6 +1968,11 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
reallyHighlighted = true
|
reallyHighlighted = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if case let .peer(peerData) = item.content, let customMessageListData = peerData.customMessageListData {
|
||||||
|
if customMessageListData.isInTransparentContainer {
|
||||||
|
reallyHighlighted = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return reallyHighlighted
|
return reallyHighlighted
|
||||||
}
|
}
|
||||||
|
|||||||
@ -104,7 +104,34 @@ public extension CALayer {
|
|||||||
|
|
||||||
return animation
|
return animation
|
||||||
} else if timingFunction == kCAMediaTimingFunctionSpring {
|
} 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)
|
let animation = makeSpringAnimation(keyPath)
|
||||||
animation.fromValue = from
|
animation.fromValue = from
|
||||||
animation.toValue = to
|
animation.toValue = to
|
||||||
|
|||||||
@ -900,3 +900,54 @@ public extension CGPoint {
|
|||||||
return CGPoint(x: self.x + dx, y: self.y + dy)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -604,7 +604,10 @@ public class Window1 {
|
|||||||
|
|
||||||
var duration: Double = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.0
|
var duration: Double = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.0
|
||||||
if duration > Double.ulpOfOne {
|
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
|
let curve: UInt = (notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber)?.uintValue ?? 7
|
||||||
|
|
||||||
|
|||||||
@ -2232,7 +2232,7 @@ final class VideoChatScreenComponent: Component {
|
|||||||
color: .white
|
color: .white
|
||||||
)),
|
)),
|
||||||
background: AnyComponent(
|
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,
|
effectAlignment: .center,
|
||||||
minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter),
|
minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter),
|
||||||
@ -2254,7 +2254,7 @@ final class VideoChatScreenComponent: Component {
|
|||||||
image: closeButtonImage(dark: false)
|
image: closeButtonImage(dark: false)
|
||||||
)),
|
)),
|
||||||
background: AnyComponent(
|
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,
|
effectAlignment: .center,
|
||||||
minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter),
|
minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter),
|
||||||
|
|||||||
@ -663,14 +663,14 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati
|
|||||||
panelBackgroundColorNoWallpaper: UIColor(rgb: 0x000000),
|
panelBackgroundColorNoWallpaper: UIColor(rgb: 0x000000),
|
||||||
panelSeparatorColor: UIColor(rgb: 0x545458, alpha: 0.55),
|
panelSeparatorColor: UIColor(rgb: 0x545458, alpha: 0.55),
|
||||||
panelControlAccentColor: UIColor(rgb: 0xffffff),
|
panelControlAccentColor: UIColor(rgb: 0xffffff),
|
||||||
panelControlColor: UIColor(rgb: 0x808080),
|
panelControlColor: UIColor(rgb: 0xffffff),
|
||||||
panelControlDisabledColor: UIColor(rgb: 0x808080, alpha: 0.5),
|
panelControlDisabledColor: UIColor(rgb: 0x808080, alpha: 0.5),
|
||||||
panelControlDestructiveColor: UIColor(rgb: 0xff3b30),
|
panelControlDestructiveColor: UIColor(rgb: 0xff3b30),
|
||||||
inputBackgroundColor: UIColor(rgb: 0x060606),
|
inputBackgroundColor: UIColor(rgb: 0x060606),
|
||||||
inputStrokeColor: UIColor(rgb: 0xffffff, alpha: 0.1),
|
inputStrokeColor: UIColor(rgb: 0xffffff, alpha: 0.1),
|
||||||
inputPlaceholderColor: UIColor(rgb: 0x7b7b7b),
|
inputPlaceholderColor: UIColor(rgb: 0x7b7b7b),
|
||||||
inputTextColor: UIColor(rgb: 0xffffff),
|
inputTextColor: UIColor(rgb: 0xffffff),
|
||||||
inputControlColor: UIColor(rgb: 0x7b7b7b),
|
inputControlColor: UIColor(rgb: 0xffffff),
|
||||||
actionControlFillColor: UIColor(rgb: 0xffffff),
|
actionControlFillColor: UIColor(rgb: 0xffffff),
|
||||||
actionControlForegroundColor: UIColor(rgb: 0x000000),
|
actionControlForegroundColor: UIColor(rgb: 0x000000),
|
||||||
primaryTextColor: UIColor(rgb: 0xffffff),
|
primaryTextColor: UIColor(rgb: 0xffffff),
|
||||||
|
|||||||
@ -943,17 +943,17 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
|
|||||||
panelBackgroundColorNoWallpaper: UIColor(rgb: 0xffffff),
|
panelBackgroundColorNoWallpaper: UIColor(rgb: 0xffffff),
|
||||||
panelSeparatorColor: UIColor(white: 1.0, alpha: 0.5),
|
panelSeparatorColor: UIColor(white: 1.0, alpha: 0.5),
|
||||||
panelControlAccentColor: defaultDayAccentColor,
|
panelControlAccentColor: defaultDayAccentColor,
|
||||||
panelControlColor: UIColor(rgb: 0x858e99),
|
panelControlColor: UIColor(rgb: 0x000000, alpha: 1.0),
|
||||||
panelControlDisabledColor: UIColor(rgb: 0x727b87, alpha: 0.5),
|
panelControlDisabledColor: UIColor(rgb: 0x727b87, alpha: 0.5),
|
||||||
panelControlDestructiveColor: UIColor(rgb: 0xff3b30),
|
panelControlDestructiveColor: UIColor(rgb: 0xff3b30),
|
||||||
inputBackgroundColor: UIColor(rgb: 0xffffff),
|
inputBackgroundColor: UIColor(rgb: 0xffffff),
|
||||||
inputStrokeColor: UIColor(rgb: 0x000000, alpha: 0.1),
|
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),
|
inputTextColor: UIColor(rgb: 0x000000),
|
||||||
inputControlColor: UIColor(rgb: 0x202020, alpha: 0.6),
|
inputControlColor: UIColor(rgb: 0x000000, alpha: 1.0),
|
||||||
actionControlFillColor: defaultDayAccentColor,
|
actionControlFillColor: defaultDayAccentColor,
|
||||||
actionControlForegroundColor: UIColor(rgb: 0xffffff),
|
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),
|
secondaryTextColor: UIColor(rgb: 0x202020, alpha: 0.6),
|
||||||
mediaRecordingDotColor: UIColor(rgb: 0xed2521),
|
mediaRecordingDotColor: UIColor(rgb: 0xed2521),
|
||||||
mediaRecordingControl: inputPanelMediaRecordingControl
|
mediaRecordingControl: inputPanelMediaRecordingControl
|
||||||
|
|||||||
@ -57,6 +57,10 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
private var cachedMaskBackgroundImage: (CGPoint, UIImage, [CGRect])?
|
private var cachedMaskBackgroundImage: (CGPoint, UIImage, [CGRect])?
|
||||||
private var absoluteRect: (CGRect, CGSize)?
|
private var absoluteRect: (CGRect, CGSize)?
|
||||||
|
|
||||||
|
override public var disablesClipping: Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
override public var visibility: ListViewItemNodeVisibility {
|
override public var visibility: ListViewItemNodeVisibility {
|
||||||
didSet {
|
didSet {
|
||||||
if oldValue != self.visibility {
|
if oldValue != self.visibility {
|
||||||
|
|||||||
@ -3442,14 +3442,14 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||||||
contentContainerNodeFrames: contentContainerNodeFrames.map { containerGroupId, containerFrame, currentItemSelection, currentContainerGroupOverlap in
|
contentContainerNodeFrames: contentContainerNodeFrames.map { containerGroupId, containerFrame, currentItemSelection, currentContainerGroupOverlap in
|
||||||
return (containerGroupId, containerFrame.offsetBy(dx: 0.0, dy: layoutInsets.top), currentItemSelection, currentContainerGroupOverlap)
|
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,
|
mosaicStatusSizeAndApply: mosaicStatusSizeAndApply,
|
||||||
unlockButtonPosition: unlockButtonPosition?.offsetBy(dx: 0.0, dy: layoutInsets.top),
|
unlockButtonPosition: unlockButtonPosition?.offsetBy(dx: 0.0, dy: layoutInsets.top),
|
||||||
unlockButtonSizeAndApply: unlockButtonSizeApply,
|
unlockButtonSizeAndApply: unlockButtonSizeApply,
|
||||||
mediaInfoOrigin: mediaInfoOrigin?.offsetBy(dx: 0.0, dy: layoutInsets.top),
|
mediaInfoOrigin: mediaInfoOrigin?.offsetBy(dx: 0.0, dy: layoutInsets.top),
|
||||||
mediaInfoSizeAndApply: mediaInfoSizeApply,
|
mediaInfoSizeAndApply: mediaInfoSizeApply,
|
||||||
needsShareButton: needsShareButton,
|
needsShareButton: needsShareButton,
|
||||||
shareButtonOffset: shareButtonOffset?.offsetBy(dx: 0.0, dy: layoutInsets.top),
|
shareButtonOffset: shareButtonOffset,
|
||||||
avatarOffset: avatarOffset,
|
avatarOffset: avatarOffset,
|
||||||
hidesHeaders: hidesHeaders,
|
hidesHeaders: hidesHeaders,
|
||||||
disablesComments: disablesComments,
|
disablesComments: disablesComments,
|
||||||
|
|||||||
@ -86,6 +86,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
|
|
||||||
private var currentProgressDisposable: Disposable?
|
private var currentProgressDisposable: Disposable?
|
||||||
|
|
||||||
|
override public var disablesClipping: Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
override public var visibility: ListViewItemNodeVisibility {
|
override public var visibility: ListViewItemNodeVisibility {
|
||||||
didSet {
|
didSet {
|
||||||
let wasVisible = oldValue != .none
|
let wasVisible = oldValue != .none
|
||||||
|
|||||||
@ -449,10 +449,10 @@ public final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
|
|||||||
self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded)
|
self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded)
|
||||||
|
|
||||||
var leftInset = leftInset
|
var leftInset = leftInset
|
||||||
leftInset += 8.0
|
leftInset += 16.0
|
||||||
|
|
||||||
var rightInset = rightInset
|
var rightInset = rightInset
|
||||||
rightInset += 8.0
|
rightInset += 16.0
|
||||||
|
|
||||||
let panelHeight = defaultHeight(metrics: metrics)
|
let panelHeight = defaultHeight(metrics: metrics)
|
||||||
|
|
||||||
|
|||||||
@ -197,6 +197,7 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag
|
|||||||
self.expandMediaInputButtonBackgroundView.contentView.addSubview(self.expandMediaInputButtonIcon)
|
self.expandMediaInputButtonBackgroundView.contentView.addSubview(self.expandMediaInputButtonIcon)
|
||||||
self.expandMediaInputButtonIcon.image = PresentationResourcesChat.chatInputPanelExpandButtonImage(presentationInterfaceState.theme)
|
self.expandMediaInputButtonIcon.image = PresentationResourcesChat.chatInputPanelExpandButtonImage(presentationInterfaceState.theme)
|
||||||
self.expandMediaInputButtonIcon.tintColor = theme.chat.inputPanel.inputControlColor
|
self.expandMediaInputButtonIcon.tintColor = theme.chat.inputPanel.inputControlColor
|
||||||
|
self.expandMediaInputButtonIcon.setMonochromaticEffect(tintColor: theme.chat.inputPanel.inputControlColor)
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -265,6 +266,7 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag
|
|||||||
public func updateTheme(theme: PresentationTheme, wallpaper: TelegramWallpaper) {
|
public func updateTheme(theme: PresentationTheme, wallpaper: TelegramWallpaper) {
|
||||||
self.micButton.updateTheme(theme: theme)
|
self.micButton.updateTheme(theme: theme)
|
||||||
self.expandMediaInputButtonIcon.tintColor = theme.chat.inputPanel.inputControlColor
|
self.expandMediaInputButtonIcon.tintColor = theme.chat.inputPanel.inputControlColor
|
||||||
|
self.expandMediaInputButtonIcon.setMonochromaticEffect(tintColor: theme.chat.inputPanel.inputControlColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var absoluteRect: (CGRect, CGSize)?
|
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))
|
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 {
|
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)
|
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)
|
self.expandMediaInputButtonIcon.center = expandIconFrame.center
|
||||||
transition.updateBounds(layer: self.expandMediaInputButtonIcon.layer, bounds: CGRect(origin: CGPoint(), size: expandIconFrame.size))
|
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))
|
transition.updateTransformScale(layer: self.expandMediaInputButtonIcon.layer, scale: CGPoint(x: 1.0, y: isMediaInputExpanded ? 1.0 : -1.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,8 +16,7 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie
|
|||||||
private var theme: PresentationTheme
|
private var theme: PresentationTheme
|
||||||
private var strings: PresentationStrings
|
private var strings: PresentationStrings
|
||||||
private var width: CGFloat
|
private var width: CGFloat
|
||||||
private let iconImageView: UIImageView
|
private let iconImageView: GlassBackgroundView.ContentImageView
|
||||||
private let tintMaskIconImageView: UIImageView
|
|
||||||
private var textView: ImmediateTextView?
|
private var textView: ImmediateTextView?
|
||||||
private var tintMaskTextView: ImmediateTextView?
|
private var tintMaskTextView: ImmediateTextView?
|
||||||
private var animationView: ComponentView<Empty>?
|
private var animationView: ComponentView<Empty>?
|
||||||
@ -34,8 +33,7 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie
|
|||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
|
|
||||||
self.iconImageView = UIImageView()
|
self.iconImageView = GlassBackgroundView.ContentImageView()
|
||||||
self.tintMaskIconImageView = UIImageView()
|
|
||||||
|
|
||||||
let (image, text, accessibilityLabel, alpha, _) = AccessoryItemIconButton.imageAndInsets(item: item, theme: theme, strings: strings)
|
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.iconImageView.isUserInteractionEnabled = false
|
||||||
self.addSubview(self.iconImageView)
|
self.addSubview(self.iconImageView)
|
||||||
|
|
||||||
self.tintMask.addSubview(self.tintMaskIconImageView)
|
self.tintMask.addSubview(self.iconImageView.tintMask)
|
||||||
|
|
||||||
switch item {
|
switch item {
|
||||||
case .input, .botInput, .silentPost:
|
case .input, .botInput, .silentPost:
|
||||||
self.iconImageView.isHidden = true
|
self.iconImageView.isHidden = true
|
||||||
self.tintMaskIconImageView.isHidden = self.iconImageView.isHidden
|
|
||||||
self.animationView = ComponentView<Empty>()
|
self.animationView = ComponentView<Empty>()
|
||||||
self.tintMaskAnimationView = UIImageView()
|
self.tintMaskAnimationView = UIImageView()
|
||||||
default:
|
default:
|
||||||
@ -93,10 +90,6 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie
|
|||||||
self.iconImageView.tintColor = theme.chat.inputPanel.inputControlColor
|
self.iconImageView.tintColor = theme.chat.inputPanel.inputControlColor
|
||||||
self.iconImageView.alpha = alpha
|
self.iconImageView.alpha = alpha
|
||||||
|
|
||||||
self.tintMaskIconImageView.image = self.iconImageView.image
|
|
||||||
self.tintMaskIconImageView.tintColor = .black
|
|
||||||
self.tintMaskIconImageView.alpha = self.iconImageView.alpha
|
|
||||||
|
|
||||||
self.accessibilityLabel = accessibilityLabel
|
self.accessibilityLabel = accessibilityLabel
|
||||||
|
|
||||||
self.highligthedChanged = { [weak self] highlighted in
|
self.highligthedChanged = { [weak self] highlighted in
|
||||||
@ -138,10 +131,6 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie
|
|||||||
self.iconImageView.tintColor = theme.chat.inputPanel.inputControlColor
|
self.iconImageView.tintColor = theme.chat.inputPanel.inputControlColor
|
||||||
self.iconImageView.alpha = alpha
|
self.iconImageView.alpha = alpha
|
||||||
|
|
||||||
self.tintMaskIconImageView.image = self.iconImageView.image
|
|
||||||
self.tintMaskIconImageView.tintColor = .black
|
|
||||||
self.tintMaskIconImageView.alpha = self.iconImageView.alpha
|
|
||||||
|
|
||||||
self.accessibilityLabel = accessibilityLabel
|
self.accessibilityLabel = accessibilityLabel
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,12 +194,13 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie
|
|||||||
|
|
||||||
if let image = self.iconImageView.image {
|
if let image = self.iconImageView.image {
|
||||||
self.iconImageView.image = updatedImage
|
self.iconImageView.image = updatedImage
|
||||||
self.tintMaskIconImageView.image = updatedImage
|
|
||||||
|
|
||||||
let bottomInset: CGFloat = 0.0
|
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.iconImageView.frame = imageFrame
|
||||||
self.tintMaskIconImageView.frame = imageFrame
|
|
||||||
|
|
||||||
if let animationView = self.animationView {
|
if let animationView = self.animationView {
|
||||||
let width = AccessoryItemIconButton.calculateWidth(item: item, image: image, text: "", strings: self.strings)
|
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)
|
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)
|
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
|
view.frame = animationFrameValue
|
||||||
if let tintMaskAnimationView = self.tintMaskAnimationView {
|
if let tintMaskAnimationView = self.tintMaskAnimationView {
|
||||||
|
|||||||
@ -214,11 +214,9 @@ private func makeTextInputTheme(context: AccountContext, interfaceState: ChatPre
|
|||||||
public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, ChatInputTextNodeDelegate {
|
public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, ChatInputTextNodeDelegate {
|
||||||
public let clippingNode: ASDisplayNode
|
public let clippingNode: ASDisplayNode
|
||||||
public let textPlaceholderNode: ImmediateTextNodeWithEntities
|
public let textPlaceholderNode: ImmediateTextNodeWithEntities
|
||||||
public let tintMaskTextPlaceholderNode: ImmediateTextNodeWithEntities
|
|
||||||
|
|
||||||
public var textLockIconNode: ASImageNode?
|
public var textLockIconNode: ASImageNode?
|
||||||
public var contextPlaceholderNode: TextNode?
|
public var contextPlaceholderNode: TextNode?
|
||||||
public var tintContextPlaceholderNode: TextNode?
|
|
||||||
public var slowmodePlaceholderNode: ChatTextInputSlowmodePlaceholderNode?
|
public var slowmodePlaceholderNode: ChatTextInputSlowmodePlaceholderNode?
|
||||||
public let textInputContainerBackgroundView: GlassBackgroundView
|
public let textInputContainerBackgroundView: GlassBackgroundView
|
||||||
public let textInputContainer: ASDisplayNode
|
public let textInputContainer: ASDisplayNode
|
||||||
@ -521,20 +519,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||||||
self.textPlaceholderNode.contentsScale = UIScreenScale
|
self.textPlaceholderNode.contentsScale = UIScreenScale
|
||||||
self.textPlaceholderNode.maximumNumberOfLines = 1
|
self.textPlaceholderNode.maximumNumberOfLines = 1
|
||||||
self.textPlaceholderNode.isUserInteractionEnabled = false
|
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 = HighlightTrackingButtonNode()
|
||||||
self.menuButton.clipsToBounds = true
|
self.menuButton.clipsToBounds = true
|
||||||
self.menuButton.cornerRadius = 16.0
|
self.menuButton.cornerRadius = 16.0
|
||||||
@ -566,7 +551,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||||||
self.attachmentButton.isAccessibilityElement = true
|
self.attachmentButton.isAccessibilityElement = true
|
||||||
|
|
||||||
self.attachmentButtonBackground = GlassBackgroundView(frame: CGRect())
|
self.attachmentButtonBackground = GlassBackgroundView(frame: CGRect())
|
||||||
self.attachmentButtonBackground.isUserInteractionEnabled = false
|
|
||||||
self.attachmentButton.addSubview(self.attachmentButtonBackground)
|
self.attachmentButton.addSubview(self.attachmentButtonBackground)
|
||||||
|
|
||||||
self.attachmentButtonIcon = GlassBackgroundView.ContentImageView()
|
self.attachmentButtonIcon = GlassBackgroundView.ContentImageView()
|
||||||
@ -785,7 +769,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||||||
self.clippingNode.addSubnode(self.textInputBackgroundNode)
|
self.clippingNode.addSubnode(self.textInputBackgroundNode)
|
||||||
|
|
||||||
self.textInputContainerBackgroundView.contentView.addSubview(self.textPlaceholderNode.view)
|
self.textInputContainerBackgroundView.contentView.addSubview(self.textPlaceholderNode.view)
|
||||||
self.textInputContainerBackgroundView.maskContentView.addSubview(self.tintMaskTextPlaceholderNode.view)
|
|
||||||
|
|
||||||
self.menuButton.view.addSubview(self.menuButtonBackgroundView)
|
self.menuButton.view.addSubview(self.menuButtonBackgroundView)
|
||||||
self.menuButton.addSubnode(self.menuButtonClippingNode)
|
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) {
|
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)
|
var textFieldInsets = self.textFieldInsets(metrics: metrics)
|
||||||
if self.actionButtons.frame.width > 40.0 {
|
if self.actionButtons.frame.width > 40.0 {
|
||||||
textFieldInsets.right = self.actionButtons.frame.width - 2.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 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)
|
let updatedMaxHeight = (CGFloat(maxNumberOfLines) * (22.0 + 2.0) + 10.0)
|
||||||
|
|
||||||
@ -1256,6 +1241,8 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||||||
) -> CGFloat {
|
) -> CGFloat {
|
||||||
let previousAdditionalSideInsets = self.validLayout?.4
|
let previousAdditionalSideInsets = self.validLayout?.4
|
||||||
self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded)
|
self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded)
|
||||||
|
|
||||||
|
let placeholderColor: UIColor = interfaceState.theme.chat.inputPanel.inputPlaceholderColor
|
||||||
|
|
||||||
var transition = transition
|
var transition = transition
|
||||||
var additionalOffset: CGFloat = 0.0
|
var additionalOffset: CGFloat = 0.0
|
||||||
@ -2423,21 +2410,16 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||||||
|
|
||||||
if interfaceState.slowmodeState == nil || isScheduledMessages, let contextPlaceholder = interfaceState.inputTextPanelState.contextPlaceholder {
|
if interfaceState.slowmodeState == nil || isScheduledMessages, let contextPlaceholder = interfaceState.inputTextPanelState.contextPlaceholder {
|
||||||
let placeholderLayout = TextNode.asyncLayout(self.contextPlaceholderNode)
|
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 (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)
|
let tintContextPlaceholder = NSMutableAttributedString(attributedString: contextPlaceholder)
|
||||||
tintContextPlaceholder.addAttribute(.foregroundColor, value: UIColor.black, range: NSRange(location: 0, length: tintContextPlaceholder.length))
|
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 contextPlaceholderNode = placeholderApply()
|
||||||
let tintContextPlaceholderNode = tintPlaceholderApply()
|
|
||||||
if let currentContextPlaceholderNode = self.contextPlaceholderNode, currentContextPlaceholderNode !== contextPlaceholderNode {
|
if let currentContextPlaceholderNode = self.contextPlaceholderNode, currentContextPlaceholderNode !== contextPlaceholderNode {
|
||||||
self.contextPlaceholderNode = nil
|
self.contextPlaceholderNode = nil
|
||||||
currentContextPlaceholderNode.removeFromSupernode()
|
currentContextPlaceholderNode.removeFromSupernode()
|
||||||
}
|
}
|
||||||
if let currentTintContextPlaceholderNode = self.tintContextPlaceholderNode, currentTintContextPlaceholderNode !== tintContextPlaceholderNode {
|
|
||||||
self.tintContextPlaceholderNode = nil
|
|
||||||
currentTintContextPlaceholderNode.removeFromSupernode()
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.contextPlaceholderNode !== contextPlaceholderNode {
|
if self.contextPlaceholderNode !== contextPlaceholderNode {
|
||||||
contextPlaceholderNode.displaysAsynchronously = false
|
contextPlaceholderNode.displaysAsynchronously = false
|
||||||
@ -2445,12 +2427,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||||||
self.contextPlaceholderNode = contextPlaceholderNode
|
self.contextPlaceholderNode = contextPlaceholderNode
|
||||||
self.textInputContainerBackgroundView.contentView.insertSubview(contextPlaceholderNode.view, aboveSubview: self.textPlaceholderNode.view)
|
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()
|
let _ = placeholderApply()
|
||||||
|
|
||||||
@ -2460,21 +2436,14 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||||||
} else {
|
} else {
|
||||||
placeholderTransition = .immediate
|
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))
|
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.alpha = audioRecordingItemsAlpha
|
contextPlaceholderNode.view.setMonochromaticEffect(tintColor: placeholderColor)
|
||||||
|
contextPlaceholderNode.alpha = audioRecordingItemsAlpha * placeholderColor.alpha
|
||||||
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
|
|
||||||
} else {
|
} else {
|
||||||
if let contextPlaceholderNode = self.contextPlaceholderNode {
|
if let contextPlaceholderNode = self.contextPlaceholderNode {
|
||||||
self.contextPlaceholderNode = nil
|
self.contextPlaceholderNode = nil
|
||||||
contextPlaceholderNode.removeFromSupernode()
|
contextPlaceholderNode.removeFromSupernode()
|
||||||
self.textPlaceholderNode.alpha = 1.0
|
self.textPlaceholderNode.alpha = 1.0 * placeholderColor.alpha
|
||||||
self.tintMaskTextPlaceholderNode.alpha = 1.0
|
|
||||||
}
|
|
||||||
if let tintContextPlaceholderNode = self.tintContextPlaceholderNode {
|
|
||||||
self.tintContextPlaceholderNode = nil
|
|
||||||
tintContextPlaceholderNode.removeFromSupernode()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2499,11 +2468,9 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||||||
|
|
||||||
if (interfaceState.slowmodeState != nil && rightSlowModeInset.isZero && !isScheduledMessages && interfaceState.editMessageState == nil) || interfaceState.inputTextPanelState.contextPlaceholder != nil {
|
if (interfaceState.slowmodeState != nil && rightSlowModeInset.isZero && !isScheduledMessages && interfaceState.editMessageState == nil) || interfaceState.inputTextPanelState.contextPlaceholder != nil {
|
||||||
self.textPlaceholderNode.isHidden = true
|
self.textPlaceholderNode.isHidden = true
|
||||||
self.tintMaskTextPlaceholderNode.isHidden = true
|
|
||||||
self.slowmodePlaceholderNode?.isHidden = inputHasText
|
self.slowmodePlaceholderNode?.isHidden = inputHasText
|
||||||
} else {
|
} else {
|
||||||
self.textPlaceholderNode.isHidden = inputHasText
|
self.textPlaceholderNode.isHidden = inputHasText
|
||||||
self.tintMaskTextPlaceholderNode.isHidden = inputHasText
|
|
||||||
self.slowmodePlaceholderNode?.isHidden = true
|
self.slowmodePlaceholderNode?.isHidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2539,38 +2506,24 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||||||
let textPlaceholderSize: CGSize
|
let textPlaceholderSize: CGSize
|
||||||
let textPlaceholderMaxWidth: CGFloat = max(1.0, nextButtonTopRight.x - 12.0)
|
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 {
|
if (updatedPlaceholder != nil && self.currentPlaceholder != updatedPlaceholder) || themeUpdated {
|
||||||
let currentPlaceholder = updatedPlaceholder ?? self.currentPlaceholder ?? ""
|
let currentPlaceholder = updatedPlaceholder ?? self.currentPlaceholder ?? ""
|
||||||
self.currentPlaceholder = currentPlaceholder
|
self.currentPlaceholder = currentPlaceholder
|
||||||
let baseFontSize = max(minInputFontSize, interfaceState.fontSize.baseDisplaySize)
|
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: "#") {
|
if placeholderHasStar, let range = attributedPlaceholder.string.range(of: "#") {
|
||||||
attributedPlaceholder.addAttribute(.attachment, value: PresentationResourcesChat.chatPlaceholderStarIcon(interfaceState.theme)!, range: NSRange(range, in: attributedPlaceholder.string))
|
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))
|
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.textPlaceholderNode.attributedText = attributedPlaceholder
|
||||||
self.tintMaskTextPlaceholderNode.attributedText = attributedTintMaskPlaceholder
|
self.textPlaceholderNode.view.setMonochromaticEffect(tintColor: placeholderColor)
|
||||||
|
|
||||||
self.textInputNode?.textView.accessibilityHint = currentPlaceholder
|
self.textInputNode?.textView.accessibilityHint = currentPlaceholder
|
||||||
|
|
||||||
let placeholderSize = self.textPlaceholderNode.updateLayout(CGSize(width: textPlaceholderMaxWidth, height: CGFloat.greatestFiniteMagnitude))
|
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() {
|
if transition.isAnimated, let snapshotLayer = self.textPlaceholderNode.layer.snapshotContentTree() {
|
||||||
self.textPlaceholderNode.supernode?.layer.insertSublayer(snapshotLayer, above: self.textPlaceholderNode.layer)
|
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)
|
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
|
textPlaceholderSize = placeholderSize
|
||||||
} else {
|
} else {
|
||||||
textPlaceholderSize = self.textPlaceholderNode.bounds.size
|
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.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.textPlaceholderNode, alpha: textPlaceholderAlpha)
|
||||||
transition.updateAlpha(node: self.tintMaskTextPlaceholderNode, alpha: textPlaceholderAlpha)
|
|
||||||
|
|
||||||
if let removeAccessoryButtons = removeAccessoryButtons {
|
if let removeAccessoryButtons {
|
||||||
for button in removeAccessoryButtons {
|
for button in removeAccessoryButtons {
|
||||||
let buttonFrame = CGRect(origin: CGPoint(x: button.frame.origin.x + additionalOffset, y: textInputFrame.maxY - minimalInputHeight), size: button.frame.size)
|
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)
|
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))
|
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.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(layer: self.attachmentButton.layer, frame: attachmentButtonFrame)
|
||||||
transition.updateFrame(node: self.attachmentButtonDisabledNode, frame: self.attachmentButton.frame)
|
transition.updateFrame(node: self.attachmentButtonDisabledNode, frame: self.attachmentButton.frame)
|
||||||
@ -3667,11 +3609,9 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||||||
if let interfaceState = self.presentationInterfaceState {
|
if let interfaceState = self.presentationInterfaceState {
|
||||||
if (interfaceState.slowmodeState != nil && !isScheduledMessages && interfaceState.editMessageState == nil) || interfaceState.inputTextPanelState.contextPlaceholder != nil {
|
if (interfaceState.slowmodeState != nil && !isScheduledMessages && interfaceState.editMessageState == nil) || interfaceState.inputTextPanelState.contextPlaceholder != nil {
|
||||||
self.textPlaceholderNode.isHidden = true
|
self.textPlaceholderNode.isHidden = true
|
||||||
self.tintMaskTextPlaceholderNode.isHidden = true
|
|
||||||
self.slowmodePlaceholderNode?.isHidden = inputHasText
|
self.slowmodePlaceholderNode?.isHidden = inputHasText
|
||||||
} else {
|
} else {
|
||||||
self.textPlaceholderNode.isHidden = inputHasText
|
self.textPlaceholderNode.isHidden = inputHasText
|
||||||
self.tintMaskTextPlaceholderNode.isHidden = inputHasText
|
|
||||||
self.slowmodePlaceholderNode?.isHidden = true
|
self.slowmodePlaceholderNode?.isHidden = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4721,7 +4661,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||||||
public func frameForAccessoryButton(_ item: ChatTextInputAccessoryItem) -> CGRect? {
|
public func frameForAccessoryButton(_ item: ChatTextInputAccessoryItem) -> CGRect? {
|
||||||
for (buttonItem, buttonNode) in self.accessoryItemButtons {
|
for (buttonItem, buttonNode) in self.accessoryItemButtons {
|
||||||
if buttonItem == item {
|
if buttonItem == item {
|
||||||
return buttonNode.frame
|
return self.view.convert(buttonNode.bounds.insetBy(dx: 0.0, dy: 6.0), from: buttonNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -4744,9 +4684,9 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||||||
public func frameForInputActionButton() -> CGRect? {
|
public func frameForInputActionButton() -> CGRect? {
|
||||||
if !self.actionButtons.alpha.isZero {
|
if !self.actionButtons.alpha.isZero {
|
||||||
if self.actionButtons.micButton.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 {
|
} 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
|
return nil
|
||||||
@ -4755,7 +4695,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||||||
public func frameForStickersButton() -> CGRect? {
|
public func frameForStickersButton() -> CGRect? {
|
||||||
for (item, button) in self.accessoryItemButtons {
|
for (item, button) in self.accessoryItemButtons {
|
||||||
if case let .input(_, inputMode) = item, case .stickers = inputMode {
|
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
|
return nil
|
||||||
@ -4764,7 +4704,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||||||
public func frameForEmojiButton() -> CGRect? {
|
public func frameForEmojiButton() -> CGRect? {
|
||||||
for (item, button) in self.accessoryItemButtons {
|
for (item, button) in self.accessoryItemButtons {
|
||||||
if case let .input(_, inputMode) = item, case .emoji = inputMode {
|
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
|
return nil
|
||||||
@ -4773,7 +4713,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||||||
public func frameForGiftButton() -> CGRect? {
|
public func frameForGiftButton() -> CGRect? {
|
||||||
for (item, button) in self.accessoryItemButtons {
|
for (item, button) in self.accessoryItemButtons {
|
||||||
if case .gift = item {
|
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
|
return nil
|
||||||
|
|||||||
@ -420,11 +420,12 @@ public final class ChatTextInputMediaRecordingButton: TGModernConversationInputM
|
|||||||
animationName = "anim_micToVideo"
|
animationName = "anim_micToVideo"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let animationTintColor = self.useDarkTheme ? .white : self.theme.chat.inputPanel.inputControlColor
|
||||||
let _ = self.animationView.update(
|
let _ = self.animationView.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(LottieComponent(
|
component: AnyComponent(LottieComponent(
|
||||||
content: LottieComponent.AppBundleContent(name: animationName),
|
content: LottieComponent.AppBundleContent(name: animationName),
|
||||||
color: self.useDarkTheme ? .white : self.theme.chat.inputPanel.inputControlColor
|
color: animationTintColor
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: animationFrame.size
|
containerSize: animationFrame.size
|
||||||
@ -437,6 +438,7 @@ public final class ChatTextInputMediaRecordingButton: TGModernConversationInputM
|
|||||||
view.output = self.animationOutput
|
view.output = self.animationOutput
|
||||||
self.updateShadow()
|
self.updateShadow()
|
||||||
}
|
}
|
||||||
|
view.setMonochromaticEffect(tintColor: animationTintColor)
|
||||||
view.frame = animationFrame
|
view.frame = animationFrame
|
||||||
|
|
||||||
if previousMode != mode {
|
if previousMode != mode {
|
||||||
|
|||||||
@ -65,22 +65,12 @@ final class LockView: UIButton, TGModernConversationInputMicButtonLock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateTheme(_ theme: PresentationTheme) {
|
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" }) {
|
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" }) {
|
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))
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// [
|
// [
|
||||||
|
|||||||
@ -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) {
|
override public init(frame: CGRect) {
|
||||||
self.tintImageView = UIImageView()
|
self.tintImageView = UIImageView()
|
||||||
|
|
||||||
@ -252,16 +260,19 @@ public class GlassBackgroundView: UIView {
|
|||||||
let cornerRadius: CGFloat
|
let cornerRadius: CGFloat
|
||||||
let isDark: Bool
|
let isDark: Bool
|
||||||
let tintColor: TintColor
|
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.cornerRadius = cornerRadius
|
||||||
self.isDark = isDark
|
self.isDark = isDark
|
||||||
self.tintColor = tintColor
|
self.tintColor = tintColor
|
||||||
|
self.isInteractive = isInteractive
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private let backgroundNode: NavigationBackgroundNode?
|
private let backgroundNode: NavigationBackgroundNode?
|
||||||
private let nativeView: UIVisualEffectView?
|
private let nativeView: UIVisualEffectView?
|
||||||
|
private let nativeContainerView: UIVisualEffectView?
|
||||||
|
|
||||||
private let foregroundView: UIImageView?
|
private let foregroundView: UIImageView?
|
||||||
private let shadowView: UIImageView?
|
private let shadowView: UIImageView?
|
||||||
@ -283,19 +294,23 @@ public class GlassBackgroundView: UIView {
|
|||||||
public override init(frame: CGRect) {
|
public override init(frame: CGRect) {
|
||||||
if #available(iOS 26.0, *) {
|
if #available(iOS 26.0, *) {
|
||||||
self.backgroundNode = nil
|
self.backgroundNode = nil
|
||||||
let glassEffect = UIGlassEffect(style: .clear)
|
|
||||||
|
let glassEffect = UIGlassEffect(style: .regular)
|
||||||
glassEffect.isInteractive = false
|
glassEffect.isInteractive = false
|
||||||
let nativeView = UIVisualEffectView(effect: glassEffect)
|
let nativeView = UIVisualEffectView(effect: glassEffect)
|
||||||
nativeView.layer.cornerCurve = .circular
|
|
||||||
self.nativeView = nativeView
|
self.nativeView = nativeView
|
||||||
nativeView.overrideUserInterfaceStyle = .light
|
|
||||||
nativeView.traitOverrides.userInterfaceStyle = .light
|
let glassContainerEffect = UIGlassContainerEffect()
|
||||||
//self.foregroundView = UIImageView()
|
let nativeContainerView = UIVisualEffectView(effect: glassContainerEffect)
|
||||||
|
self.nativeContainerView = nativeContainerView
|
||||||
|
nativeContainerView.contentView.addSubview(nativeView)
|
||||||
|
|
||||||
self.foregroundView = nil
|
self.foregroundView = nil
|
||||||
self.shadowView = UIImageView()
|
self.shadowView = nil
|
||||||
} else {
|
} else {
|
||||||
self.backgroundNode = NavigationBackgroundNode(color: .black, enableBlur: true, customBlurRadius: 5.0)
|
self.backgroundNode = NavigationBackgroundNode(color: .black, enableBlur: true, customBlurRadius: 5.0)
|
||||||
self.nativeView = nil
|
self.nativeView = nil
|
||||||
|
self.nativeContainerView = nil
|
||||||
self.foregroundView = UIImageView()
|
self.foregroundView = UIImageView()
|
||||||
self.shadowView = UIImageView()
|
self.shadowView = UIImageView()
|
||||||
}
|
}
|
||||||
@ -316,8 +331,8 @@ public class GlassBackgroundView: UIView {
|
|||||||
if let shadowView = self.shadowView {
|
if let shadowView = self.shadowView {
|
||||||
self.addSubview(shadowView)
|
self.addSubview(shadowView)
|
||||||
}
|
}
|
||||||
if let nativeView = self.nativeView {
|
if let nativeContainerView = self.nativeContainerView {
|
||||||
self.addSubview(nativeView)
|
self.addSubview(nativeContainerView)
|
||||||
}
|
}
|
||||||
if let backgroundNode = self.backgroundNode {
|
if let backgroundNode = self.backgroundNode {
|
||||||
self.addSubview(backgroundNode.view)
|
self.addSubview(backgroundNode.view)
|
||||||
@ -333,8 +348,17 @@ public class GlassBackgroundView: UIView {
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
public func update(size: CGSize, cornerRadius: CGFloat, isDark: Bool, tintColor: TintColor, transition: ComponentTransition) {
|
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
if let nativeView = self.nativeView {
|
/*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
|
let previousFrame = nativeView.frame
|
||||||
|
|
||||||
if transition.animation.isImmediate {
|
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)
|
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 {
|
if let backgroundNode = self.backgroundNode {
|
||||||
backgroundNode.updateColor(color: .clear, forceKeepBlur: tintColor.color.alpha != 1.0, transition: transition.containedViewLayoutTransition)
|
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 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 {
|
if self.params != params {
|
||||||
self.params = params
|
self.params = params
|
||||||
|
|
||||||
@ -378,18 +404,21 @@ public class GlassBackgroundView: UIView {
|
|||||||
if let foregroundView = self.foregroundView {
|
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)
|
foregroundView.image = GlassBackgroundView.generateLegacyGlassImage(size: CGSize(width: cornerRadius * 2.0, height: cornerRadius * 2.0), inset: shadowInset, isDark: isDark, fillColor: tintColor.color)
|
||||||
} else {
|
} else {
|
||||||
if let nativeView {
|
if let nativeContainerView = self.nativeContainerView, let nativeView {
|
||||||
if #available(iOS 26.0, *) {
|
if #available(iOS 26.0, *) {
|
||||||
let glassEffect = UIGlassEffect(style: .clear)
|
let glassEffect = UIGlassEffect(style: .regular)
|
||||||
switch tintColor.kind {
|
switch tintColor.kind {
|
||||||
case .panel:
|
case .panel:
|
||||||
glassEffect.tintColor = tintColor.color.withMultipliedAlpha(1.2)
|
glassEffect.tintColor = nil
|
||||||
case .custom:
|
case .custom:
|
||||||
glassEffect.tintColor = tintColor.color
|
glassEffect.tintColor = tintColor.color
|
||||||
}
|
}
|
||||||
glassEffect.isInteractive = false
|
glassEffect.isInteractive = params.isInteractive
|
||||||
|
|
||||||
nativeView.effect = glassEffect
|
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 final class VariableBlurView: UIVisualEffectView {
|
||||||
public let maxBlurRadius: CGFloat
|
public let maxBlurRadius: CGFloat
|
||||||
|
|
||||||
@ -536,8 +586,7 @@ public extension GlassBackgroundView {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Your requested closure:
|
let addShadow: (Bool, CGPoint, CGFloat, CGFloat, UIColor, Bool) -> Void = { isOuter, position, blur, spread, shadowColor, isMultiply in
|
||||||
let addShadow: (Bool, CGPoint, CGFloat, CGFloat, UIColor) -> Void = { isOuter, position, blur, spread, shadowColor in
|
|
||||||
var blur = blur
|
var blur = blur
|
||||||
blur += abs(spread)
|
blur += abs(spread)
|
||||||
|
|
||||||
@ -571,132 +620,70 @@ public extension GlassBackgroundView {
|
|||||||
context.fillPath()
|
context.fillPath()
|
||||||
context.setBlendMode(.normal)
|
context.setBlendMode(.normal)
|
||||||
} else {
|
} else {
|
||||||
context.beginTransparencyLayer(auxiliaryInfo: nil)
|
if let image = generateImage(size, rotatedContext: { size, context in
|
||||||
context.saveGState()
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
defer {
|
let spreadRect = CGRect(origin: CGPoint(x: inset, y: inset), size: innerSize).insetBy(dx: -0.25, dy: -0.25)
|
||||||
context.restoreGState()
|
let spreadPath = UIBezierPath(
|
||||||
context.endTransparencyLayer()
|
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 {
|
if isDark {
|
||||||
addShadow(true, CGPoint(), 16.0, 0.0, UIColor(white: 0.0, alpha: 0.12))
|
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))
|
addShadow(true, CGPoint(), 8.0, 0.0, UIColor(white: 0.0, alpha: 0.1), false)
|
||||||
|
|
||||||
context.setFillColor(fillColor.cgColor)
|
context.setFillColor(fillColor.cgColor)
|
||||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset, dy: inset))
|
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: 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))
|
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))
|
addShadow(false, CGPoint(x: -3.0, y: 3.0), 2.0, 0.0, UIColor(white: 1.0, alpha: 0.25), false)
|
||||||
} else {
|
} else {
|
||||||
addShadow(true, CGPoint(), 16.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(), 8.0, 0.0, UIColor(white: 0.0, alpha: 0.08))
|
addShadow(true, CGPoint(), 16.0, 0.0, UIColor(white: 0.0, alpha: 0.08), false)
|
||||||
|
|
||||||
context.setFillColor(fillColor.cgColor)
|
context.setFillColor(fillColor.cgColor)
|
||||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset, dy: inset))
|
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))
|
let highlightColor: UIColor
|
||||||
addShadow(false, CGPoint(x: -2.0, y: 2.0), 0.5, 0.0, UIColor.black.withMultipliedAlpha(0.15))
|
if fillColor.hsb.s > 0.5 {
|
||||||
}
|
highlightColor = fillColor.withMultiplied(hue: 1.0, saturation: 2.0, brightness: 1.0).adjustedPerceivedBrightness(2.0)
|
||||||
|
|
||||||
if "".isEmpty {
|
let shadowColor = fillColor.withMultiplied(hue: 1.0, saturation: 2.0, brightness: 1.0).adjustedPerceivedBrightness(0.5).withMultipliedAlpha(0.2)
|
||||||
return
|
addShadow(false, CGPoint(x: -2.0, y: 2.0), 0.5, 0.0, shadowColor, false)
|
||||||
}
|
} else {
|
||||||
|
highlightColor = UIColor(white: 1.0, alpha: 0.4)
|
||||||
let maxColor = UIColor(white: 1.0, alpha: isDark ? 0.25 : 0.9)
|
addShadow(false, CGPoint(x: -2.0, y: 2.0), 0.5, 0.0, UIColor.black.withMultipliedAlpha(0.15), true)
|
||||||
let minColor = UIColor(white: 1.0, alpha: 0.0)
|
addShadow(false, CGPoint(x: -2.0, y: 2.0), 0.6, 0.0, UIColor(white: 0.0, alpha: 0.1), false)
|
||||||
|
}
|
||||||
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 colorSpace = CGColorSpaceCreateDeviceRGB()
|
addShadow(false, CGPoint(x: 2.0, y: -2.0), 0.5, 0.0, highlightColor, false)
|
||||||
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())
|
|
||||||
}
|
}
|
||||||
})!.stretchableImage(withLeftCapWidth: Int(size.width * 0.5), topCapHeight: Int(size.height * 0.5))
|
})!.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 {
|
public final class GlassBackgroundComponent: Component {
|
||||||
private let size: CGSize
|
private let size: CGSize
|
||||||
|
private let isDark: Bool
|
||||||
private let tintColor: GlassBackgroundView.TintColor
|
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.size = size
|
||||||
|
self.isDark = isDark
|
||||||
self.tintColor = tintColor
|
self.tintColor = tintColor
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -795,6 +784,9 @@ public final class GlassBackgroundComponent: Component {
|
|||||||
if lhs.size != rhs.size {
|
if lhs.size != rhs.size {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.isDark != rhs.isDark {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.tintColor != rhs.tintColor {
|
if lhs.tintColor != rhs.tintColor {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -803,7 +795,7 @@ public final class GlassBackgroundComponent: Component {
|
|||||||
|
|
||||||
public final class View: GlassBackgroundView {
|
public final class View: GlassBackgroundView {
|
||||||
func update(component: GlassBackgroundComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
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)
|
self.frame = CGRect(origin: .zero, size: component.size)
|
||||||
|
|
||||||
return component.size
|
return component.size
|
||||||
|
|||||||
@ -315,6 +315,8 @@ public final class TabBarComponent: Component {
|
|||||||
self.component = component
|
self.component = component
|
||||||
self.state = state
|
self.state = state
|
||||||
|
|
||||||
|
self.overrideUserInterfaceStyle = component.theme.overallDarkAppearance ? .dark : .light
|
||||||
|
|
||||||
if let nativeTabBar = self.nativeTabBar {
|
if let nativeTabBar = self.nativeTabBar {
|
||||||
if nativeTabBar.items?.count != component.items.count {
|
if nativeTabBar.items?.count != component.items.count {
|
||||||
nativeTabBar.items = (0 ..< component.items.count).map { i in
|
nativeTabBar.items = (0 ..< component.items.count).map { i in
|
||||||
|
|||||||
@ -191,7 +191,6 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
|
|||||||
enum ImageKey: Hashable {
|
enum ImageKey: Hashable {
|
||||||
case flip
|
case flip
|
||||||
case flash
|
case flash
|
||||||
case buttonBackground
|
|
||||||
case flashImage
|
case flashImage
|
||||||
}
|
}
|
||||||
private var cachedImages: [ImageKey: UIImage] = [:]
|
private var cachedImages: [ImageKey: UIImage] = [:]
|
||||||
@ -205,9 +204,6 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
|
|||||||
image = UIImage(bundleImageName: "Camera/VideoMessageFlip")!.withRenderingMode(.alwaysTemplate)
|
image = UIImage(bundleImageName: "Camera/VideoMessageFlip")!.withRenderingMode(.alwaysTemplate)
|
||||||
case .flash:
|
case .flash:
|
||||||
image = UIImage(bundleImageName: "Camera/VideoMessageFlash")!.withRenderingMode(.alwaysTemplate)
|
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:
|
case .flashImage:
|
||||||
image = generateImage(CGSize(width: 393.0, height: 852.0), rotatedContext: { size, context in
|
image = generateImage(CGSize(width: 393.0, height: 852.0), rotatedContext: { size, context in
|
||||||
context.clear(CGRect(origin: .zero, size: size))
|
context.clear(CGRect(origin: .zero, size: size))
|
||||||
@ -590,6 +586,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
|
|||||||
let flipButtonBackground = flipButtonBackground.update(
|
let flipButtonBackground = flipButtonBackground.update(
|
||||||
component: GlassBackgroundComponent(
|
component: GlassBackgroundComponent(
|
||||||
size: CGSize(width: 40.0, height: 40.0),
|
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))
|
tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7))
|
||||||
),
|
),
|
||||||
availableSize: CGSize(width: 40.0, height: 40.0),
|
availableSize: CGSize(width: 40.0, height: 40.0),
|
||||||
@ -691,6 +688,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
|
|||||||
let flashButtonBackground = flashButtonBackground.update(
|
let flashButtonBackground = flashButtonBackground.update(
|
||||||
component: GlassBackgroundComponent(
|
component: GlassBackgroundComponent(
|
||||||
size: CGSize(width: 40.0, height: 40.0),
|
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))
|
tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7))
|
||||||
),
|
),
|
||||||
availableSize: CGSize(width: 40.0, height: 40.0),
|
availableSize: CGSize(width: 40.0, height: 40.0),
|
||||||
@ -719,9 +717,10 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
|
|||||||
AnyComponentWithIdentity(
|
AnyComponentWithIdentity(
|
||||||
id: "background",
|
id: "background",
|
||||||
component: AnyComponent(
|
component: AnyComponent(
|
||||||
Image(
|
GlassBackgroundComponent(
|
||||||
image: state.image(.buttonBackground, theme: environment.theme),
|
size: CGSize(width: 40.0, height: 40.0),
|
||||||
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
|
transition: context.transition
|
||||||
)
|
)
|
||||||
context.add(viewOnceButton
|
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))
|
.appear(.default(scale: true, alpha: true))
|
||||||
.disappear(.default(scale: true, alpha: true))
|
.disappear(.default(scale: true, alpha: true))
|
||||||
)
|
)
|
||||||
@ -764,6 +763,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent {
|
|||||||
id: "background",
|
id: "background",
|
||||||
component: AnyComponent(GlassBackgroundComponent(
|
component: AnyComponent(GlassBackgroundComponent(
|
||||||
size: CGSize(width: 40.0, height: 40.0),
|
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))
|
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))
|
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))
|
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 {
|
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)
|
transition.setPosition(view: self.backgroundView, position: actualBackgroundFrame.center)
|
||||||
|
|||||||
@ -330,12 +330,6 @@ extension ChatControllerImpl {
|
|||||||
self?.canReadHistory.set(true)
|
self?.canReadHistory.set(true)
|
||||||
}
|
}
|
||||||
controller.immediateItemsTransitionAnimation = disableTransitionAnimations
|
controller.immediateItemsTransitionAnimation = disableTransitionAnimations
|
||||||
controller.getOverlayViews = { [weak self] in
|
|
||||||
guard let self else {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
return [self.chatDisplayNode.navigateButtons.view]
|
|
||||||
}
|
|
||||||
self.currentContextController = controller
|
self.currentContextController = controller
|
||||||
|
|
||||||
controller.premiumReactionsSelected = { [weak self, weak controller] in
|
controller.premiumReactionsSelected = { [weak self, weak controller] in
|
||||||
|
|||||||
@ -1311,6 +1311,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
previousInputPanelOrigin.y -= inputPanelNode.bounds.size.height
|
previousInputPanelOrigin.y -= inputPanelNode.bounds.size.height
|
||||||
}
|
}
|
||||||
if let secondaryInputPanelNode = self.secondaryInputPanelNode {
|
if let secondaryInputPanelNode = self.secondaryInputPanelNode {
|
||||||
|
previousInputPanelOrigin.y -= 8.0
|
||||||
previousInputPanelOrigin.y -= secondaryInputPanelNode.bounds.size.height
|
previousInputPanelOrigin.y -= secondaryInputPanelNode.bounds.size.height
|
||||||
}
|
}
|
||||||
self.containerLayoutAndNavigationBarHeight = (layout, navigationBarHeight)
|
self.containerLayoutAndNavigationBarHeight = (layout, navigationBarHeight)
|
||||||
@ -1568,6 +1569,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
inputPanelNodeBaseHeight += inputPanelNode.minimalHeight(interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics)
|
inputPanelNodeBaseHeight += inputPanelNode.minimalHeight(interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics)
|
||||||
}
|
}
|
||||||
if let secondaryInputPanelNode = self.secondaryInputPanelNode {
|
if let secondaryInputPanelNode = self.secondaryInputPanelNode {
|
||||||
|
inputPanelNodeBaseHeight += 8.0
|
||||||
inputPanelNodeBaseHeight += secondaryInputPanelNode.minimalHeight(interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics)
|
inputPanelNodeBaseHeight += secondaryInputPanelNode.minimalHeight(interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1739,6 +1741,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let secondaryInputPanelSize = secondaryInputPanelSize {
|
if let secondaryInputPanelSize = secondaryInputPanelSize {
|
||||||
|
maximumInputNodeHeight -= 8.0
|
||||||
maximumInputNodeHeight -= secondaryInputPanelSize.height
|
maximumInputNodeHeight -= secondaryInputPanelSize.height
|
||||||
}
|
}
|
||||||
if let accessoryPanelSize = accessoryPanelSize {
|
if let accessoryPanelSize = accessoryPanelSize {
|
||||||
@ -2128,8 +2131,11 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
if overlayContextPanelNode !== self.overlayContextPanelNode {
|
if overlayContextPanelNode !== self.overlayContextPanelNode {
|
||||||
dismissedOverlayContextPanelNode = self.overlayContextPanelNode
|
dismissedOverlayContextPanelNode = self.overlayContextPanelNode
|
||||||
self.overlayContextPanelNode = overlayContextPanelNode
|
self.overlayContextPanelNode = overlayContextPanelNode
|
||||||
|
if let navigationBar = self.navigationBar {
|
||||||
self.contentContainerNode.contentNode.addSubnode(overlayContextPanelNode)
|
self.contentContainerNode.contentNode.insertSubnode(overlayContextPanelNode, belowSubnode: navigationBar)
|
||||||
|
} else {
|
||||||
|
self.contentContainerNode.contentNode.addSubnode(overlayContextPanelNode)
|
||||||
|
}
|
||||||
immediatelyLayoutOverlayContextPanelAndAnimateAppearance = true
|
immediatelyLayoutOverlayContextPanelAndAnimateAppearance = true
|
||||||
}
|
}
|
||||||
} else if let overlayContextPanelNode = self.overlayContextPanelNode {
|
} else if let overlayContextPanelNode = self.overlayContextPanelNode {
|
||||||
@ -2147,10 +2153,10 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
var inputPanelHideOffset: CGFloat = 0.0
|
var inputPanelHideOffset: CGFloat = 0.0
|
||||||
if let inputNode = self.inputNode, inputNode.hideInput {
|
if let inputNode = self.inputNode, inputNode.hideInput {
|
||||||
if let inputPanelSize = inputPanelSize {
|
if let inputPanelSize = inputPanelSize {
|
||||||
inputPanelHideOffset += -inputPanelSize.height
|
inputPanelHideOffset += -inputPanelSize.height - 80.0
|
||||||
}
|
}
|
||||||
if let accessoryPanelSize = accessoryPanelSize {
|
if let accessoryPanelSize = accessoryPanelSize {
|
||||||
inputPanelHideOffset += -accessoryPanelSize.height
|
inputPanelHideOffset += -accessoryPanelSize.height - 80.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2164,11 +2170,11 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.secondaryInputPanelNode != nil {
|
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 {
|
if self.dismissedAsOverlay {
|
||||||
secondaryInputPanelFrame!.origin.y = layout.size.height
|
secondaryInputPanelFrame!.origin.y = layout.size.height
|
||||||
}
|
}
|
||||||
inputPanelsHeight += secondaryInputPanelSize!.height
|
inputPanelsHeight += 8.0 + secondaryInputPanelSize!.height
|
||||||
}
|
}
|
||||||
|
|
||||||
var accessoryPanelFrame: CGRect?
|
var accessoryPanelFrame: CGRect?
|
||||||
|
|||||||
@ -161,6 +161,7 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode {
|
|||||||
let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: width - leftInset - rightInset - 8.0 * 2.0, height: panelHeight))
|
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 originX: CGFloat = leftInset + floor((width - leftInset - rightInset - textSize.width) / 2.0)
|
||||||
|
var totalWidth = textSize.width
|
||||||
|
|
||||||
if let iconImage {
|
if let iconImage {
|
||||||
let iconView: UIImageView
|
let iconView: UIImageView
|
||||||
@ -173,7 +174,7 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode {
|
|||||||
}
|
}
|
||||||
iconView.image = iconImage
|
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)
|
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
|
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)
|
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
|
combinedFrame.origin.y += 1.0
|
||||||
|
|
||||||
self.textNode.frame = textFrame.offsetBy(dx: -combinedFrame.minX, dy: -combinedFrame.minY)
|
self.textNode.frame = textFrame.offsetBy(dx: -combinedFrame.minX, dy: -combinedFrame.minY)
|
||||||
|
|||||||
@ -243,7 +243,8 @@ private struct CommandChatInputContextPanelEntry: Comparable, Identifiable {
|
|||||||
messageCount: shortcut.totalCount,
|
messageCount: shortcut.totalCount,
|
||||||
hideSeparator: false,
|
hideSeparator: false,
|
||||||
hideDate: true,
|
hideDate: true,
|
||||||
hidePeerStatus: true
|
hidePeerStatus: true,
|
||||||
|
isInTransparentContainer: true
|
||||||
)
|
)
|
||||||
)),
|
)),
|
||||||
editing: false,
|
editing: false,
|
||||||
|
|||||||
@ -84,7 +84,6 @@ private func preparedTransition(from fromEntries: [HorizontalListContextResultsC
|
|||||||
|
|
||||||
final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputContextPanelNode {
|
final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputContextPanelNode {
|
||||||
private let listView: ListView
|
private let listView: ListView
|
||||||
private let separatorNode: ASDisplayNode
|
|
||||||
private var currentExternalResults: ChatContextResultCollection?
|
private var currentExternalResults: ChatContextResultCollection?
|
||||||
private var currentProcessedResults: ChatContextResultCollection?
|
private var currentProcessedResults: ChatContextResultCollection?
|
||||||
private var currentEntries: [HorizontalListContextResultsChatInputContextPanelEntry]?
|
private var currentEntries: [HorizontalListContextResultsChatInputContextPanelEntry]?
|
||||||
@ -97,11 +96,6 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
|
|||||||
private let batchVideoContext: QueueLocalObject<BatchVideoRenderingContext>
|
private let batchVideoContext: QueueLocalObject<BatchVideoRenderingContext>
|
||||||
|
|
||||||
override init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, fontSize: PresentationFontSize, chatPresentationContext: ChatPresentationContext) {
|
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 = ListView()
|
||||||
self.listView.isOpaque = true
|
self.listView.isOpaque = true
|
||||||
self.listView.backgroundColor = theme.list.plainBackgroundColor
|
self.listView.backgroundColor = theme.list.plainBackgroundColor
|
||||||
@ -121,7 +115,6 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
|
|||||||
self.clipsToBounds = true
|
self.clipsToBounds = true
|
||||||
|
|
||||||
self.addSubnode(self.listView)
|
self.addSubnode(self.listView)
|
||||||
self.addSubnode(self.separatorNode)
|
|
||||||
|
|
||||||
self.listView.displayedItemRangeChanged = { [weak self] displayedRange, opaqueTransactionState in
|
self.listView.displayedItemRangeChanged = { [weak self] displayedRange, opaqueTransactionState in
|
||||||
if let strongSelf = self, let state = opaqueTransactionState as? HorizontalListContextResultsOpaqueState {
|
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
|
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 {
|
if let strongSelf = self, firstTime {
|
||||||
let position = strongSelf.listView.position
|
|
||||||
let separatorPosition = strongSelf.separatorNode.layer.position
|
|
||||||
|
|
||||||
strongSelf.listView.isHidden = false
|
strongSelf.listView.isHidden = false
|
||||||
strongSelf.separatorNode.isHidden = false
|
|
||||||
|
|
||||||
strongSelf.listView.position = CGPoint(x: position.x, y: position.y + strongSelf.listView.bounds.size.width)
|
strongSelf.layer.allowsGroupOpacity = true
|
||||||
strongSelf.separatorNode.position = CGPoint(x: separatorPosition.x, y: separatorPosition.y + strongSelf.listView.bounds.size.width)
|
strongSelf.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
||||||
ContainedViewLayoutTransition.animated(duration: 0.3, curve: .spring).animateView {
|
|
||||||
strongSelf.listView.position = position
|
|
||||||
strongSelf.separatorNode.position = separatorPosition
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -378,7 +363,6 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
|
|||||||
override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) {
|
override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) {
|
||||||
let listHeight: CGFloat = 105.0
|
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)
|
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))
|
//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 {
|
if self.theme !== interfaceState.theme {
|
||||||
self.theme = interfaceState.theme
|
self.theme = interfaceState.theme
|
||||||
self.separatorNode.backgroundColor = theme.list.itemPlainSeparatorColor
|
self.listView.backgroundColor = self.theme.list.plainBackgroundColor
|
||||||
self.listView.backgroundColor = theme.list.plainBackgroundColor
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateOut(completion: @escaping () -> Void) {
|
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
|
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()
|
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? {
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
|
|||||||
@ -8,8 +8,13 @@ import SwiftSignalKit
|
|||||||
import LocalizedPeerData
|
import LocalizedPeerData
|
||||||
import ChatPresentationInterfaceState
|
import ChatPresentationInterfaceState
|
||||||
import ChatInputPanelNode
|
import ChatInputPanelNode
|
||||||
|
import ComponentFlow
|
||||||
|
import MultilineTextComponent
|
||||||
|
import GlassBackgroundComponent
|
||||||
|
|
||||||
final class SecretChatHandshakeStatusInputPanelNode: ChatInputPanelNode {
|
final class SecretChatHandshakeStatusInputPanelNode: ChatInputPanelNode {
|
||||||
|
private let titleBackground: GlassBackgroundView
|
||||||
|
private let title = ComponentView<Empty>()
|
||||||
private let button: HighlightableButtonNode
|
private let button: HighlightableButtonNode
|
||||||
|
|
||||||
private var statusDisposable: Disposable?
|
private var statusDisposable: Disposable?
|
||||||
@ -22,9 +27,12 @@ final class SecretChatHandshakeStatusInputPanelNode: ChatInputPanelNode {
|
|||||||
self.button.titleNode.maximumNumberOfLines = 2
|
self.button.titleNode.maximumNumberOfLines = 2
|
||||||
self.button.titleNode.truncationMode = .byTruncatingMiddle
|
self.button.titleNode.truncationMode = .byTruncatingMiddle
|
||||||
|
|
||||||
|
self.titleBackground = GlassBackgroundView()
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.addSubnode(self.button)
|
self.addSubnode(self.button)
|
||||||
|
self.button.view.addSubview(self.titleBackground)
|
||||||
|
|
||||||
self.button.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: [.touchUpInside])
|
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 {
|
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
|
||||||
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 {
|
if let renderedPeer = interfaceState.renderedPeer, let peer = renderedPeer.peer as? TelegramSecretChat, let userPeer = renderedPeer.peers[peer.regularPeerId] {
|
||||||
case .handshake:
|
switch peer.embeddedState {
|
||||||
let text: String
|
case .handshake:
|
||||||
switch peer.role {
|
switch peer.role {
|
||||||
case .creator:
|
case .creator:
|
||||||
text = interfaceState.strings.DialogList_AwaitingEncryption(EnginePeer(userPeer).compactDisplayTitle).string
|
text = interfaceState.strings.DialogList_AwaitingEncryption(EnginePeer(userPeer).compactDisplayTitle).string
|
||||||
case .participant:
|
case .participant:
|
||||||
text = interfaceState.strings.Conversation_EncryptionProcessing
|
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
|
|
||||||
}
|
}
|
||||||
|
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)
|
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
|
return panelHeight
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,17 +84,13 @@ final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItem
|
|||||||
|
|
||||||
private let buttonNode: HighlightTrackingButtonNode
|
private let buttonNode: HighlightTrackingButtonNode
|
||||||
private let titleNode: TextNode
|
private let titleNode: TextNode
|
||||||
private let topSeparatorNode: ASDisplayNode
|
|
||||||
private let separatorNode: ASDisplayNode
|
private let separatorNode: ASDisplayNode
|
||||||
|
|
||||||
private var item: VerticalListContextResultsChatInputPanelButtonItem?
|
private var item: VerticalListContextResultsChatInputPanelButtonItem?
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
self.buttonNode = HighlightTrackingButtonNode()
|
self.buttonNode = HighlightTrackingButtonNode()
|
||||||
|
|
||||||
self.topSeparatorNode = ASDisplayNode()
|
|
||||||
self.topSeparatorNode.isLayerBacked = true
|
|
||||||
|
|
||||||
self.separatorNode = ASDisplayNode()
|
self.separatorNode = ASDisplayNode()
|
||||||
self.separatorNode.isLayerBacked = true
|
self.separatorNode.isLayerBacked = true
|
||||||
|
|
||||||
@ -102,7 +98,6 @@ final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItem
|
|||||||
|
|
||||||
super.init(layerBacked: false, dynamicBounce: false)
|
super.init(layerBacked: false, dynamicBounce: false)
|
||||||
|
|
||||||
self.addSubnode(self.topSeparatorNode)
|
|
||||||
self.addSubnode(self.separatorNode)
|
self.addSubnode(self.separatorNode)
|
||||||
|
|
||||||
self.addSubnode(self.titleNode)
|
self.addSubnode(self.titleNode)
|
||||||
@ -145,7 +140,7 @@ final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItem
|
|||||||
titleFont = Font.regular(17.0)
|
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()))
|
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.item = item
|
||||||
|
|
||||||
strongSelf.separatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor
|
strongSelf.separatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor
|
||||||
strongSelf.topSeparatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor
|
|
||||||
|
|
||||||
let titleOffsetY: CGFloat
|
let titleOffsetY: CGFloat
|
||||||
switch item.style {
|
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.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.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)
|
strongSelf.buttonNode.frame = CGRect(origin: CGPoint(), size: nodeLayout.contentSize)
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
double animationDurationFactorImpl();
|
double animationDurationFactorImpl();
|
||||||
|
|
||||||
CABasicAnimation * _Nonnull makeSpringAnimationImpl(NSString * _Nonnull keyPath);
|
CABasicAnimation * _Nonnull makeSpringAnimationImpl(NSString * _Nonnull keyPath);
|
||||||
|
CABasicAnimation * _Nonnull make26SpringAnimationImpl(NSString * _Nonnull keyPath, double duration);
|
||||||
CABasicAnimation * _Nonnull makeSpringBounceAnimationImpl(NSString * _Nonnull keyPath, CGFloat initialVelocity, CGFloat damping);
|
CABasicAnimation * _Nonnull makeSpringBounceAnimationImpl(NSString * _Nonnull keyPath, CGFloat initialVelocity, CGFloat damping);
|
||||||
CGFloat springAnimationValueAtImpl(CABasicAnimation * _Nonnull animation, CGFloat t);
|
CGFloat springAnimationValueAtImpl(CABasicAnimation * _Nonnull animation, CGFloat t);
|
||||||
|
|
||||||
@ -36,3 +37,5 @@ void setLayerDisableScreenshots(CALayer * _Nonnull layer, bool disableScreenshot
|
|||||||
bool getLayerDisableScreenshots(CALayer * _Nonnull layer);
|
bool getLayerDisableScreenshots(CALayer * _Nonnull layer);
|
||||||
|
|
||||||
void setLayerContentsMaskMode(CALayer * _Nonnull layer, bool maskMode);
|
void setLayerContentsMaskMode(CALayer * _Nonnull layer, bool maskMode);
|
||||||
|
|
||||||
|
void setMonochromaticEffectImpl(UIView * _Nonnull view, bool isEnabled);
|
||||||
|
|||||||
@ -61,6 +61,24 @@ CABasicAnimation * _Nonnull makeSpringAnimationImpl(NSString * _Nonnull keyPath)
|
|||||||
return springAnimation;
|
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) {
|
CABasicAnimation * _Nonnull makeSpringBounceAnimationImpl(NSString * _Nonnull keyPath, CGFloat initialVelocity, CGFloat damping) {
|
||||||
CASpringAnimation *springAnimation = [CASpringAnimation animationWithKeyPath:keyPath];
|
CASpringAnimation *springAnimation = [CASpringAnimation animationWithKeyPath:keyPath];
|
||||||
springAnimation.mass = 5.0f;
|
springAnimation.mass = 5.0f;
|
||||||
@ -134,6 +152,20 @@ static void setBoolField(NSObject *object, NSString *name, BOOL value) {
|
|||||||
[inv invoke];
|
[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) {
|
UIBlurEffect *makeCustomZoomBlurEffectImpl(bool isLight) {
|
||||||
if (@available(iOS 13.0, *)) {
|
if (@available(iOS 13.0, *)) {
|
||||||
if (isLight) {
|
if (isLight) {
|
||||||
@ -299,3 +331,27 @@ void setLayerContentsMaskMode(CALayer * _Nonnull layer, bool maskMode) {
|
|||||||
[layer setValue:@"RGBA" forKey:key];
|
[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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user