-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathUpdateController.m
238 lines (185 loc) · 6.84 KB
/
UpdateController.m
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
#import "UpdateController.h"
#import <DBBackgroundView/DBBackgroundView.h>
#import "SUHost.h"
#import "SUStatusController.h"
#import "SUUpdateAlert.h"
#import "SUUIBasedUpdateDriver.h"
@interface SUUpdater ()
- (id)initForBundle:(NSBundle *)bundle;
- (void)checkForUpdatesWithDriver:(SUUpdateDriver *)updateDriver;
@end
@interface ComBelkadanWebmailer_KnownItemUpdateDriver : SUUIBasedUpdateDriver
- (id)initWithUpdater:(SUUpdater *)updater updateItem:(SUAppcastItem *)updateItem;
@end
extern NSString * const SUSkippedVersionKey;
static const CGFloat kUpdateBarHeight = 29;
@interface ComBelkadanWebmailer_UpdateController ()
- (void)showUpdateBar;
- (void)getFramesForUpdateBarHeightChange:(CGFloat)deltaUpdateHeight updateBarFrame:(NSRect *)updateFrame mainFrame:(NSRect *)mainFrame;
@property(retain) SUAppcastItem *availableUpdate;
@end
@implementation ComBelkadanWebmailer_UpdateController
@synthesize availableUpdate;
+ (id)sharedUpdater {
return [self updaterForBundle:[NSBundle bundleForClass:[self class]]];
}
- (id)init {
return [self initForBundle:[NSBundle bundleForClass:[self class]]];
}
- (void)dealloc {
[availableUpdate release];
[updateAlert release];
[super dealloc];
}
#pragma mark -
- (void)awakeFromNib {
// Hide update bar
NSRect updateFrame, mainFrame;
[self getFramesForUpdateBarHeightChange:-kUpdateBarHeight updateBarFrame:&updateFrame mainFrame:&mainFrame];
[mainView setFrame:mainFrame];
[updateBar setFrame:updateFrame];
[updateBar setHidden:YES];
// Set update bar gradient
NSGradient *gradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithCalibratedWhite:0.19 alpha:1.0] endingColor:[NSColor colorWithCalibratedWhite:0.09 alpha:1.0]];
[updateBar setBackgroundGradient:gradient];
[gradient release];
// And check for updates
[self setDelegate:self];
if ([self automaticallyChecksForUpdates]) [self checkForUpdateInformation];
else hasPerformedInitialCheck = YES;
}
- (void)getFramesForUpdateBarHeightChange:(CGFloat)deltaUpdateHeight updateBarFrame:(NSRect *)updateFrame mainFrame:(NSRect *)mainFrame {
BOOL isFlipped = [[mainView superview] isFlipped];
*updateFrame = [updateBar frame];
*mainFrame = [mainView frame];
updateFrame->size.height += deltaUpdateHeight;
mainFrame->size.height -= deltaUpdateHeight;
if (isFlipped) {
mainFrame->origin.y += deltaUpdateHeight;
} else {
updateFrame->origin.y -= deltaUpdateHeight;
}
}
- (void)showUpdateBar {
if (![updateBar isHidden]) return;
CGFloat deltaUpdateHeight = kUpdateBarHeight;
[updateBar setHidden:NO];
NSRect updateFrame, mainFrame;
[self getFramesForUpdateBarHeightChange:deltaUpdateHeight updateBarFrame:&updateFrame mainFrame:&mainFrame];
NSViewAnimation *animation = [[NSViewAnimation alloc] initWithViewAnimations:
[NSArray arrayWithObjects:
[NSDictionary dictionaryWithObjectsAndKeys:
updateBar, NSViewAnimationTargetKey,
[NSValue valueWithRect:updateFrame], NSViewAnimationEndFrameKey,
nil],
[NSDictionary dictionaryWithObjectsAndKeys:
mainView, NSViewAnimationTargetKey,
[NSValue valueWithRect:mainFrame], NSViewAnimationEndFrameKey,
nil],
nil]
];
[animation setDuration:0.25];
[animation startAnimation];
[animation release];
}
#pragma mark -
- (void)updater:(SUUpdater *)updater didFindValidUpdate:(SUAppcastItem *)update {
self.availableUpdate = update;
if (hasPerformedInitialCheck) {
[self performSelector:@selector(showUpdateBar) withObject:nil afterDelay:1];
} else {
[self showUpdateBar];
}
hasPerformedInitialCheck = YES;
}
- (void)updaterDidNotFindUpdate:(SUUpdater *)update {
hasPerformedInitialCheck = YES;
}
- (IBAction)showReleaseNotes:(id)sender {
if (availableUpdate) {
updateAlert = [[SUUpdateAlert alloc] initWithAppcastItem:availableUpdate host:host];
[updateAlert setDelegate:self];
[NSApp beginSheet:[updateAlert window] modalForWindow:[updateBar window] modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
} else {
NSBeep();
}
}
- (void)updateAlert:(SUUpdateAlert *)alert finishedWithChoice:(SUUpdateAlertChoice)updateChoice {
[NSApp endSheet:[alert window]];
switch (updateChoice) {
case SUInstallUpdateChoice:
[self installUpdate:nil];
break;
case SUSkipThisVersionChoice:
[host setObject:[availableUpdate versionString] forUserDefaultsKey:SUSkippedVersionKey];
// no break
default:
; // no action necessary
}
[updateAlert release];
updateAlert = nil;
}
- (IBAction)installUpdate:(id)sender {
if (availableUpdate) {
[self checkForUpdatesWithDriver:[[[ComBelkadanWebmailer_KnownItemUpdateDriver alloc] initWithUpdater:self updateItem:availableUpdate] autorelease]];
} else {
NSBeep();
}
}
- (NSString *)currentVersion {
NSString *versionString = [[self hostBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
if (!versionString) {
versionString = [[self hostBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
}
return versionString;
}
@end
// From Sparkle.pch
#define SPARKLE_BUNDLE [NSBundle bundleWithIdentifier:@"org.andymatuschak.Sparkle"]
#define SULocalizedString(key,comment) NSLocalizedStringFromTableInBundle(key, @"Sparkle", SPARKLE_BUNDLE, comment)
@interface SUBasicUpdateDriver ()
- (BOOL)shouldInstallSynchronously;
@end
@implementation ComBelkadanWebmailer_KnownItemUpdateDriver
- (id)initWithUpdater:(SUUpdater *)givenUupdater updateItem:(SUAppcastItem *)item {
self = [super initWithUpdater:givenUupdater];
if (self) {
updateItem = [item retain];
}
return self;
}
- (void)checkForUpdatesAtURL:(NSURL *)givenURL host:(SUHost *)givenHost {
// skip the checking stage
appcastURL = [givenURL copy];
host = [givenHost retain];
statusController = [[SUStatusController alloc] initWithHost:host];
[statusController beginActionWithTitle:SULocalizedString(@"Downloading update...", @"Take care not to overflow the status window.") maxProgressValue:0 statusText:nil];
[statusController setButtonTitle:SULocalizedString(@"Cancel", nil) target:self action:@selector(cancelDownload:) isDefault:NO];
[NSApp beginSheet:[statusController window] modalForWindow:[NSApp mainWindow] modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
[self downloadUpdate];
}
- (BOOL)shouldInstallSynchronously { return YES; }
- (void)unarchiverDidFinish:(SUUnarchiver *)ua {
[self installUpdate]; // since we're running a sheet, don't wait to confirm
}
- (void)cleanUp {
if (statusController) {
[NSApp endSheet:[statusController window]];
[[statusController window] orderOut:self];
}
[super cleanUp];
}
- (void)abortUpdate {
if (statusController) {
[NSApp endSheet:[statusController window]];
}
[super abortUpdate];
}
- (void)showModalAlert:(NSAlert *)alert {
[alert setIcon:[host icon]];
[self performSelector:@selector(runAlert:) withObject:alert afterDelay:0];
}
- (void)runAlert:(NSAlert *)alert {
[alert beginSheetModalForWindow:[NSApp mainWindow] modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
}
@end