Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
805 | - | 1 | // |
2 | // InAppSettingsViewController.m |
||
3 | // InAppSettings |
||
4 | // |
||
5 | // Created by David Keegan on 11/21/09. |
||
6 | // Copyright 2009 InScopeApps{+}. All rights reserved. |
||
7 | // |
||
8 | |||
9 | #import "InAppSettings.h" |
||
10 | #import "InAppSettingsConstants.h" |
||
11 | #import "InAppSettingsPSMultiValueSpecifierTable.h" |
||
12 | |||
13 | @implementation InAppSettings |
||
14 | |||
15 | + (void) registerDefaults { |
||
16 | [[[InAppSettingsReaderRegisterDefaults alloc] init] release]; |
||
17 | } |
||
18 | |||
19 | @end |
||
20 | |||
21 | @implementation InAppSettingsModalViewController |
||
22 | |||
23 | - (id) init { |
||
24 | InAppSettingsViewController * settings = [[InAppSettingsViewController alloc] init]; |
||
25 | |||
26 | self = [[UINavigationController alloc] initWithRootViewController:settings]; |
||
27 | [settings addDoneButton]; |
||
28 | [settings release]; |
||
29 | return self; |
||
30 | } |
||
31 | |||
32 | @end |
||
33 | |||
34 | @implementation InAppSettingsViewController |
||
35 | |||
36 | @synthesize file; |
||
37 | @synthesize settingsTableView; |
||
38 | @synthesize firstResponder; |
||
39 | @synthesize settingsReader; |
||
40 | @synthesize delegate; |
||
41 | @synthesize dataSource; |
||
42 | |||
43 | |||
44 | #pragma mark modal view |
||
45 | |||
46 | - (void) dismissModalView { |
||
47 | [self.navigationController dismissModalViewControllerAnimated:YES]; |
||
48 | } |
||
49 | |||
50 | - (void) addDoneButton { |
||
51 | UIBarButtonItem * doneButton = [[UIBarButtonItem alloc] |
||
52 | initWithBarButtonSystemItem:UIBarButtonSystemItemDone |
||
53 | target:self |
||
54 | action:@selector(dismissModalView)]; |
||
55 | |||
56 | self.navigationItem.rightBarButtonItem = doneButton; |
||
57 | [doneButton release]; |
||
58 | } |
||
59 | |||
60 | #pragma mark setup view |
||
61 | |||
62 | - (id) initWithFile:(NSString *)inputFile { |
||
63 | self = [super init]; |
||
64 | if (self != nil) { |
||
65 | self.file = inputFile; |
||
66 | } |
||
67 | return self; |
||
68 | } |
||
69 | |||
70 | - (void) viewDidLoad { |
||
71 | // setup the table |
||
72 | self.settingsTableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; |
||
73 | self.settingsTableView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); |
||
74 | self.settingsTableView.delegate = self; |
||
75 | self.settingsTableView.dataSource = self; |
||
76 | [self.view addSubview:self.settingsTableView]; |
||
77 | |||
78 | // if the title is nil set it to Settings |
||
79 | if (!self.title) { |
||
80 | self.title = NSLocalizedString(@"Settings", nil); |
||
81 | } |
||
82 | |||
83 | // load settigns plist |
||
84 | if (!self.file) { |
||
85 | self.file = InAppSettingsRootFile; |
||
86 | } |
||
87 | |||
88 | InAppSettingsReader* tmpSettingsReader = [[InAppSettingsReader alloc] initWithFile:self.file dataSource:dataSource]; |
||
89 | self.settingsReader = tmpSettingsReader; |
||
90 | [tmpSettingsReader release]; |
||
91 | |||
92 | |||
93 | // setup keyboard notification |
||
94 | self.firstResponder = nil; |
||
95 | [self registerForKeyboardNotifications]; |
||
96 | } |
||
97 | |||
98 | - (void) viewWillAppear:(BOOL)animated { |
||
99 | self.firstResponder = nil; |
||
100 | |||
101 | self.settingsTableView.contentInset = UIEdgeInsetsZero; |
||
102 | self.settingsTableView.scrollIndicatorInsets = UIEdgeInsetsZero; |
||
103 | |||
104 | [self.settingsTableView reloadData]; |
||
105 | [super viewWillAppear:animated]; |
||
106 | } |
||
107 | |||
108 | - (void) viewWillDisappear:(BOOL)animated { |
||
109 | self.firstResponder = nil; |
||
110 | [super viewWillDisappear:animated]; |
||
111 | } |
||
112 | |||
113 | - (void) dealloc { |
||
114 | self.firstResponder = nil; |
||
115 | self.delegate = nil; |
||
116 | |||
117 | [file release]; |
||
118 | [settingsTableView release]; |
||
119 | [settingsReader release]; |
||
120 | [super dealloc]; |
||
121 | } |
||
122 | |||
123 | #pragma mark text field cell delegate |
||
124 | |||
125 | - (void) textFieldDidBeginEditing:(UITextField *)cellTextField { |
||
126 | self.firstResponder = cellTextField; |
||
127 | |||
128 | // TODO: find a better way to get the cell from the text view |
||
129 | NSIndexPath * indexPath = [self.settingsTableView indexPathForCell:(UITableViewCell *)[[cellTextField superview] superview]]; |
||
130 | [self.settingsTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; |
||
131 | } |
||
132 | |||
133 | - (BOOL) textFieldShouldReturn:(UITextField *)cellTextField { |
||
134 | self.firstResponder = nil; |
||
135 | [cellTextField resignFirstResponder]; |
||
136 | return YES; |
||
137 | } |
||
138 | |||
139 | #pragma mark keyboard notification |
||
140 | |||
141 | - (void) registerForKeyboardNotifications { |
||
142 | [[NSNotificationCenter defaultCenter] addObserver:self |
||
143 | selector:@selector(keyboardWillShow:) |
||
144 | name:UIKeyboardWillShowNotification object:nil]; |
||
145 | |||
146 | [[NSNotificationCenter defaultCenter] addObserver:self |
||
147 | selector:@selector(keyboardWillHide:) |
||
148 | name:UIKeyboardWillHideNotification object:nil]; |
||
149 | } |
||
150 | |||
151 | - (void) keyboardWillShow:(NSNotification *)notification { |
||
152 | if (self.firstResponder == nil) { |
||
153 | // get the keybaord rect |
||
154 | CGRect keyboardRect = [[[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue]; |
||
155 | |||
156 | // determin the bottom inset for the table view |
||
157 | UIEdgeInsets settingsTableInset = self.settingsTableView.contentInset; |
||
158 | CGPoint tableViewScreenSpace = [self.settingsTableView.superview convertPoint:self.settingsTableView.frame.origin toView:nil]; |
||
159 | CGFloat tableViewBottomOffset = InAppSettingsScreenHeight - (tableViewScreenSpace.y + self.settingsTableView.frame.size.height); |
||
160 | settingsTableInset.bottom = keyboardRect.size.height - tableViewBottomOffset; |
||
161 | |||
162 | [UIView beginAnimations:nil context:nil]; |
||
163 | [UIView setAnimationDuration:InAppSettingsKeyboardAnimation]; |
||
164 | [UIView setAnimationBeginsFromCurrentState:YES]; |
||
165 | self.settingsTableView.contentInset = settingsTableInset; |
||
166 | self.settingsTableView.scrollIndicatorInsets = settingsTableInset; |
||
167 | [UIView commitAnimations]; |
||
168 | } |
||
169 | } |
||
170 | |||
171 | - (void) keyboardWillHide:(NSNotification *)notification { |
||
172 | if (self.firstResponder == nil) { |
||
173 | [UIView beginAnimations:nil context:nil]; |
||
174 | [UIView setAnimationDuration:InAppSettingsKeyboardAnimation]; |
||
175 | [UIView setAnimationBeginsFromCurrentState:YES]; |
||
176 | self.settingsTableView.contentInset = UIEdgeInsetsZero; |
||
177 | self.settingsTableView.scrollIndicatorInsets = UIEdgeInsetsZero; |
||
178 | [UIView commitAnimations]; |
||
179 | } |
||
180 | } |
||
181 | |||
182 | #pragma mark specifier delegate |
||
183 | |||
184 | - (void) settingsSpecifierUpdated:(InAppSettingsSpecifier *)specifier { |
||
185 | if ([self.delegate respondsToSelector:@selector(InAppSettingsValue:forKey:)]) { |
||
186 | [self.delegate InAppSettingsValue:[specifier getValue] forKey:[specifier getKey]]; |
||
187 | } |
||
188 | } |
||
189 | |||
190 | #pragma mark Table view methods |
||
191 | |||
192 | - (InAppSettingsSpecifier *) settingAtIndexPath:(NSIndexPath *)indexPath { |
||
193 | return [[self.settingsReader.settings objectAtIndex:indexPath.section] objectAtIndex:indexPath.row]; |
||
194 | } |
||
195 | |||
196 | - (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView { |
||
197 | return [self.settingsReader.headers count]; |
||
198 | } |
||
199 | |||
200 | - (NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { |
||
201 | return [self.settingsReader.headers objectAtIndex:section]; |
||
202 | } |
||
203 | |||
204 | - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { |
||
205 | return [[self.settingsReader.settings objectAtIndex:section] count]; |
||
206 | } |
||
207 | |||
208 | - (CGFloat) tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { |
||
209 | if (InAppSettingsDisplayPowered && [self.file isEqualToString:InAppSettingsRootFile] && section == (NSInteger)[self.settingsReader.headers count] - 1) { |
||
210 | return InAppSettingsPowerFooterHeight; |
||
211 | } |
||
212 | return 0.0f; |
||
213 | } |
||
214 | |||
215 | - (UIView *) tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { |
||
216 | if (InAppSettingsDisplayPowered && [self.file isEqualToString:InAppSettingsRootFile] && section == (NSInteger)[self.settingsReader.headers count] - 1) { |
||
217 | UIView * powerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, InAppSettingsScreenWidth, InAppSettingsPowerFooterHeight)]; |
||
218 | |||
219 | // InAppSettings label |
||
220 | CGSize InAppSettingsSize = [InAppSettingsProjectName sizeWithFont:InAppSettingsFooterFont]; |
||
221 | CGPoint InAppSettingsPos = CGPointMake((CGFloat)round((InAppSettingsScreenWidth * 0.5f) - (InAppSettingsSize.width * 0.5f)), |
||
222 | (CGFloat)round((InAppSettingsPowerFooterHeight * 0.5f) - (InAppSettingsSize.height * 0.5f)) - 1); |
||
223 | UILabel * InAppLabel = [[UILabel alloc] initWithFrame:CGRectMake(InAppSettingsPos.x, InAppSettingsPos.y, InAppSettingsSize.width, InAppSettingsSize.height)]; |
||
224 | InAppLabel.text = InAppSettingsProjectName; |
||
225 | InAppLabel.font = InAppSettingsFooterFont; |
||
226 | InAppLabel.backgroundColor = [UIColor clearColor]; |
||
227 | InAppLabel.textColor = InAppSettingsFooterBlue; |
||
228 | InAppLabel.shadowColor = [UIColor whiteColor]; |
||
229 | InAppLabel.shadowOffset = CGSizeMake(0.0f, 1.0f); |
||
230 | [powerView addSubview:InAppLabel]; |
||
231 | [InAppLabel release]; |
||
232 | |||
233 | // lighting bolts |
||
234 | CGPoint leftLightningBoltPos = CGPointMake(InAppSettingsPos.x - InAppSettingsLightingBoltSize, |
||
235 | (CGFloat)round((InAppSettingsPowerFooterHeight * 0.5f) - (InAppSettingsLightingBoltSize * 0.5f))); |
||
236 | InAppSettingsLightningBolt * leftLightningBolt = [[InAppSettingsLightningBolt alloc] |
||
237 | initWithFrame:CGRectMake(leftLightningBoltPos.x, leftLightningBoltPos.y, |
||
238 | InAppSettingsLightingBoltSize, InAppSettingsLightingBoltSize)]; |
||
239 | [powerView addSubview:leftLightningBolt]; |
||
240 | [leftLightningBolt release]; |
||
241 | |||
242 | CGPoint rightLightningBoltPos = CGPointMake((CGFloat)round(InAppSettingsPos.x + InAppSettingsSize.width), leftLightningBoltPos.y); |
||
243 | InAppSettingsLightningBolt * rightLightningBolt = [[InAppSettingsLightningBolt alloc] |
||
244 | initWithFrame:CGRectMake(rightLightningBoltPos.x, rightLightningBoltPos.y, |
||
245 | InAppSettingsLightingBoltSize, InAppSettingsLightingBoltSize)]; |
||
246 | rightLightningBolt.flip = YES; |
||
247 | [powerView addSubview:rightLightningBolt]; |
||
248 | [rightLightningBolt release]; |
||
249 | |||
250 | return [powerView autorelease]; |
||
251 | } |
||
252 | return nil; |
||
253 | } |
||
254 | |||
255 | - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { |
||
256 | InAppSettingsSpecifier * setting = [self settingAtIndexPath:indexPath]; |
||
257 | |||
258 | setting.delegate = self; |
||
259 | |||
260 | // get the NSClass for a specifier, if there is none use the base class InAppSettingsTableCell |
||
261 | NSString * cellType = [setting cellName]; |
||
262 | Class nsclass = NSClassFromString(cellType); |
||
263 | if (!nsclass) { |
||
264 | cellType = @"InAppSettingsTableCell"; |
||
265 | nsclass = NSClassFromString(cellType); |
||
266 | } |
||
267 | |||
268 | InAppSettingsTableCell * cell = ((InAppSettingsTableCell *)[tableView dequeueReusableCellWithIdentifier:cellType]); |
||
269 | if (cell == nil) { |
||
270 | cell = [[[nsclass alloc] initWithReuseIdentifier:cellType] autorelease]; |
||
271 | // setup the cells controlls |
||
272 | [cell setupCell]; |
||
273 | } |
||
274 | |||
275 | // set the values of the cell, this is separated from setupCell for reloading the table |
||
276 | cell.setting = setting; |
||
277 | [cell setValueDelegate:self]; |
||
278 | [cell setUIValues]; |
||
279 | |||
280 | return cell; |
||
281 | } |
||
282 | |||
283 | - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { |
||
284 | InAppSettingsSpecifier * setting = [self settingAtIndexPath:indexPath]; |
||
285 | |||
286 | if ([setting isType:InAppSettingsPSMultiValueSpecifier]) { |
||
287 | InAppSettingsPSMultiValueSpecifierTable * multiValueSpecifier = [[InAppSettingsPSMultiValueSpecifierTable alloc] initWithSetting:setting]; |
||
288 | [self.navigationController pushViewController:multiValueSpecifier animated:YES]; |
||
289 | [multiValueSpecifier release]; |
||
290 | } else if ([setting isType:InAppSettingsPSChildPaneSpecifier]) { |
||
291 | |||
292 | if ( [setting valueForKey:InAppSettingsSpecifierInAppChildPaneClass] ) { |
||
293 | |||
294 | UIViewController * childPane; |
||
295 | |||
296 | Class childPaneClass = NSClassFromString([setting valueForKey:InAppSettingsSpecifierInAppChildPaneClass]); |
||
297 | if ( [childPaneClass conformsToProtocol:@protocol(InAppSettingsChildPane)] ) { |
||
298 | childPane = [[childPaneClass alloc] initWithSetting:setting]; |
||
299 | } else { |
||
300 | childPane = [[childPaneClass alloc] init]; |
||
301 | } |
||
302 | |||
303 | childPane.title = [setting localizedTitle]; |
||
304 | [self.navigationController pushViewController:childPane animated:YES]; |
||
305 | [childPane release]; |
||
306 | } else { |
||
307 | |||
308 | InAppSettingsViewController * childPane = [[InAppSettingsViewController alloc] initWithFile:[setting valueForKey:InAppSettingsSpecifierFile]]; |
||
309 | childPane.title = [setting localizedTitle]; |
||
310 | childPane.dataSource = self.dataSource; |
||
311 | [self.navigationController pushViewController:childPane animated:YES]; |
||
312 | [childPane release]; |
||
313 | } |
||
314 | } else if ([setting isType:InAppSettingsPSTitleValueSpecifier]) { |
||
315 | InAppSettingsOpenUrl([NSURL URLWithString:[setting valueForKey:InAppSettingsSpecifierInAppURL]]); |
||
316 | } |
||
317 | } |
||
318 | |||
319 | - (NSIndexPath *) tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath { |
||
320 | InAppSettingsTableCell * cell = ((InAppSettingsTableCell *)[tableView cellForRowAtIndexPath:indexPath]); |
||
321 | |||
322 | if ([cell.setting isType:@"PSTextFieldSpecifier"]) { |
||
323 | [cell.valueInput becomeFirstResponder]; |
||
324 | } else if (cell.canSelectCell) { |
||
325 | [self.firstResponder resignFirstResponder]; |
||
326 | return indexPath; |
||
327 | } |
||
328 | return nil; |
||
329 | } |
||
330 | |||
331 | @end |
||
332 | |||
333 | @implementation InAppSettingsLightningBolt |
||
334 | |||
335 | @synthesize flip; |
||
336 | |||
337 | - (id) initWithFrame:(CGRect)frame { |
||
338 | self = [super initWithFrame:frame]; |
||
339 | if (self != nil) { |
||
340 | self.flip = NO; |
||
341 | self.backgroundColor = [UIColor clearColor]; |
||
342 | } |
||
343 | return self; |
||
344 | } |
||
345 | |||
346 | - (void) drawRect:(CGRect)rect { |
||
347 | CGContextRef context = UIGraphicsGetCurrentContext(); |
||
348 | |||
349 | CGContextSetFillColorWithColor(context, [InAppSettingsFooterBlue CGColor]); |
||
350 | #if __IPHONE_3_2 |
||
351 | CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 1.0f), 0.0f, [[UIColor whiteColor] CGColor]); |
||
352 | #else |
||
353 | CGContextSetShadowWithColor(context, CGSizeMake(0.0f, -1.0f), 0.0f, [[UIColor whiteColor] CGColor]); |
||
354 | #endif |
||
355 | if (self.flip) { |
||
356 | CGContextMoveToPoint(context, 4.0f, 1.0f); |
||
357 | CGContextAddLineToPoint(context, 13.0f, 1.0f); |
||
358 | CGContextAddLineToPoint(context, 10.0f, 5.0f); |
||
359 | CGContextAddLineToPoint(context, 12.0f, 7.0f); |
||
360 | CGContextAddLineToPoint(context, 2.0f, 15.0f); |
||
361 | CGContextAddLineToPoint(context, 5.0f, 7.0f); |
||
362 | CGContextAddLineToPoint(context, 3.0f, 5.0f); |
||
363 | } else { |
||
364 | CGContextMoveToPoint(context, 3.0f, 1.0f); |
||
365 | CGContextAddLineToPoint(context, 12.0f, 1.0f); |
||
366 | CGContextAddLineToPoint(context, 13.0f, 5.0f); |
||
367 | CGContextAddLineToPoint(context, 11.0f, 7.0f); |
||
368 | CGContextAddLineToPoint(context, 14.0f, 15.0f); |
||
369 | CGContextAddLineToPoint(context, 4.0f, 7.0f); |
||
370 | CGContextAddLineToPoint(context, 6.0f, 5.0f); |
||
371 | } |
||
372 | CGContextFillPath(context); |
||
373 | } |
||
374 | |||
375 | @end |