RCTRedBoxExtraDataViewController.m 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #import "RCTRedBoxExtraDataViewController.h"
  8. @interface RCTRedBoxExtraDataCell : UITableViewCell
  9. @property (nonatomic, strong) UILabel *keyLabel;
  10. @property (nonatomic, strong) UILabel *valueLabel;
  11. @end
  12. @implementation RCTRedBoxExtraDataCell
  13. - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
  14. {
  15. if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
  16. self.backgroundColor = [UIColor colorWithRed:0.8 green:0 blue:0 alpha:1];
  17. UILayoutGuide *contentLayout = self.contentView.layoutMarginsGuide;
  18. self.keyLabel = [UILabel new];
  19. [self.contentView addSubview:self.keyLabel];
  20. self.keyLabel.translatesAutoresizingMaskIntoConstraints = NO;
  21. [self.keyLabel.leadingAnchor constraintEqualToAnchor:contentLayout.leadingAnchor].active = YES;
  22. [self.keyLabel.topAnchor constraintEqualToAnchor:contentLayout.topAnchor].active = YES;
  23. [self.keyLabel.bottomAnchor constraintEqualToAnchor:contentLayout.bottomAnchor].active = YES;
  24. [self.keyLabel.widthAnchor constraintEqualToAnchor:contentLayout.widthAnchor multiplier:0.3].active = YES;
  25. self.keyLabel.textColor = [UIColor whiteColor];
  26. self.keyLabel.numberOfLines = 0;
  27. #if !TARGET_OS_TV
  28. self.keyLabel.lineBreakMode = NSLineBreakByWordWrapping;
  29. self.keyLabel.font = [UIFont fontWithName:@"Menlo-Regular" size:12.0f];
  30. #endif
  31. self.valueLabel = [UILabel new];
  32. [self.contentView addSubview:self.valueLabel];
  33. self.valueLabel.translatesAutoresizingMaskIntoConstraints = NO;
  34. [self.valueLabel.leadingAnchor constraintEqualToAnchor:self.keyLabel.trailingAnchor constant:10.f].active = YES;
  35. [self.valueLabel.trailingAnchor constraintEqualToAnchor:contentLayout.trailingAnchor].active = YES;
  36. [self.valueLabel.topAnchor constraintEqualToAnchor:contentLayout.topAnchor].active = YES;
  37. [self.valueLabel.bottomAnchor constraintEqualToAnchor:contentLayout.bottomAnchor].active = YES;
  38. self.valueLabel.textColor = [UIColor whiteColor];
  39. self.valueLabel.numberOfLines = 0;
  40. #if !TARGET_OS_TV
  41. self.valueLabel.lineBreakMode = NSLineBreakByWordWrapping;
  42. self.valueLabel.font = [UIFont fontWithName:@"Menlo-Regular" size:12.0f];
  43. #endif
  44. }
  45. return self;
  46. }
  47. @end
  48. @interface RCTRedBoxExtraDataViewController ()
  49. @end
  50. @implementation RCTRedBoxExtraDataViewController {
  51. UITableView *_tableView;
  52. NSMutableArray *_extraDataTitle;
  53. NSMutableArray *_extraData;
  54. }
  55. @synthesize actionDelegate = _actionDelegate;
  56. - (instancetype)init
  57. {
  58. if (self = [super init]) {
  59. _extraData = [NSMutableArray new];
  60. _extraDataTitle = [NSMutableArray new];
  61. self.view.backgroundColor = [UIColor colorWithRed:0.8 green:0 blue:0 alpha:1];
  62. _tableView = [UITableView new];
  63. _tableView.delegate = self;
  64. _tableView.dataSource = self;
  65. _tableView.backgroundColor = [UIColor clearColor];
  66. _tableView.estimatedRowHeight = 200;
  67. #if !TARGET_OS_TV
  68. _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
  69. #endif
  70. _tableView.rowHeight = UITableViewAutomaticDimension;
  71. _tableView.allowsSelection = NO;
  72. #if TARGET_OS_SIMULATOR || TARGET_OS_MACCATALYST
  73. NSString *reloadText = @"Reload JS (\u2318R)";
  74. NSString *dismissText = @"Dismiss (ESC)";
  75. #else
  76. NSString *reloadText = @"Reload JS";
  77. NSString *dismissText = @"Dismiss";
  78. #endif
  79. UIButton *dismissButton = [UIButton buttonWithType:UIButtonTypeCustom];
  80. dismissButton.translatesAutoresizingMaskIntoConstraints = NO;
  81. dismissButton.accessibilityIdentifier = @"redbox-extra-data-dismiss";
  82. dismissButton.titleLabel.font = [UIFont systemFontOfSize:13];
  83. [dismissButton setTitle:dismissText forState:UIControlStateNormal];
  84. [dismissButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateNormal];
  85. [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
  86. [dismissButton addTarget:self action:@selector(dismiss) forControlEvents:UIControlEventTouchUpInside];
  87. UIButton *reloadButton = [UIButton buttonWithType:UIButtonTypeCustom];
  88. reloadButton.accessibilityIdentifier = @"redbox-reload";
  89. reloadButton.titleLabel.font = [UIFont systemFontOfSize:13];
  90. [reloadButton setTitle:reloadText forState:UIControlStateNormal];
  91. [reloadButton setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateNormal];
  92. [reloadButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
  93. [reloadButton addTarget:self action:@selector(reload) forControlEvents:UIControlEventTouchUpInside];
  94. UIStackView *buttonStackView = [UIStackView new];
  95. buttonStackView.axis = UILayoutConstraintAxisHorizontal;
  96. buttonStackView.distribution = UIStackViewDistributionEqualSpacing;
  97. buttonStackView.alignment = UIStackViewAlignmentFill;
  98. buttonStackView.spacing = 20;
  99. [buttonStackView addArrangedSubview:dismissButton];
  100. [buttonStackView addArrangedSubview:reloadButton];
  101. buttonStackView.translatesAutoresizingMaskIntoConstraints = NO;
  102. UIStackView *mainStackView = [UIStackView new];
  103. mainStackView.axis = UILayoutConstraintAxisVertical;
  104. mainStackView.backgroundColor = [UIColor colorWithRed:0.8 green:0 blue:0 alpha:1];
  105. [mainStackView addArrangedSubview:_tableView];
  106. [mainStackView addArrangedSubview:buttonStackView];
  107. mainStackView.translatesAutoresizingMaskIntoConstraints = NO;
  108. [self.view addSubview:mainStackView];
  109. CGFloat tableHeight = self.view.bounds.size.height - 60.f;
  110. [_tableView.heightAnchor constraintEqualToConstant:tableHeight].active = YES;
  111. [_tableView.widthAnchor constraintEqualToAnchor:self.view.widthAnchor].active = YES;
  112. CGFloat buttonWidth = self.view.bounds.size.width / 4;
  113. [dismissButton.heightAnchor constraintEqualToConstant:60].active = YES;
  114. [dismissButton.widthAnchor constraintEqualToConstant:buttonWidth].active = YES;
  115. [reloadButton.heightAnchor constraintEqualToConstant:60].active = YES;
  116. [reloadButton.widthAnchor constraintEqualToConstant:buttonWidth].active = YES;
  117. }
  118. return self;
  119. }
  120. - (void)viewDidAppear:(BOOL)animated
  121. {
  122. [super viewDidAppear:animated];
  123. [_tableView reloadData];
  124. }
  125. - (NSInteger)tableView:(__unused UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  126. {
  127. return [[_extraData objectAtIndex:section] count];
  128. }
  129. - (CGFloat)tableView:(__unused UITableView *)tableView heightForHeaderInSection:(__unused NSInteger)section
  130. {
  131. return 40;
  132. }
  133. - (UIView *)tableView:(__unused UITableView *)tableView viewForHeaderInSection:(NSInteger)section
  134. {
  135. UIView *view = [UIView new];
  136. view.backgroundColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
  137. UILabel *header = [UILabel new];
  138. [view addSubview:header];
  139. header.translatesAutoresizingMaskIntoConstraints = NO;
  140. [header.leadingAnchor constraintEqualToAnchor:view.leadingAnchor constant:5].active = YES;
  141. [header.trailingAnchor constraintEqualToAnchor:view.trailingAnchor].active = YES;
  142. [header.topAnchor constraintEqualToAnchor:view.topAnchor].active = YES;
  143. [header.bottomAnchor constraintEqualToAnchor:view.bottomAnchor].active = YES;
  144. header.textColor = [UIColor whiteColor];
  145. header.font = [UIFont fontWithName:@"Menlo-Bold" size:14.0f];
  146. header.text = [_extraDataTitle[section] uppercaseString];
  147. return view;
  148. }
  149. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  150. {
  151. static NSString *reuseIdentifier = @"RedBoxExtraData";
  152. RCTRedBoxExtraDataCell *cell =
  153. (RCTRedBoxExtraDataCell *)[tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
  154. if (cell == nil) {
  155. cell = [[RCTRedBoxExtraDataCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
  156. }
  157. NSArray *dataKVPair = _extraData[indexPath.section][indexPath.row];
  158. cell.keyLabel.text = dataKVPair[0];
  159. cell.valueLabel.text = dataKVPair[1];
  160. return cell;
  161. }
  162. - (NSInteger)numberOfSectionsInTableView:(__unused UITableView *)tableView
  163. {
  164. return _extraDataTitle.count;
  165. }
  166. - (void)addExtraData:(NSDictionary *)data forIdentifier:(NSString *)identifier
  167. {
  168. dispatch_async(dispatch_get_main_queue(), ^{
  169. NSMutableArray *newData = [NSMutableArray new];
  170. for (id key in data) {
  171. [newData addObject:@[
  172. [NSString stringWithFormat:@"%@", key],
  173. [NSString stringWithFormat:@"%@", [data objectForKey:key]]
  174. ]];
  175. }
  176. NSInteger idx = [self->_extraDataTitle indexOfObject:identifier];
  177. if (idx == NSNotFound) {
  178. [self->_extraDataTitle addObject:identifier];
  179. [self->_extraData addObject:newData];
  180. } else {
  181. [self->_extraData replaceObjectAtIndex:idx withObject:newData];
  182. }
  183. [self->_tableView reloadData];
  184. });
  185. }
  186. - (void)dismiss
  187. {
  188. [self dismissViewControllerAnimated:YES completion:nil];
  189. }
  190. - (void)reload
  191. {
  192. [_actionDelegate reload];
  193. }
  194. #pragma mark - Key commands
  195. - (NSArray<UIKeyCommand *> *)keyCommands
  196. {
  197. return @[
  198. // Dismiss
  199. [UIKeyCommand keyCommandWithInput:UIKeyInputEscape modifierFlags:0 action:@selector(dismiss)],
  200. // Reload
  201. [UIKeyCommand keyCommandWithInput:@"r" modifierFlags:UIKeyModifierCommand action:@selector(reload)]
  202. ];
  203. }
  204. @end