GLEGram 12.5 — Initial public release

Based on Swiftgram 12.5 (Telegram iOS 12.5).
All GLEGram features ported and organized in GLEGram/ folder.

Features: Ghost Mode, Saved Deleted Messages, Content Protection Bypass,
Font Replacement, Fake Profile, Chat Export, Plugin System, and more.

See CHANGELOG_12.5.md for full details.
This commit is contained in:
Leeksov
2026-04-06 09:48:12 +03:00
commit 4647310322
39685 changed files with 11052678 additions and 0 deletions
@@ -0,0 +1,9 @@
#import <Foundation/Foundation.h>
@interface NSBag : NSObject
- (NSInteger)addItem:(id)item;
- (void)enumerateItems:(void (^)(id))block;
- (void)removeItem:(NSInteger)key;
@end
@@ -0,0 +1,64 @@
#import "NSBag.h"
@interface NSBag ()
{
NSInteger _nextKey;
NSMutableArray *_items;
NSMutableArray *_itemKeys;
}
@end
@implementation NSBag
- (instancetype)init
{
self = [super init];
if (self != nil)
{
_items = [[NSMutableArray alloc] init];
_itemKeys = [[NSMutableArray alloc] init];
}
return self;
}
- (NSInteger)addItem:(id)item
{
if (item == nil)
return -1;
NSInteger key = _nextKey;
[_items addObject:item];
[_itemKeys addObject:@(key)];
_nextKey++;
return key;
}
- (void)enumerateItems:(void (^)(id))block
{
if (block)
{
for (id item in _items)
{
block(item);
}
}
}
- (void)removeItem:(NSInteger)key
{
NSUInteger index = 0;
for (NSNumber *itemKey in _itemKeys)
{
if ([itemKey integerValue] == key)
{
[_items removeObjectAtIndex:index];
[_itemKeys removeObjectAtIndex:index];
break;
}
index++;
}
}
@end
@@ -0,0 +1,9 @@
#import <Foundation/Foundation.h>
@interface NSWeakReference : NSObject
@property (nonatomic, weak) id value;
- (instancetype)initWithValue:(id)value;
@end
@@ -0,0 +1,13 @@
#import "NSWeakReference.h"
@implementation NSWeakReference
- (instancetype)initWithValue:(id)value {
self = [super init];
if (self != nil) {
self.value = value;
}
return self;
}
@end
@@ -0,0 +1,9 @@
#import <Foundation/Foundation.h>
typedef bool (^NotificationHandlerBlock)(NSString *, id, NSDictionary *, void (^)());
@interface NotificationCenterUtils : NSObject
+ (void)addNotificationHandler:(NotificationHandlerBlock)handler;
@end
@@ -0,0 +1,70 @@
#import "NotificationCenterUtils.h"
#import <ObjCRuntimeUtils/RuntimeUtils.h>
#import <UIKit/UIKit.h>
static NSMutableArray *notificationHandlers() {
static NSMutableArray *array = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
array = [[NSMutableArray alloc] init];
});
return array;
}
@interface NSNotificationCenter (_a65afc19)
@end
@implementation NSNotificationCenter (_a65afc19)
- (void)_a65afc19_postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo
{
if ([NSThread isMainThread]) {
for (NotificationHandlerBlock handler in notificationHandlers())
{
if (handler(aName, anObject, aUserInfo, ^{
[self _a65afc19_postNotificationName:aName object:anObject userInfo:aUserInfo];
})) {
return;
}
}
}
[self _a65afc19_postNotificationName:aName object:anObject userInfo:aUserInfo];
}
@end
@interface CATransaction (Swizzle)
+ (void)swizzle_flush;
@end
@implementation CATransaction (Swizzle)
+ (void)swizzle_flush {
//printf("===flush\n");
[self swizzle_flush];
}
@end
@implementation NotificationCenterUtils
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[RuntimeUtils swizzleInstanceMethodOfClass:[NSNotificationCenter class] currentSelector:@selector(postNotificationName:object:userInfo:) newSelector:@selector(_a65afc19_postNotificationName:object:userInfo:)];
//[RuntimeUtils swizzleClassMethodOfClass:[CATransaction class] currentSelector:@selector(flush) newSelector:@selector(swizzle_flush)];
});
}
+ (void)addNotificationHandler:(NotificationHandlerBlock)handler {
[notificationHandlers() addObject:[handler copy]];
}
@end
@@ -0,0 +1,24 @@
#import <UIKit/UIKit.h>
#import <AsyncDisplayKit/ASDisplayNode.h>
typedef void (^UIBarButtonItemSetTitleListener)(NSString *);
typedef void (^UIBarButtonItemSetEnabledListener)(BOOL);
@interface UIBarButtonItem (Proxy)
@property (nonatomic, strong, readonly) ASDisplayNode *customDisplayNode;
@property (nonatomic, readonly) bool backButtonAppearance;
- (instancetype)initWithCustomDisplayNode:(ASDisplayNode *)customDisplayNode;
- (instancetype)initWithBackButtonAppearanceWithTitle:(NSString *)title target:(id)target action:(SEL)action;
- (void)performActionOnTarget;
- (NSInteger)addSetTitleListener:(UIBarButtonItemSetTitleListener)listener;
- (void)removeSetTitleListener:(NSInteger)key;
- (NSInteger)addSetEnabledListener:(UIBarButtonItemSetEnabledListener)listener;
- (void)removeSetEnabledListener:(NSInteger)key;
- (void)setCustomAction:(void (^)())customAction;
@end
@@ -0,0 +1,122 @@
#import "UIBarButtonItem+Proxy.h"
#import "NSBag.h"
#import <ObjCRuntimeUtils/RuntimeUtils.h>
static const void *setEnabledListenerBagKey = &setEnabledListenerBagKey;
static const void *setTitleListenerBagKey = &setTitleListenerBagKey;
static const void *customDisplayNodeKey = &customDisplayNodeKey;
static const void *backButtonAppearanceKey = &backButtonAppearanceKey;
static const void *customActionKey = &customActionKey;
@implementation UIBarButtonItem (Proxy)
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
[RuntimeUtils swizzleInstanceMethodOfClass:[UIBarButtonItem class] currentSelector:@selector(setEnabled:) newSelector:@selector(_c1e56039_setEnabled:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UIBarButtonItem class] currentSelector:@selector(setTitle:) newSelector:@selector(_c1e56039_setTitle:)];
});
}
- (instancetype)initWithCustomDisplayNode:(ASDisplayNode *)customDisplayNode {
self = [self init];
if (self != nil) {
[self setAssociatedObject:customDisplayNode forKey:customDisplayNodeKey];
}
return self;
}
- (instancetype)initWithBackButtonAppearanceWithTitle:(NSString *)title target:(id)target action:(SEL)action {
self = [self initWithTitle:title style:UIBarButtonItemStylePlain target:target action:action];
if (self != nil) {
[self setAssociatedObject:@true forKey:backButtonAppearanceKey];
}
return self;
}
- (ASDisplayNode *)customDisplayNode {
return [self associatedObjectForKey:customDisplayNodeKey];
}
- (bool)backButtonAppearance {
return [[self associatedObjectForKey:backButtonAppearanceKey] boolValue];
}
- (void)setCustomAction:(void (^)())customAction {
[self setAssociatedObject:[customAction copy] forKey:customActionKey];
}
- (void)_c1e56039_setEnabled:(BOOL)enabled
{
[self _c1e56039_setEnabled:enabled];
[(NSBag *)[self associatedObjectForKey:setEnabledListenerBagKey] enumerateItems:^(UIBarButtonItemSetEnabledListener listener)
{
listener(enabled);
}];
}
- (void)_c1e56039_setTitle:(NSString *)title
{
[self _c1e56039_setTitle:title];
[(NSBag *)[self associatedObjectForKey:setTitleListenerBagKey] enumerateItems:^(UIBarButtonItemSetTitleListener listener)
{
listener(title);
}];
}
- (void)performActionOnTarget
{
void (^customAction)() = [self associatedObjectForKey:customActionKey];
if (customAction) {
customAction();
return;
}
if (self.target == nil) {
return;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[self.target performSelector:self.action];
#pragma clang diagnostic pop
}
- (NSInteger)addSetTitleListener:(UIBarButtonItemSetTitleListener)listener
{
NSBag *bag = [self associatedObjectForKey:setTitleListenerBagKey];
if (bag == nil)
{
bag = [[NSBag alloc] init];
[self setAssociatedObject:bag forKey:setTitleListenerBagKey];
}
return [bag addItem:[listener copy]];
}
- (void)removeSetTitleListener:(NSInteger)key
{
[(NSBag *)[self associatedObjectForKey:setTitleListenerBagKey] removeItem:key];
}
- (NSInteger)addSetEnabledListener:(UIBarButtonItemSetEnabledListener)listener
{
NSBag *bag = [self associatedObjectForKey:setEnabledListenerBagKey];
if (bag == nil)
{
bag = [[NSBag alloc] init];
[self setAssociatedObject:bag forKey:setEnabledListenerBagKey];
}
return [bag addItem:[listener copy]];
}
- (void)removeSetEnabledListener:(NSInteger)key
{
[(NSBag *)[self associatedObjectForKey:setEnabledListenerBagKey] removeItem:key];
}
@end
@@ -0,0 +1,43 @@
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
double animationDurationFactorImpl();
CABasicAnimation * _Nonnull makeSpringAnimationImpl(NSString * _Nonnull keyPath, double duration);
CABasicAnimation * _Nonnull make26SpringAnimationImpl(NSString * _Nonnull keyPath, double duration);
CASpringAnimation * _Nonnull makeSpringBounceAnimationImpl(NSString * _Nonnull keyPath, CGFloat initialVelocity, CGFloat damping);
CGFloat springAnimationValueAtImpl(CABasicAnimation * _Nonnull animation, CGFloat t);
UIBlurEffect * _Nonnull makeCustomZoomBlurEffectImpl(bool isLight);
void applySmoothRoundedCornersImpl(CALayer * _Nonnull layer);
@protocol UIKitPortalViewProtocol <NSObject>
@property(nonatomic) __weak UIView * _Nullable sourceView;
@property(nonatomic) _Bool forwardsClientHitTestingToSourceView;
@property(nonatomic) _Bool allowsHitTesting; // @dynamic allowsHitTesting;
@property(nonatomic) _Bool allowsBackdropGroups; // @dynamic allowsBackdropGroups;
@property(nonatomic) _Bool matchesPosition; // @dynamic matchesPosition;
@property(nonatomic) _Bool matchesTransform; // @dynamic matchesTransform;
@property(nonatomic) _Bool matchesAlpha; // @dynamic matchesAlpha;
@property(nonatomic) _Bool hidesSourceView; // @dynamic hidesSourceView;
@end
UIView<UIKitPortalViewProtocol> * _Nullable makePortalView(bool matchPosition);
bool isViewPortalView(UIView * _Nonnull view);
UIView * _Nullable getPortalViewSourceView(UIView * _Nonnull portalView);
NSObject * _Nullable makeBlurFilter();
NSObject * _Nullable makeVariableBlurFilter();
NSObject * _Nullable makeLuminanceToAlphaFilter();
NSObject * _Nullable makeColorInvertFilter();
NSObject * _Nullable makeMonochromeFilter();
NSObject * _Nullable makeDisplacementMapFilter();
void setLayerDisableScreenshots(CALayer * _Nonnull layer, bool disableScreenshots);
bool getLayerDisableScreenshots(CALayer * _Nonnull layer);
void setLayerContentsMaskMode(CALayer * _Nonnull layer, bool maskMode);
void setMonochromaticEffectImpl(UIView * _Nonnull view, bool isEnabled);
@@ -0,0 +1,373 @@
#import "UIKitUtils.h"
#import <ObjCRuntimeUtils/RuntimeUtils.h>
#import <objc/runtime.h>
#if TARGET_IPHONE_SIMULATOR
UIKIT_EXTERN float UIAnimationDragCoefficient();
#endif
double animationDurationFactorImpl() {
#if TARGET_IPHONE_SIMULATOR
return (double)UIAnimationDragCoefficient();
#endif
return 1.0f;
}
@interface CASpringAnimation ()
@end
@implementation CASpringAnimation (AnimationUtils)
- (CGFloat)valueAt:(CGFloat)t {
static dispatch_once_t onceToken;
static float (*impl)(id, float) = NULL;
static double (*dimpl)(id, double) = NULL;
dispatch_once(&onceToken, ^{
Method method = class_getInstanceMethod([CASpringAnimation class], NSSelectorFromString([@"_" stringByAppendingString:@"solveForInput:"]));
if (method) {
const char *encoding = method_getTypeEncoding(method);
NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:encoding];
const char *argType = [signature getArgumentTypeAtIndex:2];
if (strncmp(argType, "f", 1) == 0) {
impl = (float (*)(id, float))method_getImplementation(method);
} else if (strncmp(argType, "d", 1) == 0) {
dimpl = (double (*)(id, double))method_getImplementation(method);
}
}
});
if (impl) {
float result = impl(self, (float)t);
return (CGFloat)result;
} else if (dimpl) {
double result = dimpl(self, (double)t);
return (CGFloat)result;
}
return t;
}
@end
CABasicAnimation * _Nonnull makeSpringAnimationImpl(NSString * _Nonnull keyPath, double duration) {
if (@available(iOS 26.0, *)) {
return make26SpringAnimationImpl(keyPath, duration);
}
CASpringAnimation *springAnimation = [CASpringAnimation animationWithKeyPath:keyPath];
springAnimation.mass = 3.0f;
springAnimation.stiffness = 1000.0f;
springAnimation.damping = 500.0f;
springAnimation.duration = 0.5;
springAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
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;
}
CASpringAnimation * _Nonnull makeSpringBounceAnimationImpl(NSString * _Nonnull keyPath, CGFloat initialVelocity, CGFloat damping) {
CASpringAnimation *springAnimation = [CASpringAnimation animationWithKeyPath:keyPath];
springAnimation.mass = 5.0f;
springAnimation.stiffness = 900.0f;
springAnimation.damping = damping;
static bool canSetInitialVelocity = true;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
canSetInitialVelocity = [springAnimation respondsToSelector:@selector(setInitialVelocity:)];
});
if (canSetInitialVelocity) {
springAnimation.initialVelocity = initialVelocity;
springAnimation.duration = springAnimation.settlingDuration;
} else {
springAnimation.duration = 0.1;
}
springAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
return springAnimation;
}
CGFloat springAnimationValueAtImpl(CABasicAnimation * _Nonnull animation, CGFloat t) {
return [(CASpringAnimation *)animation valueAt:t];
}
@interface CustomBlurEffect : UIBlurEffect
+ (id)effectWithStyle:(long long)arg1;
@end
static void setField(CustomBlurEffect *object, NSString *name, double 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];
}
static void setNilField(CustomBlurEffect *object, NSString *name) {
SEL selector = NSSelectorFromString(name);
NSMethodSignature *signature = [[object class] instanceMethodSignatureForSelector:selector];
if (signature == nil) {
return;
}
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:signature];
[inv setSelector:selector];
id value = nil;
[inv setArgument:&value atIndex:2];
[inv setTarget:object];
[inv invoke];
}
static void setBoolField(NSObject *object, NSString *name, BOOL 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];
}
static void setLongLongField(NSObject *object, NSString *name, long long value) {
SEL selector = NSSelectorFromString(name);
NSMethodSignature *signature = [[object class] instanceMethodSignatureForSelector:selector];
if (signature == nil) {
return;
}
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:signature];
[inv setSelector:selector];
[inv setArgument:&value atIndex:2];
[inv setTarget:object];
[inv invoke];
}
UIBlurEffect *makeCustomZoomBlurEffectImpl(bool isLight) {
if (@available(iOS 13.0, *)) {
if (isLight) {
return [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight];
} else {
return [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark];
}
} else if (@available(iOS 11.0, *)) {
NSString *string = [@[@"_", @"UI", @"Custom", @"BlurEffect"] componentsJoinedByString:@""];
CustomBlurEffect *result = (CustomBlurEffect *)[NSClassFromString(string) effectWithStyle:0];
setField(result, [@[@"set", @"BlurRadius", @":"] componentsJoinedByString:@""], 10.0);
setNilField(result, [@[@"set", @"Color", @"Tint", @":"] componentsJoinedByString:@""]);
setField(result, [@[@"set", @"Color", @"Tint", @"Alpha", @":"] componentsJoinedByString:@""], 0.0);
setField(result, [@[@"set", @"Darkening", @"Tint", @"Alpha", @":"] componentsJoinedByString:@""], 0.0);
setField(result, [@[@"set", @"Grayscale", @"Tint", @"Alpha", @":"] componentsJoinedByString:@""], 0.0);
setField(result, [@[@"set", @"Saturation", @"Delta", @"Factor", @":"] componentsJoinedByString:@""], 1.0);
if ([UIScreen mainScreen].scale > 2.5f) {
setField(result, @"setScale:", 0.3);
} else {
setField(result, @"setScale:", 0.5);
}
return result;
} else {
return [UIBlurEffect effectWithStyle:UIBlurEffectStyleRegular];
}
}
void applySmoothRoundedCornersImpl(CALayer * _Nonnull layer) {
if (@available(iOS 13.0, *)) {
layer.cornerCurve = kCACornerCurveContinuous;
} else {
setBoolField(layer, [@[@"set", @"Continuous", @"Corners", @":"] componentsJoinedByString:@""], true);
}
}
UIView<UIKitPortalViewProtocol> * _Nullable makePortalView(bool matchPosition) {
static Class portalViewClass = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
portalViewClass = NSClassFromString([@[@"_", @"UI", @"Portal", @"View"] componentsJoinedByString:@""]);
});
if (!portalViewClass) {
return nil;
}
UIView<UIKitPortalViewProtocol> *view = [[portalViewClass alloc] init];
if (!view) {
return nil;
}
if (@available(iOS 14.0, *)) {
view.forwardsClientHitTestingToSourceView = false;
}
view.matchesPosition = matchPosition;
view.matchesTransform = matchPosition;
view.matchesAlpha = false;
if (@available(iOS 14.0, *)) {
view.allowsHitTesting = false;
}
return view;
}
bool isViewPortalView(UIView * _Nonnull view) {
static Class portalViewClass = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
portalViewClass = NSClassFromString([@[@"_", @"UI", @"Portal", @"View"] componentsJoinedByString:@""]);
});
if ([view isKindOfClass:portalViewClass]) {
return true;
} else {
return false;
}
}
UIView * _Nullable getPortalViewSourceView(UIView * _Nonnull portalView) {
if (!isViewPortalView(portalView)) {
return nil;
}
UIView<UIKitPortalViewProtocol> *view = (UIView<UIKitPortalViewProtocol> *)portalView;
return view.sourceView;
}
@protocol GraphicsFilterProtocol <NSObject>
- (NSObject * _Nullable)filterWithName:(NSString * _Nonnull)name;
@end
NSObject * _Nullable makeBlurFilter() {
return [(id<GraphicsFilterProtocol>)NSClassFromString(@"CAFilter") filterWithName:@"gaussianBlur"];
}
NSObject * _Nullable makeVariableBlurFilter() {
return [(id<GraphicsFilterProtocol>)NSClassFromString(@"CAFilter") filterWithName:@"variableBlur"];
}
NSObject * _Nullable makeLuminanceToAlphaFilter() {
return [(id<GraphicsFilterProtocol>)NSClassFromString(@"CAFilter") filterWithName:@"luminanceToAlpha"];
}
NSObject * _Nullable makeColorInvertFilter() {
return [(id<GraphicsFilterProtocol>)NSClassFromString(@"CAFilter") filterWithName:@"colorInvert"];
}
NSObject * _Nullable makeMonochromeFilter() {
return [(id<GraphicsFilterProtocol>)NSClassFromString(@"CAFilter") filterWithName:@"colorMonochrome"];
}
NSObject * _Nullable makeDisplacementMapFilter() {
if (@available(iOS 26.0, *)) {
return [(id<GraphicsFilterProtocol>)NSClassFromString(@"CAFilter") filterWithName:@"displacementMap"];
} else {
return nil;
}
}
static const void *layerDisableScreenshotsKey = &layerDisableScreenshotsKey;
void setLayerDisableScreenshots(CALayer * _Nonnull layer, bool disableScreenshots) {
static UITextField *textField = nil;
static UIView *secureView = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
textField = [[UITextField alloc] init];
for (UIView *subview in textField.subviews) {
if ([NSStringFromClass([subview class]) containsString:@"TextLayoutCanvasView"]) {
secureView = subview;
break;
}
}
});
if (secureView == nil) {
return;
}
CALayer *previousLayer = secureView.layer;
[secureView setValue:layer forKey:@"layer"];
if (disableScreenshots) {
textField.secureTextEntry = false;
textField.secureTextEntry = true;
} else {
textField.secureTextEntry = true;
textField.secureTextEntry = false;
}
[secureView setValue:previousLayer forKey:@"layer"];
[layer setAssociatedObject:@(disableScreenshots) forKey:layerDisableScreenshotsKey associationPolicy:NSObjectAssociationPolicyRetain];
}
bool getLayerDisableScreenshots(CALayer * _Nonnull layer) {
id result = [layer associatedObjectForKey:layerDisableScreenshotsKey];
if ([result respondsToSelector:@selector(boolValue)]) {
return [(NSNumber *)result boolValue];
} else {
return false;
}
}
void setLayerContentsMaskMode(CALayer * _Nonnull layer, bool maskMode) {
static NSString *key = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
key = [@"contents" stringByAppendingString:@"Swizzle"];
});
if (key == nil) {
return;
}
if (maskMode) {
[layer setValue:@"AAAA" forKey:key];
} else {
[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);
}
}
}
@@ -0,0 +1,13 @@
#import <UIKit/UIKit.h>
@interface UIMenuItem (Icons)
- (instancetype)initWithTitle:(NSString *)title icon:(UIImage *)icon action:(SEL)action;
@end
@interface UILabel (DateLabel)
+ (void)setDateLabelColor:(UIColor *)color;
@end
@@ -0,0 +1,164 @@
#import "UIMenuItem+Icons.h"
#import "NSBag.h"
#import <ObjCRuntimeUtils/RuntimeUtils.h>
static const void *imageKey = &imageKey;
static const void *imageViewKey = &imageViewKey;
static NSString *const imageItemIdetifier = @"\uFEFF\u200B";
@interface UIMenuController (Icons)
@end
@implementation UIMenuController (Icons)
- (UIMenuItem *)findImageItemByTitle:(NSString *)title {
if ([title hasSuffix:imageItemIdetifier]) {
for (UIMenuItem *item in self.menuItems) {
if ([item.title isEqualToString:title]) {
return item;
}
}
}
return nil;
}
@end
@implementation UIMenuItem (Icons)
- (instancetype)initWithTitle:(NSString *)title icon:(UIImage *)icon action:(SEL)action {
NSString *combinedTitle = title;
if (icon != nil) {
combinedTitle = [NSString stringWithFormat:@"%@%@", title, imageItemIdetifier];
}
self = [self initWithTitle:combinedTitle action:action];
if (self != nil) {
if (icon != nil) {
[self _tg_setImage:icon];
}
}
return self;
}
- (UIImage *)_tg_image {
return (UIImage *)[self associatedObjectForKey:imageKey];
}
- (void)_tg_setImage:(UIImage *)image {
[self setAssociatedObject:image forKey:imageKey associationPolicy:NSObjectAssociationPolicyRetain];
}
@end
@interface NSString (Items)
@end
@implementation NSString (Items)
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
[RuntimeUtils swizzleInstanceMethodOfClass:[NSString class] currentSelector:@selector(sizeWithAttributes:) newSelector:@selector(_78724db9_sizeWithAttributes:)];
});
}
- (CGSize)_78724db9_sizeWithAttributes:(NSDictionary<NSAttributedStringKey,id> *)attrs {
UIMenuItem *item = [[UIMenuController sharedMenuController] findImageItemByTitle:self];
UIImage *image = item._tg_image;
if (image != nil) {
return image.size;
} else {
return [self _78724db9_sizeWithAttributes:attrs];
}
}
@end
@interface UILabel (Icons)
@end
static UIColor *DateLabelColor = nil;
@implementation UILabel (DateLabel)
+ (void)setDateLabelColor:(UIColor *)color
{
DateLabelColor = color;
}
@end
@implementation UILabel (Icons)
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
[RuntimeUtils swizzleInstanceMethodOfClass:[UILabel class] currentSelector:@selector(drawTextInRect:) newSelector:@selector(_78724db9_drawTextInRect:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UILabel class] currentSelector:@selector(layoutSubviews) newSelector:@selector(_78724db9_layoutSubviews)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UILabel class] currentSelector:@selector(setFrame:) newSelector:@selector(_78724db9_setFrame:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UILabel class] currentSelector:@selector(setTextColor:) newSelector:@selector(_78724db9_setTextColor:)];
});
}
- (void)_78724db9_drawTextInRect:(CGRect)rect {
UIMenuItem *item = [[UIMenuController sharedMenuController] findImageItemByTitle:self.text];
UIImage *image = item._tg_image;
if (image == nil) {
[self _78724db9_drawTextInRect:rect];
}
}
- (void)_78724db9_setTextColor:(UIColor *)color {
if ([NSStringFromClass(self.superview.class) hasPrefix:@"UIDatePicker"] && DateLabelColor != nil) {
[self _78724db9_setTextColor:DateLabelColor];
} else {
[self _78724db9_setTextColor:color];
}
}
- (void)_78724db9_layoutSubviews {
if ([NSStringFromClass(self.superview.class) hasPrefix:@"UIDatePicker"] && DateLabelColor != nil) {
[self _78724db9_setTextColor:DateLabelColor];
}
UIMenuItem *item = [[UIMenuController sharedMenuController] findImageItemByTitle:self.text];
UIImage *image = item._tg_image;
if (image == nil) {
[self _78724db9_layoutSubviews];
return;
}
CGPoint point = CGPointMake(ceil((self.bounds.size.width - image.size.width) / 2.0), ceil((self.bounds.size.height - image.size.height) / 2.0));
UIImageView *imageView = [self associatedObjectForKey:imageViewKey];
if (imageView == nil) {
imageView = [[UIImageView alloc] init];
[self addSubview:imageView];
[self setAssociatedObject:imageView forKey:imageViewKey associationPolicy:NSObjectAssociationPolicyRetain];
}
imageView.image = image;
imageView.frame = CGRectMake(point.x, point.y, image.size.width, image.size.height);
}
- (void)_78724db9_setFrame:(CGRect)frame
{
bool hasImage = [[UIMenuController sharedMenuController] findImageItemByTitle:self.text]._tg_image != nil;
CGRect rect = frame;
if (hasImage && self.superview != nil) {
rect = self.superview.bounds;
}
[self _78724db9_setFrame:rect];
}
@end
@@ -0,0 +1,55 @@
#import <UIKit/UIKit.h>
typedef void (^UINavigationItemSetTitleListener)(NSString * _Nullable, bool);
typedef void (^UINavigationItemSetTitleViewListener)(UIView * _Nullable);
typedef void (^UINavigationItemSetImageListener)(UIImage * _Nullable);
typedef void (^UINavigationItemSetBarButtonItemListener)(UIBarButtonItem * _Nullable, UIBarButtonItem * _Nullable, BOOL);
typedef void (^UINavigationItemSetMutipleBarButtonItemsListener)(NSArray<UIBarButtonItem *> * _Nullable, BOOL);
typedef void (^UITabBarItemSetBadgeListener)(NSString * _Nullable);
@interface UINavigationItem (Proxy)
- (void)setTargetItem:(UINavigationItem * _Nullable)targetItem;
- (BOOL)hasTargetItem;
- (void)setTitle:(NSString * _Nullable)title animated:(bool)animated;
- (NSInteger)addSetTitleListener:(UINavigationItemSetTitleListener _Nonnull)listener;
- (void)removeSetTitleListener:(NSInteger)key;
- (NSInteger)addSetTitleViewListener:(UINavigationItemSetTitleViewListener _Nonnull)listener;
- (void)removeSetTitleViewListener:(NSInteger)key;
- (NSInteger)addSetLeftBarButtonItemListener:(UINavigationItemSetBarButtonItemListener _Nonnull)listener;
- (void)removeSetLeftBarButtonItemListener:(NSInteger)key;
- (NSInteger)addSetRightBarButtonItemListener:(UINavigationItemSetBarButtonItemListener _Nonnull)listener;
- (void)removeSetRightBarButtonItemListener:(NSInteger)key;
- (NSInteger)addSetMultipleRightBarButtonItemsListener:(UINavigationItemSetMutipleBarButtonItemsListener _Nonnull)listener;
- (void)removeSetMultipleRightBarButtonItemsListener:(NSInteger)key;
- (NSInteger)addSetBackBarButtonItemListener:(UINavigationItemSetBarButtonItemListener _Nonnull)listener;
- (void)removeSetBackBarButtonItemListener:(NSInteger)key;
- (NSInteger)addSetBadgeListener:(UITabBarItemSetBadgeListener _Nonnull)listener;
- (void)removeSetBadgeListener:(NSInteger)key;
@property (nonatomic, strong) NSString * _Nullable badge;
@end
NSInteger UITabBarItem_addSetBadgeListener(UITabBarItem * _Nonnull item, UITabBarItemSetBadgeListener _Nonnull listener);
@interface UITabBarItem (Proxy)
- (void)removeSetBadgeListener:(NSInteger)key;
- (NSInteger)addSetTitleListener:(UINavigationItemSetTitleListener _Nonnull)listener;
- (void)removeSetTitleListener:(NSInteger)key;
- (NSInteger)addSetImageListener:(UINavigationItemSetImageListener _Nonnull)listener;
- (void)removeSetImageListener:(NSInteger)key;
- (NSInteger)addSetSelectedImageListener:(UINavigationItemSetImageListener _Nonnull)listener;
- (void)removeSetSelectedImageListener:(NSInteger)key;
@property (nonatomic, strong) NSString * _Nullable animationName;
@property (nonatomic, assign) CGPoint animationOffset;
@property (nonatomic, assign) bool ringSelection;
@end
@@ -0,0 +1,431 @@
#import "UINavigationItem+Proxy.h"
#import "NSBag.h"
#import <ObjCRuntimeUtils/RuntimeUtils.h>
#import "NSWeakReference.h"
static const void *sourceItemKey = &sourceItemKey;
static const void *targetItemKey = &targetItemKey;
static const void *setTitleListenerBagKey = &setTitleListenerBagKey;
static const void *setImageListenerBagKey = &setImageListenerBagKey;
static const void *setSelectedImageListenerBagKey = &setSelectedImageListenerBagKey;
static const void *setTitleViewListenerBagKey = &setTitleViewListenerBagKey;
static const void *setLeftBarButtonItemListenerBagKey = &setLeftBarButtonItemListenerBagKey;
static const void *setRightBarButtonItemListenerBagKey = &setRightBarButtonItemListenerBagKey;
static const void *setMultipleRightBarButtonItemsListenerKey = &setMultipleRightBarButtonItemsListenerKey;
static const void *setBackBarButtonItemListenerBagKey = &setBackBarButtonItemListenerBagKey;
static const void *setBadgeListenerBagKey = &setBadgeListenerBagKey;
static const void *badgeKey = &badgeKey;
static const void *animationNameKey = &animationNameKey;
static const void *animationOffsetKey = &animationOffsetKey;
static const void *ringSelectionKey = &ringSelectionKey;
@implementation UINavigationItem (Proxy)
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
[RuntimeUtils swizzleInstanceMethodOfClass:[UINavigationItem class] currentSelector:@selector(setTitle:) newSelector:@selector(_ac91f40f_setTitle:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UINavigationItem class] currentSelector:@selector(setTitleView:) newSelector:@selector(_ac91f40f_setTitleView:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UINavigationItem class] currentSelector:@selector(setLeftBarButtonItem:) newSelector:@selector(_ac91f40f_setLeftBarButtonItem:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UINavigationItem class] currentSelector:@selector(setLeftBarButtonItem:animated:) newSelector:@selector(_ac91f40f_setLeftBarButtonItem:animated:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UINavigationItem class] currentSelector:@selector(setRightBarButtonItem:) newSelector:@selector(_ac91f40f_setRightBarButtonItem:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UINavigationItem class] currentSelector:@selector(setRightBarButtonItem:animated:) newSelector:@selector(_ac91f40f_setRightBarButtonItem:animated:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UINavigationItem class] currentSelector:@selector(setRightBarButtonItems:) newSelector:@selector(_ac91f40f_setRightBarButtonItems:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UINavigationItem class] currentSelector:@selector(setRightBarButtonItems:animated:) newSelector:@selector(_ac91f40f_setRightBarButtonItems:animated:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UINavigationItem class] currentSelector:@selector(setBackBarButtonItem:) newSelector:@selector(_ac91f40f_setBackBarButtonItem:)];
});
}
- (void)_ac91f40f_setTitle:(NSString *)title
{
[self _ac91f40f_setTitle:title];
UINavigationItem *targetItem = [self associatedObjectForKey:targetItemKey];
if (targetItem != nil) {
[targetItem setTitle:title];
} else {
[(NSBag *)[self associatedObjectForKey:setTitleListenerBagKey] enumerateItems:^(UINavigationItemSetTitleListener listener) {
listener(title, false);
}];
}
}
- (void)setTitle:(NSString * _Nullable)title animated:(bool)animated {
[self _ac91f40f_setTitle:title];
UINavigationItem *targetItem = [self associatedObjectForKey:targetItemKey];
if (targetItem != nil) {
[targetItem setTitle:title];
} else {
[(NSBag *)[self associatedObjectForKey:setTitleListenerBagKey] enumerateItems:^(UINavigationItemSetTitleListener listener) {
listener(title, animated);
}];
}
}
- (void)_ac91f40f_setTitleView:(UIView *)titleView
{
[self _ac91f40f_setTitleView:titleView];
UINavigationItem *targetItem = [self associatedObjectForKey:targetItemKey];
if (targetItem != nil) {
[targetItem setTitleView:titleView];
} else {
[(NSBag *)[self associatedObjectForKey:setTitleViewListenerBagKey] enumerateItems:^(UINavigationItemSetTitleViewListener listener) {
listener(titleView);
}];
}
}
- (void)_ac91f40f_setLeftBarButtonItem:(UIBarButtonItem *)leftBarButtonItem {
[self setLeftBarButtonItem:leftBarButtonItem animated:false];
}
- (void)_ac91f40f_setLeftBarButtonItem:(UIBarButtonItem *)leftBarButtonItem animated:(BOOL)animated
{
UIBarButtonItem *previousItem = self.leftBarButtonItem;
[self _ac91f40f_setLeftBarButtonItem:leftBarButtonItem animated:animated];
UINavigationItem *targetItem = [self associatedObjectForKey:targetItemKey];
if (targetItem != nil) {
[targetItem setLeftBarButtonItem:leftBarButtonItem animated:animated];
} else {
[(NSBag *)[self associatedObjectForKey:setLeftBarButtonItemListenerBagKey] enumerateItems:^(UINavigationItemSetBarButtonItemListener listener) {
listener(previousItem, leftBarButtonItem, animated);
}];
}
}
- (void)_ac91f40f_setRightBarButtonItem:(UIBarButtonItem *)rightBarButtonItem {
[self setRightBarButtonItem:rightBarButtonItem animated:false];
}
- (void)_ac91f40f_setRightBarButtonItem:(UIBarButtonItem *)rightBarButtonItem animated:(BOOL)animated
{
UIBarButtonItem *previousItem = self.rightBarButtonItem;
[self _ac91f40f_setRightBarButtonItem:rightBarButtonItem animated:animated];
UINavigationItem *targetItem = [self associatedObjectForKey:targetItemKey];
if (targetItem != nil) {
[targetItem setRightBarButtonItem:rightBarButtonItem animated:animated];
} else {
[(NSBag *)[self associatedObjectForKey:setRightBarButtonItemListenerBagKey] enumerateItems:^(UINavigationItemSetBarButtonItemListener listener) {
listener(previousItem, rightBarButtonItem, animated);
}];
}
}
- (void)_ac91f40f_setRightBarButtonItems:(NSArray<UIBarButtonItem *> *)rightBarButtonItems {
[self setRightBarButtonItems:rightBarButtonItems animated:false];
}
- (void)_ac91f40f_setRightBarButtonItems:(NSArray<UIBarButtonItem *> *)rightBarButtonItems animated:(BOOL)animated
{
[self _ac91f40f_setRightBarButtonItems:rightBarButtonItems animated:animated];
UINavigationItem *targetItem = [self associatedObjectForKey:targetItemKey];
if (targetItem != nil) {
[targetItem setRightBarButtonItems:rightBarButtonItems animated:animated];
} else {
[(NSBag *)[self associatedObjectForKey:setMultipleRightBarButtonItemsListenerKey] enumerateItems:^(UINavigationItemSetMutipleBarButtonItemsListener listener) {
listener(rightBarButtonItems, animated);
}];
}
}
- (void)_ac91f40f_setBackBarButtonItem:(UIBarButtonItem *)backBarButtonItem
{
UIBarButtonItem *previousItem = self.backBarButtonItem;
[self _ac91f40f_setBackBarButtonItem:backBarButtonItem];
UINavigationItem *targetItem = [self associatedObjectForKey:targetItemKey];
if (targetItem != nil) {
[targetItem setBackBarButtonItem:backBarButtonItem];
} else {
[(NSBag *)[self associatedObjectForKey:setBackBarButtonItemListenerBagKey] enumerateItems:^(UINavigationItemSetBarButtonItemListener listener) {
listener(previousItem, backBarButtonItem, false);
}];
}
}
- (void)setTargetItem:(UINavigationItem *)targetItem {
NSWeakReference *previousSourceItem = [targetItem associatedObjectForKey:sourceItemKey];
[(UINavigationItem *)previousSourceItem.value setAssociatedObject:nil forKey:targetItemKey associationPolicy:NSObjectAssociationPolicyRetain];
[self setAssociatedObject:targetItem forKey:targetItemKey associationPolicy:NSObjectAssociationPolicyRetain];
[targetItem setAssociatedObject:[[NSWeakReference alloc] initWithValue:self] forKey:sourceItemKey associationPolicy:NSObjectAssociationPolicyRetain];
if ((targetItem.title != nil) != (self.title != nil) || ![targetItem.title isEqualToString:self.title]) {
targetItem.title = self.title;
}
if (targetItem.titleView != self.titleView) {
[targetItem setTitleView:self.titleView];
}
if (targetItem.leftBarButtonItem != self.leftBarButtonItem) {
[targetItem setLeftBarButtonItem:self.leftBarButtonItem];
}
if (targetItem.rightBarButtonItem != self.rightBarButtonItem) {
[targetItem setRightBarButtonItem:self.rightBarButtonItem];
}
if (targetItem.backBarButtonItem != self.backBarButtonItem) {
[targetItem setBackBarButtonItem:self.backBarButtonItem];
}
}
- (BOOL)hasTargetItem {
return [self associatedObjectForKey:targetItemKey] != nil;
}
- (NSInteger)addSetTitleListener:(UINavigationItemSetTitleListener)listener
{
NSBag *bag = [self associatedObjectForKey:setTitleListenerBagKey];
if (bag == nil)
{
bag = [[NSBag alloc] init];
[self setAssociatedObject:bag forKey:setTitleListenerBagKey];
}
return [bag addItem:[listener copy]];
}
- (void)removeSetTitleListener:(NSInteger)key
{
[(NSBag *)[self associatedObjectForKey:setTitleListenerBagKey] removeItem:key];
}
- (NSInteger)addSetTitleViewListener:(UINavigationItemSetTitleViewListener)listener
{
NSBag *bag = [self associatedObjectForKey:setTitleViewListenerBagKey];
if (bag == nil)
{
bag = [[NSBag alloc] init];
[self setAssociatedObject:bag forKey:setTitleViewListenerBagKey];
}
return [bag addItem:[listener copy]];
}
- (void)removeSetTitleViewListener:(NSInteger)key
{
[(NSBag *)[self associatedObjectForKey:setTitleViewListenerBagKey] removeItem:key];
}
- (NSInteger)addSetLeftBarButtonItemListener:(UINavigationItemSetBarButtonItemListener)listener
{
NSBag *bag = [self associatedObjectForKey:setLeftBarButtonItemListenerBagKey];
if (bag == nil)
{
bag = [[NSBag alloc] init];
[self setAssociatedObject:bag forKey:setLeftBarButtonItemListenerBagKey];
}
return [bag addItem:[listener copy]];
}
- (void)removeSetLeftBarButtonItemListener:(NSInteger)key
{
[(NSBag *)[self associatedObjectForKey:setLeftBarButtonItemListenerBagKey] removeItem:key];
}
- (NSInteger)addSetRightBarButtonItemListener:(UINavigationItemSetBarButtonItemListener)listener
{
NSBag *bag = [self associatedObjectForKey:setRightBarButtonItemListenerBagKey];
if (bag == nil)
{
bag = [[NSBag alloc] init];
[self setAssociatedObject:bag forKey:setRightBarButtonItemListenerBagKey];
}
return [bag addItem:[listener copy]];
}
- (void)removeSetRightBarButtonItemListener:(NSInteger)key
{
[(NSBag *)[self associatedObjectForKey:setRightBarButtonItemListenerBagKey] removeItem:key];
}
- (NSInteger)addSetMultipleRightBarButtonItemsListener:(UINavigationItemSetMutipleBarButtonItemsListener _Nonnull)listener {
NSBag *bag = [self associatedObjectForKey:setMultipleRightBarButtonItemsListenerKey];
if (bag == nil)
{
bag = [[NSBag alloc] init];
[self setAssociatedObject:bag forKey:setMultipleRightBarButtonItemsListenerKey];
}
return [bag addItem:[listener copy]];
}
- (void)removeSetMultipleRightBarButtonItemsListener:(NSInteger)key {
[(NSBag *)[self associatedObjectForKey:setMultipleRightBarButtonItemsListenerKey] removeItem:key];
}
- (NSInteger)addSetBackBarButtonItemListener:(UINavigationItemSetBarButtonItemListener)listener {
NSBag *bag = [self associatedObjectForKey:setBackBarButtonItemListenerBagKey];
if (bag == nil)
{
bag = [[NSBag alloc] init];
[self setAssociatedObject:bag forKey:setBackBarButtonItemListenerBagKey];
}
return [bag addItem:[listener copy]];
}
- (void)removeSetBackBarButtonItemListener:(NSInteger)key {
[(NSBag *)[self associatedObjectForKey:setBackBarButtonItemListenerBagKey] removeItem:key];
}
- (NSInteger)addSetBadgeListener:(UITabBarItemSetBadgeListener)listener {
NSBag *bag = [self associatedObjectForKey:setBadgeListenerBagKey];
if (bag == nil)
{
bag = [[NSBag alloc] init];
[self setAssociatedObject:bag forKey:setBadgeListenerBagKey];
}
return [bag addItem:[listener copy]];
}
- (void)removeSetBadgeListener:(NSInteger)key {
[(NSBag *)[self associatedObjectForKey:setBadgeListenerBagKey] removeItem:key];
}
- (void)setBadge:(NSString *)badge {
[self setAssociatedObject:badge forKey:badgeKey];
[(NSBag *)[self associatedObjectForKey:setBadgeListenerBagKey] enumerateItems:^(UITabBarItemSetBadgeListener listener) {
listener(badge);
}];
}
- (NSString *)badge {
return [self associatedObjectForKey:badgeKey];
}
@end
@implementation UITabBarItem (Proxy)
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
[RuntimeUtils swizzleInstanceMethodOfClass:[UITabBarItem class] currentSelector:@selector(setBadgeValue:) newSelector:@selector(_ac91f40f_setBadgeValue:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UITabBarItem class] currentSelector:@selector(setTitle:) newSelector:@selector(_ac91f40f_setTitle:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UITabBarItem class] currentSelector:@selector(setImage:) newSelector:@selector(_ac91f40f_setImage:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UITabBarItem class] currentSelector:@selector(setSelectedImage:) newSelector:@selector(_ac91f40f_setSelectedImage:)];
});
}
NSInteger UITabBarItem_addSetBadgeListener(UITabBarItem *item, UITabBarItemSetBadgeListener listener) {
NSBag *bag = [item associatedObjectForKey:setBadgeListenerBagKey];
if (bag == nil)
{
bag = [[NSBag alloc] init];
[item setAssociatedObject:bag forKey:setBadgeListenerBagKey];
}
return [bag addItem:[listener copy]];
}
- (void)removeSetBadgeListener:(NSInteger)key {
[(NSBag *)[self associatedObjectForKey:setBadgeListenerBagKey] removeItem:key];
}
- (void)_ac91f40f_setBadgeValue:(NSString *)value {
[self _ac91f40f_setBadgeValue:value];
[(NSBag *)[self associatedObjectForKey:setBadgeListenerBagKey] enumerateItems:^(UITabBarItemSetBadgeListener listener) {
listener(value);
}];
}
- (void)_ac91f40f_setTitle:(NSString *)value {
[self _ac91f40f_setTitle:value];
[(NSBag *)[self associatedObjectForKey:setTitleListenerBagKey] enumerateItems:^(UINavigationItemSetTitleListener listener) {
listener(value, false);
}];
}
- (void)_ac91f40f_setImage:(UIImage *)value {
[self _ac91f40f_setImage:value];
[(NSBag *)[self associatedObjectForKey:setImageListenerBagKey] enumerateItems:^(UINavigationItemSetImageListener listener) {
listener(value);
}];
}
- (void)_ac91f40f_setSelectedImage:(UIImage *)value {
[self _ac91f40f_setSelectedImage:value];
[(NSBag *)[self associatedObjectForKey:setSelectedImageListenerBagKey] enumerateItems:^(UINavigationItemSetImageListener listener) {
listener(value);
}];
}
- (NSInteger)addSetTitleListener:(UINavigationItemSetTitleListener)listener {
NSBag *bag = [self associatedObjectForKey:setTitleListenerBagKey];
if (bag == nil)
{
bag = [[NSBag alloc] init];
[self setAssociatedObject:bag forKey:setTitleListenerBagKey];
}
return [bag addItem:[listener copy]];
}
- (void)removeSetTitleListener:(NSInteger)key {
[(NSBag *)[self associatedObjectForKey:setTitleListenerBagKey] removeItem:key];
}
- (NSInteger)addSetImageListener:(UINavigationItemSetImageListener)listener {
NSBag *bag = [self associatedObjectForKey:setImageListenerBagKey];
if (bag == nil)
{
bag = [[NSBag alloc] init];
[self setAssociatedObject:bag forKey:setImageListenerBagKey];
}
return [bag addItem:[listener copy]];
}
- (void)removeSetImageListener:(NSInteger)key {
[(NSBag *)[self associatedObjectForKey:setImageListenerBagKey] removeItem:key];
}
- (NSInteger)addSetSelectedImageListener:(UINavigationItemSetImageListener)listener {
NSBag *bag = [self associatedObjectForKey:setSelectedImageListenerBagKey];
if (bag == nil)
{
bag = [[NSBag alloc] init];
[self setAssociatedObject:bag forKey:setSelectedImageListenerBagKey];
}
return [bag addItem:[listener copy]];
}
- (void)removeSetSelectedImageListener:(NSInteger)key {
[(NSBag *)[self associatedObjectForKey:setSelectedImageListenerBagKey] removeItem:key];
}
- (void)setAnimationName:(NSString *)animationName {
[self setAssociatedObject:animationName forKey:animationNameKey];
}
- (NSString *)animationName {
return [self associatedObjectForKey:animationNameKey];
}
- (void)setAnimationOffset:(CGPoint)animationOffset {
[self setAssociatedObject:[NSValue valueWithCGPoint:animationOffset] forKey:animationOffsetKey];
}
- (CGPoint)animationOffset {
return ((NSValue *)[self associatedObjectForKey:animationOffsetKey]).CGPointValue;
}
- (void)setRingSelection:(bool)ringSelection {
[self setAssociatedObject:@(ringSelection) forKey:ringSelectionKey];
}
- (bool)ringSelection {
return ((NSNumber *)[self associatedObjectForKey:ringSelectionKey]).boolValue;
}
@end
@@ -0,0 +1,114 @@
#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>
typedef NS_OPTIONS(NSUInteger, UIResponderDisableAutomaticKeyboardHandling) {
UIResponderDisableAutomaticKeyboardHandlingForward = 1 << 0,
UIResponderDisableAutomaticKeyboardHandlingBackward = 1 << 1
};
@interface UIViewController (Navigation)
- (void)setHintWillBePresentedInPreviewingContext:(BOOL)value;
- (BOOL)isPresentedInPreviewingContext;
- (void)setIgnoreAppearanceMethodInvocations:(BOOL)ignoreAppearanceMethodInvocations;
- (BOOL)ignoreAppearanceMethodInvocations;
- (void)navigation_setNavigationController:(UINavigationController * _Nullable)navigationControlller;
- (void)navigation_setPresentingViewController:(UIViewController * _Nullable)presentingViewController;
- (void)navigation_setDismiss:(void (^_Nullable)())dismiss rootController:( UIViewController * _Nullable )rootController;
- (void)state_setNeedsStatusBarAppearanceUpdate:(void (^_Nullable)())block;
@end
@interface UIApplication (Additions)
- (void)internalSetStatusBarStyle:(UIStatusBarStyle)style animated:(BOOL)animated;
- (void)internalSetStatusBarHidden:(BOOL)hidden animation:(UIStatusBarAnimation)animation;
- (UIWindow * _Nullable)internalGetKeyboard;
@end
@interface CALayerSpringParametersOverrideParameters : NSObject
- (instancetype _Nonnull)init;
@end
@interface CALayerSpringParametersOverrideParametersSpring : CALayerSpringParametersOverrideParameters
@property (nonatomic, readonly) CGFloat stiffness;
@property (nonatomic, readonly) CGFloat damping;
@property (nonatomic, readonly) double duration;
- (instancetype _Nonnull)initWithStiffness:(CGFloat)stiffness damping:(CGFloat)damping duration:(double)duration;
@end
@interface CALayerSpringParametersOverrideParametersCustomCurve : CALayerSpringParametersOverrideParameters
@property (nonatomic, readonly) CGPoint cp1;
@property (nonatomic, readonly) CGPoint cp2;
- (instancetype _Nonnull)initWithCp1:(CGPoint)cp1 cp2:(CGPoint)cp2;
@end
@interface CALayerSpringParametersOverride : NSObject
@property (nonatomic, strong, readonly) CALayerSpringParametersOverrideParameters * _Nullable parameters;
- (instancetype _Nonnull)initWithParameters:(CALayerSpringParametersOverrideParameters * _Nullable)parameters;
@end
@interface CALayer (TelegramAddAnimation)
+ (void)pushSpringParametersOverride:(CALayerSpringParametersOverride * _Nonnull)springParametersOverride;
+ (void)popSpringParametersOverride;
@end
@interface UIView (Navigation)
@property (nonatomic) bool disablesInteractiveTransitionGestureRecognizer;
@property (nonatomic) bool disablesInteractiveKeyboardGestureRecognizer;
@property (nonatomic) bool disablesInteractiveModalDismiss;
@property (nonatomic, copy) bool (^ _Nullable disablesInteractiveTransitionGestureRecognizerNow)();
@property (nonatomic) UIResponderDisableAutomaticKeyboardHandling disableAutomaticKeyboardHandling;
@property (nonatomic, copy) BOOL (^_Nullable interactiveTransitionGestureRecognizerTest)(CGPoint);
- (void)input_setInputAccessoryHeightProvider:(CGFloat (^_Nullable)())block;
- (CGFloat)input_getInputAccessoryHeight;
@end
void applyKeyboardAutocorrection(UITextView * _Nonnull textView);
@interface AboveStatusBarWindow : UIWindow
@property (nonatomic, copy) UIInterfaceOrientationMask (^ _Nullable supportedOrientations)(void);
@end
@interface UIScrollView (FrameRateRangeOverride)
- (void)fixScrollDisplayLink;
@end
void snapshotViewByDrawingInContext(UIView * _Nonnull view);
@interface EffectSettingsContainerView : UIView
@property (nonatomic) double lumaMin;
@property (nonatomic) double lumaMax;
@end
@interface WebHelpers : NSObject
+ (dispatch_block_t _Nonnull)addTrustedDomain:(NSString * _Nonnull)domain;
+ (void)forceRefreshTrustedDomains:(WKWebsiteDataStore * _Nonnull)websiteDataStore;
@end
@@ -0,0 +1,919 @@
#import "UIViewController+Navigation.h"
#import <ObjCRuntimeUtils/RuntimeUtils.h>
#import <objc/runtime.h>
#import "NSWeakReference.h"
#import <UIKitRuntimeUtils/UIKitUtils.h>
#import <dlfcn.h>
@interface UIViewControllerPresentingProxy : UIViewController
@property (nonatomic, copy) void (^dismiss)();
@property (nonatomic, strong, readonly) UIViewController *rootController;
@end
@implementation UIViewControllerPresentingProxy
- (instancetype)initWithRootController:(UIViewController *)rootController {
_rootController = rootController;
return self;
}
- (void)dismissViewControllerAnimated:(BOOL)__unused flag completion:(void (^)(void))completion {
if (_dismiss) {
_dismiss();
}
if (completion) {
completion();
}
}
@end
static const void *UIViewControllerIgnoreAppearanceMethodInvocationsKey = &UIViewControllerIgnoreAppearanceMethodInvocationsKey;
static const void *UIViewControllerNavigationControllerKey = &UIViewControllerNavigationControllerKey;
static const void *UIViewControllerPresentingControllerKey = &UIViewControllerPresentingControllerKey;
static const void *UIViewControllerPresentingProxyControllerKey = &UIViewControllerPresentingProxyControllerKey;
static const void *disablesInteractiveTransitionGestureRecognizerKey = &disablesInteractiveTransitionGestureRecognizerKey;
static const void *disablesInteractiveKeyboardGestureRecognizerKey = &disablesInteractiveKeyboardGestureRecognizerKey;
static const void *disablesInteractiveTransitionGestureRecognizerNowKey = &disablesInteractiveTransitionGestureRecognizerNowKey;
static const void *disableAutomaticKeyboardHandlingKey = &disableAutomaticKeyboardHandlingKey;
static const void *setNeedsStatusBarAppearanceUpdateKey = &setNeedsStatusBarAppearanceUpdateKey;
static const void *inputAccessoryHeightProviderKey = &inputAccessoryHeightProviderKey;
static const void *interactiveTransitionGestureRecognizerTestKey = &interactiveTransitionGestureRecognizerTestKey;
static const void *UIViewControllerHintWillBePresentedInPreviewingContextKey = &UIViewControllerHintWillBePresentedInPreviewingContextKey;
static const void *disablesInteractiveModalDismissKey = &disablesInteractiveModalDismissKey;
static const void *forceFullRefreshRateKey = &forceFullRefreshRateKey;
static bool notyfyingShiftState = false;
@interface UIKeyboardImpl_65087dc8: UIView
@end
@implementation UIKeyboardImpl_65087dc8
- (void)notifyShiftState {
static void (*impl)(id, SEL) = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method m = class_getInstanceMethod([UIKeyboardImpl_65087dc8 class], @selector(notifyShiftState));
impl = (typeof(impl))method_getImplementation(m);
});
if (impl) {
notyfyingShiftState = true;
impl(self, @selector(notifyShiftState));
notyfyingShiftState = false;
}
}
@end
@interface UIInputWindowController_65087dc8: UIViewController
@end
@implementation UIInputWindowController_65087dc8
- (void)updateViewConstraints {
static void (*impl)(id, SEL) = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method m = class_getInstanceMethod([UIInputWindowController_65087dc8 class], @selector(updateViewConstraints));
impl = (typeof(impl))method_getImplementation(m);
});
if (impl) {
if (!notyfyingShiftState) {
impl(self, @selector(updateViewConstraints));
}
}
}
@end
@interface CADisplayLink (FrameRateRangeOverride)
- (void)_65087dc8_setPreferredFrameRateRange:(CAFrameRateRange)range API_AVAILABLE(ios(15.0));
@end
@implementation CADisplayLink (FrameRateRangeOverride)
- (void)_65087dc8_setPreferredFrameRateRange:(CAFrameRateRange)range API_AVAILABLE(ios(15.0)) {
if ([self associatedObjectForKey:forceFullRefreshRateKey] != nil) {
float maxFps = [UIScreen mainScreen].maximumFramesPerSecond;
if (maxFps > 61.0f) {
range = CAFrameRateRangeMake(maxFps, maxFps, maxFps);
}
}
[self _65087dc8_setPreferredFrameRateRange:range];
}
@end
@implementation CALayerSpringParametersOverrideParameters
- (instancetype _Nonnull)init {
self = [super init];
if (self != nil) {
}
return self;
}
@end
@implementation CALayerSpringParametersOverrideParametersSpring
- (instancetype _Nonnull)initWithStiffness:(CGFloat)stiffness damping:(CGFloat)damping duration:(double)duration {
self = [super init];
if (self != nil) {
_stiffness = stiffness;
_damping = damping;
_duration = duration;
}
return self;
}
@end
@implementation CALayerSpringParametersOverrideParametersCustomCurve
- (instancetype _Nonnull)initWithCp1:(CGPoint)cp1 cp2:(CGPoint)cp2 {
self = [super init];
if (self != nil) {
_cp1 = cp1;
_cp2 = cp2;
}
return self;
}
@end
@implementation CALayerSpringParametersOverride
- (instancetype _Nonnull)initWithParameters:(CALayerSpringParametersOverrideParameters * _Nullable)parameters {
self = [super init];
if (self != nil) {
_parameters = parameters;
}
return self;
}
@end
static NSMutableArray<CALayerSpringParametersOverride *> *currentSpringParametersOverrideStack() {
static NSMutableArray *array = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
array = [[NSMutableArray alloc] init];
});
return array;
}
@implementation CALayer (TelegramAddAnimation)
+ (void)pushSpringParametersOverride:(CALayerSpringParametersOverride * _Nonnull)springParametersOverride {
if (springParametersOverride) {
[currentSpringParametersOverrideStack() addObject:springParametersOverride];
}
}
+ (void)popSpringParametersOverride {
if (currentSpringParametersOverrideStack().count != 0) {
[currentSpringParametersOverrideStack() removeLastObject];
}
}
- (void)_65087dc8_addAnimation:(CAAnimation *)anim forKey:(NSString *)key {
CAAnimation *updatedAnimation = anim;
if (currentSpringParametersOverrideStack().count != 0 && [anim isKindOfClass:[CASpringAnimation class]]) {
CALayerSpringParametersOverride *overrideData = [currentSpringParametersOverrideStack() lastObject];
if (overrideData) {
if ([overrideData.parameters isKindOfClass:[CALayerSpringParametersOverrideParametersSpring class]]) {
CALayerSpringParametersOverrideParametersSpring *parameters = (CALayerSpringParametersOverrideParametersSpring *)overrideData.parameters;
CABasicAnimation *sourceAnimation = (CABasicAnimation *)anim;
CASpringAnimation *animation = makeSpringBounceAnimationImpl(sourceAnimation.keyPath, 0.0, parameters.damping);
animation.stiffness = parameters.stiffness;
animation.fromValue = sourceAnimation.fromValue;
animation.toValue = sourceAnimation.toValue;
animation.byValue = sourceAnimation.byValue;
animation.additive = sourceAnimation.additive;
animation.removedOnCompletion = sourceAnimation.isRemovedOnCompletion;
animation.fillMode = sourceAnimation.fillMode;
animation.beginTime = sourceAnimation.beginTime;
animation.timeOffset = sourceAnimation.timeOffset;
animation.repeatCount = sourceAnimation.repeatCount;
animation.autoreverses = sourceAnimation.autoreverses;
float k = animationDurationFactorImpl();
__unused float speed = 1.0f;
if (k != 0.0 && k != 1.0) {
speed = 1.0f / k;
}
animation.speed = sourceAnimation.speed * (float)(animation.duration / parameters.duration);
updatedAnimation = animation;
} else if ([overrideData.parameters isKindOfClass:[CALayerSpringParametersOverrideParametersCustomCurve class]]) {
CALayerSpringParametersOverrideParametersCustomCurve *parameters = (CALayerSpringParametersOverrideParametersCustomCurve *)overrideData.parameters;
CABasicAnimation *sourceAnimation = (CABasicAnimation *)anim;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:sourceAnimation.keyPath];
animation.fromValue = sourceAnimation.fromValue;
animation.toValue = sourceAnimation.toValue;
animation.byValue = sourceAnimation.byValue;
animation.additive = sourceAnimation.additive;
animation.duration = sourceAnimation.duration;
animation.timingFunction = [[CAMediaTimingFunction alloc] initWithControlPoints:parameters.cp1.x :parameters.cp1.y :parameters.cp2.x :parameters.cp2.y];
animation.removedOnCompletion = sourceAnimation.isRemovedOnCompletion;
animation.fillMode = sourceAnimation.fillMode;
animation.speed = sourceAnimation.speed;
animation.beginTime = sourceAnimation.beginTime;
animation.timeOffset = sourceAnimation.timeOffset;
animation.repeatCount = sourceAnimation.repeatCount;
animation.autoreverses = sourceAnimation.autoreverses;
float k = animationDurationFactorImpl();
float speed = 1.0f;
if (k != 0.0 && k != 1.0) {
speed = 1.0f / k;
}
animation.speed = speed * sourceAnimation.speed;
updatedAnimation = animation;
} else {
bool isNativeGlass = false;
if (@available(iOS 26.0, *)) {
isNativeGlass = true;
}
if (isNativeGlass && ABS(anim.duration - 0.3832) <= 0.0001) {
} else if (ABS(anim.duration - 0.5) <= 0.0001) {
} else {
CABasicAnimation *sourceAnimation = (CABasicAnimation *)anim;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:sourceAnimation.keyPath];
animation.fromValue = sourceAnimation.fromValue;
animation.toValue = sourceAnimation.toValue;
animation.byValue = sourceAnimation.byValue;
animation.additive = sourceAnimation.additive;
animation.duration = sourceAnimation.duration;
animation.timingFunction = [[CAMediaTimingFunction alloc] initWithControlPoints:0.380 :0.700 :0.125 :1.000];
animation.removedOnCompletion = sourceAnimation.isRemovedOnCompletion;
animation.fillMode = sourceAnimation.fillMode;
animation.speed = sourceAnimation.speed;
animation.beginTime = sourceAnimation.beginTime;
animation.timeOffset = sourceAnimation.timeOffset;
animation.repeatCount = sourceAnimation.repeatCount;
animation.autoreverses = sourceAnimation.autoreverses;
float k = animationDurationFactorImpl();
float speed = 1.0f;
if (k != 0.0 && k != 1.0) {
speed = 1.0f / k;
}
animation.speed = speed * sourceAnimation.speed;
updatedAnimation = animation;
}
}
}
}
[self _65087dc8_addAnimation:updatedAnimation forKey:key];
}
@end
@implementation UIScrollView (FrameRateRangeOverride)
- (void)fixScrollDisplayLink {
if (@available(iOS 16.0, *)) {
return;
}
static NSString *scrollHeartbeatKey = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
scrollHeartbeatKey = [NSString stringWithFormat:@"_%@", @"scrollHeartbeat"];
});
id value = [self valueForKey:scrollHeartbeatKey];
if ([value isKindOfClass:[CADisplayLink class]]) {
CADisplayLink *displayLink = (CADisplayLink *)value;
if ([displayLink associatedObjectForKey:forceFullRefreshRateKey] == nil) {
[displayLink setAssociatedObject:@true forKey:forceFullRefreshRateKey];
if (@available(iOS 15.0, *)) {
float maxFps = [UIScreen mainScreen].maximumFramesPerSecond;
if (maxFps > 61.0f) {
[displayLink setPreferredFrameRateRange:CAFrameRateRangeMake(maxFps, maxFps, maxFps)];
}
}
}
}
}
@end
@interface UIWindow (Telegram)
@end
@implementation UIWindow (Telegram)
- (instancetype)_65087dc8_initWithFrame:(CGRect)frame {
return [self _65087dc8_initWithFrame:frame];
}
@end
@protocol UIRemoteKeyboardWindowProtocol
+ (UIWindow * _Nullable)remoteKeyboardWindowForScreen:(UIScreen * _Nullable)screen create:(BOOL)create;
@end
@interface UIFocusSystem (Telegram)
@end
@implementation UIFocusSystem (Telegram)
- (void)_65087dc8_updateFocusIfNeeded {
//TODO:Re-enable
}
@end
static EffectSettingsContainerView *findTopmostEffectSuperview(UIView *view, int depth) {
if (depth > 10) {
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 NSString *TGEncodeText(NSString *string, int key) {
NSMutableString *result = [[NSMutableString alloc] init];
for (int i = 0; i < (int)[string length]; i++) {
unichar c = [string characterAtIndex:i];
c += key;
[result appendString:[NSString stringWithCharacters:&c length:1]];
}
return result;
}
static void registerEffectViewOverrides(void) {
NSMutableArray<NSString *> *nameList = [[NSMutableArray alloc] init];
[nameList addObject:TGEncodeText(@"_TtC5UIKitP33_ACD4A08F4BE9D00246F2A9C24A80CA8817UISDFBackdropView", 0)];
NSString *selectorString = [@"backdropLayer" stringByAppendingString:@":didChangeLuma:"];
for (NSString *name in nameList) {
Class classValue = NSClassFromString(name);
if (classValue == nil) {
continue;
}
Method method = (Method)[RuntimeUtils getMethodOfClass:classValue 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:classValue selector:NSSelectorFromString(selectorString) replacement:(IMP)&replacement_backdropLayerDidChangeLuma];
}
}
break;
}
}
static NSLock *webHelpersLock() {
static NSLock *value = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
value = [[NSLock alloc] init];
});
return value;
}
@interface TrustedWebRecord : NSObject
@property (nonatomic) NSInteger nextReference;
@property (nonatomic, strong, readonly) NSMutableSet<NSNumber *> *references;
@end
@implementation TrustedWebRecord
- (instancetype)init {
self = [super init];
if (self != nil) {
_references = [[NSMutableSet alloc] init];
}
return self;
}
- (NSInteger)addReference {
NSInteger reference = _nextReference;
_nextReference += 1;
[_references addObject:@(reference)];
return reference;
}
- (void)removeReference:(NSInteger)reference {
[_references removeObject:@(reference)];
}
- (bool)isEmpty {
return _references.count == 0;
}
@end
static NSMutableDictionary<NSString *, TrustedWebRecord *> *trustedWebRecords() {
static NSMutableDictionary *value = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
value = [[NSMutableDictionary alloc] init];
});
return value;
}
@implementation WebHelpers
+ (NSArray<NSString *> * _Nonnull)threadSafeTrustedDomains {
[webHelpersLock() lock];
NSMutableArray<NSString *> *result = [[NSMutableArray alloc] init];
for (NSString *domain in trustedWebRecords()) {
[result addObject:domain];
}
[result sortUsingSelector:@selector(compare:)];
[webHelpersLock() unlock];
return result;
}
+ (dispatch_block_t _Nonnull)addTrustedDomain:(NSString * _Nonnull)domain {
[webHelpersLock() lock];
TrustedWebRecord *record = trustedWebRecords()[domain];
if (record == nil) {
record = [[TrustedWebRecord alloc] init];
trustedWebRecords()[domain] = record;
}
NSInteger reference = [record addReference];
__block __weak TrustedWebRecord *weakRecord = record;
[webHelpersLock() unlock];
return ^{
[webHelpersLock() lock];
TrustedWebRecord *strongRecord = weakRecord;
if (strongRecord && trustedWebRecords()[domain] == strongRecord) {
[strongRecord removeReference:reference];
if ([strongRecord isEmpty]) {
[trustedWebRecords() removeObjectForKey:domain];
}
}
[webHelpersLock() unlock];
};
}
+ (void)forceRefreshTrustedDomains:(WKWebsiteDataStore * _Nonnull)websiteDataStore {
static void (*reinitializeFunction)(CFTypeRef dataStoreRef) = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *nameString = [NSString stringWithFormat:@"WK%@", @"WebsiteDataStoreReinitializeAppBoundDomains"];
reinitializeFunction = dlsym(RTLD_DEFAULT, [nameString UTF8String]);
});
if (reinitializeFunction) {
reinitializeFunction((__bridge CFTypeRef)(websiteDataStore));
}
}
@end
@implementation NSBundle (Telegram)
- (id)_65087dc8_objectForInfoDictionaryKey:(NSString *)key {
if ([key isEqualToString:@"WKAppBoundDomains"]) {
NSArray *result = [WebHelpers threadSafeTrustedDomains];
if (result.count != 0) {
return result;
}
}
return [self _65087dc8_objectForInfoDictionaryKey:key];
}
@end
@implementation UIViewController (Navigation)
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
[RuntimeUtils swizzleInstanceMethodOfClass:[UIViewController class] currentSelector:@selector(viewWillAppear:) newSelector:@selector(_65087dc8_viewWillAppear:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UIViewController class] currentSelector:@selector(viewDidAppear:) newSelector:@selector(_65087dc8_viewDidAppear:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UIViewController class] currentSelector:@selector(viewWillDisappear:) newSelector:@selector(_65087dc8_viewWillDisappear:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UIViewController class] currentSelector:@selector(viewDidDisappear:) newSelector:@selector(_65087dc8_viewDidDisappear:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UIViewController class] currentSelector:@selector(navigationController) newSelector:@selector(_65087dc8_navigationController)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UIViewController class] currentSelector:@selector(presentingViewController) newSelector:@selector(_65087dc8_presentingViewController)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UIViewController class] currentSelector:@selector(presentViewController:animated:completion:) newSelector:@selector(_65087dc8_presentViewController:animated:completion:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UIViewController class] currentSelector:@selector(setNeedsStatusBarAppearanceUpdate) newSelector:@selector(_65087dc8_setNeedsStatusBarAppearanceUpdate)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UIWindow class] currentSelector:@selector(initWithFrame:) newSelector:@selector(_65087dc8_initWithFrame:)];
if (@available(iOS 16.0, *)) {
} else if (@available(iOS 15.0, *)) {
[RuntimeUtils swizzleInstanceMethodOfClass:[CADisplayLink class] currentSelector:@selector(setPreferredFrameRateRange:) newSelector:@selector(_65087dc8_setPreferredFrameRateRange:)];
}
[RuntimeUtils swizzleInstanceMethodOfClass:[CALayer class] currentSelector:@selector(addAnimation:forKey:) newSelector:@selector(_65087dc8_addAnimation:forKey:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UIFocusSystem class] currentSelector:@selector(updateFocusIfNeeded) newSelector:@selector(_65087dc8_updateFocusIfNeeded)];
[RuntimeUtils swizzleInstanceMethodOfClass:[NSBundle class] currentSelector:@selector(objectForInfoDictionaryKey:) newSelector:@selector(_65087dc8_objectForInfoDictionaryKey:)];
if (@available(iOS 26.0, *)) {
registerEffectViewOverrides();
}
/*#if DEBUG
Class cls = NSClassFromString(@"WKBrowsingContextController");
SEL sel = NSSelectorFromString(@"registerSchemeForCustomProtocol:");
if ([cls respondsToSelector:sel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[cls performSelector:sel withObject:@"http"];
[cls performSelector:sel withObject:@"https"];
#pragma clang diagnostic pop
}
#endif*/
});
}
- (void)setHintWillBePresentedInPreviewingContext:(BOOL)value {
[self setAssociatedObject:@(value) forKey:UIViewControllerHintWillBePresentedInPreviewingContextKey];
}
- (BOOL)isPresentedInPreviewingContext {
if ([[self associatedObjectForKey:UIViewControllerHintWillBePresentedInPreviewingContextKey] boolValue]) {
return true;
} else {
return false;
}
}
- (void)setIgnoreAppearanceMethodInvocations:(BOOL)ignoreAppearanceMethodInvocations
{
[self setAssociatedObject:@(ignoreAppearanceMethodInvocations) forKey:UIViewControllerIgnoreAppearanceMethodInvocationsKey];
}
- (BOOL)ignoreAppearanceMethodInvocations
{
return [[self associatedObjectForKey:UIViewControllerIgnoreAppearanceMethodInvocationsKey] boolValue];
}
- (void)_65087dc8_viewWillAppear:(BOOL)animated
{
if (![self ignoreAppearanceMethodInvocations])
[self _65087dc8_viewWillAppear:animated];
}
- (void)_65087dc8_viewDidAppear:(BOOL)animated
{
if (![self ignoreAppearanceMethodInvocations])
[self _65087dc8_viewDidAppear:animated];
}
- (void)_65087dc8_viewWillDisappear:(BOOL)animated
{
if (![self ignoreAppearanceMethodInvocations])
[self _65087dc8_viewWillDisappear:animated];
}
- (void)_65087dc8_viewDidDisappear:(BOOL)animated
{
if (![self ignoreAppearanceMethodInvocations])
[self _65087dc8_viewDidDisappear:animated];
}
- (void)navigation_setNavigationController:(UINavigationController * _Nullable)navigationControlller {
[self setAssociatedObject:[[NSWeakReference alloc] initWithValue:navigationControlller] forKey:UIViewControllerNavigationControllerKey];
}
- (UINavigationController *)_65087dc8_navigationController {
UINavigationController *navigationController = self._65087dc8_navigationController;
if (navigationController != nil) {
return navigationController;
}
UIViewController *parentController = self.parentViewController;
navigationController = parentController.navigationController;
if (navigationController != nil) {
return navigationController;
}
return ((NSWeakReference *)[self associatedObjectForKey:UIViewControllerNavigationControllerKey]).value;
}
- (void)navigation_setPresentingViewController:(UIViewController *)presentingViewController {
[self setAssociatedObject:[[NSWeakReference alloc] initWithValue:presentingViewController] forKey:UIViewControllerPresentingControllerKey];
}
- (void)navigation_setDismiss:(void (^_Nullable)())dismiss rootController:(UIViewController *)rootController {
UIViewControllerPresentingProxy *proxy = [[UIViewControllerPresentingProxy alloc] initWithRootController:rootController];
proxy.dismiss = dismiss;
[self setAssociatedObject:proxy forKey:UIViewControllerPresentingProxyControllerKey];
}
- (UIViewController *)_65087dc8_presentingViewController {
UINavigationController *navigationController = self.navigationController;
if (navigationController.presentingViewController != nil) {
return navigationController.presentingViewController;
}
UIViewController *controller = ((NSWeakReference *)[self associatedObjectForKey:UIViewControllerPresentingControllerKey]).value;
if (controller != nil) {
return controller;
}
UIViewController *result = [self associatedObjectForKey:UIViewControllerPresentingProxyControllerKey];
if (result != nil) {
return result;
}
return [self _65087dc8_presentingViewController];
}
- (void)_65087dc8_presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
[self _65087dc8_presentViewController:viewControllerToPresent animated:flag completion:completion];
}
- (void)_65087dc8_setNeedsStatusBarAppearanceUpdate {
[self _65087dc8_setNeedsStatusBarAppearanceUpdate];
void (^block)() = [self associatedObjectForKey:setNeedsStatusBarAppearanceUpdateKey];
if (block) {
block();
}
}
- (void)state_setNeedsStatusBarAppearanceUpdate:(void (^_Nullable)())block {
[self setAssociatedObject:[block copy] forKey:setNeedsStatusBarAppearanceUpdateKey];
}
@end
@implementation UIApplication (Additions)
- (void)internalSetStatusBarStyle:(UIStatusBarStyle)style animated:(BOOL)animated {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[self setStatusBarStyle:style animated:animated];
#pragma clang diagnostic pop
}
- (void)internalSetStatusBarHidden:(BOOL)hidden animation:(UIStatusBarAnimation)animation {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[self setStatusBarHidden:hidden withAnimation:animation];
#pragma clang diagnostic pop
}
/*static void dumpViews(UIView *view, NSString *indent) {
NSLog(@"%@%@", indent, [view debugDescription]);
NSString *nextIndent = [indent stringByAppendingString:@"-"];
if ([view isKindOfClass:[UIVisualEffectView class]]) {
UIVisualEffectView *effectView = (UIVisualEffectView *)view;
if (@available(iOS 26.0, *)) {
if ([effectView.effect isKindOfClass:[UIGlassEffect class]]) {
UIGlassEffect *effect = (UIGlassEffect *)effectView.effect;
NSObject *glass = [effect valueForKey:@"glass"];
NSLog(@"glass %@", glass.debugDescription);
}
}
}
for (UIView *subview in view.subviews) {
dumpViews(subview, nextIndent);
}
}*/
- (UIWindow * _Nullable)internalGetKeyboard {
Class windowClass = NSClassFromString(@"UIRemoteKeyboardWindow");
if (!windowClass) {
return nil;
}
UIWindow *result = [(id<UIRemoteKeyboardWindowProtocol>)windowClass remoteKeyboardWindowForScreen:[UIScreen mainScreen] create:false];
if (result) {
//dumpViews(result, @"");
}
return result;
}
@end
@implementation UIView (Navigation)
- (bool)disablesInteractiveTransitionGestureRecognizer {
return [[self associatedObjectForKey:disablesInteractiveTransitionGestureRecognizerKey] boolValue];
}
- (void)setDisablesInteractiveTransitionGestureRecognizer:(bool)disablesInteractiveTransitionGestureRecognizer {
[self setAssociatedObject:@(disablesInteractiveTransitionGestureRecognizer) forKey:disablesInteractiveTransitionGestureRecognizerKey];
}
- (bool)disablesInteractiveKeyboardGestureRecognizer {
return [[self associatedObjectForKey:disablesInteractiveKeyboardGestureRecognizerKey] boolValue];
}
- (void)setDisablesInteractiveKeyboardGestureRecognizer:(bool)disablesInteractiveKeyboardGestureRecognizer {
[self setAssociatedObject:@(disablesInteractiveKeyboardGestureRecognizer) forKey:disablesInteractiveKeyboardGestureRecognizerKey];
}
- (bool (^)())disablesInteractiveTransitionGestureRecognizerNow {
return [self associatedObjectForKey:disablesInteractiveTransitionGestureRecognizerNowKey];
}
- (void)setDisablesInteractiveTransitionGestureRecognizerNow:(bool (^)())disablesInteractiveTransitionGestureRecognizerNow {
[self setAssociatedObject:[disablesInteractiveTransitionGestureRecognizerNow copy] forKey:disablesInteractiveTransitionGestureRecognizerNowKey];
}
- (bool)disablesInteractiveModalDismiss {
return [self associatedObjectForKey:disablesInteractiveModalDismissKey];
}
- (void)setDisablesInteractiveModalDismiss:(bool)disablesInteractiveModalDismiss {
[self setAssociatedObject:@(disablesInteractiveModalDismiss) forKey:disablesInteractiveModalDismissKey];
}
- (BOOL (^)(CGPoint))interactiveTransitionGestureRecognizerTest {
return [self associatedObjectForKey:interactiveTransitionGestureRecognizerTestKey];
}
- (void)setInteractiveTransitionGestureRecognizerTest:(BOOL (^)(CGPoint))block {
[self setAssociatedObject:[block copy] forKey:interactiveTransitionGestureRecognizerTestKey];
}
- (UIResponderDisableAutomaticKeyboardHandling)disableAutomaticKeyboardHandling {
return (UIResponderDisableAutomaticKeyboardHandling)[[self associatedObjectForKey:disableAutomaticKeyboardHandlingKey] unsignedIntegerValue];
}
- (void)setDisableAutomaticKeyboardHandling:(UIResponderDisableAutomaticKeyboardHandling)disableAutomaticKeyboardHandling {
[self setAssociatedObject:@(disableAutomaticKeyboardHandling) forKey:disableAutomaticKeyboardHandlingKey];
}
- (void)input_setInputAccessoryHeightProvider:(CGFloat (^_Nullable)())block {
[self setAssociatedObject:[block copy] forKey:inputAccessoryHeightProviderKey];
}
- (CGFloat)input_getInputAccessoryHeight {
CGFloat (^block)() = [self associatedObjectForKey:inputAccessoryHeightProviderKey];
if (block) {
return block();
}
return 0.0f;
}
@end
void applyKeyboardAutocorrection(UITextView * _Nonnull textView) {
NSRange rangeCopy = textView.selectedRange;
NSRange fakeRange = rangeCopy;
if (fakeRange.location != 0) {
fakeRange.location--;
}
[textView unmarkText];
[textView setSelectedRange:fakeRange];
[textView setSelectedRange:rangeCopy];
}
@interface AboveStatusBarWindowController : UIViewController
@property (nonatomic, copy) UIInterfaceOrientationMask (^ _Nullable supportedOrientations)(void);
@end
@implementation AboveStatusBarWindowController
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nil bundle:nil];
if (self != nil) {
self.extendedLayoutIncludesOpaqueBars = true;
}
return self;
}
- (void)loadView {
self.view = [[UIView alloc] initWithFrame:CGRectZero];
self.view.opaque = false;
self.view.backgroundColor = nil;
[self viewDidLoad];
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
@end
@implementation AboveStatusBarWindow
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self != nil) {
self.windowLevel = UIWindowLevelStatusBar + 1.0f;
self.rootViewController = [[AboveStatusBarWindowController alloc] initWithNibName:nil bundle:nil];
if (self.gestureRecognizers != nil) {
for (UIGestureRecognizer *recognizer in self.gestureRecognizers) {
recognizer.delaysTouchesBegan = false;
}
}
}
return self;
}
- (void)setSupportedOrientations:(UIInterfaceOrientationMask (^)(void))supportedOrientations {
_supportedOrientations = [supportedOrientations copy];
((AboveStatusBarWindowController *)self.rootViewController).supportedOrientations = _supportedOrientations;
}
- (BOOL)shouldAffectStatusBarAppearance {
return false;
}
- (BOOL)canBecomeKeyWindow {
return false;
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *result = [super hitTest:point withEvent:event];
if (result == self || result == self.rootViewController.view) {
return nil;
}
return result;
}
+ (void)initialize {
NSString *canAffectSelectorString = [@[@"_can", @"Affect", @"Status", @"Bar", @"Appearance"] componentsJoinedByString:@""];
SEL canAffectSelector = NSSelectorFromString(canAffectSelectorString);
Method shouldAffectMethod = class_getInstanceMethod(self, @selector(shouldAffectStatusBarAppearance));
IMP canAffectImplementation = method_getImplementation(shouldAffectMethod);
class_addMethod(self, canAffectSelector, canAffectImplementation, method_getTypeEncoding(shouldAffectMethod));
NSString *canBecomeKeySelectorString = [NSString stringWithFormat:@"_%@", NSStringFromSelector(@selector(canBecomeKeyWindow))];
SEL canBecomeKeySelector = NSSelectorFromString(canBecomeKeySelectorString);
Method canBecomeKeyMethod = class_getInstanceMethod(self, @selector(canBecomeKeyWindow));
IMP canBecomeKeyImplementation = method_getImplementation(canBecomeKeyMethod);
class_addMethod(self, canBecomeKeySelector, canBecomeKeyImplementation, method_getTypeEncoding(canBecomeKeyMethod));
}
@end
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
@@ -0,0 +1,11 @@
#import <UIKit/UIKit.h>
@interface UIWindow (OrientationChange)
- (bool)isRotating;
+ (void)addPostDeviceOrientationDidChangeBlock:(void (^)())block;
+ (bool)isDeviceRotating;
- (void)_updateToInterfaceOrientation:(int)arg1 duration:(double)arg2 force:(BOOL)arg3;
@end
@@ -0,0 +1,128 @@
#import "UIWindow+OrientationChange.h"
#import <ObjCRuntimeUtils/RuntimeUtils.h>
#import "NotificationCenterUtils.h"
static const void *isRotatingKey = &isRotatingKey;
static NSMutableArray *postDeviceDidChangeOrientationBlocks() {
static NSMutableArray *array = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
array = [[NSMutableArray alloc] init];
});
return array;
}
static bool _isDeviceRotating = false;
@interface UIView (OrientationChangeDeps)
- (void)_updateToInterfaceOrientation:(int)arg1 duration:(double)arg2 force:(BOOL)arg3;
@end
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincomplete-implementation"
@implementation UIWindow (OrientationChange)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^ {
[NotificationCenterUtils addNotificationHandler:^bool(NSString *name, id object, NSDictionary *userInfo, void (^passNotification)()) {
if ([name isEqualToString:@"UIWindowWillRotateNotification"]) {
[(UIWindow *)object setRotating:true];
if (NSClassFromString(@"NSUserActivity") == NULL) {
UIInterfaceOrientation orientation = [userInfo[@"UIWindowNewOrientationUserInfoKey"] integerValue];
CGSize screenSize = [UIScreen mainScreen].bounds.size;
if (screenSize.width > screenSize.height)
{
CGFloat tmp = screenSize.height;
screenSize.height = screenSize.width;
screenSize.width = tmp;
}
CGSize windowSize = CGSizeZero;
CGFloat windowRotation = 0.0;
__unused bool landscape = false;
switch (orientation) {
case UIInterfaceOrientationPortrait:
windowSize = screenSize;
break;
case UIInterfaceOrientationPortraitUpsideDown:
windowRotation = (CGFloat)(M_PI);
windowSize = screenSize;
break;
case UIInterfaceOrientationLandscapeLeft:
landscape = true;
windowRotation = (CGFloat)(-M_PI / 2.0);
windowSize = CGSizeMake(screenSize.height, screenSize.width);
break;
case UIInterfaceOrientationLandscapeRight:
landscape = true;
windowRotation = (CGFloat)(M_PI / 2.0);
windowSize = CGSizeMake(screenSize.height, screenSize.width);
break;
default:
break;
}
[UIView animateWithDuration:0.3 animations:^
{
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformRotate(transform, windowRotation);
((UIWindow *)object).transform = transform;
((UIWindow *)object).bounds = CGRectMake(0.0f, 0.0f, windowSize.width, windowSize.height);
}];
}
passNotification();
return true;
} else if ([name isEqualToString:@"UIWindowDidRotateNotification"]) {
[(UIWindow *)object setRotating:false];
} else if ([name isEqualToString:UIDeviceOrientationDidChangeNotification]) {
_isDeviceRotating = true;
passNotification();
if (postDeviceDidChangeOrientationBlocks().count != 0) {
NSArray *blocks = [postDeviceDidChangeOrientationBlocks() copy];
[postDeviceDidChangeOrientationBlocks() removeAllObjects];
for (dispatch_block_t block in blocks) {
block();
}
}
_isDeviceRotating = false;
return true;
}
return false;
}];
});
}
+ (void)addPostDeviceOrientationDidChangeBlock:(void (^)())block {
[postDeviceDidChangeOrientationBlocks() addObject:[block copy]];
}
- (void)setRotating:(bool)rotating
{
[self setAssociatedObject:@(rotating) forKey:isRotatingKey];
}
- (bool)isRotating
{
return [[self associatedObjectForKey:isRotatingKey] boolValue];
}
+ (bool)isDeviceRotating {
return _isDeviceRotating;
}
@end
#pragma clang diagnostic pop