mirror of
https://github.com/SoPat712/YTLitePlus.git
synced 2025-08-25 11:55:28 -04:00
added files via upload
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
//
|
||||
// FLEXArgumentInputJSONObjectView.m
|
||||
// Flipboard
|
||||
//
|
||||
// Created by Ryan Olson on 6/15/14.
|
||||
// Copyright (c) 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FLEXArgumentInputObjectView.h"
|
||||
#import "FLEXRuntimeUtility.h"
|
||||
|
||||
static const CGFloat kSegmentInputMargin = 10;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, FLEXArgInputObjectType) {
|
||||
FLEXArgInputObjectTypeJSON,
|
||||
FLEXArgInputObjectTypeAddress
|
||||
};
|
||||
|
||||
@interface FLEXArgumentInputObjectView ()
|
||||
|
||||
@property (nonatomic) UISegmentedControl *objectTypeSegmentControl;
|
||||
@property (nonatomic) FLEXArgInputObjectType inputType;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FLEXArgumentInputObjectView
|
||||
|
||||
- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
|
||||
self = [super initWithArgumentTypeEncoding:typeEncoding];
|
||||
if (self) {
|
||||
// Start with the numbers and punctuation keyboard since quotes, curly braces, or
|
||||
// square brackets are likely to be the first characters type for the JSON.
|
||||
self.inputTextView.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
|
||||
self.targetSize = FLEXArgumentInputViewSizeLarge;
|
||||
|
||||
self.objectTypeSegmentControl = [[UISegmentedControl alloc] initWithItems:@[@"Value", @"Address"]];
|
||||
[self.objectTypeSegmentControl addTarget:self action:@selector(didChangeType) forControlEvents:UIControlEventValueChanged];
|
||||
self.objectTypeSegmentControl.selectedSegmentIndex = 0;
|
||||
[self addSubview:self.objectTypeSegmentControl];
|
||||
|
||||
self.inputType = [[self class] preferredDefaultTypeForObjCType:typeEncoding withCurrentValue:nil];
|
||||
self.objectTypeSegmentControl.selectedSegmentIndex = self.inputType;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)didChangeType {
|
||||
self.inputType = self.objectTypeSegmentControl.selectedSegmentIndex;
|
||||
|
||||
if (super.inputValue) {
|
||||
// Trigger an update to the text field to show
|
||||
// the address of the stored object we were given,
|
||||
// or to show a JSON representation of the object
|
||||
[self populateTextAreaFromValue:super.inputValue];
|
||||
} else {
|
||||
// Clear the text field
|
||||
[self populateTextAreaFromValue:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setInputType:(FLEXArgInputObjectType)inputType {
|
||||
if (_inputType == inputType) return;
|
||||
|
||||
_inputType = inputType;
|
||||
|
||||
// Resize input view
|
||||
switch (inputType) {
|
||||
case FLEXArgInputObjectTypeJSON:
|
||||
self.targetSize = FLEXArgumentInputViewSizeLarge;
|
||||
break;
|
||||
case FLEXArgInputObjectTypeAddress:
|
||||
self.targetSize = FLEXArgumentInputViewSizeSmall;
|
||||
break;
|
||||
}
|
||||
|
||||
// Change placeholder
|
||||
switch (inputType) {
|
||||
case FLEXArgInputObjectTypeJSON:
|
||||
self.inputPlaceholderText =
|
||||
@"You can put any valid JSON here, such as a string, number, array, or dictionary:"
|
||||
"\n\"This is a string\""
|
||||
"\n1234"
|
||||
"\n{ \"name\": \"Bob\", \"age\": 47 }"
|
||||
"\n["
|
||||
"\n 1, 2, 3"
|
||||
"\n]";
|
||||
break;
|
||||
case FLEXArgInputObjectTypeAddress:
|
||||
self.inputPlaceholderText = @"0x0000deadb33f";
|
||||
break;
|
||||
}
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self.superview setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)setInputValue:(id)inputValue {
|
||||
super.inputValue = inputValue;
|
||||
[self populateTextAreaFromValue:inputValue];
|
||||
}
|
||||
|
||||
- (id)inputValue {
|
||||
switch (self.inputType) {
|
||||
case FLEXArgInputObjectTypeJSON:
|
||||
return [FLEXRuntimeUtility objectValueFromEditableJSONString:self.inputTextView.text];
|
||||
case FLEXArgInputObjectTypeAddress: {
|
||||
NSScanner *scanner = [NSScanner scannerWithString:self.inputTextView.text];
|
||||
|
||||
unsigned long long objectPointerValue;
|
||||
if ([scanner scanHexLongLong:&objectPointerValue]) {
|
||||
return (__bridge id)(void *)objectPointerValue;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)populateTextAreaFromValue:(id)value {
|
||||
if (!value) {
|
||||
self.inputTextView.text = nil;
|
||||
} else {
|
||||
if (self.inputType == FLEXArgInputObjectTypeJSON) {
|
||||
self.inputTextView.text = [FLEXRuntimeUtility editableJSONStringForObject:value];
|
||||
} else if (self.inputType == FLEXArgInputObjectTypeAddress) {
|
||||
self.inputTextView.text = [NSString stringWithFormat:@"%p", value];
|
||||
}
|
||||
}
|
||||
|
||||
// Delegate methods are not called for programmatic changes
|
||||
[self textViewDidChange:self.inputTextView];
|
||||
}
|
||||
|
||||
- (CGSize)sizeThatFits:(CGSize)size {
|
||||
CGSize fitSize = [super sizeThatFits:size];
|
||||
fitSize.height += [self.objectTypeSegmentControl sizeThatFits:size].height + kSegmentInputMargin;
|
||||
|
||||
return fitSize;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
CGFloat segmentHeight = [self.objectTypeSegmentControl sizeThatFits:self.frame.size].height;
|
||||
self.objectTypeSegmentControl.frame = CGRectMake(
|
||||
0.0,
|
||||
// Our segmented control is taking the position
|
||||
// of the text view, as far as super is concerned,
|
||||
// and we override this property to be different
|
||||
super.topInputFieldVerticalLayoutGuide,
|
||||
self.frame.size.width,
|
||||
segmentHeight
|
||||
);
|
||||
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
- (CGFloat)topInputFieldVerticalLayoutGuide {
|
||||
// Our text view is offset from the segmented control
|
||||
CGFloat segmentHeight = [self.objectTypeSegmentControl sizeThatFits:self.frame.size].height;
|
||||
return segmentHeight + super.topInputFieldVerticalLayoutGuide + kSegmentInputMargin;
|
||||
}
|
||||
|
||||
+ (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value {
|
||||
NSParameterAssert(type);
|
||||
// Must be object type
|
||||
return type[0] == FLEXTypeEncodingObjcObject || type[0] == FLEXTypeEncodingObjcClass;
|
||||
}
|
||||
|
||||
+ (FLEXArgInputObjectType)preferredDefaultTypeForObjCType:(const char *)type withCurrentValue:(id)value {
|
||||
NSParameterAssert(type[0] == FLEXTypeEncodingObjcObject || type[0] == FLEXTypeEncodingObjcClass);
|
||||
|
||||
if (value) {
|
||||
// If there's a current value, it must be serializable to JSON
|
||||
// to display the JSON editor. Otherwise display the address field.
|
||||
if ([FLEXRuntimeUtility editableJSONStringForObject:value]) {
|
||||
return FLEXArgInputObjectTypeJSON;
|
||||
} else {
|
||||
return FLEXArgInputObjectTypeAddress;
|
||||
}
|
||||
} else {
|
||||
// Otherwise, see if we have more type information than just 'id'.
|
||||
// If we do, make sure the encoding is something serializable to JSON.
|
||||
// Properties and ivars keep more detailed type encoding information than method arguments.
|
||||
if (strcmp(type, @encode(id)) != 0) {
|
||||
BOOL isJSONSerializableType = NO;
|
||||
|
||||
// Parse class name out of the string,
|
||||
// which is in the form `@"ClassName"`
|
||||
Class cls = NSClassFromString(({
|
||||
NSString *className = nil;
|
||||
NSScanner *scan = [NSScanner scannerWithString:@(type)];
|
||||
NSCharacterSet *allowed = [NSCharacterSet
|
||||
characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$"
|
||||
];
|
||||
|
||||
// Skip over the @" then scan the name
|
||||
if ([scan scanString:@"@\"" intoString:nil]) {
|
||||
[scan scanCharactersFromSet:allowed intoString:&className];
|
||||
}
|
||||
|
||||
className;
|
||||
}));
|
||||
|
||||
// Note: we can't use @encode(NSString) here because that drops
|
||||
// the class information and just goes to @encode(id).
|
||||
NSArray<Class> *jsonTypes = @[
|
||||
[NSString class],
|
||||
[NSNumber class],
|
||||
[NSArray class],
|
||||
[NSDictionary class],
|
||||
];
|
||||
|
||||
// Look for matching types
|
||||
for (Class jsonClass in jsonTypes) {
|
||||
if ([cls isSubclassOfClass:jsonClass]) {
|
||||
isJSONSerializableType = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isJSONSerializableType) {
|
||||
return FLEXArgInputObjectTypeJSON;
|
||||
} else {
|
||||
return FLEXArgInputObjectTypeAddress;
|
||||
}
|
||||
} else {
|
||||
return FLEXArgInputObjectTypeAddress;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
Reference in New Issue
Block a user