This commit is contained in:
Isaac 2025-09-30 17:41:32 +08:00
parent b5e8c8960d
commit a7385ad068
11 changed files with 78 additions and 34 deletions

View file

@ -707,7 +707,7 @@ final class ComposePollScreenComponent: Component {
hasStickers: false,
hasGifs: false,
hideBackground: true,
maskEdge: true,
maskEdge: .fade,
sendGif: nil
)
)

View file

@ -950,7 +950,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
inputStrokeColor: UIColor(rgb: 0x000000, alpha: 0.1),
inputPlaceholderColor: UIColor(rgb: 0x000000, alpha: 0.4),
inputTextColor: UIColor(rgb: 0x000000),
inputControlColor: UIColor(rgb: 0x000000, alpha: 0.4),
inputControlColor: UIColor(rgb: 0x000000, alpha: 0.5),
actionControlFillColor: defaultDayAccentColor,
actionControlForegroundColor: UIColor(rgb: 0xffffff),
primaryTextColor: UIColor(rgb: 0x000000, alpha: 1.0),

View file

@ -402,7 +402,7 @@ public final class ChatInputMessageAccessoryPanel: Component {
}
self.closeButtonIcon.tintColor = environment.theme.chat.inputPanel.inputControlColor
let secondaryTextColor = environment.theme.chat.inputPanel.inputControlColor.withMultipliedBrightnessBy(0.5)
let secondaryTextColor = environment.theme.chat.inputPanel.inputPlaceholderColor
var textString: NSAttributedString
var isPhoto = false
@ -492,7 +492,7 @@ public final class ChatInputMessageAccessoryPanel: Component {
isMedia = false
isText = true
default:
isMedia = true
isMedia = effectiveMessage.text.isEmpty
isText = false
}

View file

@ -1958,7 +1958,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
}
self.updateActionButtons(hasText: inputHasText, hideMicButton: hideMicButton, animated: transition.isAnimated)
self.updateActionButtons(hasText: inputHasText, hideMicButton: hideMicButton, hideMicButtonBackground: mediaRecordingState != nil, animated: transition.isAnimated)
var actionButtonsSize = CGSize(width: 40.0, height: 40.0)
if let presentationInterfaceState = self.presentationInterfaceState {
@ -1995,8 +1995,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
audioRecordingItemsAlpha = 0.0
}
transition.updateAlpha(layer: self.actionButtons.micButtonBackgroundView.layer, alpha: mediaRecordingState != nil ? 0.01 : 1.0)
if let mediaRecordingState {
audioRecordingItemsAlpha = 0.0
@ -3675,7 +3673,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
self.updateTextHeight(animated: animated)
}
private func updateActionButtons(hasText: Bool, hideMicButton: Bool, animated: Bool) {
private func updateActionButtons(hasText: Bool, hideMicButton: Bool, hideMicButtonBackground: Bool, animated: Bool) {
var hideMicButton = hideMicButton
var mediaInputIsActive = false
@ -3832,19 +3830,15 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
}
}
let alphaTransition: ContainedViewLayoutTransition = .animated(duration: 0.2, curve: .easeInOut)
if hideMicButton {
if !self.actionButtons.micButton.alpha.isZero {
self.actionButtons.micButton.alpha = 0.0
if animated {
self.actionButtons.micButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
}
self.actionButtons.micButtonBackgroundView.alpha = 0.0
if animated {
self.actionButtons.micButtonBackgroundView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
}
alphaTransition.updateAlpha(layer: self.actionButtons.micButton.layer, alpha: 0.0)
}
alphaTransition.updateAlpha(layer: self.actionButtons.micButtonBackgroundView.layer, alpha: 0.0)
} else {
alphaTransition.updateAlpha(layer: self.actionButtons.micButtonBackgroundView.layer, alpha: hideMicButtonBackground ? 0.0 : 1.0)
let micAlpha: CGFloat = self.actionButtons.micButton.fadeDisabled ? 0.5 : 1.0
if !self.actionButtons.micButton.alpha.isEqual(to: micAlpha) {
self.actionButtons.micButton.alpha = micAlpha

View file

@ -169,7 +169,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
hasStickers: Bool = true,
hasGifs: Bool = true,
hideBackground: Bool = false,
maskEdge: Bool = false,
maskEdge: EmojiPagerContentComponent.MaskEdgeMode = .none,
forceHasPremium: Bool = false,
sendGif: ((FileMediaReference, UIView, CGRect, Bool, Bool) -> Bool)?
) -> Signal<InputData, NoError> {
@ -213,7 +213,8 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
hasEdit: hasEdit,
hasAdd: hasEdit,
subject: .chatStickers,
hideBackground: hideBackground
hideBackground: hideBackground,
maskEdge: maskEdge
)
|> map(Optional.init)
} else {
@ -1915,7 +1916,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
externalTopPanelContainer: self.externalTopPanelContainerImpl,
externalBottomPanelContainer: nil,
externalTintMaskContainer: self.backgroundTintMaskContentView,
displayTopPanelBackground: self.opaqueTopPanelBackground ? .opaque : .blur,
displayTopPanelBackground: self.opaqueTopPanelBackground ? .opaque : .none,
topPanelExtensionUpdated: { [weak self] topPanelExtension, transition in
guard let strongSelf = self else {
return

View file

@ -610,6 +610,12 @@ public final class EmojiPagerContentComponent: Component {
}
}
public enum MaskEdgeMode {
case none
case fade
case clip
}
public let id: AnyHashable
public let context: AccountContext
public let avatarPeer: EnginePeer?
@ -623,7 +629,7 @@ public final class EmojiPagerContentComponent: Component {
public let searchState: SearchState
public let warpContentsOnEdges: Bool
public let hideBackground: Bool
public let maskEdge: Bool
public let maskEdge: MaskEdgeMode
public let displaySearchWithPlaceholder: String?
public let searchCategories: EmojiSearchCategories?
public let searchInitiallyHidden: Bool
@ -649,7 +655,7 @@ public final class EmojiPagerContentComponent: Component {
searchState: SearchState,
warpContentsOnEdges: Bool,
hideBackground: Bool,
maskEdge: Bool,
maskEdge: MaskEdgeMode,
displaySearchWithPlaceholder: String?,
searchCategories: EmojiSearchCategories?,
searchInitiallyHidden: Bool,
@ -1383,6 +1389,7 @@ public final class EmojiPagerContentComponent: Component {
private let backgroundView: BlurredBackgroundView
private let backgroundTintView: UIView
private var fadingMaskLayer: FadingMaskLayer?
private var tintFadingMaskLayer: FadingMaskLayer?
private var vibrancyClippingView: UIView
private var vibrancyEffectView: UIView?
public private(set) var mirrorContentClippingView: UIView?
@ -4007,6 +4014,9 @@ public final class EmojiPagerContentComponent: Component {
if let fadingMaskLayer = self.fadingMaskLayer {
fadingMaskLayer.internalAlpha = max(0.0, min(1.0, self.scrollView.contentOffset.y / 30.0))
}
if let tintFadingMaskLayer = self.tintFadingMaskLayer {
tintFadingMaskLayer.internalAlpha = max(0.0, min(1.0, self.scrollView.contentOffset.y / 30.0))
}
}
private func updateShimmerIfNeeded() {
@ -4075,18 +4085,31 @@ public final class EmojiPagerContentComponent: Component {
if component.hideBackground {
self.backgroundView.isHidden = true
if component.maskEdge {
if component.maskEdge != .none {
let maskLayer: FadingMaskLayer
if let current = self.fadingMaskLayer {
maskLayer = current
} else {
maskLayer = FadingMaskLayer()
maskLayer = FadingMaskLayer(isHard: component.maskEdge == .clip)
self.fadingMaskLayer = maskLayer
}
let tintFadingMaskLayer: FadingMaskLayer
if let current = self.tintFadingMaskLayer {
tintFadingMaskLayer = current
} else {
tintFadingMaskLayer = FadingMaskLayer(isHard: component.maskEdge == .clip)
self.tintFadingMaskLayer = tintFadingMaskLayer
}
if self.layer.mask == nil {
self.layer.mask = maskLayer
}
maskLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: floorToScreenPixels((topPanelHeight - 34.0) * 0.75)), size: backgroundFrame.size)
if self.mirrorContentClippingView?.layer.mask != tintFadingMaskLayer {
self.mirrorContentClippingView?.layer.mask = tintFadingMaskLayer
}
maskLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: topPanelHeight - 40.0), size: backgroundFrame.size)
tintFadingMaskLayer.frame = maskLayer.frame
}
} else if component.warpContentsOnEdges {
self.backgroundView.isHidden = true
@ -4910,18 +4933,38 @@ private final class FadingMaskLayer: SimpleLayer {
let fillLayer = SimpleLayer()
let gradientFillLayer = SimpleLayer()
private let isHard: Bool
var internalAlpha: CGFloat = 1.0 {
didSet {
self.gradientFillLayer.opacity = Float(1.0 - self.internalAlpha)
}
}
init(isHard: Bool) {
self.isHard = isHard
super.init()
}
override init(layer: Any) {
self.isHard = false
super.init(layer: layer)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSublayers() {
let gradientHeight: CGFloat = 66.0
if self.gradientLayer.contents == nil {
self.addSublayer(self.gradientLayer)
if !self.isHard {
self.addSublayer(self.gradientLayer)
}
self.addSublayer(self.fillLayer)
self.addSublayer(self.gradientFillLayer)
if !self.isHard {
self.addSublayer(self.gradientFillLayer)
}
let gradientImage = generateGradientImage(size: CGSize(width: 1.0, height: gradientHeight), colors: [UIColor.white.withAlphaComponent(0.0), UIColor.white.withAlphaComponent(0.0), UIColor.white, UIColor.white], locations: [0.0, 0.4, 0.9, 1.0], direction: .vertical)
self.gradientLayer.contents = gradientImage?.cgImage
@ -4932,7 +4975,12 @@ private final class FadingMaskLayer: SimpleLayer {
self.gradientLayer.frame = CGRect(origin: .zero, size: CGSize(width: self.bounds.width, height: gradientHeight))
self.gradientFillLayer.frame = self.gradientLayer.frame
self.fillLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: gradientHeight), size: CGSize(width: self.bounds.width, height: self.bounds.height - gradientHeight))
if self.isHard {
let hardHeight: CGFloat = 40.0
self.fillLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: hardHeight), size: CGSize(width: self.bounds.width, height: self.bounds.height - hardHeight))
} else {
self.fillLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: gradientHeight), size: CGSize(width: self.bounds.width, height: self.bounds.height - gradientHeight))
}
}
}

View file

@ -66,7 +66,7 @@ public extension EmojiPagerContentComponent {
forceHasPremium: Bool = false,
premiumIfSavedMessages: Bool = true,
hideBackground: Bool = false,
maskEdge: Bool = false
maskEdge: EmojiPagerContentComponent.MaskEdgeMode = .none
) -> Signal<EmojiPagerContentComponent, NoError> {
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
let isPremiumDisabled = premiumConfiguration.isPremiumDisabled
@ -1635,7 +1635,7 @@ public extension EmojiPagerContentComponent {
searchIsPlaceholderOnly: Bool = true,
subject: StickersSubject = .chatStickers,
hideBackground: Bool = false,
maskEdge: Bool = false
maskEdge: EmojiPagerContentComponent.MaskEdgeMode = .none
) -> Signal<EmojiPagerContentComponent, NoError> {
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
let isPremiumDisabled = premiumConfiguration.isPremiumDisabled
@ -2202,7 +2202,7 @@ public extension EmojiPagerContentComponent {
animationRenderer: MultiAnimationRenderer,
hasSearch: Bool,
hideBackground: Bool = false,
maskEdge: Bool = false
maskEdge: EmojiPagerContentComponent.MaskEdgeMode = .none
) -> Signal<EmojiPagerContentComponent, NoError> {
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
let isPremiumDisabled = premiumConfiguration.isPremiumDisabled

View file

@ -469,7 +469,7 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode
searchState: .empty(hasResults: false),
warpContentsOnEdges: false,
hideBackground: false,
maskEdge: false,
maskEdge: .none,
displaySearchWithPlaceholder: self.presentationData.strings.EmojiSearch_SearchEmojiPlaceholder,
searchCategories: nil,
searchInitiallyHidden: false,

View file

@ -696,7 +696,7 @@ public extension GlassBackgroundView {
fillColor.getHue(nil, saturation: &s, brightness: &b, alpha: &a)
let innerImage: UIImage
if size == CGSize(width: 40.0 + inset * 2.0, height: 40.0 + inset * 2.0) {
if size == CGSize(width: 40.0 + inset * 2.0, height: 40.0 + inset * 2.0), b >= 0.2 {
innerImage = UIGraphicsImageRenderer(size: size).image { ctx in
let context = ctx.cgContext

View file

@ -407,7 +407,7 @@ final class MediaEditorScreenComponent: Component {
areCustomEmojiEnabled: true,
hasSearch: true,
hideBackground: true,
maskEdge: true,
maskEdge: .fade,
sendGif: nil
) |> map { inputData -> ChatEntityKeyboardInputNode.InputData in
return ChatEntityKeyboardInputNode.InputData(

View file

@ -3856,6 +3856,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
areCustomEmojiEnabled: self.chatPresentationInterfaceState.customEmojiAvailable,
hasEdit: true,
hideBackground: true,
maskEdge: .clip,
sendGif: { [weak self] fileReference, sourceView, sourceRect, silentPosting, schedule in
if let self {
return self.controllerInteraction.sendGif(fileReference, sourceView, sourceRect, silentPosting, schedule)