mirror of
				https://github.com/SoPat712/YTLitePlus.git
				synced 2025-10-31 04:44:14 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			244 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
	
	
| //
 | |
| //  FLEXObjectExplorerFactory.m
 | |
| //  Flipboard
 | |
| //
 | |
| //  Created by Ryan Olson on 5/15/14.
 | |
| //  Copyright (c) 2020 FLEX Team. All rights reserved.
 | |
| //
 | |
| 
 | |
| #import "FLEXObjectExplorerFactory.h"
 | |
| #import "FLEXGlobalsViewController.h"
 | |
| #import "FLEXClassShortcuts.h"
 | |
| #import "FLEXViewShortcuts.h"
 | |
| #import "FLEXViewControllerShortcuts.h"
 | |
| #import "FLEXUIAppShortcuts.h"
 | |
| #import "FLEXImageShortcuts.h"
 | |
| #import "FLEXLayerShortcuts.h"
 | |
| #import "FLEXColorPreviewSection.h"
 | |
| #import "FLEXDefaultsContentSection.h"
 | |
| #import "FLEXBundleShortcuts.h"
 | |
| #import "FLEXNSStringShortcuts.h"
 | |
| #import "FLEXNSDataShortcuts.h"
 | |
| #import "FLEXBlockShortcuts.h"
 | |
| #import "FLEXUtility.h"
 | |
| 
 | |
| @implementation FLEXObjectExplorerFactory
 | |
| static NSMutableDictionary<id<NSCopying>, Class> *classesToRegisteredSections = nil;
 | |
| 
 | |
| + (void)initialize {
 | |
|     if (self == [FLEXObjectExplorerFactory class]) {
 | |
|         // DO NOT USE STRING KEYS HERE
 | |
|         // We NEED to use the class as a key, because we CANNOT
 | |
|         // differentiate a class's name from the metaclass's name.
 | |
|         // These mappings are per-class-object, not per-class-name.
 | |
|         //
 | |
|         // For example, if we used class names, this would result in
 | |
|         // the object explorer trying to render a color preview for
 | |
|         // the UIColor class object, which is not a color itself.
 | |
|         #define ClassKey(name) (id<NSCopying>)[name class]
 | |
|         #define ClassKeyByName(str) (id<NSCopying>)NSClassFromString(@ #str)
 | |
|         #define MetaclassKey(meta) (id<NSCopying>)object_getClass([meta class])
 | |
|         classesToRegisteredSections = [NSMutableDictionary dictionaryWithDictionary:@{
 | |
|             MetaclassKey(NSObject)     : [FLEXClassShortcuts class],
 | |
|             ClassKey(NSArray)          : [FLEXCollectionContentSection class],
 | |
|             ClassKey(NSSet)            : [FLEXCollectionContentSection class],
 | |
|             ClassKey(NSDictionary)     : [FLEXCollectionContentSection class],
 | |
|             ClassKey(NSOrderedSet)     : [FLEXCollectionContentSection class],
 | |
|             ClassKey(NSUserDefaults)   : [FLEXDefaultsContentSection class],
 | |
|             ClassKey(UIViewController) : [FLEXViewControllerShortcuts class],
 | |
|             ClassKey(UIApplication)    : [FLEXUIAppShortcuts class],
 | |
|             ClassKey(UIView)           : [FLEXViewShortcuts class],
 | |
|             ClassKey(UIImage)          : [FLEXImageShortcuts class],
 | |
|             ClassKey(CALayer)          : [FLEXLayerShortcuts class],
 | |
|             ClassKey(UIColor)          : [FLEXColorPreviewSection class],
 | |
|             ClassKey(NSBundle)         : [FLEXBundleShortcuts class],
 | |
|             ClassKey(NSString)         : [FLEXNSStringShortcuts class],
 | |
|             ClassKey(NSData)           : [FLEXNSDataShortcuts class],
 | |
|             ClassKeyByName(NSBlock)    : [FLEXBlockShortcuts class],
 | |
|         }];
 | |
|         #undef ClassKey
 | |
|         #undef ClassKeyByName
 | |
|         #undef MetaclassKey
 | |
|     }
 | |
| }
 | |
| 
 | |
| + (FLEXObjectExplorerViewController *)explorerViewControllerForObject:(id)object {
 | |
|     // Can't explore nil
 | |
|     if (!object) {
 | |
|         return nil;
 | |
|     }
 | |
| 
 | |
|     // If we're given an object, this will look up it's class hierarchy
 | |
|     // until it finds a registration. This will work for KVC classes,
 | |
|     // since they are children of the original class, and not siblings.
 | |
|     // If we are given an object, object_getClass will return a metaclass,
 | |
|     // and the same thing will happen. FLEXClassShortcuts is the default
 | |
|     // shortcut section for NSObject.
 | |
|     //
 | |
|     // TODO: rename it to FLEXNSObjectShortcuts or something?
 | |
|     FLEXShortcutsSection *shortcutsSection = [FLEXShortcutsSection forObject:object];
 | |
|     NSArray *sections = @[shortcutsSection];
 | |
|     
 | |
|     Class customSectionClass = nil;
 | |
|     Class cls = object_getClass(object);
 | |
|     do {
 | |
|         customSectionClass = classesToRegisteredSections[(id<NSCopying>)cls];
 | |
|     } while (!customSectionClass && (cls = [cls superclass]));
 | |
| 
 | |
|     if (customSectionClass) {
 | |
|         id customSection = [customSectionClass forObject:object];
 | |
|         BOOL isFLEXShortcutSection = [customSection respondsToSelector:@selector(isNewSection)];
 | |
|         
 | |
|         // If the section "replaces" the default shortcuts section,
 | |
|         // only return that section. Otherwise, return both this
 | |
|         // section and the default shortcuts section.
 | |
|         if (isFLEXShortcutSection && ![customSection isNewSection]) {
 | |
|             sections = @[customSection];
 | |
|         } else {
 | |
|             // Custom section will go before shortcuts
 | |
|             sections = @[customSection, shortcutsSection];            
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return [FLEXObjectExplorerViewController
 | |
|         exploringObject:object
 | |
|         customSections:sections
 | |
|     ];
 | |
| }
 | |
| 
 | |
| + (void)registerExplorerSection:(Class)explorerClass forClass:(Class)objectClass {
 | |
|     classesToRegisteredSections[(id<NSCopying>)objectClass] = explorerClass;
 | |
| }
 | |
| 
 | |
| #pragma mark - FLEXGlobalsEntry
 | |
| 
 | |
| + (NSString *)globalsEntryTitle:(FLEXGlobalsRow)row  {
 | |
|     switch (row) {
 | |
|         case FLEXGlobalsRowAppDelegate:
 | |
|             return @"🎟  App Delegate";
 | |
|         case FLEXGlobalsRowKeyWindow:
 | |
|             return @"🔑  Key Window";
 | |
|         case FLEXGlobalsRowRootViewController:
 | |
|             return @"🌴  Root View Controller";
 | |
|         case FLEXGlobalsRowProcessInfo:
 | |
|             return @"🚦  NSProcessInfo.processInfo";
 | |
|         case FLEXGlobalsRowUserDefaults:
 | |
|             return @"💾  Preferences";
 | |
|         case FLEXGlobalsRowMainBundle:
 | |
|             return @"📦  NSBundle.mainBundle";
 | |
|         case FLEXGlobalsRowApplication:
 | |
|             return @"🚀  UIApplication.sharedApplication";
 | |
|         case FLEXGlobalsRowMainScreen:
 | |
|             return @"💻  UIScreen.mainScreen";
 | |
|         case FLEXGlobalsRowCurrentDevice:
 | |
|             return @"📱  UIDevice.currentDevice";
 | |
|         case FLEXGlobalsRowPasteboard:
 | |
|             return @"📋  UIPasteboard.generalPasteboard";
 | |
|         case FLEXGlobalsRowURLSession:
 | |
|             return @"📡  NSURLSession.sharedSession";
 | |
|         case FLEXGlobalsRowURLCache:
 | |
|             return @"⏳  NSURLCache.sharedURLCache";
 | |
|         case FLEXGlobalsRowNotificationCenter:
 | |
|             return @"🔔  NSNotificationCenter.defaultCenter";
 | |
|         case FLEXGlobalsRowMenuController:
 | |
|             return @"📎  UIMenuController.sharedMenuController";
 | |
|         case FLEXGlobalsRowFileManager:
 | |
|             return @"🗄  NSFileManager.defaultManager";
 | |
|         case FLEXGlobalsRowTimeZone:
 | |
|             return @"🌎  NSTimeZone.systemTimeZone";
 | |
|         case FLEXGlobalsRowLocale:
 | |
|             return @"🗣  NSLocale.currentLocale";
 | |
|         case FLEXGlobalsRowCalendar:
 | |
|             return @"📅  NSCalendar.currentCalendar";
 | |
|         case FLEXGlobalsRowMainRunLoop:
 | |
|             return @"🏃🏻♂️  NSRunLoop.mainRunLoop";
 | |
|         case FLEXGlobalsRowMainThread:
 | |
|             return @"🧵  NSThread.mainThread";
 | |
|         case FLEXGlobalsRowOperationQueue:
 | |
|             return @"📚  NSOperationQueue.mainQueue";
 | |
|         default: return nil;
 | |
|     }
 | |
| }
 | |
| 
 | |
| + (UIViewController *)globalsEntryViewController:(FLEXGlobalsRow)row  {
 | |
|     switch (row) {
 | |
|         case FLEXGlobalsRowAppDelegate: {
 | |
|             id<UIApplicationDelegate> appDelegate = UIApplication.sharedApplication.delegate;
 | |
|             return [self explorerViewControllerForObject:appDelegate];
 | |
|         }
 | |
|         case FLEXGlobalsRowProcessInfo:
 | |
|             return [self explorerViewControllerForObject:NSProcessInfo.processInfo];
 | |
|         case FLEXGlobalsRowUserDefaults:
 | |
|             return [self explorerViewControllerForObject:NSUserDefaults.standardUserDefaults];
 | |
|         case FLEXGlobalsRowMainBundle:
 | |
|             return [self explorerViewControllerForObject:NSBundle.mainBundle];
 | |
|         case FLEXGlobalsRowApplication:
 | |
|             return [self explorerViewControllerForObject:UIApplication.sharedApplication];
 | |
|         case FLEXGlobalsRowMainScreen:
 | |
|             return [self explorerViewControllerForObject:UIScreen.mainScreen];
 | |
|         case FLEXGlobalsRowCurrentDevice:
 | |
|             return [self explorerViewControllerForObject:UIDevice.currentDevice];
 | |
|         case FLEXGlobalsRowPasteboard:
 | |
|             return [self explorerViewControllerForObject:UIPasteboard.generalPasteboard];
 | |
|             case FLEXGlobalsRowURLSession:
 | |
|             return [self explorerViewControllerForObject:NSURLSession.sharedSession];
 | |
|         case FLEXGlobalsRowURLCache:
 | |
|             return [self explorerViewControllerForObject:NSURLCache.sharedURLCache];
 | |
|         case FLEXGlobalsRowNotificationCenter:
 | |
|             return [self explorerViewControllerForObject:NSNotificationCenter.defaultCenter];
 | |
|         case FLEXGlobalsRowMenuController:
 | |
|             return [self explorerViewControllerForObject:UIMenuController.sharedMenuController];
 | |
|         case FLEXGlobalsRowFileManager:
 | |
|             return [self explorerViewControllerForObject:NSFileManager.defaultManager];
 | |
|         case FLEXGlobalsRowTimeZone:
 | |
|             return [self explorerViewControllerForObject:NSTimeZone.systemTimeZone];
 | |
|         case FLEXGlobalsRowLocale:
 | |
|             return [self explorerViewControllerForObject:NSLocale.currentLocale];
 | |
|         case FLEXGlobalsRowCalendar:
 | |
|             return [self explorerViewControllerForObject:NSCalendar.currentCalendar];
 | |
|         case FLEXGlobalsRowMainRunLoop:
 | |
|             return [self explorerViewControllerForObject:NSRunLoop.mainRunLoop];
 | |
|         case FLEXGlobalsRowMainThread:
 | |
|             return [self explorerViewControllerForObject:NSThread.mainThread];
 | |
|         case FLEXGlobalsRowOperationQueue:
 | |
|             return [self explorerViewControllerForObject:NSOperationQueue.mainQueue];
 | |
| 
 | |
|         case FLEXGlobalsRowKeyWindow:
 | |
|             return [FLEXObjectExplorerFactory
 | |
|                 explorerViewControllerForObject:FLEXUtility.appKeyWindow
 | |
|             ];
 | |
|         case FLEXGlobalsRowRootViewController: {
 | |
|             id<UIApplicationDelegate> delegate = UIApplication.sharedApplication.delegate;
 | |
|             if ([delegate respondsToSelector:@selector(window)]) {
 | |
|                 return [self explorerViewControllerForObject:delegate.window.rootViewController];
 | |
|             }
 | |
| 
 | |
|             return nil;
 | |
|         }
 | |
|         default: return nil;
 | |
|     }
 | |
| }
 | |
| 
 | |
| + (FLEXGlobalsEntryRowAction)globalsEntryRowAction:(FLEXGlobalsRow)row {
 | |
|     switch (row) {
 | |
|         case FLEXGlobalsRowRootViewController: {
 | |
|             // Check if the app delegate responds to -window. If not, present an alert
 | |
|             return ^(UITableViewController *host) {
 | |
|                 id<UIApplicationDelegate> delegate = UIApplication.sharedApplication.delegate;
 | |
|                 if ([delegate respondsToSelector:@selector(window)]) {
 | |
|                     UIViewController *explorer = [self explorerViewControllerForObject:
 | |
|                         delegate.window.rootViewController
 | |
|                     ];
 | |
|                     [host.navigationController pushViewController:explorer animated:YES];
 | |
|                 } else {
 | |
|                     NSString *msg = @"The app delegate doesn't respond to -window";
 | |
|                     [FLEXAlert showAlert:@":(" message:msg from:host];
 | |
|                 }
 | |
|             };
 | |
|         }
 | |
|         default: return nil;
 | |
|     }
 | |
| }
 | |
| 
 | |
| @end
 | 
