FLEXPropertyEditorViewController.m 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. //
  2. // FLEXPropertyEditorViewController.m
  3. // Flipboard
  4. //
  5. // Created by Ryan Olson on 5/20/14.
  6. // Copyright (c) 2014 Flipboard. All rights reserved.
  7. //
  8. #import "FLEXPropertyEditorViewController.h"
  9. #import "FLEXRuntimeUtility.h"
  10. #import "FLEXFieldEditorView.h"
  11. #import "FLEXArgumentInputView.h"
  12. #import "FLEXArgumentInputViewFactory.h"
  13. #import "FLEXArgumentInputSwitchView.h"
  14. #import "FLEXUtility.h"
  15. @interface FLEXPropertyEditorViewController () <FLEXArgumentInputViewDelegate>
  16. @property (nonatomic) objc_property_t property;
  17. @end
  18. @implementation FLEXPropertyEditorViewController
  19. - (id)initWithTarget:(id)target property:(objc_property_t)property
  20. {
  21. self = [super initWithTarget:target];
  22. if (self) {
  23. self.property = property;
  24. self.title = @"Property";
  25. }
  26. return self;
  27. }
  28. - (void)viewDidLoad
  29. {
  30. [super viewDidLoad];
  31. self.fieldEditorView.fieldDescription = [FLEXRuntimeUtility fullDescriptionForProperty:self.property];
  32. id currentValue = [FLEXRuntimeUtility valueForProperty:self.property onObject:self.target];
  33. self.setterButton.enabled = [[self class] canEditProperty:self.property onObject:self.target currentValue:currentValue];
  34. const char *typeEncoding = [FLEXRuntimeUtility typeEncodingForProperty:self.property].UTF8String;
  35. FLEXArgumentInputView *inputView = [FLEXArgumentInputViewFactory argumentInputViewForTypeEncoding:typeEncoding];
  36. inputView.backgroundColor = self.view.backgroundColor;
  37. inputView.inputValue = [FLEXRuntimeUtility valueForProperty:self.property onObject:self.target];
  38. inputView.delegate = self;
  39. self.fieldEditorView.argumentInputViews = @[inputView];
  40. // Don't show a "set" button for switches - just call the setter immediately after the switch toggles.
  41. if ([inputView isKindOfClass:[FLEXArgumentInputSwitchView class]]) {
  42. self.navigationItem.rightBarButtonItem = nil;
  43. }
  44. }
  45. - (void)actionButtonPressed:(id)sender
  46. {
  47. [super actionButtonPressed:sender];
  48. id userInputObject = self.firstInputView.inputValue;
  49. NSArray *arguments = userInputObject ? @[userInputObject] : nil;
  50. SEL setterSelector = [FLEXRuntimeUtility setterSelectorForProperty:self.property];
  51. NSError *error = nil;
  52. [FLEXRuntimeUtility performSelector:setterSelector onObject:self.target withArguments:arguments error:&error];
  53. if (error) {
  54. [FLEXAlert showAlert:@"Property Setter Failed" message:[error localizedDescription] from:self];
  55. self.firstInputView.inputValue = [FLEXRuntimeUtility valueForProperty:self.property onObject:self.target];
  56. } else {
  57. // If the setter was called without error, pop the view controller to indicate that and make the user's life easier.
  58. // Don't do this for simulated taps on the action button (i.e. from switch/BOOL editors). The experience is weird there.
  59. if (sender) {
  60. [self.navigationController popViewControllerAnimated:YES];
  61. }
  62. }
  63. }
  64. - (void)getterButtonPressed:(id)sender
  65. {
  66. [super getterButtonPressed:sender];
  67. id returnedObject = [FLEXRuntimeUtility valueForProperty:self.property onObject:self.target];
  68. [self exploreObjectOrPopViewController:returnedObject];
  69. }
  70. - (void)argumentInputViewValueDidChange:(FLEXArgumentInputView *)argumentInputView
  71. {
  72. if ([argumentInputView isKindOfClass:[FLEXArgumentInputSwitchView class]]) {
  73. [self actionButtonPressed:nil];
  74. }
  75. }
  76. + (BOOL)canEditProperty:(objc_property_t)property onObject:(id)object currentValue:(id)value
  77. {
  78. const char *typeEncoding = [FLEXRuntimeUtility typeEncodingForProperty:property].UTF8String;
  79. BOOL canEditType = [FLEXArgumentInputViewFactory canEditFieldWithTypeEncoding:typeEncoding currentValue:value];
  80. SEL setterSelector = [FLEXRuntimeUtility setterSelectorForProperty:property];
  81. BOOL isReadonly = [FLEXRuntimeUtility isReadonlyProperty:property] && (!setterSelector || ![object respondsToSelector:setterSelector]);
  82. return canEditType && !isReadonly;
  83. }
  84. @end