]> git.saurik.com Git - cydget.git/blob - CydgetSettings.mm
Checkpoint for Welcome.
[cydget.git] / CydgetSettings.mm
1 /* CydgetScript - open-source IntelliDial replacement
2 * Copyright (C) 2009 Jay Freeman (saurik)
3 */
4
5 /*
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
17 * distribution.
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #import <Foundation/Foundation.h>
39 #import <UIKit/UIKit.h>
40 #import <Preferences/PSListController.h>
41 #import <Preferences/PSSpecifier.h>
42 #import <Preferences/PSTableCell.h>
43 #import <UIKit/UINavigationButton.h>
44
45 extern NSString *PSTableCellKey;
46 extern "C" UIImage *_UIImageWithName(NSString *);
47
48 static UIImage *checkImage;
49 static UIImage *uncheckedImage;
50
51 static BOOL settingsChanged;
52 static NSMutableDictionary *_settings;
53 static NSString *_plist;
54
55 /* Theme Settings Controller {{{ */
56 @interface CydgetOrderController: PSViewController <UITableViewDelegate, UITableViewDataSource> {
57 UITableView *_tableView;
58 NSMutableArray *_themes;
59 }
60
61 @property (nonatomic, retain) NSMutableArray *themes;
62
63 + (void) load;
64
65 - (id) initForContentSize:(CGSize)size;
66 - (id) view;
67 - (id) navigationTitle;
68 - (void) themesChanged;
69
70 - (int) numberOfSectionsInTableView:(UITableView *)tableView;
71 - (id) tableView:(UITableView *)tableView titleForHeaderInSection:(int)section;
72 - (int) tableView:(UITableView *)tableView numberOfRowsInSection:(int)section;
73 - (id) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
74 - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
75 - (void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath;
76 - (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
77 - (BOOL) tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath;
78 - (BOOL) tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;
79
80 @end
81
82 @implementation CydgetOrderController
83
84 @synthesize themes = _themes;
85
86 + (void) load {
87 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
88 checkImage = [_UIImageWithName(@"UIPreferencesBlueCheck.png") retain];
89 uncheckedImage = [[UIImage imageWithContentsOfFile:@"/System/Library/PreferenceBundles/CydgetSettings.bundle/SearchResultsCheckmarkClear.png"] retain];
90 [pool release];
91 }
92
93 - (id) initForContentSize:(CGSize)size {
94 if ((self = [super initForContentSize:size]) != nil) {
95 self.themes = [_settings objectForKey:@"LockCydgets"];
96 if (!_themes) {
97 self.themes = [NSMutableArray arrayWithObjects:[NSMutableDictionary dictionaryWithObjectsAndKeys:
98 @"AwayView", @"Name", [NSNumber numberWithBool:YES], @"Active", nil
99 ], [NSMutableDictionary dictionaryWithObjectsAndKeys:
100 @"CydgetCentral", @"Name", [NSNumber numberWithBool:YES], @"Active", nil
101 ], nil];
102
103 [_settings setObject:_themes forKey:@"LockCydgets"];
104 }
105
106 NSMutableArray *themesOnDisk([NSMutableArray arrayWithCapacity:4]);
107 for (NSString *theme in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/System/Library/LockCydgets" error:NULL])
108 if ([theme hasSuffix:@".cydget"])
109 [themesOnDisk addObject:[theme stringByDeletingPathExtension]];
110
111 NSMutableSet *themesSet([NSMutableSet set]);
112
113 for (int i = 0, count = [_themes count]; i < count; i++) {
114 NSDictionary *theme([_themes objectAtIndex:i]);
115 NSString *name([theme objectForKey:@"Name"]);
116
117 if (!name || ![themesOnDisk containsObject:name]) {
118 [_themes removeObjectAtIndex:i];
119 i--;
120 count--;
121 } else {
122 [themesSet addObject:name];
123 }
124 }
125
126 for (NSString *theme in themesOnDisk) {
127 if ([themesSet containsObject:theme])
128 continue;
129 [themesSet addObject:theme];
130
131 [_themes insertObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:
132 theme, @"Name",
133 [NSNumber numberWithBool:NO], @"Active",
134 nil] atIndex:0];
135 }
136
137 _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 480-64) style:UITableViewStyleGrouped];
138 [_tableView setDataSource:self];
139 [_tableView setDelegate:self];
140 [_tableView setEditing:YES];
141 [_tableView setAllowsSelectionDuringEditing:YES];
142 [self showLeftButton:@"Cydget" withStyle:1 rightButton:nil withStyle:0];
143 }
144 return self;
145 }
146
147 - (void) dealloc {
148 [_tableView release];
149 [_themes release];
150 [super dealloc];
151 }
152
153 - (id) navigationTitle {
154 return @"Lock Cydgets";
155 }
156
157 - (id) view {
158 return _tableView;
159 }
160
161 - (void) themesChanged {
162 settingsChanged = YES;
163 }
164
165 /* UITableViewDelegate / UITableViewDataSource Methods {{{ */
166 - (int) numberOfSectionsInTableView:(UITableView *)tableView {
167 return 1;
168 }
169
170 - (id) tableView:(UITableView *)tableView titleForHeaderInSection:(int)section {
171 return nil;
172 }
173
174 - (int) tableView:(UITableView *)tableView numberOfRowsInSection:(int)section {
175 return _themes.count;
176 }
177
178 - (id) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
179 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ThemeCell"];
180 if (!cell) {
181 cell = [[[UITableViewCell alloc] initWithFrame:CGRectMake(0, 0, 100, 100) reuseIdentifier:@"ThemeCell"] autorelease];
182 //[cell setTableViewStyle:UITableViewCellStyleDefault];
183 }
184
185 NSDictionary *theme([_themes objectAtIndex:indexPath.row]);
186 cell.text = [theme objectForKey:@"Name"];
187 cell.hidesAccessoryWhenEditing = NO;
188 NSNumber *active([theme objectForKey:@"Active"]);
189 BOOL inactive(active == nil || ![active boolValue]);
190 [cell setImage:(inactive ? uncheckedImage : checkImage)];
191 return cell;
192 }
193
194 - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
195 UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
196 NSMutableDictionary *theme = [_themes objectAtIndex:indexPath.row];
197 NSNumber *active = [theme objectForKey:@"Active"];
198 BOOL inactive = active == nil || ![active boolValue];
199 [theme setObject:[NSNumber numberWithBool:inactive] forKey:@"Active"];
200 [cell setImage:(!inactive ? uncheckedImage : checkImage)];
201 [tableView deselectRowAtIndexPath:(NSIndexPath *)indexPath animated:YES];
202 [self themesChanged];
203 }
204
205 - (void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
206 NSUInteger fromIndex = [fromIndexPath row];
207 NSUInteger toIndex = [toIndexPath row];
208 if (fromIndex == toIndex)
209 return;
210 NSMutableDictionary *theme = [[[_themes objectAtIndex:fromIndex] retain] autorelease];
211 [_themes removeObjectAtIndex:fromIndex];
212 [_themes insertObject:theme atIndex:toIndex];
213 [self themesChanged];
214 }
215
216 - (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
217 return UITableViewCellEditingStyleNone;
218 }
219
220 - (BOOL) tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath {
221 return NO;
222 }
223
224 - (BOOL) tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
225 return YES;
226 }
227 /* }}} */
228 @end
229 /* }}} */
230
231 @interface CydgetSettingsController: PSListController {
232 }
233
234 - (id) initForContentSize:(CGSize)size;
235 - (void) dealloc;
236 - (void) suspend;
237 - (void) navigationBarButtonClicked:(int)buttonIndex;
238 - (void) viewWillRedisplay;
239 - (void) pushController:(id)controller;
240 - (id) specifiers;
241 - (void) settingsChanged;
242 - (NSString *) title;
243 - (void) setPreferenceValue:(id)value specifier:(PSSpecifier *)spec;
244 - (id) readPreferenceValue:(PSSpecifier *)spec;
245
246 @end
247
248 @implementation CydgetSettingsController
249
250 - (id) initForContentSize:(CGSize)size {
251 if ((self = [super initForContentSize:size]) != nil) {
252 _plist = [[NSString stringWithFormat:@"%@/Library/Preferences/com.saurik.Cydget.plist", NSHomeDirectory()] retain];
253 _settings = [([NSMutableDictionary dictionaryWithContentsOfFile:_plist] ?: [NSMutableDictionary dictionary]) retain];
254 } return self;
255 }
256
257 - (void) dealloc {
258 [_settings release];
259 [_plist release];
260 [super dealloc];
261 }
262
263 - (void) suspend {
264 if (!settingsChanged)
265 return;
266
267 NSData *data([NSPropertyListSerialization dataFromPropertyList:_settings format:NSPropertyListBinaryFormat_v1_0 errorDescription:NULL]);
268 if (!data)
269 return;
270 if (![data writeToFile:_plist options:NSAtomicWrite error:NULL])
271 return;
272
273 unlink("/User/Library/Caches/com.apple.springboard-imagecache-icons");
274 unlink("/User/Library/Caches/com.apple.springboard-imagecache-icons.plist");
275 unlink("/User/Library/Caches/com.apple.springboard-imagecache-smallicons");
276 unlink("/User/Library/Caches/com.apple.springboard-imagecache-smallicons.plist");
277 // XXX: recursively delete directory!!
278 unlink("/User/Library/Caches/SpringBoardIconCache");
279 unlink("/User/Library/Caches/SpringBoardIconCache-small");
280 system("killall SpringBoard");
281 }
282
283 - (void) navigationBarButtonClicked:(int)buttonIndex {
284 if (!settingsChanged) {
285 [super navigationBarButtonClicked:buttonIndex];
286 return;
287 }
288
289 if (buttonIndex == 0)
290 settingsChanged = NO;
291
292 [self suspend];
293 [self.rootController popController];
294 }
295
296 - (void) viewWillRedisplay {
297 if (settingsChanged)
298 [self settingsChanged];
299 [super viewWillRedisplay];
300 }
301
302 - (void) pushController:(id)controller {
303 [self hideNavigationBarButtons];
304 [super pushController:controller];
305 }
306
307 - (id) specifiers {
308 if (!_specifiers)
309 _specifiers = [[self loadSpecifiersFromPlistName:@"Cydget" target:self] retain];
310 return _specifiers;
311 }
312
313 - (void) settingsChanged {
314 [self showLeftButton:@"Respring" withStyle:2 rightButton:@"Cancel" withStyle:0];
315 settingsChanged = YES;
316 }
317
318 - (NSString *) title {
319 return @"Cydget";
320 }
321
322 - (void) setPreferenceValue:(id)value specifier:(PSSpecifier *)spec {
323 if ([[spec propertyForKey:@"negate"] boolValue])
324 value = [NSNumber numberWithBool:(![value boolValue])];
325 [_settings setValue:value forKey:[spec propertyForKey:@"key"]];
326 [self settingsChanged];
327 }
328
329 - (id) readPreferenceValue:(PSSpecifier *)spec {
330 NSString *key([spec propertyForKey:@"key"]);
331 id defaultValue([spec propertyForKey:@"default"]);
332 id plistValue([_settings objectForKey:key]);
333 if (!plistValue)
334 return defaultValue;
335 if ([[spec propertyForKey:@"negate"] boolValue])
336 plistValue = [NSNumber numberWithBool:(![plistValue boolValue])];
337 return plistValue;
338 }
339
340 @end