Bläddra i källkod

First step refactor of FLEXArgumentInputView

We will now have a generic FLEXArgumentInputView superclass that just shows a title and declares the common interface for setting an initial value for the argument, getting the user’s input, etc.

With FLEXArgumentInputViewFactory, we will be able to pick different FLEXArgumentInputView subclasses depending on the type encoding of the argument. This will allow us to go beyond string-only input to have things like switches for BOOLs, multiple fields for structs, color pickers for UIColors, font pickers, etc.
Ryan Olson 12 år sedan
förälder
incheckning
b9ade564a4

+ 13 - 0
Classes/Editing/Argument Input Views/FLEXArgumentInputTextView.h

@@ -0,0 +1,13 @@
+//
+//  FLEXArgumentInputTextView.h
+//  FLEXInjected
+//
+//  Created by Ryan Olson on 6/15/14.
+//
+//
+
+#import "FLEXArgumentInputView.h"
+
+@interface FLEXArgumentInputTextView : FLEXArgumentInputView
+
+@end

+ 99 - 0
Classes/Editing/Argument Input Views/FLEXArgumentInputTextView.m

@@ -0,0 +1,99 @@
+//
+//  FLEXArgumentInputTextView.m
+//  FLEXInjected
+//
+//  Created by Ryan Olson on 6/15/14.
+//
+//
+
+#import "FLEXArgumentInputTextView.h"
+#import "FLEXUtility.h"
+
+@interface FLEXArgumentInputTextView ()
+
+@property (nonatomic, strong) UITextView *inputTextView;
+@property (nonatomic, readonly) NSUInteger numberOfInputLines;
+
+@end
+
+@implementation FLEXArgumentInputTextView
+
+- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding
+{
+    self = [super initWithArgumentTypeEncoding:typeEncoding];
+    if (self) {
+        self.inputTextView = [[UITextView alloc] init];
+        self.inputTextView.font = [[self class] inputFont];
+        self.inputTextView.backgroundColor = [UIColor whiteColor];
+        self.inputTextView.layer.borderColor = [[UIColor blackColor] CGColor];
+        self.inputTextView.layer.borderWidth = 1.0;
+        self.inputTextView.autocapitalizationType = UITextAutocapitalizationTypeNone;
+        self.inputTextView.autocorrectionType = UITextAutocorrectionTypeNo;
+        [self addSubview:self.inputTextView];
+    }
+    return self;
+}
+
+
+#pragma mark - Input/Output
+
+- (void)setInputOutput:(id)inputOutput
+{
+    self.inputTextView.text = inputOutput;
+}
+
+- (id)inputOutput
+{
+    return [self.inputTextView.text copy];
+}
+
+
+#pragma mark - Layout and Sizing
+
+- (void)layoutSubviews
+{
+    [super layoutSubviews];
+    
+    CGFloat originY = 0;
+    if (self.showsTitle) {
+        originY = CGRectGetMaxY(self.titleLabel.frame) + [[self class] titleBottomPadding];
+    }
+    self.inputTextView.frame = CGRectMake(0, originY, self.bounds.size.width, [self inputTextViewHeight]);
+}
+
+- (NSUInteger)numberOfInputLines
+{
+    NSUInteger numberOfInputLines = 0;
+    switch (self.targetSize) {
+        case FLEXArgumentInputViewSizeDefault:
+            numberOfInputLines = 2;
+            break;
+            
+        case FLEXArgumentInputViewSizeLarge:
+            numberOfInputLines = 8;
+            break;
+    }
+    return numberOfInputLines;
+}
+
+- (CGFloat)inputTextViewHeight
+{
+    return ceil([[self class] inputFont].lineHeight * self.numberOfInputLines) + 20.0;
+}
+
+- (CGSize)sizeThatFits:(CGSize)size
+{
+    CGSize fitSize = [super sizeThatFits:size];
+    fitSize.height += [self inputTextViewHeight];
+    return fitSize;
+}
+
+
+#pragma mark - Class Helpers
+
++ (UIFont *)inputFont
+{
+    return [FLEXUtility defaultFontOfSize:14.0];
+}
+
+@end

+ 44 - 0
Classes/Editing/Argument Input Views/FLEXArgumentInputView.h

@@ -0,0 +1,44 @@
+//
+//  FLEXArgumentInputView.h
+//  Flipboard
+//
+//  Created by Ryan Olson on 5/30/14.
+//  Copyright (c) 2014 Flipboard. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+typedef NS_ENUM(NSUInteger, FLEXArgumentInputViewSize) {
+    FLEXArgumentInputViewSizeDefault = 0,
+    FLEXArgumentInputViewSizeLarge
+};
+
+@interface FLEXArgumentInputView : UIView
+
+- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding;
+
+/// The name of the field. Optional (can be nil).
+@property (nonatomic, copy) NSString *title;
+
+/// To populate the filed with an initial value, set this property.
+/// To reteive the value input by the user, access the property.
+/// Primitive types and structs should/will be boxed in NSValue containers.
+@property (nonatomic, strong) id inputOutput;
+
+/// Setting this value to large will make some argument input views increase the size of their input field(s).
+/// Useful to increase the use of space if there is only one input view on screen (i.e. for property and ivar editing).
+@property (nonatomic, assign) FLEXArgumentInputViewSize targetSize;
+
+// Subclasses can override
+
+/// If the input view has one or more text views, returns YES when one of them is focused.
+@property (nonatomic, readonly) BOOL inputViewIsFirstResponder;
+
+// For subclass eyes only
+
+@property (nonatomic, strong, readonly) UILabel *titleLabel;
+@property (nonatomic, assign, readonly) const char *typeEncoding;
+@property (nonatomic, readonly) BOOL showsTitle;
++ (CGFloat)titleBottomPadding;
+
+@end

+ 105 - 0
Classes/Editing/Argument Input Views/FLEXArgumentInputView.m

@@ -0,0 +1,105 @@
+//
+//  FLEXArgumentInputView.m
+//  Flipboard
+//
+//  Created by Ryan Olson on 5/30/14.
+//  Copyright (c) 2014 Flipboard. All rights reserved.
+//
+
+#import "FLEXArgumentInputView.h"
+#import "FLEXUtility.h"
+
+@interface FLEXArgumentInputView ()
+
+@property (nonatomic, strong) UILabel *titleLabel;
+@property (nonatomic, assign) const char *typeEncoding;
+
+@end
+
+@implementation FLEXArgumentInputView
+
+- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding
+{
+    self = [super initWithFrame:CGRectZero];
+    if (self) {
+        self.typeEncoding = typeEncoding;
+    }
+    return self;
+}
+
+- (void)layoutSubviews
+{
+    [super layoutSubviews];
+    
+    if (self.showsTitle) {
+        CGSize constrainSize = CGSizeMake(self.bounds.size.width, CGFLOAT_MAX);
+        CGSize labelSize = [self.titleLabel sizeThatFits:constrainSize];
+        self.titleLabel.frame = CGRectMake(0, 0, labelSize.width, labelSize.height);
+    }
+}
+
+- (void)setTitle:(NSString *)title
+{
+    if (![_title isEqual:title]) {
+        _title = title;
+        self.titleLabel.text = title;
+        [self setNeedsLayout];
+    }
+}
+
+- (UILabel *)titleLabel
+{
+    if (!_titleLabel) {
+        _titleLabel = [[UILabel alloc] init];
+        _titleLabel.font = [[self class] titleFont];
+        _titleLabel.backgroundColor = self.backgroundColor;
+        _titleLabel.textColor = [UIColor colorWithWhite:0.3 alpha:1.0];
+        _titleLabel.numberOfLines = 0;
+        [self addSubview:_titleLabel];
+    }
+    return _titleLabel;
+}
+
+- (BOOL)showsTitle
+{
+    return [self.title length] > 0;
+}
+
+
+#pragma mark - Subclasses Can Override
+
+- (BOOL)inputViewIsFirstResponder
+{
+    return NO;
+}
+
+
+#pragma mark - Class Helpers
+
++ (UIFont *)titleFont
+{
+    return [FLEXUtility defaultFontOfSize:12.0];
+}
+
++ (CGFloat)titleBottomPadding
+{
+    return 4.0;
+}
+
+
+#pragma mark - Sizing
+
+- (CGSize)sizeThatFits:(CGSize)size
+{
+    CGFloat height = 0;
+    
+    if ([self.title length] > 0) {
+        CGSize constrainSize = CGSizeMake(size.width, CGFLOAT_MAX);
+        height += ceil([self.title sizeWithFont:[[self class] titleFont] constrainedToSize:constrainSize].height);
+        height += [[self class] titleBottomPadding];
+    }
+    
+    return CGSizeMake(size.width, height);
+}
+
+@end

+ 17 - 0
Classes/Editing/Argument Input Views/FLEXArgumentInputViewFactory.h

@@ -0,0 +1,17 @@
+//
+//  FLEXArgumentInputViewFactory.h
+//  FLEXInjected
+//
+//  Created by Ryan Olson on 6/15/14.
+//
+//
+
+#import <Foundation/Foundation.h>
+
+@class FLEXArgumentInputView;
+
+@interface FLEXArgumentInputViewFactory : NSObject
+
++ (FLEXArgumentInputView *)argumentInputViewForTypeEncoding:(const char *)typeEncoding;
+
+@end

+ 20 - 0
Classes/Editing/Argument Input Views/FLEXArgumentInputViewFactory.m

@@ -0,0 +1,20 @@
+//
+//  FLEXArgumentInputViewFactory.m
+//  FLEXInjected
+//
+//  Created by Ryan Olson on 6/15/14.
+//
+//
+
+#import "FLEXArgumentInputViewFactory.h"
+#import "FLEXArgumentInputView.h"
+#import "FLEXArgumentInputTextView.h"
+
+@implementation FLEXArgumentInputViewFactory
+
++ (FLEXArgumentInputView *)argumentInputViewForTypeEncoding:(const char *)typeEncoding
+{
+    return [[FLEXArgumentInputTextView alloc] initWithArgumentTypeEncoding:typeEncoding];
+}
+
+@end

+ 0 - 19
Classes/Editing/FLEXArgumentInputView.h

@@ -1,19 +0,0 @@
-//
-//  FLEXArgumentInputView.h
-//  Flipboard
-//
-//  Created by Ryan Olson on 5/30/14.
-//  Copyright (c) 2014 Flipboard. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface FLEXArgumentInputView : UIView
-
-@property (nonatomic, copy) NSString *title;
-@property (nonatomic, copy) NSString *inputText;
-@property (nonatomic, assign) UIKeyboardType keyboardType;
-@property (nonatomic, readonly) BOOL inputViewIsFirstResponder;
-@property (nonatomic, assign) NSUInteger numberOfInputLines;
-
-@end

+ 0 - 145
Classes/Editing/FLEXArgumentInputView.m

@@ -1,145 +0,0 @@
-//
-//  FLEXArgumentInputView.m
-//  Flipboard
-//
-//  Created by Ryan Olson on 5/30/14.
-//  Copyright (c) 2014 Flipboard. All rights reserved.
-//
-
-#import "FLEXArgumentInputView.h"
-#import "FLEXUtility.h"
-
-@interface FLEXArgumentInputView ()
-
-@property (nonatomic, strong) UILabel *titleLabel;
-@property (nonatomic, strong) UITextView *inputTextView;
-
-@end
-
-@implementation FLEXArgumentInputView
-
-- (id)initWithFrame:(CGRect)frame
-{
-    self = [super initWithFrame:frame];
-    if (self) {
-        // Default to two lines in the text view. Users of the class can customize.
-        self.numberOfInputLines = 2;
-        
-        self.inputTextView = [[UITextView alloc] init];
-        self.inputTextView.font = [[self class] inputFont];
-        self.inputTextView.backgroundColor = [UIColor whiteColor];
-        self.inputTextView.layer.borderColor = [[UIColor blackColor] CGColor];
-        self.inputTextView.layer.borderWidth = 1.0;
-        self.inputTextView.autocapitalizationType = UITextAutocapitalizationTypeNone;
-        self.inputTextView.autocorrectionType = UITextAutocorrectionTypeNo;
-        [self addSubview:self.inputTextView];
-    }
-    return self;
-}
-
-- (void)layoutSubviews
-{
-    CGFloat originY = 0;
-    CGFloat contentWidth = self.bounds.size.width;
-    if ([self.title length] > 0) {
-        CGSize constrainSize = CGSizeMake(contentWidth, CGFLOAT_MAX);
-        CGSize labelSize = [self.titleLabel sizeThatFits:constrainSize];
-        self.titleLabel.frame = CGRectMake(0, originY, labelSize.width, labelSize.height);
-        originY = CGRectGetMaxY(self.titleLabel.frame) + [[self class] titleBottomPadding];
-    }
-    
-    self.inputTextView.frame = CGRectMake(0, originY, contentWidth, [self inputTextViewHeight]);
-}
-
-- (void)setTitle:(NSString *)title
-{
-    if (![_title isEqual:title]) {
-        _title = title;
-        self.titleLabel.text = title;
-        [self setNeedsLayout];
-    }
-}
-
-- (UILabel *)titleLabel
-{
-    if (!_titleLabel) {
-        _titleLabel = [[UILabel alloc] init];
-        _titleLabel.font = [[self class] titleFont];
-        _titleLabel.backgroundColor = self.backgroundColor;
-        _titleLabel.textColor = [UIColor colorWithWhite:0.3 alpha:1.0];
-        _titleLabel.numberOfLines = 0;
-        [self addSubview:_titleLabel];
-    }
-    return _titleLabel;
-}
-
-
-#pragma mark - Text View Passthroughs
-
-- (void)setKeyboardType:(UIKeyboardType)keyboardType
-{
-    self.inputTextView.keyboardType = keyboardType;
-}
-
-- (UIKeyboardType)keyboardType
-{
-    return self.inputTextView.keyboardType;
-}
-
-- (void)setInputText:(NSString *)inputText
-{
-    self.inputTextView.text = inputText;
-}
-
-- (NSString *)inputText
-{
-    return self.inputTextView.text;
-}
-
-- (BOOL)inputViewIsFirstResponder
-{
-    return self.inputTextView.isFirstResponder;
-}
-
-
-#pragma mark - Class Helpers
-
-+ (UIFont *)inputFont
-{
-    return [FLEXUtility defaultFontOfSize:14.0];
-}
-
-+ (UIFont *)titleFont
-{
-    return [FLEXUtility defaultFontOfSize:12.0];
-}
-
-+ (CGFloat)titleBottomPadding
-{
-    return 4.0;
-}
-
-
-#pragma mark - Sizing
-
-- (CGFloat)inputTextViewHeight
-{
-    return ceil([[self class] inputFont].lineHeight * self.numberOfInputLines) + 20.0;
-}
-
-- (CGSize)sizeThatFits:(CGSize)size
-{
-    CGFloat height = 0;
-    
-    if ([self.title length] > 0) {
-        CGSize constrainSize = CGSizeMake(size.width, CGFLOAT_MAX);
-        height += ceil([self.title sizeWithFont:[[self class] titleFont] constrainedToSize:constrainSize].height);
-        height += [[self class] titleBottomPadding];
-    }
-    
-    height += [self inputTextViewHeight];
-    
-    return CGSizeMake(size.width, height);
-}
-
-@end

+ 2 - 2
Classes/Editing/FLEXDefaultEditorViewController.m

@@ -48,7 +48,7 @@
 {
     [super actionButtonPressed:sender];
     
-    id value = [FLEXRuntimeUtility objectValueFromEditableString:self.firstInputView.inputText];
+    id value = [FLEXRuntimeUtility objectValueFromEditableString:self.firstInputView.inputOutput];
     if (value) {
         [self.defaults setObject:value forKey:self.key];
     } else {
@@ -61,7 +61,7 @@
 - (void)updateTextFieldString
 {
     id defaultsValue = [self.defaults objectForKey:self.key];
-    self.firstInputView.inputText = [FLEXRuntimeUtility editiableDescriptionForObject:defaultsValue];
+    self.firstInputView.inputOutput = [FLEXRuntimeUtility editiableDescriptionForObject:defaultsValue];
 }
 
 + (BOOL)canEditDefaultWithValue:(id)currentValue

+ 3 - 2
Classes/Editing/FLEXFieldEditorViewController.m

@@ -11,6 +11,7 @@
 #import "FLEXRuntimeUtility.h"
 #import "FLEXUtility.h"
 #import "FLEXArgumentInputView.h"
+#import "FLEXArgumentInputViewFactory.h"
 
 @interface FLEXFieldEditorViewController () <UIScrollViewDelegate>
 
@@ -89,9 +90,9 @@
     [self.scrollView addSubview:self.fieldEditorView];
     
     // One argument input view by default. Subclasses can configure the field editor view with more/different argument input views if needed.
-    FLEXArgumentInputView *inputView = [[FLEXArgumentInputView alloc] init];
+    FLEXArgumentInputView *inputView = [FLEXArgumentInputViewFactory argumentInputViewForTypeEncoding:NULL];
     inputView.backgroundColor = self.view.backgroundColor;
-    inputView.numberOfInputLines = 8;
+    inputView.targetSize = FLEXArgumentInputViewSizeLarge;
     self.fieldEditorView.argumentInputViews = @[inputView];
     
     self.setterButton = [[UIBarButtonItem alloc] initWithTitle:[self titleForActionButton] style:UIBarButtonItemStyleDone target:self action:@selector(actionButtonPressed:)];

+ 4 - 12
Classes/Editing/FLEXIvarEditorViewController.m

@@ -36,33 +36,25 @@
     self.fieldEditorView.fieldDescription = [FLEXRuntimeUtility prettyNameForIvar:self.ivar];
     
     [self updateTextFieldString];
-    
-    // Use the numeric keyboard for primitives and the letter keyboard for strings
-    NSString *typeEncoding = @(ivar_getTypeEncoding(self.ivar));
-    if ([typeEncoding isEqual:[[self class] stringTypeEncoding]]) {
-        self.firstInputView.keyboardType = UIKeyboardTypeAlphabet;
-    } else {
-        self.firstInputView.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
-    }
 }
 
 - (void)actionButtonPressed:(id)sender
 {
     [super actionButtonPressed:sender];
     
-    [self updatePropertyFromString:self.firstInputView.inputText];
+    [self updateIvarFromString:self.firstInputView.inputOutput];
     [self updateTextFieldString];
 }
 
 - (void)updateTextFieldString
 {
     id ivarValue = [FLEXRuntimeUtility valueForIvar:self.ivar onObject:self.target];
-    self.firstInputView.inputText = [FLEXRuntimeUtility editiableDescriptionForObject:ivarValue];
+    self.firstInputView.inputOutput = [FLEXRuntimeUtility editiableDescriptionForObject:ivarValue];
 }
 
-- (void)updatePropertyFromString:(NSString *)string
+- (void)updateIvarFromString:(NSString *)string
 {
-    [FLEXRuntimeUtility setIvar:self.ivar onObject:self.target withInputString:self.firstInputView.inputText];
+    [FLEXRuntimeUtility setIvar:self.ivar onObject:self.target withInputString:self.firstInputView.inputOutput];
 }
 
 + (BOOL)canEditIvar:(Ivar)ivar currentValue:(id)value

+ 4 - 3
Classes/Editing/FLEXMethodCallingViewController.m

@@ -12,6 +12,7 @@
 #import "FLEXObjectExplorerFactory.h"
 #import "FLEXObjectExplorerViewController.h"
 #import "FLEXArgumentInputView.h"
+#import "FLEXArgumentInputViewFactory.h"
 
 @interface FLEXMethodCallingViewController ()
 
@@ -41,7 +42,7 @@
     NSMutableArray *argumentInputViews = [NSMutableArray array];
     unsigned int argumentIndex = kFLEXNumberOfImplicitArgs;
     for (NSString *methodComponent in methodComponents) {
-        FLEXArgumentInputView *inputView = [[FLEXArgumentInputView alloc] init];
+        FLEXArgumentInputView *inputView = [FLEXArgumentInputViewFactory argumentInputViewForTypeEncoding:NULL];
         inputView.backgroundColor = self.view.backgroundColor;
         inputView.title = methodComponent;
         
@@ -50,7 +51,7 @@
         char *argumentTypeEncoding = method_copyArgumentType(self.method, argumentIndex);
         NSValue *defaultValue = [[self class] defaultValueForEncoding:argumentTypeEncoding];
         if (defaultValue) {
-            inputView.inputText = [FLEXRuntimeUtility editiableDescriptionForObject:defaultValue];
+            inputView.inputOutput = [FLEXRuntimeUtility editiableDescriptionForObject:defaultValue];
         }
         free(argumentTypeEncoding);
         
@@ -76,7 +77,7 @@
     
     NSMutableArray *arguments = [NSMutableArray array];
     for (FLEXArgumentInputView *inputView in self.fieldEditorView.argumentInputViews) {
-        NSString *argumentString = inputView.inputText;
+        NSString *argumentString = inputView.inputOutput;
         if (!argumentString) {
             // Use empty string as a placeholder in the array. It will be interpreted as nil.
             argumentString = @"";

+ 5 - 13
Classes/Editing/FLEXPropertyEditorViewController.m

@@ -37,29 +37,21 @@
     id currentValue = [FLEXRuntimeUtility valueForProperty:self.property onObject:self.target];
     self.setterButton.enabled = [[self class] canEditProperty:self.property currentValue:currentValue];
     
-    [self updateTextFieldString];
-    
-    // Use the numeric keyboard for primitives and the letter keyboard for strings
-    NSString *typeEncoding = [FLEXRuntimeUtility typeEncodingForProperty:self.property];
-    if ([typeEncoding isEqual:[[self class] stringTypeEncoding]]) {
-        self.firstInputView.keyboardType = UIKeyboardTypeAlphabet;
-    } else {
-        self.firstInputView.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
-    }
+    [self updateArgumentInputView];
 }
 
 - (void)actionButtonPressed:(id)sender
 {
     [super actionButtonPressed:sender];
     
-    [self updatePropertyFromString:self.firstInputView.inputText];
-    [self updateTextFieldString];
+    [self updatePropertyFromString:self.firstInputView.inputOutput];
+    [self updateArgumentInputView];
 }
 
-- (void)updateTextFieldString
+- (void)updateArgumentInputView
 {
     id propertyValue = [FLEXRuntimeUtility valueForProperty:self.property onObject:self.target];
-    self.firstInputView.inputText = [FLEXRuntimeUtility editiableDescriptionForObject:propertyValue];
+    self.firstInputView.inputOutput = [FLEXRuntimeUtility editiableDescriptionForObject:propertyValue];
 }
 
 - (void)updatePropertyFromString:(NSString *)string