]>
Commit | Line | Data |
---|---|---|
62b2dbad JF |
1 | /* WinterBoard - Theme Manager for the iPhone |
2 | * Copyright (C) 2008 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 <CoreGraphics/CGGeometry.h> | |
40 | #import <UIKit/UIKit.h> | |
41 | ||
d5fb6e01 JF |
42 | #define _trace() NSLog(@"WE:_trace(%u)", __LINE__); |
43 | ||
44 | static NSString *plist_; | |
45 | static NSMutableDictionary *settings_; | |
f22a8989 | 46 | static BOOL changed_; |
d5fb6e01 JF |
47 | |
48 | @interface WBThemeTableViewCell : UITableViewCell { | |
49 | UILabel *label; | |
50 | } | |
51 | ||
52 | @end | |
53 | ||
54 | @implementation WBThemeTableViewCell | |
55 | ||
56 | ||
57 | @end | |
62b2dbad JF |
58 | |
59 | @interface WBApplication : UIApplication < | |
60 | UITableViewDataSource, | |
61 | UITableViewDelegate | |
62 | > { | |
63 | UIWindow *window_; | |
64 | UITableView *themesTable_; | |
26c43b47 | 65 | NSMutableArray *themesArray_; |
62b2dbad JF |
66 | } |
67 | ||
68 | @end | |
69 | ||
70 | @implementation WBApplication | |
71 | ||
72 | - (void) dealloc { | |
73 | [window_ release]; | |
74 | [themesTable_ release]; | |
75 | [themesArray_ release]; | |
76 | [super dealloc]; | |
77 | } | |
78 | ||
d5fb6e01 | 79 | - (void) applicationWillTerminate:(UIApplication *)application { |
f22a8989 | 80 | if (changed_) { |
9c64bab2 JF |
81 | NSString *description = nil; |
82 | NSData *data = [NSPropertyListSerialization dataFromPropertyList:settings_ format:NSPropertyListBinaryFormat_v1_0 errorDescription:&description]; | |
83 | if (data == nil) { | |
84 | NSLog(@"WB:Error:dataFromPropertyList:%@", description); | |
85 | return; | |
86 | } | |
87 | ||
88 | NSError *error = nil; | |
89 | if (![data writeToFile:plist_ options:NSAtomicWrite error:&error]) { | |
f22a8989 | 90 | NSLog(@"WB:Error:writeToFile"); |
9c64bab2 JF |
91 | return; |
92 | } | |
93 | ||
94 | unlink("/User/Library/Caches/com.apple.springboard-imagecache-icons"); | |
95 | unlink("/User/Library/Caches/com.apple.springboard-imagecache-icons.plist"); | |
96 | ||
97 | unlink("/User/Library/Caches/com.apple.springboard-imagecache-smallicons"); | |
98 | unlink("/User/Library/Caches/com.apple.springboard-imagecache-smallicons.plist"); | |
99 | ||
f22a8989 JF |
100 | system("killall SpringBoard"); |
101 | } | |
d5fb6e01 JF |
102 | } |
103 | ||
62b2dbad JF |
104 | - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { |
105 | UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero] autorelease]; | |
d5fb6e01 JF |
106 | NSMutableDictionary *theme = [themesArray_ objectAtIndex:[indexPath row]]; |
107 | cell.text = [theme objectForKey:@"Name"]; | |
108 | cell.hidesAccessoryWhenEditing = NO; | |
109 | NSNumber *active = [theme objectForKey:@"Active"]; | |
110 | BOOL inactive = active == nil || ![active boolValue]; | |
111 | cell.accessoryType = inactive ? UITableViewCellAccessoryNone : UITableViewCellAccessoryCheckmark; | |
62b2dbad JF |
112 | return cell; |
113 | } | |
114 | ||
d5fb6e01 JF |
115 | - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { |
116 | UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; | |
117 | NSMutableDictionary *theme = [themesArray_ objectAtIndex:[indexPath row]]; | |
118 | NSNumber *active = [theme objectForKey:@"Active"]; | |
119 | BOOL inactive = active == nil || ![active boolValue]; | |
120 | [theme setObject:[NSNumber numberWithBool:inactive] forKey:@"Active"]; | |
121 | cell.accessoryType = inactive ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone; | |
122 | [themesTable_ deselectRowAtIndexPath:(NSIndexPath *)indexPath animated:YES]; | |
f22a8989 | 123 | changed_ = YES; |
d5fb6e01 JF |
124 | } |
125 | ||
62b2dbad JF |
126 | - (NSInteger) tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section { |
127 | return [themesArray_ count]; | |
128 | } | |
129 | ||
d5fb6e01 JF |
130 | - (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { |
131 | return UITableViewCellEditingStyleNone; | |
132 | } | |
62b2dbad | 133 | |
d5fb6e01 JF |
134 | - (void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { |
135 | NSUInteger fromIndex = [fromIndexPath row]; | |
136 | NSUInteger toIndex = [toIndexPath row]; | |
137 | if (fromIndex == toIndex) | |
138 | return; | |
139 | NSMutableDictionary *theme = [[[themesArray_ objectAtIndex:fromIndex] retain] autorelease]; | |
140 | [themesArray_ removeObjectAtIndex:fromIndex]; | |
141 | [themesArray_ insertObject:theme atIndex:toIndex]; | |
f22a8989 | 142 | changed_ = YES; |
d5fb6e01 | 143 | } |
62b2dbad | 144 | |
d5fb6e01 JF |
145 | - (BOOL) tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { |
146 | return YES; | |
62b2dbad JF |
147 | } |
148 | ||
149 | - (void) applicationDidFinishLaunching:(id)unused { | |
150 | window_ = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].applicationFrame]; | |
151 | [window_ makeKeyAndVisible]; | |
152 | ||
d5fb6e01 JF |
153 | plist_ = [[NSString stringWithFormat:@"%@/Library/Preferences/com.saurik.WinterBoard.plist", |
154 | NSHomeDirectory() | |
155 | ] retain]; | |
156 | ||
157 | settings_ = [[NSMutableDictionary alloc] initWithContentsOfFile:plist_]; | |
f22a8989 JF |
158 | if (settings_ == nil) |
159 | settings_ = [[NSMutableDictionary alloc] initWithCapacity:16]; | |
d5fb6e01 JF |
160 | |
161 | themesArray_ = [settings_ objectForKey:@"Themes"]; | |
162 | if (themesArray_ == nil) { | |
163 | if (NSString *theme = [settings_ objectForKey:@"Theme"]) { | |
164 | themesArray_ = [[NSArray arrayWithObject:[[NSDictionary dictionaryWithObjectsAndKeys: | |
165 | theme, @"Name", | |
166 | [NSNumber numberWithBool:YES], @"Active", | |
167 | nil] mutableCopy]] mutableCopy]; | |
168 | ||
169 | [settings_ removeObjectForKey:@"Theme"]; | |
170 | } | |
171 | ||
172 | if (themesArray_ == nil) | |
173 | themesArray_ = [NSMutableArray arrayWithCapacity:16]; | |
174 | [settings_ setObject:themesArray_ forKey:@"Themes"]; | |
175 | } | |
176 | ||
177 | themesArray_ = [themesArray_ retain]; | |
178 | ||
179 | NSMutableSet *themesSet = [NSMutableSet setWithCapacity:32]; | |
180 | for (NSMutableDictionary *theme in themesArray_) | |
181 | if (NSString *name = [theme objectForKey:@"Name"]) | |
182 | [themesSet addObject:name]; | |
183 | ||
62b2dbad | 184 | NSFileManager *manager = [NSFileManager defaultManager]; |
26c43b47 | 185 | |
d5fb6e01 JF |
186 | NSMutableArray *themes = [NSMutableArray arrayWithCapacity:32]; |
187 | [themes addObjectsFromArray:[manager contentsOfDirectoryAtPath:@"/Library/Themes" error:NULL]]; | |
188 | [themes addObjectsFromArray:[manager contentsOfDirectoryAtPath:[NSString stringWithFormat:@"%@/Library/SummerBoard/Themes", NSHomeDirectory()] error:NULL]]; | |
189 | ||
f22a8989 JF |
190 | for (NSUInteger i(0), e([themes count]); i != e; ++i) { |
191 | NSString *theme = [themes objectAtIndex:i]; | |
d5fb6e01 | 192 | if ([theme hasSuffix:@".theme"]) |
f22a8989 JF |
193 | [themes replaceObjectAtIndex:i withObject:[theme substringWithRange:NSMakeRange(0, [theme length] - 6)]]; |
194 | } | |
195 | ||
196 | for (NSUInteger i(0), e([themesArray_ count]); i != e; ++i) { | |
197 | NSMutableDictionary *theme = [themesArray_ objectAtIndex:i]; | |
198 | NSString *name = [theme objectForKey:@"Name"]; | |
199 | if (name == nil || ![themes containsObject:name]) { | |
200 | [themesArray_ removeObjectAtIndex:i]; | |
201 | --i; --e; | |
202 | } | |
203 | } | |
204 | ||
205 | for (NSString *theme in themes) { | |
d5fb6e01 JF |
206 | if ([themesSet containsObject:theme]) |
207 | continue; | |
208 | [themesSet addObject:theme]; | |
4668cd8e | 209 | [themesArray_ insertObject:[[NSDictionary dictionaryWithObjectsAndKeys: |
d5fb6e01 JF |
210 | theme, @"Name", |
211 | [NSNumber numberWithBool:NO], @"Active", | |
4668cd8e | 212 | nil] mutableCopy] atIndex:0]; |
d5fb6e01 | 213 | } |
62b2dbad JF |
214 | |
215 | themesTable_ = [[UITableView alloc] initWithFrame:window_.bounds]; | |
216 | [window_ addSubview:themesTable_]; | |
217 | ||
218 | [themesTable_ setDataSource:self]; | |
219 | [themesTable_ setDelegate:self]; | |
220 | ||
d5fb6e01 JF |
221 | [themesTable_ setEditing:YES animated:NO]; |
222 | themesTable_.allowsSelectionDuringEditing = YES; | |
223 | ||
62b2dbad JF |
224 | [themesTable_ setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine]; |
225 | } | |
226 | ||
227 | @end | |
228 | ||
229 | int main(int argc, char *argv[]) { | |
230 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
231 | ||
232 | int value = UIApplicationMain(argc, argv, @"WBApplication", @"WBApplication"); | |
233 | ||
234 | [pool release]; | |
235 | return value; | |
236 | } |