#define TrackResize (0 && !ForRelease)
#define ManualRefresh (1 && !ForRelease)
#define ShowInternals (0 && !ForRelease)
-#define IgnoreInstall (0 && !ForRelease)
#define AlwaysReload (0 && !ForRelease)
#define TryIndexedCollation (0 && !ForRelease)
/* Random Global Variables {{{ */
static const int PulseInterval_ = 50000;
+static const NSString *UI_;
+
static int Finish_;
static NSArray *Finishes_;
static time_t now_;
bool IsWildcat_;
+static CGFloat ScreenScale_;
/* }}} */
/* Display Helpers {{{ */
NSString *title(UCLocalize("DATABASE"));
_trace();
- if (!cache_.Open(progress_, true)) { pop:
+ while (!cache_.Open(progress_, true)) { pop:
std::string error;
bool warning(!_error->PopMessage(error));
lprintf("cache_.Open():[%s]\n", error.c_str());
else if (error == "The package lists or status file could not be parsed or opened.")
[delegate_ repairWithSelector:@selector(update)];
// else if (error == "Could not open lock file /var/lib/dpkg/lock - open (13 Permission denied)")
- // else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
+ else if (error == "Could not get lock /var/lib/dpkg/lock - open (35 Resource temporarily unavailable)")
+ [delegate_ _setProgressError:[NSString stringWithUTF8String:error.c_str()] withTitle:[NSString stringWithFormat:Colon_, Error_, title]];
// else if (error == "The list of sources could not be read.")
- else
+ else {
[delegate_ _setProgressError:[NSString stringWithUTF8String:error.c_str()] withTitle:[NSString stringWithFormat:Colon_, warning ? Warning_ : Error_, title]];
+ return;
+ }
if (warning)
goto pop;
_error->Discard();
- return;
}
_trace();
@end
/* }}} */
/* Emulated Loading Controller {{{ */
-@interface CYEmulatedLoadingController : CYViewController {
+@interface CYEmulatedLoadingController : CYViewController <
+ ProgressDelegate,
+ ConfigurationDelegate
+> {
+ _transient Database *database_;
CYLoadingIndicator *indicator_;
UITabBar *tabbar_;
UINavigationBar *navbar_;
- (void) dealloc {
[self releaseSubviews];
+ [database_ setDelegate:nil];
[super dealloc];
}
+- (void) setProgressError:(NSString *)error withTitle:(NSString *)title {
+ CYAlertView *sheet([[[CYAlertView alloc]
+ initWithTitle:title
+ buttons:[NSArray arrayWithObjects:UCLocalize("OKAY"), nil]
+ defaultButtonIndex:0
+ ] autorelease]);
+
+ [sheet setMessage:error];
+ [sheet yieldToPopupAlertAnimated:YES];
+ [sheet dismiss];
+}
+
+- (void) setProgressTitle:(NSString *)title { }
+- (void) setProgressPercent:(float)percent { }
+- (void) startProgress { }
+- (void) addProgressOutput:(NSString *)output { }
+- (bool) isCancelling:(size_t)received { return NO; }
+- (void) setConfigurationData:(NSString *)data { }
+
+- (void) repairWithSelector:(SEL)selector {
+ [[indicator_ label] performSelectorOnMainThread:@selector(setText:) withObject:[NSString stringWithFormat:Elision_, UCLocalize("REPAIRING"), nil] waitUntilDone:YES];
+ [database_ performSelector:selector];
+ sleep(10);
+ [[indicator_ label] performSelectorOnMainThread:@selector(setText:) withObject:[NSString stringWithFormat:Elision_, UCLocalize("LOADING"), nil] waitUntilDone:YES];
+}
+
+- (id) initWithDatabase:(Database *)database {
+ if ((self = [super init])) {
+ database_ = database;
+ [database_ setDelegate:self];
+ } return self;
+}
+
- (void) loadView {
[self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]];
[[self view] setBackgroundColor:[UIColor pinStripeColor]];
if ((self = [super init]) != nil) {
database_ = database;
- [[self navigationItem] setTitle:UCLocalize("CONFIRM")];
-
NSMutableArray *installing = [NSMutableArray arrayWithCapacity:16];
NSMutableArray *reinstalling = [NSMutableArray arrayWithCapacity:16];
NSMutableArray *upgrading = [NSMutableArray arrayWithCapacity:16];
message:UCLocalize("REMOVING_ESSENTIALS_EX")
delegate:self
cancelButtonTitle:[NSString stringWithFormat:parenthetical, UCLocalize("CANCEL_OPERATION"), UCLocalize("SAFE")]
- otherButtonTitles:[NSString stringWithFormat:parenthetical, UCLocalize("FORCE_REMOVAL"), UCLocalize("UNSAFE")], nil
+ otherButtonTitles:
+ [NSString stringWithFormat:parenthetical, UCLocalize("FORCE_REMOVAL"), UCLocalize("UNSAFE")],
+ nil
];
[essential_ setContext:@"remove"];
SizeString([database_ fetcher].PartialPresent()),
nil];
- [self loadURL:[NSURL URLWithString:CydiaURL(@"ui/ios/confirm/")]];
+ [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/confirm/", UI_]]];
[[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc]
initWithTitle:UCLocalize("CANCEL")
}
- (void) applyRightButton {
-#if !AlwaysReload && !IgnoreInstall
+#if !AlwaysReload
if (issues_ == nil && ![self isLoading])
[[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc]
initWithTitle:UCLocalize("CONFIRM")
#if !AlwaysReload
- (void) confirmButtonClicked {
-#if IgnoreInstall
- return;
-#endif
if (essential_ != nil)
[essential_ show];
else {
message:[NSString stringWithFormat:@"%@\n\n%@", UCLocalize("CONFIGURATION_UPGRADE_EX"), ofile]
delegate:self
cancelButtonTitle:UCLocalize("KEEP_OLD_COPY")
- otherButtonTitles:UCLocalize("ACCEPT_NEW_COPY"),
- // XXX: UCLocalize("SEE_WHAT_CHANGED"),
+ otherButtonTitles:
+ UCLocalize("ACCEPT_NEW_COPY"),
+ // XXX: UCLocalize("SEE_WHAT_CHANGED"),
nil
] autorelease];
UIBarButtonItem *button_;
}
-- (id) initWithDatabase:(Database *)database;
-
-- (void) setPackage:(Package *)package withName:(NSString *)name;
-- (void) setPackage:(Package *)package;
+- (id) initWithDatabase:(Database *)database forPackage:(NSString *)name;
@end
[super dealloc];
}
-- (void) release {
- [super release];
-}
-
- (NSURL *) navigationURL {
- return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://package/%@", [package_ id]]];
+ return [NSURL URLWithString:[NSString stringWithFormat:@"cydia://package/%@", name_]];
}
/* XXX: this is not safe at all... localization of /fail/ */
}
#endif
-- (void) viewWillAppear:(BOOL)animated {
- if (![self hasLoaded])
- [self loadURL:[NSURL URLWithString:CydiaURL(@"ui/ios/package/")]];
- [super viewWillAppear:animated];
-}
-
-- (id) initWithDatabase:(Database *)database {
+- (id) initWithDatabase:(Database *)database forPackage:(NSString *)name {
if ((self = [super init]) != nil) {
database_ = database;
buttons_ = [[NSMutableArray alloc] initWithCapacity:4];
+ name_ = [[NSString alloc] initWithString:name];
} return self;
}
-- (void) setPackage:(Package *)package withName:(NSString *)name {
- if (package_ != nil) {
- [package_ autorelease];
- package_ = nil;
- }
+- (void) reloadData {
+ [super reloadData];
- if (name_ != nil)
- [name_ autorelease];
- name_ = [[NSString alloc] initWithString:name];
+ if (package_ != nil)
+ [package_ autorelease];
+ package_ = [database_ packageWithName:name_];
[buttons_ removeAllObjects];
- if (package != nil) {
- [package parse];
+ if (package_ != nil) {
+ [package_ parse];
- package_ = [package retain];
- commercial_ = [package isCommercial];
+ package_ = [package_ retain];
+ commercial_ = [package_ isCommercial];
if ([package_ mode] != nil)
[buttons_ addObject:UCLocalize("CLEAR")];
action:@selector(customButtonClicked)
];
- [self loadURL:[NSURL URLWithString:CydiaURL([NSString stringWithFormat:@"ui/ios/package/#!/%@", name])]];
-}
-
-- (void) setPackage:(Package *)package {
- [self setPackage:package withName:[package id]];
+ [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/package/#!/%@", UI_, name_]]];
}
- (bool) isLoading {
return commercial_ ? [super isLoading] : false;
}
-- (void) reloadData {
- [super reloadData];
- [self setPackage:[database_ packageWithName:name_] withName:name_];
-}
-
@end
/* }}} */
}
- (void) didSelectPackage:(Package *)package {
- CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_] autorelease]);
- [view setPackage:package];
+ CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_ forPackage:[package id]] autorelease]);
[view setDelegate:delegate_];
[[self navigationController] pushViewController:view animated:YES];
}
- (void) viewWillAppear:(BOOL)animated {
if (![self hasLoaded])
- [self loadURL:[NSURL URLWithString:CydiaURL(@"ui/ios/home/")]];
+ [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/home/", UI_]]];
[super viewWillAppear:animated];
- (void) viewWillAppear:(BOOL)animated {
if (![self hasLoaded])
- [self loadURL:[NSURL URLWithString:CydiaURL(@"ui/ios/manage/")]];
+ [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/manage/", UI_]]];
[super viewWillAppear:animated];
}
- (void) viewDidLoad {
- [[self navigationItem] setTitle:UCLocalize("MANAGE")];
-
[[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc]
initWithTitle:UCLocalize("SETTINGS")
style:UIBarButtonItemStylePlain
/* Cydia Tab Bar Controller {{{ */
@interface CYTabBarController : UITabBarController <
+ UITabBarControllerDelegate,
ProgressDelegate
> {
_transient Database *database_;
_transient NSObject<CydiaDelegate> *updatedelegate_;
id root_;
+ UIViewController *remembered_;
+ _transient UIViewController *transient_;
}
- (NSArray *) navigationURLCollection;
@implementation CYTabBarController
+- (void) setUnselectedViewController:(UIViewController *)transient {
+ NSMutableArray *controllers = [[self viewControllers] mutableCopy];
+ if (transient != nil) {
+ if (transient_ == nil)
+ remembered_ = [[controllers objectAtIndex:0] retain];
+ transient_ = transient;
+ [transient_ setTabBarItem:[remembered_ tabBarItem]];
+ [controllers replaceObjectAtIndex:0 withObject:transient_];
+ [self setSelectedIndex:0];
+ [self setViewControllers:controllers];
+ [self concealTabBarSelection];
+ } else if (remembered_ != nil) {
+ [remembered_ setTabBarItem:[transient_ tabBarItem]];
+ transient_ = transient;
+ [controllers replaceObjectAtIndex:0 withObject:remembered_];
+ [remembered_ release];
+ remembered_ = nil;
+ [self setViewControllers:controllers];
+ [self revealTabBarSelection];
+ }
+}
+
+- (UIViewController *) unselectedViewController {
+ return transient_;
+}
+
+- (void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
+ if ([self unselectedViewController])
+ [self setUnselectedViewController:nil];
+}
+
- (NSArray *) navigationURLCollection {
NSMutableArray *items([NSMutableArray array]);
for (CYViewController *controller in [self viewControllers])
[controller reloadData];
- [(CYNavigationController *)[self transientViewController] reloadData];
+ [(CYNavigationController *)[self unselectedViewController] reloadData];
}
- (void) dealloc {
- (id) initWithDatabase:(Database *)database {
if ((self = [super init]) != nil) {
database_ = database;
+ [self setDelegate:self];
[[self view] setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameChanged:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
@implementation CYNavigationController
-- (void) dealloc {
- [super dealloc];
-}
-
- (NSArray *) navigationURLCollection {
NSMutableArray *stack([NSMutableArray array]);
- (void) reloadData {
for (CYViewController *page in [self viewControllers]) {
+ // Only reload controllers that have already loaded.
+ // This prevents a page from accidentally loading too
+ // early if it hasn't been shown on the screen yet.
if ([page hasLoaded])
[page reloadData];
}
section = [sections objectForKey:key];
if (section == nil) {
_profile(SectionsView$reloadData$Section$Allocate)
- section = [[[Section alloc] initWithName:name localize:YES] autorelease];
+ section = [[[Section alloc] initWithName:key localize:YES] autorelease];
[sections setObject:section forKey:key];
_end
}
- (NSIndexPath *) tableView:(UITableView *)table willSelectRowAtIndexPath:(NSIndexPath *)path {
Package *package([self packageAtIndexPath:path]);
- CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_] autorelease]);
+ CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_ forPackage:[package id]] autorelease]);
[view setDelegate:delegate_];
- [view setPackage:package];
[[self navigationController] pushViewController:view animated:YES];
return path;
}
message:warning
delegate:self
cancelButtonTitle:UCLocalize("CANCEL")
- otherButtonTitles:UCLocalize("ADD_ANYWAY"), nil
+ otherButtonTitles:
+ UCLocalize("ADD_ANYWAY"),
+ nil
] autorelease];
[alert setContext:@"warning"];
message:nil
delegate:self
cancelButtonTitle:UCLocalize("CANCEL")
- otherButtonTitles:UCLocalize("ADD_SOURCE"), nil
+ otherButtonTitles:
+ UCLocalize("ADD_SOURCE"),
+ nil
] autorelease];
[alert setContext:@"source"];
message:UCLocalize("HALFINSTALLED_PACKAGE_EX")
delegate:self
cancelButtonTitle:UCLocalize("FORCIBLY_CLEAR")
- otherButtonTitles:UCLocalize("TEMPORARY_IGNORE"), nil
+ otherButtonTitles:
+ UCLocalize("TEMPORARY_IGNORE"),
+ nil
] autorelease];
[alert setContext:@"fixhalf"];
message:UCLocalize("ESSENTIAL_UPGRADE_EX")
delegate:self
cancelButtonTitle:UCLocalize("TEMPORARY_IGNORE")
- otherButtonTitles:UCLocalize("UPGRADE_ESSENTIAL"), UCLocalize("COMPLETE_UPGRADE"), nil
+ otherButtonTitles:
+ UCLocalize("UPGRADE_ESSENTIAL"),
+ UCLocalize("COMPLETE_UPGRADE"),
+ nil
] autorelease];
[alert setContext:@"upgrade"];
NSString *context([alert context]);
if ([context isEqualToString:@"fixhalf"]) {
- if (button == [alert firstOtherButtonIndex]) {
+ if (button == [alert cancelButtonIndex]) {
@synchronized (self) {
for (Package *broken in broken_) {
[broken remove];
[self resolve];
[self perform];
}
- } else if (button == [alert cancelButtonIndex]) {
+ } else if (button == [alert firstOtherButtonIndex]) {
[broken_ removeAllObjects];
[self _loaded];
}
}
- (CYViewController *) pageForPackage:(NSString *)name {
- CYPackageController *view([[[CYPackageController alloc] initWithDatabase:database_] autorelease]);
- [view setPackage:[database_ packageWithName:name] withName:name];
- return view;
+ return [[[CYPackageController alloc] initWithDatabase:database_ forPackage:name] autorelease];
}
- (CYViewController *) pageForURL:(NSURL *)url {
if ([base isEqualToString:@"url"]) {
// This kind of URL can contain slashes in the argument, so we can't parse them below.
NSString *destination = [[url absoluteString] substringFromIndex:([scheme length] + [@"://" length] + [base length] + [@"/" length])];
- controller = [[[CYBrowserController alloc] init] autorelease];
- [(CYBrowserController *)controller loadURL:[NSURL URLWithString:destination]];
+ controller = [[[CYBrowserController alloc] initWithURL:[NSURL URLWithString:destination]] autorelease];
} else if ([components count] == 1) {
- if ([base isEqualToString:@"storage"]) {
- controller = [[[CYBrowserController alloc] init] autorelease];
- [(CYBrowserController *)controller loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"storage" ofType:@"html"]]];
- }
-
if ([base isEqualToString:@"manage"]) {
controller = [[[ManageController alloc] init] autorelease];
}
if (page != nil) {
CYNavigationController *nav = [[[CYNavigationController alloc] init] autorelease];
[nav setViewControllers:[NSArray arrayWithObject:page]];
- [tabbar_ setTransientViewController:nav];
+ [tabbar_ setUnselectedViewController:nav];
}
return page != nil;
- (void) setupViewControllers {
tabbar_ = [[CYTabBarController alloc] initWithDatabase:database_];
- [tabbar_ setDelegate:self];
NSMutableArray *items([NSMutableArray arrayWithObjects:
[[[UITabBarItem alloc] initWithTitle:@"Cydia" image:[UIImage applicationImageNamed:@"home.png"] tag:0] autorelease],
}
- (CYEmulatedLoadingController *)showEmulatedLoadingControllerInView:(UIView *)view {
- static CYEmulatedLoadingController *fake = [[CYEmulatedLoadingController alloc] init];
+ static CYEmulatedLoadingController *fake = nil;
+
if (view != nil) {
+ if (fake == nil)
+ fake = [[CYEmulatedLoadingController alloc] initWithDatabase:database_];
[view addSubview:[fake view]];
} else {
[[fake view] removeFromSuperview];
+ [fake release];
+ fake = nil;
}
return fake;
recently = true;
}
- if (recently && [Metadata_ objectForKey:@"InterfaceState"]) {
- items = [[Metadata_ objectForKey:@"InterfaceState"] mutableCopy];
- selectedIndex = [[Metadata_ objectForKey:@"InterfaceIndex"] intValue];
- } else {
+ items = [[Metadata_ objectForKey:@"InterfaceState"] mutableCopy];
+ selectedIndex = [[Metadata_ objectForKey:@"InterfaceIndex"] intValue];
+
+ BOOL enough = YES;
+ for (NSArray *entry in items)
+ if ([entry count] <= 0)
+ enough = NO;
+
+ if (!recently || !items || !enough) {
+ selectedIndex = 0;
items = [NSMutableArray array];
[items addObject:[NSArray arrayWithObject:@"cydia://home"]];
[items addObject:[NSArray arrayWithObject:@"cydia://sections"]];
} else
IsWildcat_ = false;
+ UIScreen *screen([UIScreen mainScreen]);
+ if ([screen respondsToSelector:@selector(scale)])
+ ScreenScale_ = [screen scale];
+ else
+ ScreenScale_ = 1;
+
+ NSMutableArray *parts([NSMutableArray arrayWithCapacity:2]);
+ if (ScreenScale_ > 1)
+ [parts addObject:@"@2x"];
+ [parts addObject:(IsWildcat_ ? @"~ipad" : @"~iphone")];
+ UI_ = CydiaURL([NSString stringWithFormat:@"ui/ios%@", [parts componentsJoinedByString:@""]]);
+
PackageName = reinterpret_cast<CYString &(*)(Package *, SEL)>(method_getImplementation(class_getInstanceMethod([Package class], @selector(cyname))));
/* Library Hacks {{{ */