// // FLEXNetworkSettingsController.m // FLEXInjected // // Created by Ryan Olson on 2/20/15. // #import "FLEXNetworkSettingsController.h" #import "FLEXNetworkObserver.h" #import "FLEXNetworkRecorder.h" #import "FLEXUtility.h" #import "FLEXTableView.h" #import "FLEXColor.h" #import "NSUserDefaults+FLEX.h" #import "fakes.h" #if !TARGET_OS_TV @interface FLEXNetworkSettingsController () #else @interface FLEXNetworkSettingsController () #endif @property (nonatomic) float cacheLimitValue; @property (nonatomic, readonly) NSString *cacheLimitCellTitle; #if !TARGET_OS_TV @property (nonatomic, readonly) UISwitch *observerSwitch; @property (nonatomic, readonly) UISwitch *cacheMediaSwitch; @property (nonatomic, readonly) UISwitch *jsonViewerSwitch; @property (nonatomic, readonly) UISlider *cacheLimitSlider; #else @property (nonatomic, readonly) UIFakeSwitch *observerSwitch; @property (nonatomic, readonly) UIFakeSwitch *cacheMediaSwitch; @property (nonatomic, readonly) UIFakeSwitch *jsonViewerSwitch; @property (nonatomic, readonly) KBSlider *cacheLimitSlider; #endif @property (nonatomic) UILabel *cacheLimitLabel; @property (nonatomic) NSMutableArray *hostBlacklist; @end @implementation FLEXNetworkSettingsController - (void)viewDidLoad { [super viewDidLoad]; [self disableToolbar]; self.hostBlacklist = FLEXNetworkRecorder.defaultRecorder.hostBlacklist.mutableCopy; NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults; #if !TARGET_OS_TV _observerSwitch = [UISwitch new]; _cacheMediaSwitch = [UISwitch new]; _jsonViewerSwitch = [UISwitch new]; _cacheLimitSlider = [UISlider new]; #else _observerSwitch = [UIFakeSwitch newSwitch]; _cacheMediaSwitch = [UIFakeSwitch newSwitch]; _jsonViewerSwitch = [UIFakeSwitch newSwitch]; _cacheLimitSlider = [[KBSlider alloc] initWithFrame:CGRectMake(0, 0, 400, 53)]; #endif self.observerSwitch.on = FLEXNetworkObserver.enabled; [self.observerSwitch addTarget:self action:@selector(networkDebuggingToggled:) forControlEvents:UIControlEventValueChanged ]; self.cacheMediaSwitch.on = FLEXNetworkRecorder.defaultRecorder.shouldCacheMediaResponses; [self.cacheMediaSwitch addTarget:self action:@selector(cacheMediaResponsesToggled:) forControlEvents:UIControlEventValueChanged ]; self.jsonViewerSwitch.on = defaults.flex_registerDictionaryJSONViewerOnLaunch; [self.jsonViewerSwitch addTarget:self action:@selector(jsonViewerSettingToggled:) forControlEvents:UIControlEventValueChanged ]; [self.cacheLimitSlider addTarget:self action:@selector(cacheLimitAdjusted:) forControlEvents:UIControlEventValueChanged ]; KBSlider *slider = self.cacheLimitSlider; self.cacheLimitValue = FLEXNetworkRecorder.defaultRecorder.responseCacheByteLimit; const NSUInteger fiftyMega = 50 * 1024 * 1024; slider.minimumValue = 0; slider.maximumValue = fiftyMega; slider.value = self.cacheLimitValue; } - (void)setCacheLimitValue:(float)cacheLimitValue { _cacheLimitValue = cacheLimitValue; self.cacheLimitLabel.text = self.cacheLimitCellTitle; [FLEXNetworkRecorder.defaultRecorder setResponseCacheByteLimit:cacheLimitValue]; } - (NSString *)cacheLimitCellTitle { NSInteger cacheLimit = self.cacheLimitValue; NSInteger limitInMB = round(cacheLimit / (1024 * 1024)); return [NSString stringWithFormat:@"Cache Limit (%@ MB)", @(limitInMB)]; } #pragma mark - Settings Actions - (void)networkDebuggingToggled:(UIFakeSwitch *)sender { FLEXNetworkObserver.enabled = sender.isOn; } - (void)cacheMediaResponsesToggled:(UIFakeSwitch*)sender { FLEXNetworkRecorder.defaultRecorder.shouldCacheMediaResponses = sender.isOn; } - (void)jsonViewerSettingToggled:(UIFakeSwitch *)sender { [NSUserDefaults.standardUserDefaults flex_toggleBoolForKey:kFLEXDefaultsRegisterJSONExplorerKey]; } - (void)cacheLimitAdjusted:(KBSlider *)sender { self.cacheLimitValue = sender.value; } #pragma mark - Table View Data Source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return self.hostBlacklist.count ? 2 : 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { switch (section) { case 0: return 5; case 1: return self.hostBlacklist.count; default: return 0; } } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { switch (section) { case 0: return @"General"; case 1: return @"Host Blacklist"; default: return nil; } } - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { if (section == 0) { return @"By default, JSON is rendered in a webview. Turn on " "\"View JSON as a dictionary/array\" to convert JSON payloads " "to objects and view them in an object explorer. " "This setting requires a restart of the app."; } return nil; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:kFLEXDefaultCell forIndexPath:indexPath ]; cell.accessoryView = nil; cell.textLabel.textColor = FLEXColor.primaryTextColor; switch (indexPath.section) { // Settings case 0: { switch (indexPath.row) { case 0: cell.textLabel.text = @"Network Debugging"; cell.accessoryView = self.observerSwitch; break; case 1: cell.textLabel.text = @"Cache Media Responses"; cell.accessoryView = self.cacheMediaSwitch; break; case 2: cell.textLabel.text = @"View JSON as a dictionary/array"; cell.accessoryView = self.jsonViewerSwitch; break; case 3: cell.textLabel.text = @"Reset Host Blacklist"; cell.textLabel.textColor = tableView.tintColor; break; case 4: cell.textLabel.text = self.cacheLimitCellTitle; self.cacheLimitLabel = cell.textLabel; [self.cacheLimitSlider removeFromSuperview]; [cell.contentView addSubview:self.cacheLimitSlider]; CGRect container = cell.contentView.frame; KBSlider *slider = self.cacheLimitSlider; [slider sizeToFit]; CGFloat sliderWidth = 150.f; CGFloat sliderOriginY = FLEXFloor((container.size.height - slider.frame.size.height) / 2.0); CGFloat sliderOriginX = CGRectGetMaxX(container) - sliderWidth - tableView.separatorInset.left; self.cacheLimitSlider.frame = CGRectMake( sliderOriginX, sliderOriginY, sliderWidth, slider.frame.size.height ); // Make wider, keep in middle of cell, keep to trailing edge of cell self.cacheLimitSlider.autoresizingMask = ({ UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin; }); break; } break; } // Blacklist entries case 1: { cell.textLabel.text = self.hostBlacklist[indexPath.row]; break; } default: @throw NSInternalInconsistencyException; break; } return cell; } #pragma mark - Table View Delegate - (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)ip { // Can only select the "Reset Host Blacklist" row return ip.section == 0 && ip.row == 2; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; [FLEXAlert makeAlert:^(FLEXAlert *make) { make.title(@"Reset Host Blacklist"); make.message(@"You cannot undo this action. Are you sure?"); make.button(@"Reset").destructiveStyle().handler(^(NSArray *strings) { self.hostBlacklist = nil; [FLEXNetworkRecorder.defaultRecorder.hostBlacklist removeAllObjects]; [FLEXNetworkRecorder.defaultRecorder synchronizeBlacklist]; [self.tableView deleteSections: [NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationAutomatic]; }); make.button(@"Cancel").cancelStyle(); } showFrom:self]; } - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { return indexPath.section == 1; } - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)style forRowAtIndexPath:(NSIndexPath *)indexPath { NSParameterAssert(style == UITableViewCellEditingStyleDelete); NSString *host = self.hostBlacklist[indexPath.row]; [self.hostBlacklist removeObjectAtIndex:indexPath.row]; [FLEXNetworkRecorder.defaultRecorder.hostBlacklist removeObject:host]; [FLEXNetworkRecorder.defaultRecorder synchronizeBlacklist]; [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; } @end