DBCustomVariablesTableViewController.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. // The MIT License
  2. //
  3. // Copyright (c) 2016 Dariusz Bukowski
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. #import "DBCustomVariablesTableViewController.h"
  23. #import "UILabel+DBDebugToolkit.h"
  24. #import "NSBundle+DBDebugToolkit.h"
  25. #import "DBMenuSwitchTableViewCell.h"
  26. #import "DBTextViewTableViewCell.h"
  27. typedef NS_ENUM(NSUInteger, DBCustomVariablesTableViewControllerSection) {
  28. DBCustomVariablesTableViewControllerSectionStringVariables,
  29. DBCustomVariablesTableViewControllerSectionIntVariables,
  30. DBCustomVariablesTableViewControllerSectionDoubleVariables,
  31. DBCustomVariablesTableViewControllerSectionBoolVariables
  32. };
  33. static NSString *const DBCustomVariablesTableViewControllerSwitchCellIdentifier = @"DBMenuSwitchTableViewCell";
  34. static NSString *const DBCustomVariablesTableViewControllerTextViewCellIdentifier = @"DBTextViewTableViewCell";
  35. static NSString *const DBCustomVariablesTableViewControllerIntegerRegex = @"-?[0-9]*";
  36. static NSString *const DBCustomVariablesTableViewControllerDoubleRegex = @"-?[0-9]*([0-9]\\.)?[0-9]*";
  37. @interface DBCustomVariablesTableViewController () <DBMenuSwitchTableViewCellDelegate, DBTextViewTableViewCellDelegate>
  38. @property (nonatomic, strong) NSArray <DBCustomVariable *> *stringVariables;
  39. @property (nonatomic, strong) NSArray <DBCustomVariable *> *boolVariables;
  40. @property (nonatomic, strong) NSArray <DBCustomVariable *> *intVariables;
  41. @property (nonatomic, strong) NSArray <DBCustomVariable *> *doubleVariables;
  42. @property (nonatomic, strong) UILabel *backgroundLabel;
  43. @end
  44. @implementation DBCustomVariablesTableViewController
  45. - (void)viewDidLoad {
  46. [super viewDidLoad];
  47. NSBundle *bundle = [NSBundle debugToolkitBundle];
  48. [self.tableView registerNib:[UINib nibWithNibName:@"DBMenuSwitchTableViewCell" bundle:bundle]
  49. forCellReuseIdentifier:DBCustomVariablesTableViewControllerSwitchCellIdentifier];
  50. [self.tableView registerNib:[UINib nibWithNibName:@"DBTextViewTableViewCell" bundle:bundle]
  51. forCellReuseIdentifier:DBCustomVariablesTableViewControllerTextViewCellIdentifier];
  52. self.tableView.rowHeight = UITableViewAutomaticDimension;
  53. self.tableView.estimatedRowHeight = 44.0;
  54. [self setupBackgroundLabel];
  55. }
  56. #pragma mark - Background label
  57. - (void)setupBackgroundLabel {
  58. self.backgroundLabel = [UILabel tableViewBackgroundLabel];
  59. self.tableView.backgroundView = self.backgroundLabel;
  60. [self refreshBackgroundLabel];
  61. }
  62. - (void)refreshBackgroundLabel {
  63. NSInteger presentedVariablesCount = self.stringVariables.count + self.boolVariables.count + self.intVariables.count + self.doubleVariables.count;
  64. self.backgroundLabel.text = presentedVariablesCount == 0 ? @"There are no custom variables." : @"";
  65. }
  66. #pragma mark - Custom variables
  67. - (void)setCustomVariables:(NSArray<DBCustomVariable *> *)customVariables {
  68. self.stringVariables = [self customVariablesWithType:DBCustomVariableTypeString fromArray:customVariables];
  69. self.boolVariables = [self customVariablesWithType:DBCustomVariableTypeBool fromArray:customVariables];
  70. self.intVariables = [self customVariablesWithType:DBCustomVariableTypeInt fromArray:customVariables];
  71. self.doubleVariables = [self customVariablesWithType:DBCustomVariableTypeDouble fromArray:customVariables];
  72. [self refreshBackgroundLabel];
  73. }
  74. - (NSArray <DBCustomVariable *> *)customVariablesWithType:(DBCustomVariableType)type fromArray:(NSArray<DBCustomVariable *> *)customVariables {
  75. NSPredicate *predicate = [NSPredicate predicateWithFormat:@"type = %d", type];
  76. return [customVariables filteredArrayUsingPredicate:predicate];
  77. }
  78. - (DBCustomVariable *)customVariableWithIndexPath:(NSIndexPath *)indexPath {
  79. DBCustomVariablesTableViewControllerSection section = (DBCustomVariablesTableViewControllerSection)indexPath.section;
  80. switch (section) {
  81. case DBCustomVariablesTableViewControllerSectionStringVariables:
  82. return self.stringVariables[indexPath.row];
  83. case DBCustomVariablesTableViewControllerSectionDoubleVariables:
  84. return self.doubleVariables[indexPath.row];
  85. case DBCustomVariablesTableViewControllerSectionIntVariables:
  86. return self.intVariables[indexPath.row];
  87. case DBCustomVariablesTableViewControllerSectionBoolVariables:
  88. return self.boolVariables[indexPath.row];
  89. default:
  90. return nil;
  91. }
  92. }
  93. #pragma mark - UITableViewDelegate
  94. - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
  95. return [self heightForFooterAndHeaderInSection:section];
  96. }
  97. - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
  98. return [self heightForFooterAndHeaderInSection:section];
  99. }
  100. #pragma mark - UITableViewDataSource
  101. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
  102. return 4;
  103. }
  104. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  105. switch (section) {
  106. case DBCustomVariablesTableViewControllerSectionStringVariables:
  107. return self.stringVariables.count;
  108. case DBCustomVariablesTableViewControllerSectionIntVariables:
  109. return self.intVariables.count;
  110. case DBCustomVariablesTableViewControllerSectionDoubleVariables:
  111. return self.doubleVariables.count;
  112. case DBCustomVariablesTableViewControllerSectionBoolVariables:
  113. return self.boolVariables.count;
  114. default:
  115. return 0;
  116. }
  117. }
  118. - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
  119. if ([self tableView:tableView numberOfRowsInSection:section] == 0) {
  120. return nil;
  121. }
  122. switch (section) {
  123. case DBCustomVariablesTableViewControllerSectionStringVariables:
  124. return @"Strings";
  125. case DBCustomVariablesTableViewControllerSectionIntVariables:
  126. return @"Integers";
  127. case DBCustomVariablesTableViewControllerSectionDoubleVariables:
  128. return @"Doubles";
  129. case DBCustomVariablesTableViewControllerSectionBoolVariables:
  130. return @"Booleans";
  131. default:
  132. return nil;
  133. }
  134. }
  135. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  136. DBCustomVariablesTableViewControllerSection section = (DBCustomVariablesTableViewControllerSection)indexPath.section;
  137. switch (section) {
  138. case DBCustomVariablesTableViewControllerSectionStringVariables:
  139. case DBCustomVariablesTableViewControllerSectionIntVariables:
  140. case DBCustomVariablesTableViewControllerSectionDoubleVariables:
  141. return [self textViewCellWithIndexPath:indexPath];
  142. case DBCustomVariablesTableViewControllerSectionBoolVariables:
  143. return [self boolVariableCellWithRow:indexPath.row];
  144. default:
  145. return nil;
  146. }
  147. }
  148. #pragma mark - DBTextViewTableViewCellDelegate
  149. - (void)textViewTableViewCellDidChangeText:(DBTextViewTableViewCell *)textViewCell {
  150. NSIndexPath *cellIndexPath = [self.tableView indexPathForCell:textViewCell];
  151. CGPoint currentContentOffset = self.tableView.contentOffset;
  152. [UIView setAnimationsEnabled:NO];
  153. [self.tableView beginUpdates];
  154. [self.tableView endUpdates];
  155. [UIView setAnimationsEnabled:YES];
  156. [self.tableView setContentOffset:currentContentOffset animated:NO];
  157. DBCustomVariable *customVariable = [self customVariableWithIndexPath:cellIndexPath];
  158. [self updateCustomVariable:customVariable withValueFromText:textViewCell.textView.text];
  159. }
  160. - (BOOL)textViewTableViewCell:(DBTextViewTableViewCell *)textViewCell shouldChangeTextTo:(NSString *)text {
  161. NSIndexPath *cellIndexPath = [self.tableView indexPathForCell:textViewCell];
  162. DBCustomVariablesTableViewControllerSection section = (DBCustomVariablesTableViewControllerSection)cellIndexPath.section;
  163. switch (section) {
  164. case DBCustomVariablesTableViewControllerSectionIntVariables:
  165. return [self isTextInt:text];
  166. case DBCustomVariablesTableViewControllerSectionDoubleVariables:
  167. return [self isTextDouble:text];
  168. default:
  169. return YES;
  170. }
  171. }
  172. #pragma mark - DBMenuSwitchTableViewCell
  173. - (void)menuSwitchTableViewCell:(DBMenuSwitchTableViewCell *)menuSwitchTableViewCell didSetOn:(BOOL)isOn {
  174. NSIndexPath *indexPath = [self.tableView indexPathForCell:menuSwitchTableViewCell];
  175. DBCustomVariable *variable = self.boolVariables[indexPath.row];
  176. variable.value = @(isOn);
  177. }
  178. #pragma mark - Private methods
  179. #pragma mark - - Section heights
  180. - (CGFloat)heightForFooterAndHeaderInSection:(NSInteger)section {
  181. return [self tableView:self.tableView numberOfRowsInSection:section] > 0 ? UITableViewAutomaticDimension : CGFLOAT_MIN;
  182. }
  183. #pragma mark - - Parsing values
  184. - (void)updateCustomVariable:(DBCustomVariable *)variable withValueFromText:(NSString *)text {
  185. switch (variable.type) {
  186. case DBCustomVariableTypeString:
  187. variable.value = text;
  188. break;
  189. case DBCustomVariableTypeInt:
  190. if (text.length > 0) {
  191. variable.value = [self integerFromText:text];
  192. }
  193. break;
  194. case DBCustomVariableTypeDouble:
  195. if (text.length > 0) {
  196. variable.value = [self doubleFromText:text];
  197. }
  198. break;
  199. default:
  200. return;
  201. }
  202. }
  203. - (BOOL)isTextDouble:(NSString *)text {
  204. return [self isText:text matchingRegex:DBCustomVariablesTableViewControllerDoubleRegex];
  205. }
  206. - (BOOL)isTextInt:(NSString *)text {
  207. return [self isText:text matchingRegex:DBCustomVariablesTableViewControllerIntegerRegex];
  208. }
  209. - (BOOL)isText:(NSString *)text matchingRegex:(NSString *)regex {
  210. NSPredicate *regexPredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
  211. return [regexPredicate evaluateWithObject:text];
  212. }
  213. - (NSNumber *)integerFromText:(NSString *)text {
  214. NSInteger integerValue = [text integerValue];
  215. return [NSNumber numberWithInteger:integerValue];
  216. }
  217. - (NSNumber *)doubleFromText:(NSString *)text {
  218. CGFloat doubleValue = [text doubleValue];
  219. return [NSNumber numberWithDouble:doubleValue];
  220. }
  221. #pragma mark - - Cells
  222. - (DBTextViewTableViewCell *)textViewCellWithIndexPath:(NSIndexPath *)indexPath {
  223. DBTextViewTableViewCell *cell = (DBTextViewTableViewCell *)[self.tableView dequeueReusableCellWithIdentifier:DBCustomVariablesTableViewControllerTextViewCellIdentifier];
  224. DBCustomVariable *variable = [self customVariableWithIndexPath:indexPath];
  225. cell.titleLabel.text = variable.name;
  226. cell.textView.text = [NSString stringWithFormat:@"%@", variable.value];
  227. cell.textView.keyboardType = indexPath.section == DBCustomVariablesTableViewControllerSectionStringVariables ? UIKeyboardTypeDefault : UIKeyboardTypeNumbersAndPunctuation;
  228. cell.delegate = self;
  229. return cell;
  230. }
  231. - (DBMenuSwitchTableViewCell *)boolVariableCellWithRow:(NSInteger)row {
  232. DBMenuSwitchTableViewCell *switchCell = (DBMenuSwitchTableViewCell *)[self.tableView dequeueReusableCellWithIdentifier:DBCustomVariablesTableViewControllerSwitchCellIdentifier];
  233. DBCustomVariable *variable = self.boolVariables[row];
  234. switchCell.titleLabel.text = variable.name;
  235. switchCell.valueSwitch.on = [variable.value boolValue];
  236. switchCell.delegate = self;
  237. return switchCell;
  238. }
  239. @end