Updating inappsettingskit.

This commit is contained in:
Samuel Clay 2015-03-03 15:56:32 -05:00
parent bd39331885
commit 66a421b7b3
28 changed files with 661 additions and 269 deletions

View file

@ -64,8 +64,9 @@
@property (nonatomic, assign) IBOutlet id delegate;
@property (nonatomic, copy) NSString *file;
@property (nonatomic, assign) BOOL showCreditsFooter;
@property (nonatomic, assign) BOOL showDoneButton;
@property (nonatomic, assign) IBInspectable BOOL showDoneButton;
@property (nonatomic, retain) NSSet *hiddenKeys;
@property (nonatomic) IBInspectable BOOL neverShowPrivacySettings;
- (void)synchronizeSettings;
- (void)dismiss:(id)sender;

View file

@ -20,12 +20,12 @@
#import "IASKSettingsStoreUserDefaults.h"
#import "IASKPSSliderSpecifierViewCell.h"
#import "IASKPSTextFieldSpecifierViewCell.h"
#import "IASKPSTitleValueSpecifierViewCell.h"
#import "IASKSwitch.h"
#import "IASKSlider.h"
#import "IASKSpecifier.h"
#import "IASKSpecifierValuesViewController.h"
#import "IASKTextField.h"
#import "IASKMultipleValueSelection.h"
#if !__has_feature(objc_arc)
#error "IASK needs ARC"
@ -47,6 +47,8 @@ CGRect IASKCGRectSwap(CGRect rect);
id _currentFirstResponder;
__weak UIViewController *_currentChildViewController;
BOOL _reloadDisabled;
/// The selected index for every group (in case it's a radio group).
NSArray *_selections;
}
@property (nonatomic, strong) id currentFirstResponder;
@ -67,6 +69,9 @@ CGRect IASKCGRectSwap(CGRect rect);
- (IASKSettingsReader*)settingsReader {
if (!_settingsReader) {
_settingsReader = [[IASKSettingsReader alloc] initWithFile:self.file];
if (self.neverShowPrivacySettings) {
_settingsReader.showPrivacySettings = NO;
}
}
return _settingsReader;
}
@ -80,7 +85,7 @@ CGRect IASKCGRectSwap(CGRect rect);
- (NSString*)file {
if (!_file) {
return @"Root";
self.file = @"Root";
}
return _file;
}
@ -89,8 +94,28 @@ CGRect IASKCGRectSwap(CGRect rect);
_file = [file copy];
self.tableView.contentOffset = CGPointMake(0, 0);
self.settingsReader = nil; // automatically initializes itself
_hiddenKeys = nil;
if (!_reloadDisabled) [self.tableView reloadData];
if (!_reloadDisabled) {
[self.tableView reloadData];
[self createSelections];
}
}
- (void)createSelections {
NSMutableArray *sectionSelection = [NSMutableArray new];
for (int i = 0; i < _settingsReader.numberOfSections; i++) {
IASKSpecifier *specifier = [self.settingsReader headerSpecifierForSection:i];
if ([specifier.type isEqualToString:kIASKPSRadioGroupSpecifier]) {
IASKMultipleValueSelection *selection = [IASKMultipleValueSelection new];
selection.tableView = self.tableView;
selection.specifier = specifier;
selection.section = i;
selection.settingsStore = self.settingsStore;
[sectionSelection addObject:selection];
} else {
[sectionSelection addObject:[NSNull null]];
}
}
_selections = sectionSelection;
}
- (BOOL)isPad {
@ -143,14 +168,6 @@ CGRect IASKCGRectSwap(CGRect rect);
[self.tableView addGestureRecognizer:tapGesture];
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.view = nil;
}
- (void)viewWillAppear:(BOOL)animated {
// if there's something selected, the value might have changed
// so reload that row
@ -173,10 +190,9 @@ CGRect IASKCGRectSwap(CGRect rect);
}
if ([self.settingsStore isKindOfClass:[IASKSettingsStoreUserDefaults class]]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(userDefaultsDidChange)
name:NSUserDefaultsDidChangeNotification
object:[NSUserDefaults standardUserDefaults]];
NSNotificationCenter *dc = NSNotificationCenter.defaultCenter;
[dc addObserver:self selector:@selector(userDefaultsDidChange) name:NSUserDefaultsDidChangeNotification object:[NSUserDefaults standardUserDefaults]];
[dc addObserver:self selector:@selector(didChangeSettingViaIASK:) name:kIASKAppSettingChanged object:nil];
[self userDefaultsDidChange]; // force update in case of changes while we were hidden
}
[super viewWillAppear:animated];
@ -193,6 +209,9 @@ CGRect IASKCGRectSwap(CGRect rect);
[dc addObserver:self selector:@selector(synchronizeSettings) name:UIApplicationDidEnterBackgroundNotification object:[UIApplication sharedApplication]];
[dc addObserver:self selector:@selector(reload) name:UIApplicationWillEnterForegroundNotification object:[UIApplication sharedApplication]];
[dc addObserver:self selector:@selector(synchronizeSettings) name:UIApplicationWillTerminateNotification object:[UIApplication sharedApplication]];
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
- (void)viewWillDisappear:(BOOL)animated {
@ -207,6 +226,7 @@ CGRect IASKCGRectSwap(CGRect rect);
- (void)viewDidDisappear:(BOOL)animated {
NSNotificationCenter *dc = [NSNotificationCenter defaultCenter];
[dc removeObserver:self name:NSUserDefaultsDidChangeNotification object:[NSUserDefaults standardUserDefaults]];
[dc removeObserver:self name:kIASKAppSettingChanged object:self];
[dc removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:[UIApplication sharedApplication]];
[dc removeObserver:self name:UIApplicationWillEnterForegroundNotification object:[UIApplication sharedApplication]];
[dc removeObserver:self name:UIApplicationWillTerminateNotification object:[UIApplication sharedApplication]];
@ -214,10 +234,6 @@ CGRect IASKCGRectSwap(CGRect rect);
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (void)setHiddenKeys:(NSSet *)theHiddenKeys {
[self setHiddenKeys:theHiddenKeys animated:NO];
}
@ -229,8 +245,6 @@ CGRect IASKCGRectSwap(CGRect rect);
_hiddenKeys = theHiddenKeys;
if (animated) {
[self.tableView beginUpdates];
NSMutableSet *showKeys = [NSMutableSet setWithSet:oldHiddenKeys];
[showKeys minusSet:theHiddenKeys];
@ -255,7 +269,7 @@ CGRect IASKCGRectSwap(CGRect rect);
rowsInSection++;
}
}
if (rowsInSection >= [self.settingsReader numberOfRowsForSection:section]) {
if (rowsInSection && rowsInSection >= [self.settingsReader numberOfRowsForSection:section]) {
[hideSections addIndex:section];
}
}
@ -282,23 +296,34 @@ CGRect IASKCGRectSwap(CGRect rect);
rowsInSection++;
}
}
if (rowsInSection >= [self.settingsReader numberOfRowsForSection:section]) {
if (rowsInSection && rowsInSection >= [self.settingsReader numberOfRowsForSection:section]) {
[showSections addIndex:section];
}
}
UITableViewRowAnimation animation = animated ? UITableViewRowAnimationAutomatic : UITableViewRowAnimationNone;
[self.tableView deleteSections:hideSections withRowAnimation:animation];
[self.tableView deleteRowsAtIndexPaths:hideIndexPaths withRowAnimation:animation];
[self.tableView insertSections:showSections withRowAnimation:animation];
[self.tableView insertRowsAtIndexPaths:showIndexPaths withRowAnimation:animation];
[self.tableView endUpdates];
} else {
self.settingsReader.hiddenKeys = theHiddenKeys;
if (!_reloadDisabled) [self.tableView reloadData];
}
}
UIViewController *childViewController = _currentChildViewController;
}
if (hideSections.count || hideIndexPaths.count || showSections.count || showIndexPaths.count) {
[self.tableView beginUpdates];
UITableViewRowAnimation animation = animated ? UITableViewRowAnimationAutomatic : UITableViewRowAnimationNone;
if (hideSections.count) {
[self.tableView deleteSections:hideSections withRowAnimation:animation];
}
if (hideIndexPaths) {
[self.tableView deleteRowsAtIndexPaths:hideIndexPaths withRowAnimation:animation];
}
if (showSections.count) {
[self.tableView insertSections:showSections withRowAnimation:animation];
}
if (showIndexPaths) {
[self.tableView insertRowsAtIndexPaths:showIndexPaths withRowAnimation:animation];
}
[self.tableView endUpdates];
}
} else {
self.settingsReader.hiddenKeys = theHiddenKeys;
if (!_reloadDisabled) [self.tableView reloadData];
}
}
UIViewController *childViewController = _currentChildViewController;
if([childViewController respondsToSelector:@selector(setHiddenKeys:animated:)]) {
[(id)childViewController setHiddenKeys:theHiddenKeys animated:animated];
}
@ -377,7 +402,16 @@ CGRect IASKCGRectSwap(CGRect rect);
return 0;
}
}
return tableView.rowHeight;
IASK_IF_IOS7_OR_GREATER
(
NSDictionary *rowHeights = @{UIContentSizeCategoryExtraSmall: @(44),
UIContentSizeCategorySmall: @(44),
UIContentSizeCategoryMedium: @(44),
UIContentSizeCategoryLarge: @(44),
UIContentSizeCategoryExtraLarge: @(47)};
return (CGFloat)[rowHeights[UIApplication.sharedApplication.preferredContentSizeCategory] doubleValue] ? : 51;
);
return 44;
}
- (NSString *)tableView:(UITableView*)tableView titleForHeaderInSection:(NSInteger)section {
@ -404,25 +438,7 @@ CGRect IASKCGRectSwap(CGRect rect);
}
}
NSString *title = [self tableView:tableView titleForHeaderInSection:section];
if ([title length] > 0) {
CGSize size = CGSizeZero;
IASK_IF_PRE_IOS7
(
size = [title sizeWithFont:[UIFont boldSystemFontOfSize:[UIFont labelFontSize]]
constrainedToSize:CGSizeMake(tableView.frame.size.width - 2*kIASKHorizontalPaddingGroupTitles, INFINITY)
lineBreakMode:NSLineBreakByWordWrapping];
);
IASK_IF_IOS7_OR_GREATER
(
size = [title boundingRectWithSize:CGSizeMake(tableView.frame.size.width - 2*kIASKHorizontalPaddingGroupTitles, INFINITY)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName: [UIFont boldSystemFontOfSize:[UIFont labelFontSize]]}
context:nil].size;
);
return roundf(size.height+kIASKVerticalPaddingGroupTitles);
}
return 0;
return UITableViewAutomaticDimension;
}
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
@ -443,32 +459,42 @@ CGRect IASKCGRectSwap(CGRect rect);
}
- (UITableViewCell*)newCellForIdentifier:(NSString*)identifier {
UITableViewCell *cell = nil;
if ([identifier isEqualToString:kIASKPSToggleSwitchSpecifier]) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kIASKPSToggleSwitchSpecifier];
- (UITableViewCell*)tableView:(UITableView *)tableView newCellForSpecifier:(IASKSpecifier*)specifier {
NSString *identifier = [NSString stringWithFormat:@"%@-%ld-%d", specifier.type, (long)specifier.textAlignment, !!specifier.subtitle.length];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell) {
return cell;
}
UITableViewCellStyle style = (specifier.textAlignment == NSTextAlignmentLeft || specifier.subtitle.length) ? UITableViewCellStyleSubtitle : UITableViewCellStyleDefault;
if ([identifier hasPrefix:kIASKPSToggleSwitchSpecifier]) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:kIASKPSToggleSwitchSpecifier];
cell.accessoryView = [[IASKSwitch alloc] initWithFrame:CGRectMake(0, 0, 79, 27)];
[((IASKSwitch*)cell.accessoryView) addTarget:self action:@selector(toggledValue:) forControlEvents:UIControlEventValueChanged];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
else if ([identifier isEqualToString:kIASKPSMultiValueSpecifier] || [identifier isEqualToString:kIASKPSTitleValueSpecifier]) {
cell = [[IASKPSTitleValueSpecifierViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
cell.accessoryType = [identifier isEqualToString:kIASKPSMultiValueSpecifier] ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
else if ([identifier hasPrefix:kIASKPSMultiValueSpecifier] || [identifier hasPrefix:kIASKPSTitleValueSpecifier]) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
cell.accessoryType = [identifier hasPrefix:kIASKPSMultiValueSpecifier] ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
}
else if ([identifier isEqualToString:kIASKPSTextFieldSpecifier]) {
else if ([identifier hasPrefix:kIASKPSTextFieldSpecifier]) {
cell = [[IASKPSTextFieldSpecifierViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kIASKPSTextFieldSpecifier];
[((IASKPSTextFieldSpecifierViewCell*)cell).textField addTarget:self action:@selector(_textChanged:) forControlEvents:UIControlEventEditingChanged];
}
else if ([identifier isEqualToString:kIASKPSSliderSpecifier]) {
else if ([identifier hasPrefix:kIASKPSSliderSpecifier]) {
cell = [[IASKPSSliderSpecifierViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kIASKPSSliderSpecifier];
} else if ([identifier isEqualToString:kIASKPSChildPaneSpecifier]) {
cell = [[IASKPSTitleValueSpecifierViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
} else if ([identifier hasPrefix:kIASKPSChildPaneSpecifier]) {
cell = [[UITableViewCell alloc] initWithStyle:style reuseIdentifier:identifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
} else if ([identifier isEqualToString:kIASKMailComposeSpecifier]) {
cell = [[IASKPSTitleValueSpecifierViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
cell = [[UITableViewCell alloc] initWithStyle:style reuseIdentifier:identifier];
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
} else {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
cell = [[UITableViewCell alloc] initWithStyle:style reuseIdentifier:identifier];
if ([identifier isEqualToString:kIASKOpenURLSpecifier]) {
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
IASK_IF_PRE_IOS6(cell.textLabel.minimumFontSize = kIASKMinimumFontSize;
cell.detailTextLabel.minimumFontSize = kIASKMinimumFontSize;);
@ -485,14 +511,12 @@ CGRect IASKCGRectSwap(CGRect rect);
return cell;
}
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:specifier.type];
if(nil == cell) {
cell = [self newCellForIdentifier:specifier.type];
}
UITableViewCell* cell = [self tableView:tableView newCellForSpecifier:specifier];
if ([specifier.type isEqualToString:kIASKPSToggleSwitchSpecifier]) {
cell.textLabel.text = specifier.title;
cell.detailTextLabel.text = specifier.subtitle;
id currentValue = [self.settingsStore objectForKey:specifier.key];
BOOL toggleState;
if (currentValue) {
@ -570,13 +594,25 @@ CGRect IASKCGRectSwap(CGRect rect);
}
else if ([specifier.type isEqualToString:kIASKPSChildPaneSpecifier]) {
cell.textLabel.text = specifier.title;
cell.detailTextLabel.text = specifier.subtitle;
} else if ([specifier.type isEqualToString:kIASKOpenURLSpecifier] || [specifier.type isEqualToString:kIASKMailComposeSpecifier]) {
cell.textLabel.text = specifier.title;
cell.detailTextLabel.text = [specifier.defaultValue description];
cell.detailTextLabel.text = specifier.subtitle ? : [specifier.defaultValue description];
cell.accessoryType = (specifier.textAlignment == NSTextAlignmentLeft) ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
} else if ([specifier.type isEqualToString:kIASKButtonSpecifier]) {
NSString *value = [self.settingsStore objectForKey:specifier.key];
cell.textLabel.text = [value isKindOfClass:[NSString class]] ? [self.settingsReader titleForStringId:value] : specifier.title;
cell.detailTextLabel.text = specifier.subtitle;
IASK_IF_IOS7_OR_GREATER
(if (specifier.textAlignment != NSTextAlignmentLeft) {
cell.textLabel.textColor = tableView.tintColor;
});
cell.textLabel.textAlignment = specifier.textAlignment;
cell.accessoryType = (specifier.textAlignment == NSTextAlignmentLeft) ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
} else if ([specifier.type isEqualToString:kIASKPSRadioGroupSpecifier]) {
NSInteger index = [specifier.multipleValues indexOfObject:specifier.radioGroupValue];
cell.textLabel.text = [self.settingsReader titleForStringId:specifier.multipleTitles[index]];
[_selections[indexPath.section] updateSelectionInCell:cell indexPath:indexPath];
} else {
cell.textLabel.text = specifier.title;
}
@ -620,7 +656,7 @@ CGRect IASKCGRectSwap(CGRect rect);
[targetViewController setCurrentSpecifier:specifier];
targetViewController.settingsReader = self.settingsReader;
targetViewController.settingsStore = self.settingsStore;
targetViewController.view.tintColor = self.view.tintColor;
IASK_IF_IOS7_OR_GREATER(targetViewController.view.tintColor = self.view.tintColor;)
_currentChildViewController = targetViewController;
[[self navigationController] pushViewController:targetViewController animated:YES];
@ -631,10 +667,10 @@ CGRect IASKCGRectSwap(CGRect rect);
} else if ([[specifier type] isEqualToString:kIASKPSChildPaneSpecifier]) {
if ([specifier viewControllerStoryBoardID]){
NSString *storyBoardFileFromSpecifier = [specifier viewControllerStoryBoardFile];
storyBoardFileFromSpecifier = storyBoardFileFromSpecifier && storyBoardFileFromSpecifier.length > 0 ? storyBoardFileFromSpecifier : @"MainStoryboard";
storyBoardFileFromSpecifier = storyBoardFileFromSpecifier && storyBoardFileFromSpecifier.length > 0 ? storyBoardFileFromSpecifier : [[NSBundle mainBundle].infoDictionary objectForKey:@"UIMainStoryboardFile"];
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:storyBoardFileFromSpecifier bundle:nil];
UIViewController * vc = [storyBoard instantiateViewControllerWithIdentifier:[specifier viewControllerStoryBoardID]];
vc.view.tintColor = self.view.tintColor;
IASK_IF_IOS7_OR_GREATER(vc.view.tintColor = self.view.tintColor;)
[self.navigationController pushViewController:vc animated:YES];
return;
}
@ -656,7 +692,7 @@ CGRect IASKCGRectSwap(CGRect rect);
if ([vc respondsToSelector:@selector(setSettingsStore:)]) {
[vc performSelector:@selector(setSettingsStore:) withObject:self.settingsStore];
}
vc.view.tintColor = self.view.tintColor;
IASK_IF_IOS7_OR_GREATER(vc.view.tintColor = self.view.tintColor;)
[self.navigationController pushViewController:vc animated:YES];
return;
}
@ -676,17 +712,16 @@ CGRect IASKCGRectSwap(CGRect rect);
targetViewController.file = specifier.file;
targetViewController.hiddenKeys = self.hiddenKeys;
targetViewController.title = specifier.title;
targetViewController.view.tintColor = self.view.tintColor;
IASK_IF_IOS7_OR_GREATER(targetViewController.view.tintColor = self.view.tintColor;)
_currentChildViewController = targetViewController;
_reloadDisabled = NO;
[self.tableView reloadData];
[[self navigationController] pushViewController:targetViewController animated:YES];
} else if ([[specifier type] isEqualToString:kIASKOpenURLSpecifier]) {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:specifier.file]];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[specifier localizedObjectForKey:kIASKFile]]];
} else if ([[specifier type] isEqualToString:kIASKButtonSpecifier]) {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if ([self.delegate respondsToSelector:@selector(settingsViewController:buttonTappedForSpecifier:)]) {
@ -713,7 +748,7 @@ CGRect IASKCGRectSwap(CGRect rect);
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *mailViewController = [[MFMailComposeViewController alloc] init];
mailViewController.navigationBar.barStyle = self.navigationController.navigationBar.barStyle;
mailViewController.navigationBar.tintColor = self.navigationController.navigationBar.tintColor;
IASK_IF_IOS7_OR_GREATER(mailViewController.navigationBar.tintColor = self.navigationController.navigationBar.tintColor;);
mailViewController.navigationBar.titleTextAttributes = self.navigationController.navigationBar.titleTextAttributes;
if ([specifier localizedObjectForKey:kIASKMailComposeSubject]) {
@ -772,6 +807,8 @@ CGRect IASKCGRectSwap(CGRect rect);
} else if ([[specifier type] isEqualToString:kIASKCustomViewSpecifier] && [self.delegate respondsToSelector:@selector(settingsViewController:tableView:didSelectCustomViewSpecifier:)]) {
[self.delegate settingsViewController:self tableView:tableView didSelectCustomViewSpecifier:specifier];
} else if ([[specifier type] isEqualToString:kIASKPSRadioGroupSpecifier]) {
[_selections[indexPath.section] selectRowAtIndexPath:indexPath];
} else {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
@ -830,28 +867,32 @@ CGRect IASKCGRectSwap(CGRect rect);
static NSDictionary *oldUserDefaults = nil;
- (void)userDefaultsDidChange {
NSDictionary *currentDict = [NSUserDefaults standardUserDefaults].dictionaryRepresentation;
NSMutableArray *indexPathsToUpdate = [NSMutableArray array];
for (NSString *key in currentDict.allKeys) {
if (![[oldUserDefaults valueForKey:key] isEqual:[currentDict valueForKey:key]]) {
NSIndexPath *path = [self.settingsReader indexPathForKey:key];
if (path && ![[self.settingsReader specifierForKey:key].type isEqualToString:kIASKCustomViewSpecifier]) {
[indexPathsToUpdate addObject:path];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSDictionary *currentDict = [NSUserDefaults standardUserDefaults].dictionaryRepresentation;
NSMutableArray *indexPathsToUpdate = [NSMutableArray array];
for (NSString *key in currentDict.allKeys) {
if (oldUserDefaults && ![[oldUserDefaults valueForKey:key] isEqual:[currentDict valueForKey:key]]) {
NSIndexPath *path = [self.settingsReader indexPathForKey:key];
if (path && ![[self.settingsReader specifierForKey:key].type isEqualToString:kIASKCustomViewSpecifier] && [self.tableView.indexPathsForVisibleRows containsObject:path]) {
[indexPathsToUpdate addObject:path];
}
}
}
}
oldUserDefaults = currentDict;
for (UITableViewCell *cell in self.tableView.visibleCells) {
if ([cell isKindOfClass:[IASKPSTextFieldSpecifierViewCell class]] && [((IASKPSTextFieldSpecifierViewCell*)cell).textField isFirstResponder]) {
[indexPathsToUpdate removeObject:[self.tableView indexPathForCell:cell]];
oldUserDefaults = currentDict;
for (UITableViewCell *cell in self.tableView.visibleCells) {
if ([cell isKindOfClass:[IASKPSTextFieldSpecifierViewCell class]] && [((IASKPSTextFieldSpecifierViewCell*)cell).textField isFirstResponder]) {
[indexPathsToUpdate removeObject:[self.tableView indexPathForCell:cell]];
}
}
}
if (indexPathsToUpdate.count) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.tableView reloadRowsAtIndexPaths:indexPathsToUpdate withRowAnimation:UITableViewRowAnimationNone];
});
}
if (indexPathsToUpdate.count) {
[self.tableView reloadRowsAtIndexPaths:indexPathsToUpdate withRowAnimation:UITableViewRowAnimationAutomatic];
}
});
}
- (void)didChangeSettingViaIASK:(NSNotification*)notification {
[oldUserDefaults setValue:[self.settingsStore objectForKey:notification.object] forKey:notification.object];
}
- (void)reload {

View file

@ -54,10 +54,6 @@
[self.webView loadRequest:[NSURLRequest requestWithURL:self.url]];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
self.navigationItem.rightBarButtonItem = nil;
self.title = self.customTitle.length ? self.customTitle : [self.webView stringByEvaluatingJavaScriptFromString:@"document.title"];
@ -127,7 +123,7 @@
[mailViewController setToRecipients:toRecipients];
mailViewController.navigationBar.barStyle = self.navigationController.navigationBar.barStyle;
mailViewController.navigationBar.tintColor = self.navigationController.navigationBar.tintColor;
IASK_IF_IOS7_OR_GREATER(mailViewController.navigationBar.tintColor = self.navigationController.navigationBar.tintColor;);
mailViewController.navigationBar.titleTextAttributes = self.navigationController.navigationBar.titleTextAttributes;
UIStatusBarStyle savedStatusBarStyle = [UIApplication sharedApplication].statusBarStyle;

View file

@ -0,0 +1,19 @@
#import <UIKit/UIKit.h>
@class IASKSpecifier;
@protocol IASKSettingsStore;
/// Encapsulates the selection among multiple values.
/// This is used for PSMultiValueSpecifier and PSRadioGroupSpecifier
@interface IASKMultipleValueSelection : NSObject
@property (nonatomic, assign) UITableView *tableView;
@property (nonatomic, retain) IASKSpecifier *specifier;
@property (nonatomic, assign) NSInteger section;
@property (nonatomic, copy, readonly) NSIndexPath *checkedItem;
@property (nonatomic, strong) id<IASKSettingsStore> settingsStore;
- (void)selectRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)updateSelectionInCell:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath;
@end

View file

@ -0,0 +1,110 @@
#import "IASKMultipleValueSelection.h"
#import "IASKSettingsStore.h"
#import "IASKSettingsStoreUserDefaults.h"
#import "IASKSpecifier.h"
#import "IASKSettingsReader.h"
@implementation IASKMultipleValueSelection {
NSInteger _checkedIndex;
}
- (instancetype)init {
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(userDefaultsDidChange)
name:NSUserDefaultsDidChangeNotification
object:[NSUserDefaults standardUserDefaults]];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUserDefaultsDidChangeNotification object:nil];
}
- (void)setSpecifier:(IASKSpecifier *)specifier {
_specifier = specifier;
[self updateCheckedItem];
}
- (NSIndexPath *)checkedItem {
return [NSIndexPath indexPathForRow:_checkedIndex inSection:_section];;
}
- (void)updateCheckedItem {
// Find the currently checked item
id value = [self.settingsStore objectForKey:[_specifier key]];
if (!value) {
value = [_specifier defaultValue];
}
_checkedIndex = [[_specifier multipleValues] indexOfObject:value];
}
- (id<IASKSettingsStore>)settingsStore {
if (_settingsStore == nil) {
_settingsStore = [[IASKSettingsStoreUserDefaults alloc] init];
}
return _settingsStore;
}
#pragma mark - selection
- (void)selectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath == self.checkedItem) {
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
return;
}
NSArray *values = [_specifier multipleValues];
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
[self deselectCell:[self.tableView cellForRowAtIndexPath:self.checkedItem]];
[self selectCell:[self.tableView cellForRowAtIndexPath:indexPath]];
_checkedIndex = indexPath.row;
[self.settingsStore setObject:[values objectAtIndex:indexPath.row] forKey:[_specifier key]];
[self.settingsStore synchronize];
[[NSNotificationCenter defaultCenter] postNotificationName:kIASKAppSettingChanged
object:[_specifier key]
userInfo:@{
_specifier.key: values[indexPath.row]
}];
};
- (void)updateSelectionInCell:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath {
if ([indexPath isEqual:self.checkedItem]) {
[self selectCell:cell];
} else {
[self deselectCell:cell];
}
}
- (void)selectCell:(UITableViewCell *)cell {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
IASK_IF_PRE_IOS7([[cell textLabel] setTextColor:kIASKgrayBlueColor];);
}
- (void)deselectCell:(UITableViewCell *)cell {
[cell setAccessoryType:UITableViewCellAccessoryNone];
IASK_IF_PRE_IOS7([[cell textLabel] setTextColor:[UIColor darkTextColor]];);
}
#pragma mark Notifications
- (void)userDefaultsDidChange {
NSIndexPath *oldCheckedItem = self.checkedItem;
if (_specifier) {
[self updateCheckedItem];
}
// only reload the table if it had changed; prevents animation cancellation
if (![self.checkedItem isEqual:oldCheckedItem]) {
[self.tableView reloadData];
}
}
@end

View file

@ -24,13 +24,10 @@
UITableView *_tableView;
IASKSpecifier *_currentSpecifier;
NSIndexPath *_checkedItem;
IASKSettingsReader *_settingsReader;
id<IASKSettingsStore> _settingsStore;
}
@property (nonatomic, retain) UITableView *tableView;
@property (nonatomic, retain) NSIndexPath *checkedItem;
@property (nonatomic, retain) IASKSpecifier *currentSpecifier;
@end

View file

@ -17,39 +17,26 @@
#import "IASKSpecifierValuesViewController.h"
#import "IASKSpecifier.h"
#import "IASKSettingsReader.h"
#import "IASKSettingsStoreUserDefaults.h"
#import "IASKMultipleValueSelection.h"
#define kCellValue @"kCellValue"
@interface IASKSpecifierValuesViewController()
- (void)userDefaultsDidChange;
@property (nonatomic, strong, readonly) IASKMultipleValueSelection *selection;
@end
@implementation IASKSpecifierValuesViewController
@synthesize tableView=_tableView;
@synthesize currentSpecifier=_currentSpecifier;
@synthesize checkedItem=_checkedItem;
@synthesize settingsReader = _settingsReader;
@synthesize settingsStore = _settingsStore;
- (void) updateCheckedItem {
NSInteger index;
// Find the currently checked item
if([self.settingsStore objectForKey:[_currentSpecifier key]]) {
index = [[_currentSpecifier multipleValues] indexOfObject:[self.settingsStore objectForKey:[_currentSpecifier key]]];
} else {
index = [[_currentSpecifier multipleValues] indexOfObject:[_currentSpecifier defaultValue]];
}
[self setCheckedItem:[NSIndexPath indexPathForRow:index inSection:0]];
}
- (id<IASKSettingsStore>)settingsStore {
if(_settingsStore == nil) {
_settingsStore = [[IASKSettingsStoreUserDefaults alloc] init];
}
return _settingsStore;
- (void)setSettingsStore:(id <IASKSettingsStore>)settingsStore {
_settingsStore = settingsStore;
_selection.settingsStore = settingsStore;
}
- (void)loadView
@ -61,19 +48,24 @@
_tableView.dataSource = self;
self.view = _tableView;
_selection = [IASKMultipleValueSelection new];
_selection.tableView = _tableView;
_selection.settingsStore = _settingsStore;
}
- (void)viewWillAppear:(BOOL)animated {
if (_currentSpecifier) {
[self setTitle:[_currentSpecifier title]];
[self updateCheckedItem];
_selection.specifier = _currentSpecifier;
}
if (_tableView) {
[_tableView reloadData];
// Make sure the currently checked item is visible
[_tableView scrollToRowAtIndexPath:[self checkedItem] atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
[_tableView scrollToRowAtIndexPath:_selection.checkedItem
atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
}
[super viewWillAppear:animated];
}
@ -81,20 +73,11 @@
- (void)viewDidAppear:(BOOL)animated {
[_tableView flashScrollIndicators];
[super viewDidAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(userDefaultsDidChange)
name:NSUserDefaultsDidChangeNotification
object:[NSUserDefaults standardUserDefaults]];
}
- (void)viewDidDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUserDefaultsDidChangeNotification object:nil];
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
_selection.tableView = nil;
}
- (void)didReceiveMemoryWarning {
@ -104,13 +87,6 @@
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.tableView = nil;
}
#pragma mark -
#pragma mark UITableView delegates
@ -122,16 +98,6 @@
return [_currentSpecifier multipleValuesCount];
}
- (void)selectCell:(UITableViewCell *)cell {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
IASK_IF_PRE_IOS7([[cell textLabel] setTextColor:kIASKgrayBlueColor];);
}
- (void)deselectCell:(UITableViewCell *)cell {
[cell setAccessoryType:UITableViewCellAccessoryNone];
IASK_IF_PRE_IOS7([[cell textLabel] setTextColor:[UIColor darkTextColor]];);
}
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
return [_currentSpecifier footerText];
}
@ -143,14 +109,10 @@
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellValue];
}
if ([indexPath isEqual:[self checkedItem]]) {
[self selectCell:cell];
} else {
[self deselectCell:cell];
}
@try {
[_selection updateSelectionInCell:cell indexPath:indexPath];
@try {
[[cell textLabel] setText:[self.settingsReader titleForStringId:[titles objectAtIndex:indexPath.row]]];
}
@catch (NSException * e) {}
@ -158,44 +120,11 @@
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath == [self checkedItem]) {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
return;
}
NSArray *values = [_currentSpecifier multipleValues];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[self deselectCell:[tableView cellForRowAtIndexPath:[self checkedItem]]];
[self selectCell:[tableView cellForRowAtIndexPath:indexPath]];
[self setCheckedItem:indexPath];
[self.settingsStore setObject:[values objectAtIndex:indexPath.row] forKey:[_currentSpecifier key]];
[self.settingsStore synchronize];
[[NSNotificationCenter defaultCenter] postNotificationName:kIASKAppSettingChanged
object:[_currentSpecifier key]
userInfo:[NSDictionary dictionaryWithObject:[values objectAtIndex:indexPath.row]
forKey:[_currentSpecifier key]]];
[_selection selectRowAtIndexPath:indexPath];
}
- (CGSize)contentSizeForViewInPopover {
return [[self view] sizeThatFits:CGSizeMake(320, 2000)];
}
#pragma mark Notifications
- (void)userDefaultsDidChange {
NSIndexPath *oldCheckedItem = self.checkedItem;
if(_currentSpecifier) {
[self updateCheckedItem];
}
// only reload the table if it had changed; prevents animation cancellation
if (![self.checkedItem isEqual:oldCheckedItem]) {
[_tableView reloadData];
}
}
@end

View file

@ -37,6 +37,8 @@
#define kIASKValues @"Values"
#define kIASKTitles @"Titles"
#define kIASKShortTitles @"ShortTitles"
#define kIASKSupportedUserInterfaceIdioms @"SupportedUserInterfaceIdioms"
#define kIASKSubtitle @"IASKSubtitle"
#define kIASKViewControllerClass @"IASKViewControllerClass"
#define kIASKViewControllerSelector @"IASKViewControllerSelector"
#define kIASKViewControllerStoryBoardFile @"IASKViewControllerStoryBoardFile"
@ -77,6 +79,7 @@
#define kIASKPSGroupSpecifier @"PSGroupSpecifier"
#define kIASKPSToggleSwitchSpecifier @"PSToggleSwitchSpecifier"
#define kIASKPSMultiValueSpecifier @"PSMultiValueSpecifier"
#define kIASKPSRadioGroupSpecifier @"PSRadioGroupSpecifier"
#define kIASKPSSliderSpecifier @"PSSliderSpecifier"
#define kIASKPSTitleValueSpecifier @"PSTitleValueSpecifier"
#define kIASKPSTextFieldSpecifier @"PSTextFieldSpecifier"
@ -96,10 +99,9 @@
#define kIASKSectionHeaderIndex 0
#define kIASKSliderNoImagesPadding 11
#define kIASKSliderImagesPadding 43
#define kIASKSliderImageGap 10
#define kIASKSpacing 5
#define kIASKSpacing 8
#define kIASKMinLabelWidth 97
#define kIASKMaxLabelWidth 240
#define kIASKMinValueWidth 35
@ -121,6 +123,10 @@
#define kCFCoreFoundationVersionNumber_iOS_7_0 843.00
#endif
#ifndef kCFCoreFoundationVersionNumber_iOS_8_0
#define kCFCoreFoundationVersionNumber_iOS_8_0 1129.150000
#endif
#ifdef __IPHONE_6_0
#define IASK_IF_IOS6_OR_GREATER(...) \
if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_6_0) \
@ -167,6 +173,16 @@ _Pragma("clang diagnostic pop")
#define IASK_IF_PRE_IOS7(...) __VA_ARGS__
#endif
#ifdef __IPHONE_8_0
#define IASK_IF_IOS8_OR_GREATER(...) \
if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_8_0) \
{ \
__VA_ARGS__ \
}
#else
#define IASK_IF_IOS8_OR_GREATER(...)
#endif
@class IASKSpecifier;
@ -193,6 +209,7 @@ _Pragma("clang diagnostic pop")
- (NSInteger)numberOfSections;
- (NSInteger)numberOfRowsForSection:(NSInteger)section;
- (IASKSpecifier*)specifierForIndexPath:(NSIndexPath*)indexPath;
- (IASKSpecifier *)headerSpecifierForSection:(NSInteger)section;
- (NSIndexPath*)indexPathForKey:(NSString*)key;
- (IASKSpecifier*)specifierForKey:(NSString*)key;
- (NSString*)titleForSection:(NSInteger)section;
@ -214,6 +231,7 @@ _Pragma("clang diagnostic pop")
@property (nonatomic, retain) NSString *localizationTable;
@property (nonatomic, retain) NSArray *dataSource;
@property (nonatomic, retain) NSSet *hiddenKeys;
@property (nonatomic) BOOL showPrivacySettings;
#pragma mark - internal use. public only for testing

View file

@ -51,7 +51,21 @@
self.localizationTable = @"Root";
}
}
self.showPrivacySettings = NO;
IASK_IF_IOS8_OR_GREATER
(
NSArray *privacyRelatedInfoPlistKeys = @[@"NSBluetoothPeripheralUsageDescription", @"NSCalendarsUsageDescription", @"NSCameraUsageDescription", @"NSContactsUsageDescription", @"NSLocationAlwaysUsageDescription", @"NSLocationUsageDescription", @"NSLocationWhenInUseUsageDescription", @"NSMicrophoneUsageDescription", @"NSMotionUsageDescription", @"NSPhotoLibraryUsageDescription", @"NSRemindersUsageDescription", @"NSHealthShareUsageDescription", @"NSHealthUpdateUsageDescription"];
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
if ([fileName isEqualToString:@"Root"]) {
for (NSString* key in privacyRelatedInfoPlistKeys) {
if (infoDictionary[key]) {
self.showPrivacySettings = YES;
break;
}
}
}
);
if (self.settingsDictionary) {
[self _reinterpretBundle:self.settingsDictionary];
}
@ -77,43 +91,92 @@
}
}
- (void)setShowPrivacySettings:(BOOL)showPrivacySettings {
if (_showPrivacySettings != showPrivacySettings) {
_showPrivacySettings = showPrivacySettings;
[self _reinterpretBundle:self.settingsDictionary];
}
}
- (NSArray*)privacySettingsSpecifiers {
NSMutableDictionary *dict = [@{kIASKTitle: NSLocalizedStringFromTable(@"Privacy", @"IASKLocalizable", @"iOS 8+ Privacy cell: title"),
kIASKKey: @"IASKPrivacySettingsCellKey",
kIASKType: kIASKOpenURLSpecifier,
kIASKFile: UIApplicationOpenSettingsURLString,
} mutableCopy];
NSString *subtitle = NSLocalizedStringWithDefaultValue(@"Open in Settings app", @"IASKLocalizable", [NSBundle mainBundle], @"", @"iOS 8+ Privacy cell: subtitle");
if (subtitle.length) {
dict [kIASKSubtitle] = subtitle;
}
return @[@[[[IASKSpecifier alloc] initWithSpecifier:@{kIASKKey: @"IASKPrivacySettingsHeaderKey", kIASKType: kIASKPSGroupSpecifier}],
[[IASKSpecifier alloc] initWithSpecifier:dict]]];
}
- (void)_reinterpretBundle:(NSDictionary*)settingsBundle {
NSArray *preferenceSpecifiers = [settingsBundle objectForKey:kIASKPreferenceSpecifiers];
NSInteger sectionCount = -1;
NSMutableArray *dataSource = [NSMutableArray new];
for (NSDictionary *specifier in preferenceSpecifiers) {
if ([self.hiddenKeys containsObject:[specifier objectForKey:kIASKKey]]) {
NSMutableArray *dataSource = [NSMutableArray array];
if (self.showPrivacySettings) {
IASK_IF_IOS8_OR_GREATER
(
[dataSource addObjectsFromArray:self.privacySettingsSpecifiers];
);
}
for (NSDictionary *specifierDictionary in preferenceSpecifiers) {
IASKSpecifier *newSpecifier = [[IASKSpecifier alloc] initWithSpecifier:specifierDictionary];
newSpecifier.settingsReader = self;
if ([self.hiddenKeys containsObject:newSpecifier.key]) {
continue;
}
if ([(NSString*)[specifier objectForKey:kIASKType] isEqualToString:kIASKPSGroupSpecifier]) {
NSMutableArray *newArray = [[NSMutableArray alloc] init];
[newArray addObject:specifier];
NSString *type = newSpecifier.type;
if ([type isEqualToString:kIASKPSGroupSpecifier]
|| [type isEqualToString:kIASKPSRadioGroupSpecifier]) {
NSMutableArray *newArray = [NSMutableArray array];
[newArray addObject:newSpecifier];
[dataSource addObject:newArray];
sectionCount++;
if ([type isEqualToString:kIASKPSRadioGroupSpecifier]) {
for (NSString *value in newSpecifier.multipleValues) {
IASKSpecifier *valueSpecifier =
[[IASKSpecifier alloc] initWithSpecifier:specifierDictionary radioGroupValue:value];
valueSpecifier.settingsReader = self;
[newArray addObject:valueSpecifier];
}
}
}
else {
if (sectionCount == -1) {
NSMutableArray *newArray = [[NSMutableArray alloc] init];
[dataSource addObject:newArray];
sectionCount++;
if (dataSource.count == 0 || (dataSource.count == 1 && self.showPrivacySettings)) {
[dataSource addObject:[NSMutableArray array]];
}
IASKSpecifier *newSpecifier = [[IASKSpecifier alloc] initWithSpecifier:specifier];
[(NSMutableArray*)[dataSource objectAtIndex:sectionCount] addObject:newSpecifier];
if ([newSpecifier.userInterfaceIdioms containsObject:@(UI_USER_INTERFACE_IDIOM())]) {
[(NSMutableArray*)dataSource.lastObject addObject:newSpecifier];
}
}
}
[self setDataSource:dataSource];
}
- (BOOL)_sectionHasHeading:(NSInteger)section {
return [[[[self dataSource] objectAtIndex:section] objectAtIndex:0] isKindOfClass:[NSDictionary class]];
return [self headerSpecifierForSection:section] != nil;
}
/// Returns the specifier describing the section's header, or nil if there is no header.
- (IASKSpecifier *)headerSpecifierForSection:(NSInteger)section {
IASKSpecifier *specifier = self.dataSource[section][kIASKSectionHeaderIndex];
if ([specifier.type isEqualToString:kIASKPSGroupSpecifier]
|| [specifier.type isEqualToString:kIASKPSRadioGroupSpecifier]) {
return specifier;
}
return nil;
}
- (NSInteger)numberOfSections {
return [[self dataSource] count];
return self.dataSource.count;
}
- (NSInteger)numberOfRowsForSection:(NSInteger)section {
@ -157,26 +220,15 @@
}
- (NSString*)titleForSection:(NSInteger)section {
if ([self _sectionHasHeading:section]) {
NSDictionary *dict = [[[self dataSource] objectAtIndex:section] objectAtIndex:kIASKSectionHeaderIndex];
return [self titleForStringId:[dict objectForKey:kIASKTitle]];
}
return nil;
return [self titleForStringId:[self headerSpecifierForSection:section].title];
}
- (NSString*)keyForSection:(NSInteger)section {
if ([self _sectionHasHeading:section]) {
return [[[[self dataSource] objectAtIndex:section] objectAtIndex:kIASKSectionHeaderIndex] objectForKey:kIASKKey];
}
return nil;
return [self headerSpecifierForSection:section].key;
}
- (NSString*)footerTextForSection:(NSInteger)section {
if ([self _sectionHasHeading:section]) {
NSDictionary *dict = [[[self dataSource] objectAtIndex:section] objectAtIndex:kIASKSectionHeaderIndex];
return [self titleForStringId:[dict objectForKey:kIASKFooterText]];
}
return nil;
return [self titleForStringId:[self headerSpecifierForSection:section].footerText];
}
- (NSString*)titleForStringId:(NSString*)stringId {
@ -200,11 +252,9 @@
suffix:(NSString *)suffix
extension:(NSString *)extension {
NSString *appBundlePath = [self.applicationBundle bundlePath];
bundle = [appBundlePath stringByAppendingPathComponent:bundle];
bundle = [self.applicationBundle pathForResource:bundle ofType:nil];
file = [file stringByAppendingFormat:@"%@%@", suffix, extension];
return [bundle stringByAppendingPathComponent:file];
}
- (NSString *)locateSettingsFile: (NSString *)file {
@ -242,8 +292,10 @@
NSArray *plattformSuffixes = @[[self platformSuffixForInterfaceIdiom:UI_USER_INTERFACE_IDIOM()],
@""];
NSArray *languageFolders = @[[[[NSLocale preferredLanguages] objectAtIndex:0] stringByAppendingString:kIASKBundleLocaleFolderExtension],
NSArray *preferredLanguages = [NSLocale preferredLanguages];
NSArray *languageFolders = @[[ (preferredLanguages.count ? [preferredLanguages objectAtIndex:0] : @"en") stringByAppendingString:kIASKBundleLocaleFolderExtension],
@""];
NSString *path = nil;
NSFileManager *fileManager = [NSFileManager defaultManager];

View file

@ -25,8 +25,13 @@
@property (nonatomic, weak) IASKSettingsReader *settingsReader;
- (id)initWithSpecifier:(NSDictionary*)specifier;
/// A specifier for one entry in a radio group preceeded by a radio group specifier.
- (id)initWithSpecifier:(NSDictionary *)specifier
radioGroupValue:(NSString *)radioGroupValue;
- (NSString*)localizedObjectForKey:(NSString*)key;
- (NSString*)title;
- (NSString*)subtitle;
- (NSString*)key;
- (NSString*)type;
- (NSString*)titleForCurrentValue:(id)currentValue;
@ -58,4 +63,6 @@
- (UIImage *)highlightedCellImage;
- (BOOL)adjustsFontSizeToFitWidth;
- (NSTextAlignment)textAlignment;
- (NSArray *)userInterfaceIdioms;
- (NSString *)radioGroupValue;
@end

View file

@ -21,6 +21,7 @@
@interface IASKSpecifier ()
@property (nonatomic, retain) NSDictionary *multipleValuesDict;
@property (nonatomic, copy) NSString *radioGroupValue;
@end
@ -29,16 +30,32 @@
- (id)initWithSpecifier:(NSDictionary*)specifier {
if ((self = [super init])) {
[self setSpecifierDict:specifier];
if ([[self type] isEqualToString:kIASKPSMultiValueSpecifier] ||
[[self type] isEqualToString:kIASKPSTitleValueSpecifier]) {
[self _reinterpretValues:[self specifierDict]];
if ([self isMultiValueSpecifierType]) {
[self updateMultiValuesDict];
}
}
return self;
}
- (void)_reinterpretValues:(NSDictionary*)specifierDict {
- (BOOL)isMultiValueSpecifierType {
static NSArray *types = nil;
if (!types) {
types = @[kIASKPSMultiValueSpecifier, kIASKPSTitleValueSpecifier, kIASKPSRadioGroupSpecifier];
}
return [types containsObject:[self type]];
}
- (id)initWithSpecifier:(NSDictionary *)specifier
radioGroupValue:(NSString *)radioGroupValue {
self = [self initWithSpecifier:specifier];
if (self) {
self.radioGroupValue = radioGroupValue;
}
return self;
}
- (void)updateMultiValuesDict {
NSArray *values = [_specifierDict objectForKey:kIASKValues];
NSArray *titles = [_specifierDict objectForKey:kIASKTitles];
NSArray *shortTitles = [_specifierDict objectForKey:kIASKShortTitles];
@ -67,13 +84,28 @@
return [self localizedObjectForKey:kIASKTitle];
}
- (NSString*)subtitle {
return [self localizedObjectForKey:kIASKSubtitle];
}
- (NSString*)footerText {
return [self localizedObjectForKey:kIASKFooterText];
}
- (Class)viewControllerClass {
[IASKAppSettingsWebViewController class]; // make sure this is linked into the binary/library
return NSClassFromString([_specifierDict objectForKey:kIASKViewControllerClass]);
[IASKAppSettingsWebViewController class]; // make sure this is linked into the binary/library
return [self classFromString:([_specifierDict objectForKey:kIASKViewControllerClass])];
}
- (Class)classFromString:(NSString *)className {
Class class = NSClassFromString(className);
if (!class) {
// if the class doesn't exist as a pure Obj-C class then try to retrieve it as a Swift class.
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
NSString *classStringName = [NSString stringWithFormat:@"_TtC%lu%@%lu%@", (unsigned long)appName.length, appName, (unsigned long)className.length, className];
class = NSClassFromString(classStringName);
}
return class;
}
- (SEL)viewControllerSelector {
@ -277,7 +309,7 @@
- (NSTextAlignment)textAlignment
{
if ([[_specifierDict objectForKey:kIASKTextLabelAlignment] isEqualToString:kIASKTextLabelAlignmentLeft]) {
if (self.subtitle.length || [[_specifierDict objectForKey:kIASKTextLabelAlignment] isEqualToString:kIASKTextLabelAlignmentLeft]) {
return NSTextAlignmentLeft;
} else if ([[_specifierDict objectForKey:kIASKTextLabelAlignment] isEqualToString:kIASKTextLabelAlignmentCenter]) {
return NSTextAlignmentCenter;
@ -292,6 +324,22 @@
return NSTextAlignmentLeft;
}
- (NSArray *)userInterfaceIdioms {
NSArray *idiomStrings = _specifierDict[kIASKSupportedUserInterfaceIdioms];
if (idiomStrings.count == 0) {
return @[@(UIUserInterfaceIdiomPhone), @(UIUserInterfaceIdiomPad)];
}
NSMutableArray *idioms = [NSMutableArray new];
for (NSString *idiomString in idiomStrings) {
if ([idiomString isEqualToString:@"Phone"]) {
[idioms addObject:@(UIUserInterfaceIdiomPhone)];
} else if ([idiomString isEqualToString:@"Pad"]) {
[idioms addObject:@(UIUserInterfaceIdiomPad)];
}
}
return idioms;
}
- (id)valueForKey:(NSString *)key {
return [_specifierDict objectForKey:key];
}

View file

@ -0,0 +1,11 @@
/*
IASKLocalizable.strings
Where To
Created by Ortwin Gentz on 20.10.14.
Copyright (c) 2014 FutureTap. All rights reserved.
*/
"Privacy" = "Privacy"; // iOS 8+ Privacy cell: title
"Open in Settings app" = ""; // iOS 8+ Privacy cell: subtitle (TODO)

View file

@ -0,0 +1,11 @@
/*
IASKLocalizable.strings
Where To
Created by Ortwin Gentz on 20.10.14.
Copyright (c) 2014 FutureTap. All rights reserved.
*/
"Privacy" = "Datenschutz"; // iOS 8+ Privacy cell: title
"Open in Settings app" = "In “Einstellungen” App öffnen"; // iOS 8+ Privacy cell: subtitle

View file

@ -0,0 +1,11 @@
/*
IASKLocalizable.strings
Where To
Created by Ortwin Gentz on 20.10.14.
Copyright (c) 2014 FutureTap. All rights reserved.
*/
"Privacy" = "Απόρρητο"; // iOS 8+ Privacy cell: title
"Open in Settings app" = ""; // iOS 8+ Privacy cell: subtitle (TODO)

View file

@ -0,0 +1,11 @@
/*
IASKLocalizable.strings
Where To
Created by Ortwin Gentz on 20.10.14.
Copyright (c) 2014 FutureTap. All rights reserved.
*/
"Privacy" = "Privacy"; // iOS 8+ Privacy cell: title
"Open in Settings app" = "Open in “Settings” app"; // iOS 8+ Privacy cell: subtitle

View file

@ -0,0 +1,11 @@
/*
IASKLocalizable.strings
Where To
Created by Ortwin Gentz on 20.10.14.
Copyright (c) 2014 FutureTap. All rights reserved.
*/
"Privacy" = "Privacidad"; // iOS 8+ Privacy cell: title
"Open in Settings app" = ""; // iOS 8+ Privacy cell: subtitle (TODO!)

View file

@ -0,0 +1,11 @@
/*
IASKLocalizable.strings
Where To
Created by Ortwin Gentz on 20.10.14.
Copyright (c) 2014 FutureTap. All rights reserved.
*/
"Privacy" = "Confidentialité"; // iOS 8+ Privacy cell: title
"Open in Settings app" = ""; // iOS 8+ Privacy cell: subtitle (TODO!)

View file

@ -0,0 +1,11 @@
/*
IASKLocalizable.strings
Where To
Created by Ortwin Gentz on 20.10.14.
Copyright (c) 2014 FutureTap. All rights reserved.
*/
"Privacy" = "Privacy"; // iOS 8+ Privacy cell: title
"Open in Settings app" = ""; // iOS 8+ Privacy cell: subtitle (TODO)

View file

@ -0,0 +1,11 @@
/*
IASKLocalizable.strings
Where To
Created by Ortwin Gentz on 20.10.14.
Copyright (c) 2014 FutureTap. All rights reserved.
*/
"Privacy" = "プライバシー"; // iOS 8+ Privacy cell: title
"Open in Settings app" = ""; // iOS 8+ Privacy cell: subtitle (TODO)

View file

@ -0,0 +1,11 @@
/*
IASKLocalizable.strings
Where To
Created by Ortwin Gentz on 20.10.14.
Copyright (c) 2014 FutureTap. All rights reserved.
*/
"Privacy" = "Privacy"; // iOS 8+ Privacy cell: title
"Open in Settings app" = ""; // iOS 8+ Privacy cell: subtitle (TODO)

View file

@ -0,0 +1,11 @@
/*
IASKLocalizable.strings
Where To
Created by Ortwin Gentz on 20.10.14.
Copyright (c) 2014 FutureTap. All rights reserved.
*/
"Privacy" = "Privacidade"; // iOS 8+ Privacy cell: title
"Open in Settings app" = ""; // iOS 8+ Privacy cell: subtitle (TODO)

View file

@ -0,0 +1,11 @@
/*
IASKLocalizable.strings
Where To
Created by Ortwin Gentz on 20.10.14.
Copyright (c) 2014 FutureTap. All rights reserved.
*/
"Privacy" = "Privacidade"; // iOS 8+ Privacy cell: title
"Open in Settings app" = ""; // iOS 8+ Privacy cell: subtitle (TODO)

View file

@ -0,0 +1,11 @@
/*
IASKLocalizable.strings
Where To
Created by Ortwin Gentz on 20.10.14.
Copyright (c) 2014 FutureTap. All rights reserved.
*/
"Privacy" = "Приватность"; // iOS 8+ Privacy cell: title
"Open in Settings app" = ""; // iOS 8+ Privacy cell: subtitle (TODO)

View file

@ -0,0 +1,11 @@
/*
IASKLocalizable.strings
Where To
Created by Ortwin Gentz on 20.10.14.
Copyright (c) 2014 FutureTap. All rights reserved.
*/
"Privacy" = "Integritetsskydd"; // iOS 8+ Privacy cell: title
"Open in Settings app" = ""; // iOS 8+ Privacy cell: subtitle (TODO)

View file

@ -0,0 +1,11 @@
/*
IASKLocalizable.strings
Where To
Created by Ortwin Gentz on 20.10.14.
Copyright (c) 2014 FutureTap. All rights reserved.
*/
"Privacy" = "ความเป็นส่วนตัว"; // iOS 8+ Privacy cell: title
"Open in Settings app" = ""; // iOS 8+ Privacy cell: subtitle (TODO)

View file

@ -0,0 +1,11 @@
/*
IASKLocalizable.strings
Where To
Created by Ortwin Gentz on 20.10.14.
Copyright (c) 2014 FutureTap. All rights reserved.
*/
"Privacy" = "Gizlilik"; // iOS 8+ Privacy cell: title
"Open in Settings app" = ""; // iOS 8+ Privacy cell: subtitle (TODO)

View file

@ -51,13 +51,18 @@
- (void)layoutSubviews {
[super layoutSubviews];
UIEdgeInsets padding = (UIEdgeInsets) { 0, kIASKPaddingLeft, 0, kIASKPaddingRight };
if ([self respondsToSelector:@selector(layoutMargins)]) {
padding = [self layoutMargins];
}
CGRect sliderBounds = _slider.bounds;
CGPoint sliderCenter = _slider.center;
const CGFloat superViewWidth = _slider.superview.frame.size.width;
sliderCenter.x = superViewWidth / 2;
sliderBounds.size.width = superViewWidth - (padding.left + padding.right);
sliderCenter.x = padding.left + sliderBounds.size.width / 2;
sliderCenter.y = self.contentView.center.y;
sliderBounds.size.width = superViewWidth - kIASKSliderNoImagesPadding * 2;
_minImage.hidden = YES;
_maxImage.hidden = YES;
@ -65,18 +70,17 @@
if (_minImage.image) {
// Min image
_minImage.hidden = NO;
sliderCenter.x += (kIASKSliderImagesPadding - kIASKSliderNoImagesPadding) / 2;
sliderBounds.size.width -= (kIASKSliderImagesPadding - kIASKSliderNoImagesPadding);
_minImage.center = CGPointMake(_minImage.frame.size.width / 2 + kIASKPaddingLeft,
sliderBounds.size.width -= _minImage.frame.size.width + kIASKSliderImageGap;
sliderCenter.x += (_minImage.frame.size.width + kIASKSliderImageGap) / 2;
_minImage.center = CGPointMake(_minImage.frame.size.width / 2 + padding.left,
self.contentView.center.y);
}
if (_maxImage.image) {
// Max image
_maxImage.hidden = NO;
sliderCenter.x -= (kIASKSliderImagesPadding - kIASKSliderNoImagesPadding) / 2;
sliderBounds.size.width -= (kIASKSliderImagesPadding - kIASKSliderNoImagesPadding);
_maxImage.center = CGPointMake(self.contentView.bounds.size.width - _maxImage.frame.size.width / 2 - kIASKPaddingRight,
self.contentView.center.y);
sliderBounds.size.width -= kIASKSliderImageGap + _maxImage.frame.size.width;
sliderCenter.x -= (kIASKSliderImageGap + _maxImage.frame.size.width) / 2;
_maxImage.center = CGPointMake(superViewWidth - padding.right - _maxImage.frame.size.width /2, self.contentView.center.y );
}
_slider.bounds = sliderBounds;

View file

@ -28,7 +28,7 @@
// TextField
_textField = [[IASKTextField alloc] initWithFrame:CGRectMake(0, 0, 200, self.frame.size.height)];
_textField.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin;
_textField.font = [UIFont systemFontOfSize:17.0f];
_textField.font = [UIFont systemFontOfSize:kIASKLabelFontSize];
_textField.minimumFontSize = kIASKMinimumFontSize;
IASK_IF_PRE_IOS7(_textField.textColor = [UIColor colorWithRed:0.275f green:0.376f blue:0.522f alpha:1.000f];);
[self.contentView addSubview:_textField];
@ -41,8 +41,13 @@
- (void)layoutSubviews {
[super layoutSubviews];
UIEdgeInsets padding = (UIEdgeInsets) { 0, kIASKPaddingLeft, 0, kIASKPaddingRight };
if ([self respondsToSelector:@selector(layoutMargins)]) {
padding = [self layoutMargins];
}
// Label
CGFloat imageOffset = self.imageView.image ? self.imageView.bounds.size.width + kIASKPaddingLeft : 0;
CGFloat imageOffset = self.imageView.image ? self.imageView.bounds.size.width + padding.left : 0;
CGSize labelSize = [self.textLabel sizeThatFits:CGSizeZero];
labelSize.width = MAX(labelSize.width, kIASKMinLabelWidth - imageOffset);
self.textLabel.frame = (CGRect){self.textLabel.frame.origin, {MIN(kIASKMaxLabelWidth, labelSize.width), self.textLabel.frame.size.height}} ;
@ -51,14 +56,14 @@
_textField.center = CGPointMake(_textField.center.x, self.contentView.center.y);
CGRect textFieldFrame = _textField.frame;
textFieldFrame.origin.x = self.textLabel.frame.origin.x + MAX(kIASKMinLabelWidth - imageOffset, self.textLabel.frame.size.width) + kIASKSpacing;
textFieldFrame.size.width = _textField.superview.frame.size.width - textFieldFrame.origin.x - kIASKPaddingRight;
textFieldFrame.size.width = _textField.superview.frame.size.width - textFieldFrame.origin.x - padding.right;
if (!self.textLabel.text.length) {
textFieldFrame.origin.x = kIASKPaddingLeft + imageOffset;
textFieldFrame.size.width = self.contentView.bounds.size.width - 2* kIASKPaddingLeft - imageOffset;
textFieldFrame.origin.x = padding.left + imageOffset;
textFieldFrame.size.width = self.contentView.bounds.size.width - padding.left - padding.right - imageOffset;
} else if (_textField.textAlignment == NSTextAlignmentRight) {
textFieldFrame.origin.x = self.textLabel.frame.origin.x + labelSize.width + kIASKSpacing;
textFieldFrame.size.width = _textField.superview.frame.size.width - textFieldFrame.origin.x - kIASKPaddingRight;
textFieldFrame.size.width = _textField.superview.frame.size.width - textFieldFrame.origin.x - padding.right;
}
_textField.frame = textFieldFrame;
}