]> git.saurik.com Git - cydia.git/blobdiff - Cydia.mm
Use a static value for the width of the confirm prompt to prevent it from scrolling...
[cydia.git] / Cydia.mm
index f94b9de6d7ff6895cbf621e3c721f6b867cdb536..eb17d6a13ceed4f7565099b47dd606f64da0a6c7 100644 (file)
--- a/Cydia.mm
+++ b/Cydia.mm
@@ -116,6 +116,8 @@ extern "C" {
 
 #include <ext/hash_map>
 
+#include <notify.h>
+
 #import "UICaboodle/BrowserView.h"
 #import "UICaboodle/ResetView.h"
 
@@ -257,6 +259,15 @@ static _finline NSString *CydiaURL(NSString *path) {
     return [[NSString stringWithUTF8String:page] stringByAppendingString:path];
 }
 
+static _finline void UpdateExternalStatus(uint64_t newStatus) {
+    int notify_token;
+    if (notify_register_check("com.saurik.Cydia.status", &notify_token) == NOTIFY_STATUS_OK) {
+        notify_set_state(notify_token, newStatus);
+        notify_cancel(notify_token);
+    }
+    notify_post("com.saurik.Cydia.status");
+}
+
 /* [NSObject yieldToSelector:(withObject:)] {{{*/
 @interface NSObject (Cydia)
 - (id) yieldToSelector:(SEL)selector withObject:(id)object;
@@ -342,6 +353,18 @@ static _finline NSString *CydiaURL(NSString *path) {
     } return self;
 }
 
+- (void)_updateFrameForDisplay {
+    [super _updateFrameForDisplay];
+    if ([self cancelButtonIndex] == -1) {
+        NSArray *buttons = [self buttons];
+        if ([buttons count]) {
+            UIImage *background = [[buttons objectAtIndex:0] backgroundForState:0];
+            for (UIThreePartButton *button in buttons)
+                [button setBackground:background forState:0];
+        }
+    }
+}
+
 - (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
     button_ = buttonIndex + 1;
 }
@@ -351,11 +374,9 @@ static _finline NSString *CydiaURL(NSString *path) {
 }
 
 - (int) yieldToPopupAlertAnimated:(BOOL)animated {
+    [self setRunsModal:YES];
     button_ = 0;
     [self show];
-    NSRunLoop *loop([NSRunLoop currentRunLoop]);
-    NSDate *future([NSDate distantFuture]);
-    while (button_ == 0 && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
     return button_;
 }
 
@@ -1232,7 +1253,7 @@ bool isSectionVisible(NSString *section) {
 - (void) distUpgrade;
 - (void) updateData;
 - (void) syncData;
-- (void) askForSettings;
+- (void) showSettings;
 - (UIProgressHUD *) addProgressHUD;
 - (void) removeProgressHUD:(UIProgressHUD *)hud;
 - (UIViewController *) pageForPackage:(NSString *)name;
@@ -3889,7 +3910,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @end
 /* }}} */
 
-@interface CYBrowserController : BrowserView {
+@interface CYBrowserController : BrowserController {
     CydiaObject *cydia_;
 }
 
@@ -4010,22 +4031,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [super dealloc];
 }
 
-- (void) actionSheet:(UIActionSheet *)sheet clickedButtonAtIndex:(NSInteger)button {
-    NSString *context([sheet context]);
-
-    if ([context isEqualToString:@"cancel"]) {
-        bool clear;
-
-        if      (button == [sheet cancelButtonIndex])      return;
-        else if (button == [sheet destructiveButtonIndex]) clear = true;
-        else                                               clear = false;
-        
-        [sheet dismissWithClickedButtonIndex:0xDEADBEEF animated:YES];
-        [self dismissModalViewControllerAnimated:YES];
-        [delegate_ cancelAndClear:clear];
-    }
-}
-
 - (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button {
     NSString *context([alert context]);
 
@@ -4047,11 +4052,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     }
 }
 
+- (id) invokeDefaultMethodWithArguments:(NSArray *)args {
+    [self dismissModalViewControllerAnimated:YES];
+    [delegate_ cancelAndClear:NO];
+    
+    return nil;
+}
+
 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
     [super webView:sender didClearWindowObject:window forFrame:frame];
     [window setValue:changes_ forKey:@"changes"];
     [window setValue:issues_ forKey:@"issues"];
     [window setValue:sizes_ forKey:@"sizes"];
+    [window setValue:self forKey:@"queue"];
 }
 
 - (id) initWithDatabase:(Database *)database {
@@ -4142,7 +4155,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"confirm" ofType:@"html"]]];
 
         UIBarButtonItem *leftItem = [[UIBarButtonItem alloc]
-            initWithTitle:[NSString stringWithFormat:UCLocalize("SLASH_DELIMITED"), UCLocalize("CANCEL"), UCLocalize("QUEUE")]
+            initWithTitle:UCLocalize("CANCEL")
+            // OLD: [NSString stringWithFormat:UCLocalize("SLASH_DELIMITED"), UCLocalize("CANCEL"), UCLocalize("QUEUE")]
             style:UIBarButtonItemStylePlain
             target:self
             action:@selector(cancelButtonClicked)
@@ -4152,7 +4166,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     } return self;
 }
 
-- (void) didFinishLoading {
+- (void) applyRightButton {
     UIBarButtonItem *rightItem = [[UIBarButtonItem alloc]
         initWithTitle:UCLocalize("CONFIRM")
         style:UIBarButtonItemStylePlain
@@ -4160,27 +4174,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         action:@selector(confirmButtonClicked)
     ];
 #if !AlwaysReload && !IgnoreInstall
-    if (issues_ == nil) [[self navigationItem] setRightBarButtonItem:rightItem];
-    else [[self navigationItem] setRightBarButtonItem:nil];
+    if (issues_ == nil && ![self isLoading]) [[self navigationItem] setRightBarButtonItem:rightItem];
+    else [super applyRightButton];
+#else
+       [[self navigationItem] setRightBarButtonItem:nil];
 #endif
     [rightItem release];
 }
 
 - (void) cancelButtonClicked {
-    UIActionSheet *sheet = [[UIActionSheet alloc]
-        initWithTitle:nil
-        delegate:self
-        cancelButtonTitle:nil
-        destructiveButtonTitle:nil
-        otherButtonTitles:nil
-    ];
-
-    [sheet addButtonWithTitle:UCLocalize("CANCEL_CLEAR")];
-    [sheet setDestructiveButtonIndex:[sheet numberOfButtons] - 1];
-    [sheet addButtonWithTitle:UCLocalize("CONTINUE_QUEUING")];
-    [sheet setContext:@"cancel"];
-
-    [delegate_ showActionSheet:[sheet autorelease] fromItem:[[self navigationItem] leftBarButtonItem]];
+    [self dismissModalViewControllerAnimated:YES];
+    [delegate_ cancelAndClear:YES];
 }
 
 #if !AlwaysReload
@@ -4385,6 +4389,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 - (void) closeButtonPushed {
     running_ = NO;
 
+    UpdateExternalStatus(0);
+
     switch (Finish_) {
         case 0:
             [self dismissModalViewControllerAnimated:YES];
@@ -4458,6 +4464,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     system("su -c /usr/bin/uicache mobile");
 
+    UpdateExternalStatus(Finish_ == 0 ? 2 : 0);
+
     [delegate_ setStatusBarShowsProgress:NO];
 }
 
@@ -4469,6 +4477,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)object title:(NSString *)title {
+    UpdateExternalStatus(1);
+
     if (title_ != nil)
         [title_ release];
     if (title == nil)
@@ -5055,9 +5065,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return files_ == nil ? 0 : [files_ count];
 }
 
-- (float) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
-    return 24;
-}
+/*- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return 24.0f;
+}*/
 
 - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
     static NSString *reuseIdentifier = @"Cell";
@@ -5082,6 +5092,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         files_ = [[NSMutableArray arrayWithCapacity:32] retain];
 
         list_ = [[UITableView alloc] initWithFrame:[[self view] bounds]];
+        [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+        [list_ setRowHeight:24.0f];
         [[self view] addSubview:list_];
 
         [list_ setDataSource:self];
@@ -5246,11 +5258,18 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) actionButtonClicked {
-    if (commercial_ && [self isLoading])
-        [super _rightButtonClicked];
-    else
+       // Wait until it's done loading.
+    if (![self isLoading])
         [self _actionButtonClicked];
 }
+
+- (void) reloadButtonClicked {
+    // Don't reload a package view by clicking the button.
+}
+
+- (void) applyLoadingTitle {
+    // Don't show "Loading" as the title. Ever.
+}
 #endif
 
 - (id) initWithDatabase:(Database *)database {
@@ -5318,7 +5337,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     }
 }
 
-- (void) didFinishLoading {
+- (void) applyRightButton {
     int count = [buttons_ count];
     UIBarButtonItem *actionItem = [[UIBarButtonItem alloc]
         initWithTitle:count == 0 ? nil : count != 1 ? UCLocalize("MODIFY") : [buttons_ objectAtIndex:0]
@@ -5326,7 +5345,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         target:self
         action:@selector(actionButtonClicked)
     ];
-    [[self navigationItem] setRightBarButtonItem:actionItem];
+    if (![self isLoading]) [[self navigationItem] setRightBarButtonItem:actionItem];
+       else [super applyRightButton];
     [actionItem release];
 }
 
@@ -5416,10 +5436,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated];
 }
 
-- (CGFloat) tableView:(UITableView *)table heightForRowAtIndexPath:(NSIndexPath *)path {
-    return 73;
+/*- (CGFloat) tableView:(UITableView *)table heightForRowAtIndexPath:(NSIndexPath *)path {
     return [PackageCell heightForPackage:[self packageAtIndexPath:path]];
-}
+}*/
 
 - (NSIndexPath *) tableView:(UITableView *)table willSelectRowAtIndexPath:(NSIndexPath *)path {
     Package *package([self packageAtIndexPath:path]);
@@ -5451,6 +5470,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
         list_ = [[UITableView alloc] initWithFrame:[self bounds] style:UITableViewStylePlain];
         [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+        [list_ setRowHeight:73.0f];
         [self addSubview:list_];
 
         [list_ setDataSource:self];
@@ -6202,6 +6222,21 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     ];
     [[self navigationItem] setRightBarButtonItem:rightItem animated:animated];
     [rightItem release];
+    
+    if (IsWildcat_ && !editing) {
+        UIBarButtonItem *settingsItem = [[UIBarButtonItem alloc]
+            initWithTitle:UCLocalize("SETTINGS")
+            style:UIBarButtonItemStylePlain
+            target:self
+            action:@selector(settingsButtonClicked)
+            ];
+        [[self navigationItem] setLeftBarButtonItem:settingsItem];
+        [settingsItem release];
+    }
+}
+
+- (void) settingsButtonClicked {
+    [delegate_ showSettings];
 }
 
 - (void) editButtonClicked {
@@ -6373,20 +6408,23 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) settingsButtonClicked {
-    [delegate_ askForSettings];
-    [delegate_ updateData];
+    [delegate_ showSettings];
 }
 
 #if !AlwaysReload
 - (void) queueButtonClicked {
     [delegate_ queue];
 }
-#endif
 
-- (void) didFinishLoading {
-    [self queueStatusDidChange];
+- (void) applyLoadingTitle {
+    // No "Loading" title.
 }
 
+- (void) applyRightButton {
+    // No right button.
+}
+#endif
+
 - (void) queueStatusDidChange {
 #if !AlwaysReload
     if (!IsWildcat_ && Queuing_) {
@@ -6742,9 +6780,9 @@ freeing the view controllers on tab change */
     return editing_ ? [sections_ count] : [filtered_ count] + 1;
 }
 
-- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
-    return 45;
-}
+/*- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return 45.0f;
+}*/
 
 - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
     static NSString *reuseIdentifier = @"SectionCell";
@@ -6800,6 +6838,7 @@ freeing the view controllers on tab change */
 
         list_ = [[UITableView alloc] initWithFrame:[[self view] bounds]];
         [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+        [list_ setRowHeight:45.0f];
         [[self view] addSubview:list_];
 
         [list_ setDataSource:self];
@@ -6898,7 +6937,7 @@ freeing the view controllers on tab change */
         target:self
         action:@selector(editButtonClicked)
     ];
-    [[self navigationItem] setRightBarButtonItem:rightItem];
+    [[self navigationItem] setRightBarButtonItem:rightItem animated:[[self navigationItem] rightBarButtonItem] != nil];
     [rightItem release];
 
     [list_ reloadData];
@@ -6934,6 +6973,7 @@ freeing the view controllers on tab change */
     NSMutableArray *sections_;
     UITableView *list_;
     unsigned upgrades_;
+    BOOL hasSentFirstLoad_;
 }
 
 - (id) initWithDatabase:(Database *)database delegate:(id)delegate;
@@ -6955,7 +6995,12 @@ freeing the view controllers on tab change */
 
 - (void) viewDidAppear:(BOOL)animated {
     [super viewDidAppear:animated];
-    [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated];
+    if (!hasSentFirstLoad_) {
+        hasSentFirstLoad_ = YES;
+        [self performSelector:@selector(reloadData) withObject:nil afterDelay:0.0];
+    } else {
+        [list_ deselectRowAtIndexPath:[list_ indexPathForSelectedRow] animated:animated];
+    }
 }
 
 - (NSInteger) numberOfSectionsInTableView:(UITableView *)list {
@@ -6989,10 +7034,9 @@ freeing the view controllers on tab change */
     return cell;
 }
 
-- (CGFloat) tableView:(UITableView *)table heightForRowAtIndexPath:(NSIndexPath *)path {
-    return 73;
+/*- (CGFloat) tableView:(UITableView *)table heightForRowAtIndexPath:(NSIndexPath *)path {
     return [PackageCell heightForPackage:[self packageAtIndexPath:path]];
-}
+}*/
 
 - (NSIndexPath *) tableView:(UITableView *)table willSelectRowAtIndexPath:(NSIndexPath *)path {
     Package *package([self packageAtIndexPath:path]);
@@ -7024,13 +7068,13 @@ freeing the view controllers on tab change */
 
         list_ = [[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain];
         [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+        [list_ setRowHeight:73.0f];
         [[self view] addSubview:list_];
 
         [list_ setDataSource:self];
         [list_ setDelegate:self];
 
         delegate_ = delegate;
-        [self reloadData];
     } return self;
 }
 
@@ -7180,14 +7224,21 @@ freeing the view controllers on tab change */
 - (id) title { return nil; }
 
 - (id) initWithDatabase:(Database *)database {
-    if ((self = [super initWithDatabase:database title:UCLocalize("SEARCH") filter:@selector(isUnfilteredAndSearchedForBy:) with:nil]) != nil) {
-        search_ = [[objc_getClass("UISearchBar") alloc] initWithFrame:CGRectMake(0, 0, [[self view] frame].size.width, 44.0f)];
+    return [super initWithDatabase:database title:UCLocalize("SEARCH") filter:@selector(isUnfilteredAndSearchedForBy:) with:nil];
+}
+
+- (void)viewDidAppear:(BOOL)animated {
+       [super viewDidAppear:animated];
+       if (!search_) {
+        search_ = [[objc_getClass("UISearchBar") alloc] initWithFrame:CGRectMake(0, 0, [[self view] bounds].size.width, 44.0f)];
+        [search_ layoutSubviews];
         [search_ setPlaceholder:UCLocalize("SEARCH_EX")];
-        [search_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
+        UITextField *textField = [search_ searchField];
+        [textField setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin];
         [search_ setDelegate:self];
-        [[search_ searchField] setEnablesReturnKeyAutomatically:NO];
-        [[self navigationItem] setTitleView:search_];
-    } return self;
+        [textField setEnablesReturnKeyAutomatically:NO];
+        [[self navigationItem] setTitleView:textField];
+    }
 }
 
 - (void) _reloadData {
@@ -7201,6 +7252,11 @@ freeing the view controllers on tab change */
     [packages_ resetCursor];
 }
 
+- (void) didSelectPackage:(Package *)package {
+    [search_ resignFirstResponder];
+    [super didSelectPackage:package];
+}
+
 @end
 /* }}} */
 /* Settings Controller {{{ */
@@ -7426,6 +7482,165 @@ freeing the view controllers on tab change */
     [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"signature" ofType:@"html"]]];
 }
 
+@end
+/* }}} */
+/* Role Controller {{{ */
+@interface RoleController : CYViewController {
+    _transient Database *database_;
+    id roledelegate_;
+    UITableView *table_;
+    UISegmentedControl *segment_;
+    UIView *container_;
+}
+@end
+
+@implementation RoleController
+- (void) dealloc {
+    [table_ release];
+    [segment_ release];
+    [container_ release];
+    
+    [super dealloc];
+}
+
+- (id) initWithDatabase:(Database *)database delegate:(id)delegate {
+    if ((self = [super init])) {
+        database_ = database;
+        roledelegate_ = delegate;
+        
+        [[self navigationItem] setTitle:UCLocalize("WHO_ARE_YOU")];
+        
+        NSArray *items = [NSArray arrayWithObjects:
+            UCLocalize("USER"), 
+            UCLocalize("HACKER"),
+            UCLocalize("DEVELOPER"),
+        nil];
+        segment_ = [[UISegmentedControl alloc] initWithItems:items];
+        container_ = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [[self view] frame].size.width, 44.0f)];
+        [container_ addSubview:segment_];
+        
+        int index = -1;
+        if ([Role_ isEqualToString:@"User"]) index = 0;
+        if ([Role_ isEqualToString:@"Hacker"]) index = 1;
+        if ([Role_ isEqualToString:@"Developer"]) index = 2;
+        if (index != -1) {
+            [segment_ setSelectedSegmentIndex:index];
+            [self showDoneButton];
+        }
+        
+        [segment_ addTarget:self action:@selector(segmentChanged:) forControlEvents:UIControlEventValueChanged];
+        [self resizeSegmentedControl];
+        
+        table_ = [[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStyleGrouped];
+        [table_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+        [table_ setDelegate:self];
+        [table_ setDataSource:self];
+        [[self view] addSubview:table_];
+        [table_ reloadData];
+    } return self;
+}
+
+- (void) resizeSegmentedControl {
+    CGFloat width = [[self view] frame].size.width;
+    [segment_ setFrame:CGRectMake(width / 32.0f, 0, width - (width / 32.0f * 2.0f), 44.0f)];
+}
+
+- (void) viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    
+    [self resizeSegmentedControl];
+}
+
+- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
+    [self resizeSegmentedControl];
+}
+
+- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
+    [self resizeSegmentedControl];
+}
+
+- (void) save {
+    NSString *role = nil;
+    
+    switch ([segment_ selectedSegmentIndex]) {
+        case 0: role = @"User"; break;
+        case 1: role = @"Hacker"; break;
+        case 2: role = @"Developer"; break;
+
+        _nodefault
+    }
+
+    if (![role isEqualToString:Role_]) {
+        Role_ = role;
+        
+        Settings_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+            Role_, @"Role",
+        nil];
+
+        [Metadata_ setObject:Settings_ forKey:@"Settings"];
+
+        Changed_ = true;
+    
+        [roledelegate_ updateData];
+    }
+}
+
+- (void) segmentChanged:(UISegmentedControl *)control {
+    [self showDoneButton];
+}
+
+- (void) doneButtonClicked {
+    [self save];
+    [[self navigationController] dismissModalViewControllerAnimated:YES];
+}
+
+- (void) showDoneButton {
+    UIBarButtonItem *rightItem = [[UIBarButtonItem alloc]
+        initWithTitle:UCLocalize("DONE")
+        style:UIBarButtonItemStyleDone
+        target:self
+        action:@selector(doneButtonClicked)
+    ];
+    [[self navigationItem] setRightBarButtonItem:rightItem animated:[[self navigationItem] rightBarButtonItem] == nil];
+    [rightItem release];
+}
+
+- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
+    // XXX: For not having a single cell in the table, this sure is a lot of sections.
+    return 6;
+}
+
+- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return 0; // :(
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return nil; // This method is required by the protocol.
+}
+
+- (NSString *) tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
+    if (section == 1) 
+        return UCLocalize("ROLE_EX");
+    if (section == 4) 
+        return [NSString stringWithFormat:
+            @"%@: %@\n%@: %@\n%@: %@",
+            UCLocalize("USER"), UCLocalize("USER_EX"), 
+            UCLocalize("HACKER"), UCLocalize("HACKER_EX"), 
+            UCLocalize("DEVELOPER"), UCLocalize("DEVELOPER_EX")
+        ];
+    else return nil;
+}
+
+- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
+    if (section == 3) return 44.0f;
+    else return 0;
+}
+
+- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
+    if (section == 3) return container_;
+    else return nil;
+}
+
 @end
 /* }}} */
 
@@ -7616,8 +7831,7 @@ freeing the view controllers on tab change */
     [[root_ selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation];
 }
 
-- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
-{
+- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
     // XXX: fix Apple's layout bug
     [[root_ selectedViewController] _updateLayoutForStatusBarAndInterfaceOrientation];
 }
@@ -8104,40 +8318,11 @@ static _finline void _setHomePage(Cydia *self) {
     tag_ = tag;
 }
 
-- (void) askForSettings {
-    NSString *parenthetical(UCLocalize("PARENTHETICAL"));
-
-    CYActionSheet *role([[[CYActionSheet alloc]
-        initWithTitle:UCLocalize("WHO_ARE_YOU")
-        buttons:[NSArray arrayWithObjects:
-            [NSString stringWithFormat:parenthetical, UCLocalize("USER"), UCLocalize("USER_EX")],
-            [NSString stringWithFormat:parenthetical, UCLocalize("HACKER"), UCLocalize("HACKER_EX")],
-            [NSString stringWithFormat:parenthetical, UCLocalize("DEVELOPER"), UCLocalize("DEVELOPER_EX")],
-        nil]
-        defaultButtonIndex:-1
-    ] autorelease]);
-
-    [role setMessage:UCLocalize("ROLE_EX")];
-
-    int button([role yieldToPopupAlertAnimated:YES]);
-
-    switch (button) {
-        case 1: Role_ = @"User"; break;
-        case 2: Role_ = @"Hacker"; break;
-        case 3: Role_ = @"Developer"; break;
-
-        _nodefault
-    }
-
-    Settings_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
-        Role_, @"Role",
-    nil];
-
-    [Metadata_ setObject:Settings_ forKey:@"Settings"];
-
-    Changed_ = true;
-
-    [role dismiss];
+- (void) showSettings {
+    RoleController *role = [[RoleController alloc] initWithDatabase:database_ delegate:self];
+    CYNavigationController *nav = [[CYNavigationController alloc] initWithRootViewController:role];
+    if (IsWildcat_) [nav setModalPresentationStyle:UIModalPresentationFormSheet];
+    [container_ presentModalViewController:nav animated:YES];
 }
 
 - (void) setPackageController:(PackageController *)view {
@@ -8359,6 +8544,11 @@ static _finline void _setHomePage(Cydia *self) {
     }
 }
 
+- (void) applicationWillResignActive:(UIApplication *)application {
+    // Stop refreshing if you get a phone call or lock the device.
+    if ([container_ updating]) [container_ cancelUpdate];
+}
+
 - (void) applicationDidFinishLaunching:(id)unused {
     [CYBrowserController _initialize];
 
@@ -8417,7 +8607,7 @@ static _finline void _setHomePage(Cydia *self) {
     }
 
     if (Role_ == nil)
-        [self askForSettings];
+        [self showSettings];
 
     _trace();
 
@@ -8506,6 +8696,26 @@ MSHook(void, UIWebDocumentView$_setUIKitDelegate$, UIWebDocumentView *self, SEL
     return _UIWebDocumentView$_setUIKitDelegate$(self, _cmd, delegate);
 }
 
+static NSNumber *shouldPlayKeyboardSounds;
+
+Class $UIHardware;
+
+MSHook(void, UIHardware$_playSystemSound$, Class self, SEL _cmd, int soundIndex) {
+    switch (soundIndex) {
+        case 1104: // Keyboard Button Clicked
+        case 1105: // Keyboard Delete Repeated
+            if (!shouldPlayKeyboardSounds) {
+                NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:@"/var/mobile/Library/Preferences/com.apple.preferences.sounds.plist"];
+                shouldPlayKeyboardSounds = [[dict objectForKey:@"keyboard"] ?: (id)kCFBooleanTrue retain];
+                [dict release];
+            }
+            if (![shouldPlayKeyboardSounds boolValue])
+                break;
+        default:
+            _UIHardware$_playSystemSound$(self, _cmd, soundIndex);
+    }
+}
+
 int main(int argc, char *argv[]) { _pooled
     _trace();
 
@@ -8527,6 +8737,13 @@ int main(int argc, char *argv[]) { _pooled
         _UIWebDocumentView$_setUIKitDelegate$ = reinterpret_cast<void (*)(UIWebDocumentView *, SEL, id)>(method_getImplementation(UIWebDocumentView$_setUIKitDelegate$));
         method_setImplementation(UIWebDocumentView$_setUIKitDelegate$, reinterpret_cast<IMP>(&$UIWebDocumentView$_setUIKitDelegate$));
     }
+
+    $UIHardware = objc_getClass("UIHardware");
+    Method UIHardware$_playSystemSound$(class_getClassMethod($UIHardware, @selector(_playSystemSound:)));
+    if (UIHardware$_playSystemSound$ != NULL) {
+        _UIHardware$_playSystemSound$ = reinterpret_cast<void (*)(Class, SEL, int)>(method_getImplementation(UIHardware$_playSystemSound$));
+        method_setImplementation(UIHardware$_playSystemSound$, reinterpret_cast<IMP>(&$UIHardware$_playSystemSound$));
+    }
     /* }}} */
     /* Set Locale {{{ */
     Locale_ = CFLocaleCopyCurrent();