Oshevnev

IASKAppSettingsViewController.m

Jul 16th, 2012
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //
  2. //  IASKAppSettingsViewController.m
  3. //  http://www.inappsettingskit.com
  4. //
  5. //  Copyright (c) 2009-2010:
  6. //  Luc Vandal, Edovia Inc., http://www.edovia.com
  7. //  Ortwin Gentz, FutureTap GmbH, http://www.futuretap.com
  8. //  All rights reserved.
  9. //
  10. //  It is appreciated but not required that you give credit to Luc Vandal and Ortwin Gentz,
  11. //  as the original authors of this code. You can give credit in a blog post, a tweet or on
  12. //  a info page of your app. Also, the original authors appreciate letting them know if you use this code.
  13. //
  14. //  This code is licensed under the BSD license that is available at: http://www.opensource.org/licenses/bsd-license.php
  15. //
  16.  
  17.  
  18. #import "IASKAppSettingsViewController.h"
  19. #import "IASKSettingsReader.h"
  20. #import "IASKSettingsStoreUserDefaults.h"
  21. #import "IASKPSSliderSpecifierViewCell.h"
  22. #import "IASKPSTextFieldSpecifierViewCell.h"
  23. #import "IASKPSTitleValueSpecifierViewCell.h"
  24. #import "IASKSwitch.h"
  25. #import "IASKSlider.h"
  26. #import "IASKSpecifier.h"
  27. #import "IASKSpecifierValuesViewController.h"
  28. #import "IASKTextField.h"
  29.  
  30. static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3;
  31. static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2;
  32. static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
  33.  
  34. static NSString *kIASKCredits = @"Powered by InAppSettingsKit"; // Leave this as-is!!!
  35.  
  36. #define kIASKSpecifierValuesViewControllerIndex       0
  37. #define kIASKSpecifierChildViewControllerIndex        1
  38.  
  39. #define kIASKCreditsViewWidth                         285
  40.  
  41. CGRect IASKCGRectSwap(CGRect rect);
  42.  
  43. @interface IASKAppSettingsViewController ()
  44. @property (nonatomic, retain) NSMutableArray *viewList;
  45. @property (nonatomic, retain) id currentFirstResponder;
  46.  
  47. - (void)_textChanged:(id)sender;
  48. - (void)synchronizeSettings;
  49. - (void)userDefaultsDidChange;
  50. - (void)reload;
  51. @end
  52.  
  53. @implementation IASKAppSettingsViewController
  54.  
  55. @synthesize delegate = _delegate;
  56. @synthesize viewList = _viewList;
  57. @synthesize settingsReader = _settingsReader;
  58. @synthesize file = _file;
  59. @synthesize currentFirstResponder = _currentFirstResponder;
  60. @synthesize showCreditsFooter = _showCreditsFooter;
  61. @synthesize showDoneButton = _showDoneButton;
  62. @synthesize settingsStore = _settingsStore;
  63. @synthesize hiddenKeys = _hiddenKeys;
  64.  
  65. #pragma mark accessors
  66. - (IASKSettingsReader*)settingsReader {
  67.     if (!_settingsReader) {
  68.         _settingsReader = [[IASKSettingsReader alloc] initWithFile:self.file];
  69.     }
  70.     return _settingsReader;
  71. }
  72.  
  73. - (id<IASKSettingsStore>)settingsStore {
  74.     if (!_settingsStore) {
  75.         _settingsStore = [[IASKSettingsStoreUserDefaults alloc] init];
  76.     }
  77.     return _settingsStore;
  78. }
  79.  
  80. - (NSString*)file {
  81.     if (!_file) {
  82.         return @"Root";
  83.     }
  84.     return [[_file retain] autorelease];
  85. }
  86.  
  87. - (void)setFile:(NSString *)file {
  88.     if (file != _file) {
  89.        
  90.         [_file release];
  91.         _file = [file copy];
  92.     }
  93.    
  94.     self.tableView.contentOffset = CGPointMake(0, 0);
  95.     self.settingsReader = nil; // automatically initializes itself
  96.     [_hiddenKeys release], _hiddenKeys = nil;
  97.     [self.tableView reloadData];
  98. }
  99.  
  100. - (BOOL)isPad {
  101.     BOOL isPad = NO;
  102. #if (__IPHONE_OS_VERSION_MAX_ALLOWED >= 30200)
  103.     isPad = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad;
  104. #endif
  105.     return isPad;
  106. }
  107.  
  108. #pragma mark standard view controller methods
  109. - (id)init {
  110.     return [self initWithStyle:UITableViewStyleGrouped];
  111. }
  112.  
  113. - (id)initWithStyle:(UITableViewStyle)style
  114. {
  115.     if (style != UITableViewStyleGrouped) {
  116.         NSLog(@"only UITableViewStyleGrouped style is supported, forcing it.");
  117.     }
  118.     self = [super initWithStyle:UITableViewStyleGrouped];
  119.     if (self) {
  120.         self.tableView.delegate = self;
  121.         self.tableView.dataSource = self;
  122.         _showDoneButton = YES;
  123.         // If set to YES, will display credits for InAppSettingsKit creators
  124.         _showCreditsFooter = YES;
  125.     }
  126.     return self;
  127. }
  128.  
  129. - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
  130. {
  131.     if (!nibNameOrNil) {
  132.         return [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
  133.     }
  134.     NSLog (@"%@ is now deprecated, we are moving away from nibs.", NSStringFromSelector(_cmd));
  135.     return [self initWithStyle:UITableViewStyleGrouped];
  136. }
  137.  
  138. - (NSMutableArray *)viewList {
  139.     if (!_viewList) {
  140.         _viewList = [[NSMutableArray alloc] init];
  141.         [_viewList addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"IASKSpecifierValuesView", @"ViewName",nil]];
  142.         [_viewList addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"IASKAppSettingsView", @"ViewName",nil]];
  143.     }
  144.     return _viewList;
  145. }
  146.  
  147. - (void) viewDidLoad {
  148.   [super viewDidLoad];
  149.   if ([self isPad]) {
  150.     self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLineEtched;
  151.   }
  152.     UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapToEndEdit:)];  
  153.     tapGesture.cancelsTouchesInView = NO;
  154.     [self.tableView addGestureRecognizer:tapGesture];
  155.     [tapGesture release];
  156. }
  157.  
  158. - (void)viewDidUnload {
  159.   [super viewDidUnload];
  160.  
  161.     // Release any retained subviews of the main view.
  162.     // e.g. self.myOutlet = nil;
  163.     self.view = nil;
  164.     self.viewList = nil;
  165. }
  166.  
  167. - (void)viewWillAppear:(BOOL)animated {
  168.     // if there's something selected, the value might have changed
  169.     // so reload that row
  170.     NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
  171.     if(selectedIndexPath) {
  172.         [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:selectedIndexPath]
  173.                               withRowAnimation:UITableViewRowAnimationNone];
  174.         // and reselect it, so we get the nice default deselect animation from UITableViewController
  175.         [self.tableView selectRowAtIndexPath:selectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
  176.     }
  177.    
  178.     self.navigationItem.rightBarButtonItem = nil;
  179.     if (_showDoneButton) {
  180.         UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
  181.                                                                                     target:self
  182.                                                                                     action:@selector(dismiss:)];
  183.         self.navigationItem.rightBarButtonItem = buttonItem;
  184.         [buttonItem release];
  185.     }
  186.     if (!self.title) {
  187.         self.title = NSLocalizedString(@"Settings", @"");
  188.     }
  189.    
  190.     if ([self.settingsStore isKindOfClass:[IASKSettingsStoreUserDefaults class]]) {
  191.         [[NSNotificationCenter defaultCenter] addObserver:self
  192.                                                  selector:@selector(userDefaultsDidChange)
  193.                                                      name:NSUserDefaultsDidChangeNotification
  194.                                                    object:[NSUserDefaults standardUserDefaults]];
  195.         [self userDefaultsDidChange]; // force update in case of changes while we were hidden
  196.     }
  197.     [super viewWillAppear:animated];
  198. }
  199.  
  200. - (CGSize)contentSizeForViewInPopover {
  201.     return [[self view] sizeThatFits:CGSizeMake(320, 2000)];
  202. }
  203.  
  204. - (void)viewDidAppear:(BOOL)animated {
  205.     [super viewDidAppear:animated];
  206.  
  207.     NSNotificationCenter *dc = [NSNotificationCenter defaultCenter];
  208.     IASK_IF_IOS4_OR_GREATER([dc addObserver:self selector:@selector(synchronizeSettings) name:UIApplicationDidEnterBackgroundNotification object:[UIApplication sharedApplication]];);
  209.     IASK_IF_IOS4_OR_GREATER([dc addObserver:self selector:@selector(reload) name:UIApplicationWillEnterForegroundNotification object:[UIApplication sharedApplication]];);
  210.     [dc addObserver:self selector:@selector(synchronizeSettings) name:UIApplicationWillTerminateNotification object:[UIApplication sharedApplication]];
  211. }
  212.  
  213. - (void)viewWillDisappear:(BOOL)animated {
  214.     [NSObject cancelPreviousPerformRequestsWithTarget:self];
  215.     [super viewWillDisappear:animated];
  216. }
  217.  
  218. - (void)viewDidDisappear:(BOOL)animated {
  219.     [[NSNotificationCenter defaultCenter] removeObserver:self];
  220.  
  221.     // hide the keyboard
  222.     [self.currentFirstResponder resignFirstResponder];
  223.    
  224.     [super viewDidDisappear:animated];
  225. }
  226.  
  227. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
  228.     return YES;
  229. }
  230.  
  231. - (void)didReceiveMemoryWarning {
  232.     // Releases the view if it doesn't have a superview.
  233.     [super didReceiveMemoryWarning];
  234.    
  235.     // Release any cached data, images, etc that aren't in use.
  236. }
  237.  
  238. - (void)setHiddenKeys:(NSSet *)theHiddenKeys {
  239.     [self setHiddenKeys:theHiddenKeys animated:NO];
  240. }
  241.  
  242.  
  243. - (void)setHiddenKeys:(NSSet*)theHiddenKeys animated:(BOOL)animated {
  244.     if (_hiddenKeys != theHiddenKeys) {
  245.         NSSet *oldHiddenKeys = _hiddenKeys;
  246.         _hiddenKeys = [theHiddenKeys retain];
  247.        
  248.         if (animated) {        
  249.             [self.tableView beginUpdates];
  250.            
  251.             NSMutableSet *showKeys = [NSMutableSet setWithSet:oldHiddenKeys];
  252.             [showKeys minusSet:theHiddenKeys];
  253.            
  254.             NSMutableSet *hideKeys = [NSMutableSet setWithSet:theHiddenKeys];
  255.             [hideKeys minusSet:oldHiddenKeys];
  256.            
  257.             // calculate rows to be deleted
  258.             NSMutableArray *hideIndexPaths = [NSMutableArray array];
  259.             for (NSString *key in hideKeys) {
  260.                 NSIndexPath *indexPath = [self.settingsReader indexPathForKey:key];
  261.                 if (indexPath) {
  262.                     [hideIndexPaths addObject:indexPath];
  263.                 }
  264.             }
  265.            
  266.             // calculate sections to be deleted
  267.             NSMutableIndexSet *hideSections = [NSMutableIndexSet indexSet];
  268.             for (NSInteger section = 0; section < [self numberOfSectionsInTableView:self.tableView ]; section++) {
  269.                 NSUInteger rowsInSection = 0;
  270.                 for (NSIndexPath *indexPath in hideIndexPaths) {
  271.                     if (indexPath.section == section) {
  272.                         rowsInSection++;
  273.                     }
  274.                 }
  275.                 if (rowsInSection >= [self.settingsReader numberOfRowsForSection:section]) {
  276.                     [hideSections addIndex:section];
  277.                 }
  278.             }
  279.            
  280.             // set the datasource
  281.             self.settingsReader.hiddenKeys = theHiddenKeys;
  282.            
  283.            
  284.             // calculate rows to be inserted
  285.             NSMutableArray *showIndexPaths = [NSMutableArray array];
  286.             for (NSString *key in showKeys) {
  287.                 NSIndexPath *indexPath = [self.settingsReader indexPathForKey:key];
  288.                 if (indexPath) {
  289.                     [showIndexPaths addObject:indexPath];
  290.                 }
  291.             }
  292.            
  293.             // calculate sections to be inserted
  294.             NSMutableIndexSet *showSections = [NSMutableIndexSet indexSet];
  295.             for (NSInteger section = 0; section < [self.settingsReader numberOfSections]; section++) {
  296.                 NSUInteger rowsInSection = 0;
  297.                 for (NSIndexPath *indexPath in showIndexPaths) {
  298.                     if (indexPath.section == section) {
  299.                         rowsInSection++;
  300.                     }
  301.                 }
  302.                 if (rowsInSection >= [self.settingsReader numberOfRowsForSection:section]) {
  303.                     [showSections addIndex:section];
  304.                 }
  305.             }
  306.            
  307.             UITableViewRowAnimation animation = animated ? UITableViewRowAnimationTop : UITableViewRowAnimationNone;
  308.             [self.tableView deleteSections:hideSections withRowAnimation:animation];
  309.             [self.tableView deleteRowsAtIndexPaths:hideIndexPaths withRowAnimation:animation];
  310.             [self.tableView insertSections:showSections withRowAnimation:animation];
  311.             [self.tableView insertRowsAtIndexPaths:showIndexPaths withRowAnimation:animation];
  312.             [self.tableView endUpdates];
  313.         } else {
  314.             self.settingsReader.hiddenKeys = theHiddenKeys;
  315.             [self.tableView reloadData];
  316.         }
  317.         [oldHiddenKeys release];
  318.     }
  319. }
  320.  
  321.  
  322. - (void)dealloc {
  323.     [[NSNotificationCenter defaultCenter] removeObserver:self];
  324.  
  325.     [_viewList release], _viewList = nil;
  326.     [_file release], _file = nil;
  327.     [_currentFirstResponder release], _currentFirstResponder = nil;
  328.     [_settingsReader release], _settingsReader = nil;
  329.     [_settingsStore release], _settingsStore = nil;
  330.     [_hiddenKeys release], _hiddenKeys = nil;
  331.    
  332.     _delegate = nil;
  333.  
  334.     [super dealloc];
  335. }
  336.  
  337.  
  338. #pragma mark -
  339. #pragma mark Actions
  340.  
  341. - (void)dismiss:(id)sender {
  342.     [self.settingsStore synchronize];
  343.    
  344.     if (self.delegate && [self.delegate conformsToProtocol:@protocol(IASKSettingsDelegate)]) {
  345.         [self.delegate settingsViewControllerDidEnd:self];
  346.     }
  347. }
  348.  
  349. - (void)toggledValue:(id)sender {
  350.     IASKSwitch *toggle    = [[(IASKSwitch*)sender retain] autorelease];
  351.     IASKSpecifier *spec   = [_settingsReader specifierForKey:[toggle key]];
  352.    
  353.     if ([toggle isOn]) {
  354.         if ([spec trueValue] != nil) {
  355.             [self.settingsStore setObject:[spec trueValue] forKey:[toggle key]];
  356.         }
  357.         else {
  358.             [self.settingsStore setBool:YES forKey:[toggle key]];
  359.         }
  360.     }
  361.     else {
  362.         if ([spec falseValue] != nil) {
  363.             [self.settingsStore setObject:[spec falseValue] forKey:[toggle key]];
  364.         }
  365.         else {
  366.             [self.settingsStore setBool:NO forKey:[toggle key]];
  367.         }
  368.     }
  369.     [[NSNotificationCenter defaultCenter] postNotificationName:kIASKAppSettingChanged
  370.                                                         object:[toggle key]
  371.                                                       userInfo:[NSDictionary dictionaryWithObject:[self.settingsStore objectForKey:[toggle key]]
  372.                                                                                            forKey:[toggle key]]];
  373. }
  374.  
  375. - (void)sliderChangedValue:(id)sender {
  376.     IASKSlider *slider = [[(IASKSlider*)sender retain] autorelease];
  377.     [self.settingsStore setFloat:[slider value] forKey:[slider key]];
  378.     [[NSNotificationCenter defaultCenter] postNotificationName:kIASKAppSettingChanged
  379.                                                         object:[slider key]
  380.                                                       userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:[slider value]]
  381.                                                                                            forKey:[slider key]]];
  382. }
  383.  
  384.  
  385. #pragma mark -
  386. #pragma mark UITableView Functions
  387.  
  388. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
  389.     return [self.settingsReader numberOfSections];
  390. }
  391.  
  392. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  393.     return [self.settingsReader numberOfRowsForSection:section];
  394. }
  395.  
  396. - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
  397.     IASKSpecifier *specifier  = [self.settingsReader specifierForIndexPath:indexPath];
  398.     if ([[specifier type] isEqualToString:kIASKCustomViewSpecifier]) {
  399.         if ([self.delegate respondsToSelector:@selector(tableView:heightForSpecifier:)]) {
  400.             return [self.delegate tableView:tableView heightForSpecifier:specifier];
  401.         } else {
  402.             return 0;
  403.         }
  404.     }
  405.     return tableView.rowHeight;
  406. }
  407.  
  408. - (NSString *)tableView:(UITableView*)tableView titleForHeaderInSection:(NSInteger)section {
  409.     NSString *header = [self.settingsReader titleForSection:section];
  410.     if (0 == header.length) {
  411.         return nil;
  412.     }
  413.     return header;
  414. }
  415.  
  416. - (UIView *)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section {
  417.     if ([self.delegate respondsToSelector:@selector(settingsViewController:tableView:viewForHeaderForSection:)]) {
  418.         return [self.delegate settingsViewController:self tableView:tableView viewForHeaderForSection:section];
  419.     } else {
  420.         return nil;
  421.     }
  422. }
  423.  
  424. - (CGFloat)tableView:(UITableView*)tableView heightForHeaderInSection:(NSInteger)section {
  425.     if ([self tableView:tableView viewForHeaderInSection:section] && [self.delegate respondsToSelector:@selector(settingsViewController:tableView:heightForHeaderForSection:)]) {
  426.         CGFloat result;
  427.         if ((result = [self.delegate settingsViewController:self tableView:tableView heightForHeaderForSection:section])) {
  428.             return result;
  429.         }
  430.        
  431.     }
  432.     NSString *title;
  433.     if ((title = [self tableView:tableView titleForHeaderInSection:section])) {
  434.         CGSize size = [title sizeWithFont:[UIFont boldSystemFontOfSize:[UIFont labelFontSize]]
  435.                         constrainedToSize:CGSizeMake(tableView.frame.size.width - 2*kIASKHorizontalPaddingGroupTitles, INFINITY)
  436.                             lineBreakMode:UILineBreakModeWordWrap];
  437.         return size.height+kIASKVerticalPaddingGroupTitles;
  438.     }
  439.     return 0;
  440. }
  441.  
  442. - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
  443. {
  444.     NSString *footerText = [self.settingsReader footerTextForSection:section];
  445.     if (_showCreditsFooter && (section == [self.settingsReader numberOfSections]-1)) {
  446.         // show credits since this is the last section
  447.         if ((footerText == nil) || ([footerText length] == 0)) {
  448.             // show the credits on their own
  449.             return kIASKCredits;
  450.         } else {
  451.             // show the credits below the app's FooterText
  452.             return [NSString stringWithFormat:@"%@\n\n%@", footerText, kIASKCredits];
  453.         }
  454.     } else {
  455.         if ([footerText length] == 0) {
  456.             return nil;
  457.         }
  458.         return [self.settingsReader footerTextForSection:section];
  459.     }
  460. }
  461.  
  462. - (UITableViewCell*)newCellForIdentifier:(NSString*)identifier {
  463.     UITableViewCell *cell = nil;
  464.     if ([identifier isEqualToString:kIASKPSToggleSwitchSpecifier]) {
  465.         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kIASKPSToggleSwitchSpecifier];
  466.         cell.accessoryView = [[[IASKSwitch alloc] initWithFrame:CGRectMake(0, 0, 79, 27)] autorelease];
  467.         [((IASKSwitch*)cell.accessoryView) addTarget:self action:@selector(toggledValue:) forControlEvents:UIControlEventValueChanged];
  468.         cell.selectionStyle = UITableViewCellSelectionStyleNone;
  469.     }
  470.     else if ([identifier isEqualToString:kIASKPSMultiValueSpecifier] || [identifier isEqualToString:kIASKPSTitleValueSpecifier]) {
  471.         cell = [[IASKPSTitleValueSpecifierViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
  472.         cell.accessoryType = [identifier isEqualToString:kIASKPSMultiValueSpecifier] ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
  473.     }
  474.     else if ([identifier isEqualToString:kIASKPSTextFieldSpecifier]) {
  475.         cell = [[IASKPSTextFieldSpecifierViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kIASKPSTextFieldSpecifier];
  476.         [((IASKPSTextFieldSpecifierViewCell*)cell).textField addTarget:self action:@selector(_textChanged:) forControlEvents:UIControlEventEditingChanged];
  477.     }
  478.     else if ([identifier isEqualToString:kIASKPSSliderSpecifier]) {
  479.         cell = [[IASKPSSliderSpecifierViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kIASKPSSliderSpecifier];
  480.     } else if ([identifier isEqualToString:kIASKPSChildPaneSpecifier]) {
  481.         cell = [[IASKPSTitleValueSpecifierViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
  482.         cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  483.     } else if ([identifier isEqualToString:kIASKMailComposeSpecifier]) {
  484.         cell = [[IASKPSTitleValueSpecifierViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
  485.         [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
  486.     } else {
  487.         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
  488.     }
  489.     cell.textLabel.minimumFontSize = kIASKMinimumFontSize;
  490.     cell.detailTextLabel.minimumFontSize = kIASKMinimumFontSize;
  491.     return cell;
  492. }
  493.  
  494. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  495.     IASKSpecifier *specifier  = [self.settingsReader specifierForIndexPath:indexPath];
  496.     if ([specifier.type isEqualToString:kIASKCustomViewSpecifier] && [self.delegate respondsToSelector:@selector(tableView:cellForSpecifier:)]) {
  497.         UITableViewCell* cell = [self.delegate tableView:tableView cellForSpecifier:specifier];
  498.         assert(nil != cell && "delegate must return a UITableViewCell for custom cell types");
  499.         return cell;
  500.     }
  501.    
  502.     UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:specifier.type];
  503.     if(nil == cell) {
  504.         cell = [[self newCellForIdentifier:specifier.type] autorelease];
  505.     }
  506.    
  507.     if ([specifier.type isEqualToString:kIASKPSToggleSwitchSpecifier]) {
  508.         cell.textLabel.text = specifier.title;
  509.        
  510.         id currentValue = [self.settingsStore objectForKey:specifier.key];
  511.         BOOL toggleState;
  512.         if (currentValue) {
  513.             if ([currentValue isEqual:specifier.trueValue]) {
  514.                 toggleState = YES;
  515.             } else if ([currentValue isEqual:specifier.falseValue]) {
  516.                 toggleState = NO;
  517.             } else {
  518.                 toggleState = [currentValue boolValue];
  519.             }
  520.         } else {
  521.             toggleState = specifier.defaultBoolValue;
  522.         }
  523.         IASKSwitch *toggle = (IASKSwitch*)cell.accessoryView;
  524.         toggle.on = toggleState;
  525.         toggle.key = specifier.key;
  526.     }
  527.     else if ([specifier.type isEqualToString:kIASKPSMultiValueSpecifier]) {
  528.         cell.textLabel.text = specifier.title;
  529.         cell.detailTextLabel.text = [[specifier titleForCurrentValue:[self.settingsStore objectForKey:specifier.key] != nil ?
  530.                                       [self.settingsStore objectForKey:specifier.key] : specifier.defaultValue] description];
  531.     }
  532.     else if ([specifier.type isEqualToString:kIASKPSTitleValueSpecifier]) {
  533.         cell.textLabel.text = specifier.title;
  534.         id value = [self.settingsStore objectForKey:specifier.key] ? : specifier.defaultValue;
  535.        
  536.         NSString *stringValue;
  537.         if (specifier.multipleValues || specifier.multipleTitles) {
  538.             stringValue = [specifier titleForCurrentValue:value];
  539.         } else {
  540.             stringValue = [value description];
  541.         }
  542.        
  543.         cell.detailTextLabel.text = stringValue;
  544.         cell.userInteractionEnabled = NO;
  545.     }
  546.     else if ([specifier.type isEqualToString:kIASKPSTextFieldSpecifier]) {
  547.         cell.textLabel.text = specifier.title;
  548.        
  549.         NSString *textValue = [self.settingsStore objectForKey:specifier.key] != nil ? [self.settingsStore objectForKey:specifier.key] : specifier.defaultStringValue;
  550.         if (textValue && ![textValue isMemberOfClass:[NSString class]]) {
  551.             textValue = [NSString stringWithFormat:@"%@", textValue];
  552.         }
  553.         IASKTextField *textField = ((IASKPSTextFieldSpecifierViewCell*)cell).textField;
  554.         textField.text = textValue;
  555.         textField.key = specifier.key;
  556.         textField.delegate = self;
  557.         textField.secureTextEntry = [specifier isSecure];
  558.         textField.keyboardType = specifier.keyboardType;
  559.         textField.autocapitalizationType = specifier.autocapitalizationType;
  560.         if([specifier isSecure]){
  561.             textField.autocorrectionType = UITextAutocorrectionTypeNo;
  562.         } else {
  563.             textField.autocorrectionType = specifier.autoCorrectionType;
  564.         }
  565.         textField.textAlignment = specifier.textAlignment;
  566.         textField.adjustsFontSizeToFitWidth = specifier.adjustsFontSizeToFitWidth;
  567.     }
  568.     else if ([specifier.type isEqualToString:kIASKPSSliderSpecifier]) {
  569.         if (specifier.minimumValueImage.length > 0) {
  570.             ((IASKPSSliderSpecifierViewCell*)cell).minImage.image = [UIImage imageWithContentsOfFile:[_settingsReader pathForImageNamed:specifier.minimumValueImage]];
  571.         }
  572.        
  573.         if (specifier.maximumValueImage.length > 0) {
  574.             ((IASKPSSliderSpecifierViewCell*)cell).maxImage.image = [UIImage imageWithContentsOfFile:[_settingsReader pathForImageNamed:specifier.maximumValueImage]];
  575.         }
  576.        
  577.         IASKSlider *slider = ((IASKPSSliderSpecifierViewCell*)cell).slider;
  578.         slider.minimumValue = specifier.minimumValue;
  579.         slider.maximumValue = specifier.maximumValue;
  580.         slider.value =  [self.settingsStore objectForKey:specifier.key] != nil ? [[self.settingsStore objectForKey:specifier.key] floatValue] : [specifier.defaultValue floatValue];
  581.         [slider addTarget:self action:@selector(sliderChangedValue:) forControlEvents:UIControlEventValueChanged];
  582.         slider.key = specifier.key;
  583.         [cell setNeedsLayout];
  584.     }
  585.     else if ([specifier.type isEqualToString:kIASKPSChildPaneSpecifier]) {
  586.         cell.textLabel.text = specifier.title;
  587.     } else if ([specifier.type isEqualToString:kIASKOpenURLSpecifier] || [specifier.type isEqualToString:kIASKMailComposeSpecifier]) {
  588.         cell.textLabel.text = specifier.title;
  589.         cell.detailTextLabel.text = [specifier.defaultValue description];
  590.     } else if ([specifier.type isEqualToString:kIASKButtonSpecifier]) {
  591.         NSString *value = [self.settingsStore objectForKey:specifier.key];
  592.         cell.textLabel.text = [value isKindOfClass:[NSString class]] ? [self.settingsReader titleForStringId:value] : specifier.title;
  593.     } else {
  594.         cell.textLabel.text = specifier.title;
  595.     }
  596.    
  597.     cell.imageView.image = specifier.cellImage;
  598.     cell.imageView.highlightedImage = specifier.highlightedCellImage;
  599.    
  600.     if (![specifier.type isEqualToString:kIASKPSMultiValueSpecifier] && ![specifier.type isEqualToString:kIASKPSTitleValueSpecifier] && ![specifier.type isEqualToString:kIASKPSTextFieldSpecifier]) {
  601.         cell.textLabel.textAlignment = specifier.textAlignment;
  602.     }
  603.     cell.detailTextLabel.textAlignment = specifier.textAlignment;
  604.     cell.textLabel.adjustsFontSizeToFitWidth = specifier.adjustsFontSizeToFitWidth;
  605.     cell.detailTextLabel.adjustsFontSizeToFitWidth = specifier.adjustsFontSizeToFitWidth;
  606.     return cell;
  607. }
  608.  
  609. - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  610.     //create a set of specifier types that can't be selected
  611.     static NSSet* noSelectionTypes = nil;
  612.     if(nil == noSelectionTypes) {
  613.         noSelectionTypes = [[NSSet setWithObjects:kIASKPSToggleSwitchSpecifier, kIASKPSSliderSpecifier, nil] retain];
  614.     }
  615.  
  616.     IASKSpecifier *specifier  = [self.settingsReader specifierForIndexPath:indexPath];
  617.     if([noSelectionTypes containsObject:specifier.type]) {
  618.         return nil;
  619.     } else {
  620.         return indexPath;
  621.     }
  622. }
  623.  
  624. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  625.     IASKSpecifier *specifier  = [self.settingsReader specifierForIndexPath:indexPath];
  626.    
  627.     //switches and sliders can't be selected (should be captured by tableView:willSelectRowAtIndexPath: delegate method)
  628.     assert(![[specifier type] isEqualToString:kIASKPSToggleSwitchSpecifier]);
  629.     assert(![[specifier type] isEqualToString:kIASKPSSliderSpecifier]);
  630.  
  631.     if ([[specifier type] isEqualToString:kIASKPSMultiValueSpecifier]) {
  632.         IASKSpecifierValuesViewController *targetViewController = [[self.viewList objectAtIndex:kIASKSpecifierValuesViewControllerIndex] objectForKey:@"viewController"];
  633.        
  634.         if (targetViewController == nil) {
  635.             // the view controller has not been created yet, create it and set it to our viewList array
  636.             // create a new dictionary with the new view controller
  637.             NSMutableDictionary *newItemDict = [NSMutableDictionary dictionaryWithCapacity:3];
  638.             [newItemDict addEntriesFromDictionary: [self.viewList objectAtIndex:kIASKSpecifierValuesViewControllerIndex]];  // copy the title and explain strings
  639.            
  640.             targetViewController = [[IASKSpecifierValuesViewController alloc] init];
  641.             // add the new view controller to the dictionary and then to the 'viewList' array
  642.             [newItemDict setObject:targetViewController forKey:@"viewController"];
  643.             [self.viewList replaceObjectAtIndex:kIASKSpecifierValuesViewControllerIndex withObject:newItemDict];
  644.             [targetViewController release];
  645.            
  646.             // load the view controll back in to push it
  647.             targetViewController = [[self.viewList objectAtIndex:kIASKSpecifierValuesViewControllerIndex] objectForKey:@"viewController"];
  648.         }
  649.         [targetViewController setCurrentSpecifier:specifier];
  650.         targetViewController.settingsReader = self.settingsReader;
  651.         targetViewController.settingsStore = self.settingsStore;
  652.         [[self navigationController] pushViewController:targetViewController animated:YES];
  653.     }
  654.     else if ([[specifier type] isEqualToString:kIASKPSTextFieldSpecifier]) {
  655.         IASKPSTextFieldSpecifierViewCell *textFieldCell = (id)[tableView cellForRowAtIndexPath:indexPath];
  656.         [textFieldCell.textField becomeFirstResponder];
  657.     }
  658.     else if ([[specifier type] isEqualToString:kIASKPSChildPaneSpecifier]) {
  659.  
  660.        
  661.         Class vcClass = [specifier viewControllerClass];
  662.         if (vcClass) {
  663.             SEL initSelector = [specifier viewControllerSelector];
  664.             if (!initSelector) {
  665.                 initSelector = @selector(init);
  666.             }
  667.             UIViewController * vc = [vcClass performSelector:@selector(alloc)];
  668.             [vc performSelector:initSelector withObject:[specifier file] withObject:[specifier key]];
  669.             if ([vc respondsToSelector:@selector(setDelegate:)]) {
  670.                 [vc performSelector:@selector(setDelegate:) withObject:self.delegate];
  671.             }
  672.             if ([vc respondsToSelector:@selector(setSettingsStore:)]) {
  673.                 [vc performSelector:@selector(setSettingsStore:) withObject:self.settingsStore];
  674.             }
  675.             [self.navigationController pushViewController:vc animated:YES];
  676.             [vc performSelector:@selector(release)];
  677.             return;
  678.         }
  679.        
  680.         if (nil == [specifier file]) {
  681.             [tableView deselectRowAtIndexPath:indexPath animated:YES];
  682.             return;
  683.         }        
  684.        
  685.         IASKAppSettingsViewController *targetViewController = [[self.viewList objectAtIndex:kIASKSpecifierChildViewControllerIndex] objectForKey:@"viewController"];
  686.        
  687.         if (targetViewController == nil) {
  688.             // the view controller has not been created yet, create it and set it to our viewList array
  689.             // create a new dictionary with the new view controller
  690.             NSMutableDictionary *newItemDict = [NSMutableDictionary dictionaryWithCapacity:3];
  691.             [newItemDict addEntriesFromDictionary: [self.viewList objectAtIndex:kIASKSpecifierChildViewControllerIndex]];   // copy the title and explain strings
  692.            
  693.             targetViewController = [[[self class] alloc] init];
  694.             targetViewController.showDoneButton = NO;
  695.             targetViewController.settingsStore = self.settingsStore;
  696.             targetViewController.delegate = self.delegate;
  697.  
  698.             // add the new view controller to the dictionary and then to the 'viewList' array
  699.             [newItemDict setObject:targetViewController forKey:@"viewController"];
  700.             [self.viewList replaceObjectAtIndex:kIASKSpecifierChildViewControllerIndex withObject:newItemDict];
  701.             [targetViewController release];
  702.            
  703.             // load the view controll back in to push it
  704.             targetViewController = [[self.viewList objectAtIndex:kIASKSpecifierChildViewControllerIndex] objectForKey:@"viewController"];
  705.         }
  706.         targetViewController.file = specifier.file;
  707.         targetViewController.title = specifier.title;
  708.         targetViewController.showCreditsFooter = NO;
  709.         [[self navigationController] pushViewController:targetViewController animated:YES];
  710.     } else if ([[specifier type] isEqualToString:kIASKOpenURLSpecifier]) {
  711.         [tableView deselectRowAtIndexPath:indexPath animated:YES];
  712.         [[UIApplication sharedApplication] openURL:[NSURL URLWithString:specifier.file]];    
  713.     } else if ([[specifier type] isEqualToString:kIASKButtonSpecifier]) {
  714.         [tableView deselectRowAtIndexPath:indexPath animated:YES];
  715.         if ([self.delegate respondsToSelector:@selector(settingsViewController:buttonTappedForSpecifier:)]) {
  716.             [self.delegate settingsViewController:self buttonTappedForSpecifier:specifier];
  717.         } else if ([self.delegate respondsToSelector:@selector(settingsViewController:buttonTappedForKey:)]) {
  718.             // deprecated, provided for backward compatibility
  719.             NSLog(@"InAppSettingsKit Warning: -settingsViewController:buttonTappedForKey: is deprecated. Please use -settingsViewController:buttonTappedForSpecifier:");
  720.             [self.delegate settingsViewController:self buttonTappedForKey:[specifier key]];
  721.         } else {
  722.             // legacy code, provided for backward compatibility
  723.             // the delegate mechanism above is much cleaner and doesn't leak
  724.             Class buttonClass = [specifier buttonClass];
  725.             SEL buttonAction = [specifier buttonAction];
  726.             if ([buttonClass respondsToSelector:buttonAction]) {
  727.                 [buttonClass performSelector:buttonAction withObject:self withObject:[specifier key]];
  728.                 NSLog(@"InAppSettingsKit Warning: Using IASKButtonSpecifier without implementing the delegate method is deprecated");
  729.             }
  730.         }
  731.     } else if ([[specifier type] isEqualToString:kIASKMailComposeSpecifier]) {
  732.         [tableView deselectRowAtIndexPath:indexPath animated:YES];
  733.         if ([MFMailComposeViewController canSendMail]) {
  734.             MFMailComposeViewController *mailViewController = [[MFMailComposeViewController alloc] init];
  735.             mailViewController.navigationBar.barStyle = self.navigationController.navigationBar.barStyle;
  736.             mailViewController.navigationBar.tintColor = self.navigationController.navigationBar.tintColor;
  737.            
  738.             if ([specifier localizedObjectForKey:kIASKMailComposeSubject]) {
  739.                 [mailViewController setSubject:[specifier localizedObjectForKey:kIASKMailComposeSubject]];
  740.             }
  741.             if ([[specifier specifierDict] objectForKey:kIASKMailComposeToRecipents]) {
  742.                 [mailViewController setToRecipients:[[specifier specifierDict] objectForKey:kIASKMailComposeToRecipents]];
  743.             }
  744.             if ([[specifier specifierDict] objectForKey:kIASKMailComposeCcRecipents]) {
  745.                 [mailViewController setCcRecipients:[[specifier specifierDict] objectForKey:kIASKMailComposeCcRecipents]];
  746.             }
  747.             if ([[specifier specifierDict] objectForKey:kIASKMailComposeBccRecipents]) {
  748.                 [mailViewController setBccRecipients:[[specifier specifierDict] objectForKey:kIASKMailComposeBccRecipents]];
  749.             }
  750.             if ([specifier localizedObjectForKey:kIASKMailComposeBody]) {
  751.                 BOOL isHTML = NO;
  752.                 if ([[specifier specifierDict] objectForKey:kIASKMailComposeBodyIsHTML]) {
  753.                     isHTML = [[[specifier specifierDict] objectForKey:kIASKMailComposeBodyIsHTML] boolValue];
  754.                 }
  755.                
  756.               if ([self.delegate respondsToSelector:@selector(settingsViewController:mailComposeBodyForSpecifier:)]) {
  757.                     [mailViewController setMessageBody:[self.delegate settingsViewController:self
  758.                                                                  mailComposeBodyForSpecifier:specifier] isHTML:isHTML];
  759.                 }
  760.                 else {
  761.                     [mailViewController setMessageBody:[specifier localizedObjectForKey:kIASKMailComposeBody] isHTML:isHTML];
  762.                 }
  763.             }
  764.  
  765.             UIViewController<MFMailComposeViewControllerDelegate> *vc = nil;
  766.            
  767.           if ([self.delegate respondsToSelector:@selector(settingsViewController:viewControllerForMailComposeViewForSpecifier:)]) {
  768.             vc = [self.delegate settingsViewController:self viewControllerForMailComposeViewForSpecifier:specifier];
  769.             }
  770.            
  771.             if (vc == nil) {
  772.                 vc = self;
  773.             }
  774.            
  775.             mailViewController.mailComposeDelegate = vc;
  776.             [vc presentModalViewController:mailViewController animated:YES];
  777.             [mailViewController release];
  778.         } else {
  779.             UIAlertView *alert = [[UIAlertView alloc]
  780.                                   initWithTitle:NSLocalizedString(@"Mail not configured", @"InAppSettingsKit")
  781.                                   message:NSLocalizedString(@"This device is not configured for sending Email. Please configure the Mail settings in the Settings app.", @"InAppSettingsKit")
  782.                                   delegate: nil
  783.                                   cancelButtonTitle:NSLocalizedString(@"OK", @"InAppSettingsKit")
  784.                                   otherButtonTitles:nil];
  785.             [alert show];
  786.             [alert release];
  787.         }
  788.  
  789.     } else if ([[specifier type] isEqualToString:kIASKCustomViewSpecifier] && [self.delegate respondsToSelector:@selector(settingsViewController:tableView:didSelectCustomViewSpecifier:)]) {
  790.         [self.delegate settingsViewController:self tableView:tableView didSelectCustomViewSpecifier:specifier];
  791.     } else {
  792.         [tableView deselectRowAtIndexPath:indexPath animated:NO];
  793.     }
  794. }
  795.  
  796.  
  797. #pragma mark -
  798. #pragma mark MFMailComposeViewControllerDelegate Function
  799.  
  800. -(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
  801.    
  802.     // Forward the mail compose delegate
  803.     if ([self.delegate respondsToSelector:@selector(settingsViewController:mailComposeController:didFinishWithResult:error:)]) {
  804.          [self.delegate settingsViewController:self
  805.                          mailComposeController:controller
  806.                            didFinishWithResult:result
  807.                                          error:error];
  808.      }
  809.    
  810.     // NOTE: No error handling is done here
  811.     [self dismissModalViewControllerAnimated:YES];
  812. }
  813.  
  814. #pragma mark -
  815. #pragma mark UITextFieldDelegate Functions
  816.  
  817. - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
  818.     self.currentFirstResponder = textField;
  819.     return YES;
  820. }
  821.  
  822. - (void)_textChanged:(id)sender {
  823.     IASKTextField *text = [[(IASKTextField*)sender retain] autorelease];
  824.     [_settingsStore setObject:[text text] forKey:[text key]];
  825.     [[NSNotificationCenter defaultCenter] postNotificationName:kIASKAppSettingChanged
  826.                                                         object:[text key]
  827.                                                       userInfo:[NSDictionary dictionaryWithObject:[text text]
  828.                                                                                            forKey:[text key]]];
  829. }
  830.  
  831. - (BOOL)textFieldShouldReturn:(UITextField *)textField{
  832.     [textField resignFirstResponder];
  833.     self.currentFirstResponder = nil;
  834.     return YES;
  835. }
  836.  
  837. - (void)singleTapToEndEdit:(UIGestureRecognizer *)sender {
  838.     [self.tableView endEditing:NO];
  839. }
  840.  
  841. #pragma mark Notifications
  842.  
  843. - (void)synchronizeSettings {
  844.     [_settingsStore synchronize];
  845. }
  846.  
  847. static NSDictionary *oldUserDefaults = nil;
  848. - (void)userDefaultsDidChange {
  849.     NSDictionary *currentDict = [NSUserDefaults standardUserDefaults].dictionaryRepresentation;
  850.     NSMutableArray *indexPathsToUpdate = [NSMutableArray array];
  851.     for (NSString *key in currentDict.allKeys) {
  852.         if (![[oldUserDefaults valueForKey:key] isEqual:[currentDict valueForKey:key]]) {
  853.             NSIndexPath *path = [self.settingsReader indexPathForKey:key];
  854.             if (path && ![[self.settingsReader specifierForKey:key].type isEqualToString:kIASKCustomViewSpecifier]) {
  855.                 [indexPathsToUpdate addObject:path];
  856.             }
  857.         }
  858.     }
  859.     [oldUserDefaults release], oldUserDefaults = [currentDict retain];
  860.    
  861.    
  862.     for (UITableViewCell *cell in self.tableView.visibleCells) {
  863.         if ([cell isKindOfClass:[IASKPSTextFieldSpecifierViewCell class]] && [((IASKPSTextFieldSpecifierViewCell*)cell).textField isFirstResponder]) {
  864.             [indexPathsToUpdate removeObject:[self.tableView indexPathForCell:cell]];
  865.         }
  866.     }
  867.     if (indexPathsToUpdate.count) {
  868.         [self.tableView reloadRowsAtIndexPaths:indexPathsToUpdate withRowAnimation:UITableViewRowAnimationNone];
  869.     }
  870. }
  871.  
  872. - (void)reload {
  873.     // wait 0.5 sec until UI is available after applicationWillEnterForeground
  874.     [self.tableView performSelector:@selector(reloadData) withObject:nil afterDelay:0.5];
  875. }
  876.  
  877. #pragma mark CGRect Utility function
  878. CGRect IASKCGRectSwap(CGRect rect) {
  879.     CGRect newRect;
  880.     newRect.origin.x = rect.origin.y;
  881.     newRect.origin.y = rect.origin.x;
  882.     newRect.size.width = rect.size.height;
  883.     newRect.size.height = rect.size.width;
  884.     return newRect;
  885. }
  886. @end
Advertisement
Add Comment
Please, Sign In to add comment