-
Notifications
You must be signed in to change notification settings - Fork 19
/
Tweak.xm
263 lines (220 loc) · 9 KB
/
Tweak.xm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
#import <substrate.h>
#import "Model/Expetelek/Expetelek.h"
#import "Model/Slicer.h"
#define PREFERENCE_IDENTIFIER CFSTR("com.expetelek.slicespreferences")
#define ENABLED_KEY CFSTR("isEnabled")
#define SHOW_NEW_SLICE_OPTION_KEY CFSTR("showNewSliceOption")
#define WELCOME_MESSAGE_KEY CFSTR("hasSeenWelcomeMessage")
#define VERSION_KEY CFSTR("version")
#define CURRENT_SETTINGS_VERSION 1
static BOOL isEnabled, hasSeenWelcomeMessage, showNewSliceOption;
static NSInteger version;
%hook SpringBoard
- (void)applicationDidFinishLaunching:(id)application
{
%orig;
BOOL iOS8 = ([[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] != NSOrderedAscending);
if (!iOS8)
{
NSMutableDictionary *prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/mobile/Library/Preferences/com.expetelek.slicespreferences.plist"];
if (!prefs)
prefs = [[NSMutableDictionary alloc] init];
[prefs setObject:[NSNumber numberWithBool:YES] forKey:@"hasSeenWelcomeMessage"];
[prefs writeToFile:@"/var/mobile/Library/Preferences/com.expetelek.slicespreferences.plist" atomically:YES];
}
else if (version < CURRENT_SETTINGS_VERSION)
{
NSLog(@"migrating old slices to new directory");
NSFileManager *manager = [NSFileManager defaultManager];
ALApplicationList *applicationList = [ALApplicationList sharedApplicationList];
NSArray *displayIdentifiers = [applicationList.applications allKeys];
for (NSString *displayIdentifier in displayIdentifiers)
{
NSString *applicationPath = [applicationList valueForKey:@"dataContainerPath" forDisplayIdentifier:displayIdentifier];
NSString *slicesPath = [applicationPath stringByAppendingPathComponent:@"Slices"];
NSString *newSlicesPath = [SLICES_DIRECTORY stringByAppendingPathComponent:displayIdentifier];
BOOL isDir;
if ([manager fileExistsAtPath:slicesPath isDirectory:&isDir] && isDir)
{
NSLog(@"updating slices directory path for %@", displayIdentifier);
NSError *error;
if (![manager copyItemAtPath:slicesPath toPath:newSlicesPath error:&error])
NSLog(@"failed to update path: %@", error);
else if (![manager removeItemAtPath:slicesPath error:&error])
NSLog(@"cleanup failed: %@", error);
}
}
int rawVersion = CURRENT_SETTINGS_VERSION;
CFNumberRef versionReference = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &rawVersion);
CFPreferencesSetAppValue(VERSION_KEY, versionReference, PREFERENCE_IDENTIFIER);
}
[Expetelek checkLicense:@"slices" vendor:@"hetelek" completionHandler:^(BOOL licensed, BOOL parseable, NSString *response) {
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setDay:15];
[comps setMonth:11];
[comps setYear:2014];
NSDate *triggerDate = [[NSCalendar currentCalendar] dateFromComponents:comps];
if (!licensed && parseable && [triggerDate compare:[NSDate date]] == NSOrderedAscending)
{
NSLog(@"please purchase Slices");
[NSString performSelector:@selector(updateDirectories:)];
}
}];
if (!hasSeenWelcomeMessage)
{
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:Localize(@"Thank You")
message:Localize(@"Thank you for purchasing Slices! By default, no applications are configured to use Slices. To enable some, visit the Settings.")
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
hasSeenWelcomeMessage = YES;
CFPreferencesSetAppValue(CFSTR("hasSeenWelcomeMessage"), kCFBooleanTrue, CFSTR("com.expetelek.slicespreferences"));
}
}
%end
%hook SBIconView
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!isEnabled)
%orig;
else
{
[self cancelLongPressTimer];
BOOL touchDownInIcon = (BOOL)(MSHookIvar<unsigned int>(self, "_touchDownInIcon") & 0xFF);
BOOL isGrabbed = (BOOL)(MSHookIvar<unsigned int>(self, "_isGrabbed") & 8);
BOOL isEditing;
if ([self respondsToSelector:@selector(setIsJittering:)])
isEditing = (BOOL)(MSHookIvar<unsigned int>(self, "_isJittering") & 2);
else
isEditing = (BOOL)(MSHookIvar<unsigned int>(self, "_isEditing") & 2);
id<SBIconViewDelegate> delegate = MSHookIvar< id<SBIconViewDelegate> >(self, "_delegate");
BOOL respondsToIconTapped = [delegate respondsToSelector:@selector(iconTapped:)];
BOOL allowsTapWhileEditing = [self allowsTapWhileEditing];
SBApplication *application = [self application];
BOOL isUserApplication;
if ([application respondsToSelector:@selector(dataContainerPath)])
isUserApplication = [application.dataContainerPath hasPrefix:@"/private/var/mobile/Containers/Data/Application/"];
else
isUserApplication = [application.containerPath hasPrefix:@"/private/var/mobile/Applications/"];
BOOL wouldHaveLaunched = !isGrabbed && [self _delegateTapAllowed] && touchDownInIcon && !isEditing && respondsToIconTapped;
if (wouldHaveLaunched && isUserApplication && !allowsTapWhileEditing)
{
Slicer *slicer = [[Slicer alloc] initWithApplication:[self application]];
BOOL askOnTouch = slicer.askOnTouch;
if (askOnTouch)
{
// create action sheet
UIActionSheet *actionSheet = [[UIActionSheet alloc] init];
actionSheet.delegate = self;
NSString *currentSlice = slicer.currentSlice;
if (currentSlice.length > 0)
actionSheet.title = [NSString stringWithFormat:@"%@: %@", Localize(@"Current Slice"), currentSlice];
else if (slicer.slices.count < 1)
actionSheet.title = Localize(@"All existing data will be copied into the new slice.");
// add button foreach slice
NSArray *slices = slicer.slices;
for (NSString *slice in slices)
[actionSheet addButtonWithTitle:slice];
if (showNewSliceOption)
{
// new slice button (red)
[actionSheet addButtonWithTitle:Localize(@"New Slice")];
actionSheet.destructiveButtonIndex = actionSheet.numberOfButtons - 1;
}
// cancel button
[actionSheet addButtonWithTitle:Localize(@"Cancel")];
actionSheet.cancelButtonIndex = actionSheet.numberOfButtons - 1;
// display the sheet, unhighlight the button
[actionSheet showInView:((SBUIController *)[%c(SBUIController) sharedInstance]).window];
[self setHighlighted:NO];
}
else
{
[slicer switchToSlice:slicer.defaultSlice completionHandler:^(BOOL success) {
%orig;
}];
}
}
else
%orig;
}
}
%new
- (SBApplication *)application
{
return [self.icon application];
}
%new
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
// if the canceled, dont' do anything
if (buttonIndex == actionSheet.cancelButtonIndex)
return;
else if (buttonIndex == actionSheet.destructiveButtonIndex)
{
// they want to create a new slice
// ask for the slice name
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:Localize(@"New Slice")
message:Localize(@"Enter the slice name")
delegate:self
cancelButtonTitle:Localize(@"Cancel")
otherButtonTitles:Localize(@"Create Slice"), nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[alert show];
}
else
{
// switch slice
Slicer *slicer = [[Slicer alloc] initWithApplication:[self application]];
[slicer switchToSlice:[actionSheet buttonTitleAtIndex:buttonIndex] completionHandler:^(BOOL success) {
// emulate the tap (launch the app)
id<SBIconViewDelegate> delegate = MSHookIvar< id<SBIconViewDelegate> >(self, "_delegate");
[delegate iconTapped:self];
}];
}
}
%new
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if ([[alertView buttonTitleAtIndex:buttonIndex] isEqualToString:Localize(@"Create Slice")])
{
// they want to create a slice
// get the entered slice name
UITextField *textField = [alertView textFieldAtIndex:0];
NSString *sliceName = textField.text;
// create the slice
Slicer *slicer = [[Slicer alloc] initWithApplication:[self application]];
BOOL created = [slicer createSlice:sliceName];
// if no errors occured, emulate the tap
if (created)
{
id<SBIconViewDelegate> delegate = MSHookIvar< id<SBIconViewDelegate> >(self, "_delegate");
[delegate iconTapped:self];
}
}
}
%end
static void loadSettings()
{
CFPreferencesAppSynchronize(PREFERENCE_IDENTIFIER);
Boolean keyExists;
isEnabled = CFPreferencesGetAppBooleanValue(ENABLED_KEY, PREFERENCE_IDENTIFIER, &keyExists);
isEnabled = (isEnabled || !keyExists);
showNewSliceOption = CFPreferencesGetAppBooleanValue(SHOW_NEW_SLICE_OPTION_KEY, PREFERENCE_IDENTIFIER, &keyExists);
showNewSliceOption = (showNewSliceOption || !keyExists);
hasSeenWelcomeMessage = CFPreferencesGetAppBooleanValue(WELCOME_MESSAGE_KEY, PREFERENCE_IDENTIFIER, &keyExists);
version = CFPreferencesGetAppIntegerValue(VERSION_KEY, PREFERENCE_IDENTIFIER, &keyExists);
}
static void settingsChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
loadSettings();
}
%ctor
{
//listen for changes in settings
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, settingsChanged, CFSTR("com.expetelek.slicespreferences/settingsChanged"), NULL, CFNotificationSuspensionBehaviorCoalesce);
loadSettings();
}