]>
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 JF |
80 | if (changed_) { |
81 | if (![settings_ writeToFile:plist_ atomically:YES]) | |
82 | NSLog(@"WB:Error:writeToFile"); | |
83 | system("killall SpringBoard"); | |
84 | } | |
d5fb6e01 JF |
85 | } |
86 | ||
62b2dbad JF |
87 | - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { |
88 | UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero] autorelease]; | |
d5fb6e01 JF |
89 | NSMutableDictionary *theme = [themesArray_ objectAtIndex:[indexPath row]]; |
90 | cell.text = [theme objectForKey:@"Name"]; | |
91 | cell.hidesAccessoryWhenEditing = NO; | |
92 | NSNumber *active = [theme objectForKey:@"Active"]; | |
93 | BOOL inactive = active == nil || ![active boolValue]; | |
94 | cell.accessoryType = inactive ? UITableViewCellAccessoryNone : UITableViewCellAccessoryCheckmark; | |
62b2dbad JF |
95 | return cell; |
96 | } | |
97 | ||
d5fb6e01 JF |
98 | - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { |
99 | UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; | |
100 | NSMutableDictionary *theme = [themesArray_ objectAtIndex:[indexPath row]]; | |
101 | NSNumber *active = [theme objectForKey:@"Active"]; | |
102 | BOOL inactive = active == nil || ![active boolValue]; | |
103 | [theme setObject:[NSNumber numberWithBool:inactive] forKey:@"Active"]; | |
104 | cell.accessoryType = inactive ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone; | |
105 | [themesTable_ deselectRowAtIndexPath:(NSIndexPath *)indexPath animated:YES]; | |
f22a8989 | 106 | changed_ = YES; |
d5fb6e01 JF |
107 | } |
108 | ||
62b2dbad JF |
109 | - (NSInteger) tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section { |
110 | return [themesArray_ count]; | |
111 | } | |
112 | ||
d5fb6e01 JF |
113 | - (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { |
114 | return UITableViewCellEditingStyleNone; | |
115 | } | |
62b2dbad | 116 | |
d5fb6e01 JF |
117 | - (void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { |
118 | NSUInteger fromIndex = [fromIndexPath row]; | |
119 | NSUInteger toIndex = [toIndexPath row]; | |
120 | if (fromIndex == toIndex) | |
121 | return; | |
122 | NSMutableDictionary *theme = [[[themesArray_ objectAtIndex:fromIndex] retain] autorelease]; | |
123 | [themesArray_ removeObjectAtIndex:fromIndex]; | |
124 | [themesArray_ insertObject:theme atIndex:toIndex]; | |
f22a8989 | 125 | changed_ = YES; |
d5fb6e01 | 126 | } |
62b2dbad | 127 | |
d5fb6e01 JF |
128 | - (BOOL) tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { |
129 | return YES; | |
62b2dbad JF |
130 | } |
131 | ||
132 | - (void) applicationDidFinishLaunching:(id)unused { | |
133 | window_ = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].applicationFrame]; | |
134 | [window_ makeKeyAndVisible]; | |
135 | ||
d5fb6e01 JF |
136 | plist_ = [[NSString stringWithFormat:@"%@/Library/Preferences/com.saurik.WinterBoard.plist", |
137 | NSHomeDirectory() | |
138 | ] retain]; | |
139 | ||
140 | settings_ = [[NSMutableDictionary alloc] initWithContentsOfFile:plist_]; | |
f22a8989 JF |
141 | if (settings_ == nil) |
142 | settings_ = [[NSMutableDictionary alloc] initWithCapacity:16]; | |
d5fb6e01 JF |
143 | |
144 | themesArray_ = [settings_ objectForKey:@"Themes"]; | |
145 | if (themesArray_ == nil) { | |
146 | if (NSString *theme = [settings_ objectForKey:@"Theme"]) { | |
147 | themesArray_ = [[NSArray arrayWithObject:[[NSDictionary dictionaryWithObjectsAndKeys: | |
148 | theme, @"Name", | |
149 | [NSNumber numberWithBool:YES], @"Active", | |
150 | nil] mutableCopy]] mutableCopy]; | |
151 | ||
152 | [settings_ removeObjectForKey:@"Theme"]; | |
153 | } | |
154 | ||
155 | if (themesArray_ == nil) | |
156 | themesArray_ = [NSMutableArray arrayWithCapacity:16]; | |
157 | [settings_ setObject:themesArray_ forKey:@"Themes"]; | |
158 | } | |
159 | ||
160 | themesArray_ = [themesArray_ retain]; | |
161 | ||
162 | NSMutableSet *themesSet = [NSMutableSet setWithCapacity:32]; | |
163 | for (NSMutableDictionary *theme in themesArray_) | |
164 | if (NSString *name = [theme objectForKey:@"Name"]) | |
165 | [themesSet addObject:name]; | |
166 | ||
62b2dbad | 167 | NSFileManager *manager = [NSFileManager defaultManager]; |
26c43b47 | 168 | |
d5fb6e01 JF |
169 | NSMutableArray *themes = [NSMutableArray arrayWithCapacity:32]; |
170 | [themes addObjectsFromArray:[manager contentsOfDirectoryAtPath:@"/Library/Themes" error:NULL]]; | |
171 | [themes addObjectsFromArray:[manager contentsOfDirectoryAtPath:[NSString stringWithFormat:@"%@/Library/SummerBoard/Themes", NSHomeDirectory()] error:NULL]]; | |
172 | ||
f22a8989 JF |
173 | for (NSUInteger i(0), e([themes count]); i != e; ++i) { |
174 | NSString *theme = [themes objectAtIndex:i]; | |
d5fb6e01 | 175 | if ([theme hasSuffix:@".theme"]) |
f22a8989 JF |
176 | [themes replaceObjectAtIndex:i withObject:[theme substringWithRange:NSMakeRange(0, [theme length] - 6)]]; |
177 | } | |
178 | ||
179 | for (NSUInteger i(0), e([themesArray_ count]); i != e; ++i) { | |
180 | NSMutableDictionary *theme = [themesArray_ objectAtIndex:i]; | |
181 | NSString *name = [theme objectForKey:@"Name"]; | |
182 | if (name == nil || ![themes containsObject:name]) { | |
183 | [themesArray_ removeObjectAtIndex:i]; | |
184 | --i; --e; | |
185 | } | |
186 | } | |
187 | ||
188 | for (NSString *theme in themes) { | |
d5fb6e01 JF |
189 | if ([themesSet containsObject:theme]) |
190 | continue; | |
191 | [themesSet addObject:theme]; | |
192 | [themesArray_ addObject:[[NSDictionary dictionaryWithObjectsAndKeys: | |
193 | theme, @"Name", | |
194 | [NSNumber numberWithBool:NO], @"Active", | |
195 | nil] mutableCopy]]; | |
196 | } | |
62b2dbad JF |
197 | |
198 | themesTable_ = [[UITableView alloc] initWithFrame:window_.bounds]; | |
199 | [window_ addSubview:themesTable_]; | |
200 | ||
201 | [themesTable_ setDataSource:self]; | |
202 | [themesTable_ setDelegate:self]; | |
203 | ||
d5fb6e01 JF |
204 | [themesTable_ setEditing:YES animated:NO]; |
205 | themesTable_.allowsSelectionDuringEditing = YES; | |
206 | ||
62b2dbad JF |
207 | [themesTable_ setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine]; |
208 | } | |
209 | ||
210 | @end | |
211 | ||
212 | int main(int argc, char *argv[]) { | |
213 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
214 | ||
215 | int value = UIApplicationMain(argc, argv, @"WBApplication", @"WBApplication"); | |
216 | ||
217 | [pool release]; | |
218 | return value; | |
219 | } |