This commit is contained in:
Isaac 2025-09-24 02:35:23 +08:00
parent 7ed1261193
commit c32d05fdb2
11 changed files with 148 additions and 28 deletions

View File

@ -830,7 +830,7 @@ public extension ContainedViewLayoutTransition {
}
func updateAlpha(node: ASDisplayNode, alpha: CGFloat, beginWithCurrentState: Bool = false, force: Bool = false, delay: Double = 0.0, completion: ((Bool) -> Void)? = nil) {
if node.alpha.isEqual(to: alpha) && !force {
if node.layer.opacity == Float(alpha) && !force {
if let completion = completion {
completion(true)
}
@ -844,14 +844,18 @@ public extension ContainedViewLayoutTransition {
completion(true)
}
case let .animated(duration, curve):
let previousAlpha: CGFloat
let previousAlpha: Float
if beginWithCurrentState, let presentation = node.layer.presentation() {
previousAlpha = CGFloat(presentation.opacity)
previousAlpha = presentation.opacity
} else {
previousAlpha = node.alpha
previousAlpha = node.layer.opacity
}
node.alpha = alpha
node.layer.animateAlpha(from: previousAlpha, to: alpha, duration: duration, delay: delay, timingFunction: curve.timingFunction, mediaTimingFunction: curve.mediaTimingFunction, completion: { result in
if alpha == 0.0 {
node.layer.opacity = Float(alpha)
} else {
node.alpha = alpha
}
node.layer.animateAlpha(from: CGFloat(previousAlpha), to: alpha, duration: duration, delay: delay, timingFunction: curve.timingFunction, mediaTimingFunction: curve.mediaTimingFunction, completion: { result in
if let completion = completion {
completion(result)
}

View File

@ -9,7 +9,11 @@ private final class SwitchNodeViewLayer: CALayer {
private final class SwitchNodeView: UISwitch {
override class var layerClass: AnyClass {
return SwitchNodeViewLayer.self
if #available(iOS 26.0, *) {
return super.layerClass
} else {
return SwitchNodeViewLayer.self
}
}
}
@ -82,7 +86,11 @@ open class SwitchNode: ASDisplayNode {
}
override open func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: 51.0, height: 31.0)
if #available(iOS 26.0, *) {
return CGSize(width: 63.0, height: 28.0)
} else {
return CGSize(width: 51.0, height: 31.0)
}
}
@objc func switchValueChanged(_ view: UISwitch) {

View File

@ -11,6 +11,8 @@ typedef enum {
+ (void)swizzleInstanceMethodOfClass:(Class _Nonnull)targetClass currentSelector:(SEL _Nonnull)currentSelector newSelector:(SEL _Nonnull)newSelector;
+ (void)swizzleInstanceMethodOfClass:(Class _Nonnull)targetClass currentSelector:(SEL _Nonnull)currentSelector withAnotherClass:(Class _Nonnull)anotherClass newSelector:(SEL _Nonnull)newSelector;
+ (void)swizzleClassMethodOfClass:(Class _Nonnull)targetClass currentSelector:(SEL _Nonnull)currentSelector newSelector:(SEL _Nonnull)newSelector;
+ (void * _Nullable)getMethodOfClass:(Class _Nonnull)targetClass selector:(SEL _Nonnull)selector;
+ (void)replaceMethodImplementationOfClass:(Class _Nonnull)targetClass selector:(SEL _Nonnull)selector replacement:(IMP _Nonnull)replacement;
+ (CALayer * _Nonnull)makeLayerHostCopy:(CALayer * _Nonnull)another;
@end
@ -30,3 +32,4 @@ typedef enum {
@end
SEL _Nonnull makeSelectorFromString(NSString * _Nonnull string);

View File

@ -59,6 +59,17 @@
}
}
+ (void * _Nullable)getMethodOfClass:(Class _Nonnull)targetClass selector:(SEL _Nonnull)selector {
return class_getInstanceMethod(targetClass, selector);
}
+ (void)replaceMethodImplementationOfClass:(Class _Nonnull)targetClass selector:(SEL _Nonnull)selector replacement:(IMP _Nonnull)replacement {
Method method = class_getInstanceMethod(targetClass, selector);
if (method) {
method_setImplementation(method, replacement);
}
}
@end
@implementation NSObject (AssociatedObject)

View File

@ -33,9 +33,9 @@ open class ChatInputPanelNode: ASDisplayNode {
open func defaultHeight(metrics: LayoutMetrics) -> CGFloat {
if case .regular = metrics.widthClass, case .regular = metrics.heightClass {
return 49.0
return 40.0
} else {
return 45.0
return 40.0
}
}

View File

@ -13,6 +13,7 @@ swift_library(
"//submodules/Display",
"//submodules/ComponentFlow",
"//submodules/Components/ComponentDisplayAdapters",
"//submodules/UIKitRuntimeUtils",
],
visibility = [
"//visibility:public",

View File

@ -3,6 +3,7 @@ import UIKit
import Display
import ComponentFlow
import ComponentDisplayAdapters
import UIKitRuntimeUtils
private final class ContentContainer: UIView {
private let maskContentView: UIView
@ -273,6 +274,7 @@ public class GlassBackgroundView: UIView {
private let backgroundNode: NavigationBackgroundNode?
private let nativeView: UIVisualEffectView?
private let nativeContainerView: UIVisualEffectView?
private let nativeParamsView: EffectSettingsContainerView?
private let foregroundView: UIImageView?
private let shadowView: UIImageView?
@ -305,13 +307,20 @@ public class GlassBackgroundView: UIView {
self.nativeContainerView = nativeContainerView
nativeContainerView.contentView.addSubview(nativeView)
let nativeParamsView = EffectSettingsContainerView(frame: CGRect())
self.nativeParamsView = nativeParamsView
nativeParamsView.addSubview(nativeContainerView)
self.foregroundView = nil
self.shadowView = nil
} else {
self.backgroundNode = NavigationBackgroundNode(color: .black, enableBlur: true, customBlurRadius: 5.0)
self.nativeView = nil
self.nativeContainerView = nil
self.nativeParamsView = nil
self.foregroundView = UIImageView()
self.shadowView = UIImageView()
}
@ -331,8 +340,8 @@ public class GlassBackgroundView: UIView {
if let shadowView = self.shadowView {
self.addSubview(shadowView)
}
if let nativeContainerView = self.nativeContainerView {
self.addSubview(nativeContainerView)
if let nativeParamsView = self.nativeParamsView {
self.addSubview(nativeParamsView)
}
if let backgroundNode = self.backgroundNode {
self.addSubview(backgroundNode.view)
@ -372,7 +381,7 @@ public class GlassBackgroundView: UIView {
nativeView.layer.animateFrame(from: previousFrame, to: CGRect(origin: CGPoint(), size: size), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring)
}
transition.setFrame(view: nativeContainerView, frame: CGRect(origin: CGPoint(), size: size))
transition.setFrame(view: nativeContainerView, frame: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: max(size.height, 400.0))))
}
if let backgroundNode = self.backgroundNode {
backgroundNode.updateColor(color: .clear, forceKeepBlur: tintColor.color.alpha != 1.0, transition: transition.containedViewLayoutTransition)
@ -404,7 +413,7 @@ public class GlassBackgroundView: UIView {
if let foregroundView = self.foregroundView {
foregroundView.image = GlassBackgroundView.generateLegacyGlassImage(size: CGSize(width: cornerRadius * 2.0, height: cornerRadius * 2.0), inset: shadowInset, isDark: isDark, fillColor: tintColor.color)
} else {
if let nativeContainerView = self.nativeContainerView, let nativeView {
if let nativeParamsView = self.nativeParamsView, let nativeContainerView = self.nativeContainerView, let nativeView {
if #available(iOS 26.0, *) {
let glassEffect = UIGlassEffect(style: .regular)
switch tintColor.kind {
@ -416,9 +425,16 @@ public class GlassBackgroundView: UIView {
glassEffect.isInteractive = params.isInteractive
nativeView.effect = glassEffect
let _ = nativeContainerView
//nativeContainerView.overrideUserInterfaceStyle = .light// isDark ? .dark : .light
self.overrideUserInterfaceStyle = isDark ? .dark : .light
if isDark {
nativeParamsView.lumaMin = 0.0
nativeParamsView.lumaMax = 0.15
} else {
nativeParamsView.lumaMin = 0.25
nativeParamsView.lumaMax = 1.0
}
nativeContainerView.overrideUserInterfaceStyle = isDark ? .dark : .light
}
}
}
@ -665,7 +681,6 @@ public extension GlassBackgroundView {
addShadow(false, CGPoint(x: 3.0, y: -3.0), 2.0, 0.0, UIColor(white: 1.0, alpha: 0.25), false)
addShadow(false, CGPoint(x: -3.0, y: 3.0), 2.0, 0.0, UIColor(white: 1.0, alpha: 0.25), false)
} else {
addShadow(true, CGPoint(), 32.0, 0.0, UIColor(white: 0.0, alpha: 0.08), false)
addShadow(true, CGPoint(), 16.0, 0.0, UIColor(white: 0.0, alpha: 0.08), false)
context.setFillColor(fillColor.cgColor)
@ -673,17 +688,18 @@ public extension GlassBackgroundView {
let highlightColor: UIColor
if fillColor.hsb.s > 0.5 {
highlightColor = fillColor.withMultiplied(hue: 1.0, saturation: 2.0, brightness: 1.0).adjustedPerceivedBrightness(2.0)
var (h, s, v) = fillColor.hsb
s = max(0.0, min(1.0, s * 0.25))
v = max(v, 0.95)
h = max(0.0, min(1.0, h - 0.1))
let shadowColor = fillColor.withMultiplied(hue: 1.0, saturation: 2.0, brightness: 1.0).adjustedPerceivedBrightness(0.5).withMultipliedAlpha(0.2)
addShadow(false, CGPoint(x: -2.0, y: 2.0), 0.5, 0.0, shadowColor, false)
highlightColor = UIColor(hue: h, saturation: s, brightness: v, alpha: fillColor.alpha)
} else {
highlightColor = UIColor(white: 1.0, alpha: 0.4)
addShadow(false, CGPoint(x: -2.0, y: 2.0), 0.5, 0.0, UIColor.black.withMultipliedAlpha(0.15), true)
addShadow(false, CGPoint(x: -2.0, y: 2.0), 0.6, 0.0, UIColor(white: 0.0, alpha: 0.1), false)
highlightColor = UIColor(white: 1.0, alpha: min(1.0, fillColor.alpha * 1.2))
}
addShadow(false, CGPoint(x: 2.0, y: -2.0), 0.5, 0.0, highlightColor, false)
addShadow(false, CGPoint(x: 2.0, y: -2.0), 1.0, 0.0, highlightColor, false)
addShadow(false, CGPoint(x: -2.0, y: 2.0), 1.0, 0.0, highlightColor, false)
}
})!.stretchableImage(withLeftCapWidth: Int(size.width * 0.5), topCapHeight: Int(size.height * 0.5))
}

View File

@ -192,7 +192,7 @@ final class ChatHistoryNavigationButtons: ASDisplayNode {
transition.updateAlpha(node: self.downButton, alpha: 1.0)
transition.updateTransformScale(node: self.downButton, scale: 1.0)
} else {
transition.updateAlpha(node: self.downButton, alpha: 0.1, completion: { [weak self] completed in
transition.updateAlpha(node: self.downButton, alpha: 0.0, completion: { [weak self] completed in
guard let strongSelf = self, completed else {
return
}

View File

@ -279,9 +279,9 @@ final class ChatTagSearchInputPanelNode: ChatInputPanelNode {
let height: CGFloat
if case .regular = params.metrics.widthClass {
height = 49.0
height = 40.0
} else {
height = 45.0
height = 40.0
}
var modeButtonTitle: [AnimatedTextComponent.Item] = []

View File

@ -57,3 +57,10 @@ void applyKeyboardAutocorrection(UITextView * _Nonnull textView);
@end
void snapshotViewByDrawingInContext(UIView * _Nonnull view);
@interface EffectSettingsContainerView : UIView
@property (nonatomic) double lumaMin;
@property (nonatomic) double lumaMax;
@end

View File

@ -173,6 +173,59 @@ static bool notyfyingShiftState = false;
@end
static EffectSettingsContainerView *findTopmostEffectSuperview(UIView *view, int depth) {
if (depth > 5) {
return nil;
}
if ([view isKindOfClass:[EffectSettingsContainerView class]]) {
return (EffectSettingsContainerView* )view;
}
if (view.superview != nil) {
return findTopmostEffectSuperview(view.superview, depth + 1);
} else {
return nil;
}
}
static id (*original_backdropLayerDidChangeLuma)(UIView *, SEL, CALayer *, double) = NULL;
static void replacement_backdropLayerDidChangeLuma(UIView *self, SEL selector, CALayer *layer, double luma) {
EffectSettingsContainerView *topmostSuperview = findTopmostEffectSuperview(self, 0);
if (topmostSuperview) {
luma = MIN(MAX(luma, topmostSuperview.lumaMin), topmostSuperview.lumaMax);
}
original_backdropLayerDidChangeLuma(self, selector, layer, luma);
}
static void registerEffectViewOverrides(void) {
int classCount = objc_getClassList(NULL, 0);
if (classCount > 0) {
__unsafe_unretained Class *classList = (Class *)malloc(classCount * sizeof(Class));
objc_getClassList(classList, classCount);
NSString *searchString = [@"UISD" stringByAppendingString:@"FBackdropView"];
NSString *selectorString = [@"backdropLayer" stringByAppendingString:@":didChangeLuma:"];
for (int i = 0; i < classCount; i++)
{
const char *className = class_getName(classList[i]);
NSString *name = [[NSString alloc] initWithCString:className encoding:NSASCIIStringEncoding];
if ([name hasSuffix:searchString]) {
Method method = (Method)[RuntimeUtils getMethodOfClass:classList[i] selector:NSSelectorFromString(selectorString)];
if (method) {
const char *typeEncoding = method_getTypeEncoding(method);
if (strcmp(typeEncoding, "v32@0:8@16d24") == 0) {
original_backdropLayerDidChangeLuma = (id (*)(id, SEL, CALayer *, double))method_getImplementation(method);
[RuntimeUtils replaceMethodImplementationOfClass:classList[i] selector:NSSelectorFromString(selectorString) replacement:(IMP)&replacement_backdropLayerDidChangeLuma];
}
}
break;
}
}
free(classList);
}
}
@implementation UIViewController (Navigation)
+ (void)load
@ -197,6 +250,10 @@ static bool notyfyingShiftState = false;
}
[RuntimeUtils swizzleInstanceMethodOfClass:[UIFocusSystem class] currentSelector:@selector(updateFocusIfNeeded) newSelector:@selector(_65087dc8_updateFocusIfNeeded)];
if (@available(iOS 26.0, *)) {
registerEffectViewOverrides();
}
});
}
@ -501,3 +558,16 @@ void applyKeyboardAutocorrection(UITextView * _Nonnull textView) {
void snapshotViewByDrawingInContext(UIView * _Nonnull view) {
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:false];
}
@implementation EffectSettingsContainerView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self != nil) {
_lumaMin = 0.0;
_lumaMax = 0.0;
}
return self;
}
@end