Showing posts tagged iOS

Ally Bank is an Internet bank without a brick-and-mortar presence. I find it ironic that to date they still don’t have a mobile-optimized experience. And when I say mobile-optimized experience, I mean iPhone app.

Recently, I had a need for a bank with a mobile app that could deposit checks using the iPhone’s camera. I had considered Chase bank, but I just don’t like them. I think banks with a “you’re just a number” attitude like Chase will be given a run for their money by more forward thinking banking experiences like BankSimple, due to open this year.

I opened an account with PNC because they had an iPhone app with remote deposit. Unfortunately, the app is utter crap. It times out on login eight out of ten times. You can’t even access remote deposit until you’ve banked with them for 30 days, but they don’t mention that anywhere in the app’s description. Instead you’re left to hunt all over the app for a button that doesn’t exist. I wasted a good thirty minutes looking for it and Googling for some kind of manual. I’m likely going to close the account.

I like Ally Bank, the absence of hidden and ATM fees, and their decent web experience, but I’m left wishing that they had a top-notch mobile experience to match. I’m not alone. Point your browser at their blog and do a search for “iPhone” to see what I’m talking about. To see if I could take this discussion from their blog into a more public arena, I created the Ally Bank needs an iPhone app Facebook page. I also created an app mockup to use as an avatar and to exercise my Photoshop skills a bit. If only all banking applications looked as good and worked as well as Tweetbot.

Anyway, I guess I’ll wait until someone gets online banking right. I’m banking (pun intended) on BankSimple, but I also have high hopes for Ally. If you happen to be an Ally customer, I hope you’ll like my Facebook page.

A phone number formatting category on NSString

Actually, all the credit goes to Ahmed Abdelkader for this code. All I did was stick it in an easy-to-use category.

This work is licensed under a Creative Commons Attribution 3.0 License which basically means you can use it free for any purpose as long as you give proper attribution.

NSString+PhoneNumberFormatting.m

//
//  NSString+PhoneNumberFormatting.m
//
//  Created by Mike Manzano on 7/28/11.
//
//	This work is licensed under a Creative Commons Attribution 3.0 License.
//
//	Adapted from work by Ahmed Abdelkader on 1/22/10, whose work is
//  licensed under a Creative Commons Attribution 3.0 License.
//	http://the-lost-beauty.blogspot.com/2010/01/locale-sensitive-phone-number.html

#import 

// Supported locales
extern NSString *xPhoneNumberLocale_US ;
extern NSString *xPhoneNumberLocale_UK ;
extern NSString *xPhoneNumberLocale_JP;

@interface NSString (PhoneNumberFormatting)
- (NSString *)formattedPhoneNumberForLocale:(NSString *)xPhoneNumberLocale ;
@end

NSString+PhoneNumberFormatting.m

//
//  NSString+PhoneNumberFormatting.m
//
//  Created by Mike Manzano on 7/28/11.
//
//	This work is licensed under a Creative Commons Attribution 3.0 License.
//
//	Adapted from work by Ahmed Abdelkader on 1/22/10, whose work is
//  licensed under a Creative Commons Attribution 3.0 License.
//	http://the-lost-beauty.blogspot.com/2010/01/locale-sensitive-phone-number.html


#import "NSString+PhoneNumberFormatting.h"

NSString *xPhoneNumberLocale_US = @"us" ;
NSString *xPhoneNumberLocale_UK = @"uk" ;
NSString *xPhoneNumberLocale_JP = @"jp" ;


@implementation NSString (PhoneNumberFormatting)

+ (NSDictionary *) sharedPhoneFormats
	{
	static NSDictionary *formats = nil ;
	
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		NSArray *usPhoneFormats = [NSArray arrayWithObjects:
								   @"+1 (###) ###-####",
								   @"1 (###) ###-####",
								   @"011 $",
								   @"###-####",
								   @"(###) ###-####", nil];
		
		NSArray *ukPhoneFormats = [NSArray arrayWithObjects:
								   @"+44 ##########",
								   @"00 $",
								   @"0### - ### ####",
								   @"0## - #### ####",
								   @"0#### - ######", nil];
		
		NSArray *jpPhoneFormats = [NSArray arrayWithObjects:
								   @"+81 ############",
								   @"001 $",
								   @"(0#) #######",
								   @"(0#) #### ####", nil];
		
		formats = [[NSDictionary alloc] initWithObjectsAndKeys:
							 usPhoneFormats, xPhoneNumberLocale_US,
							 ukPhoneFormats, xPhoneNumberLocale_UK,
							 jpPhoneFormats, xPhoneNumberLocale_JP,
							 nil];
		});
	
	return formats ;
	}


- (BOOL)canBeInputByPhonePad:(char)c 
	{
	if(c == '+' || c == '*' || c == '#') return YES;
	if(c >= '0' && c <= '9') return YES;
	return NO;
	}

// Strips out invalid characters
- (NSString *)strip:(NSString *)phoneNumber 
	{
	NSMutableString *res = [[[NSMutableString alloc] init] autorelease];
	for(int i = 0; i < [phoneNumber length]; i++) 
		{
		char next = [phoneNumber characterAtIndex:i];
		if([self canBeInputByPhonePad:next])
			[res appendFormat:@"%c", next];
		}
	return res;
	}


- (NSString *)formattedPhoneNumberForLocale:(NSString *)xPhoneNumberLocale 
	{
	NSString *phoneNumber = self ;
	NSArray *localeFormats = [[NSString sharedPhoneFormats] objectForKey:xPhoneNumberLocale];
	if(localeFormats == nil) return phoneNumber;
	NSString *input = [self strip:phoneNumber];
	for(NSString *phoneFormat in localeFormats) 
		{
		int i = 0;
		NSMutableString *temp = [[[NSMutableString alloc] init] autorelease];
		for(int p = 0; temp != nil && i < [input length] && p < [phoneFormat length]; p++) 
			{
			char c = [phoneFormat characterAtIndex:p];
			BOOL required = [self canBeInputByPhonePad:c];
			char next = [input characterAtIndex:i];
			switch(c) 
				{
				case '$':
					p--;
					[temp appendFormat:@"%c", next]; i++;
					break;
				case '#':
					if(next < '0' || next > '9') 
						{
						temp = nil;
						break;
						}
					[temp appendFormat:@"%c", next]; i++;
					break;
				default:
					if(required) 
						{
						if(next != c) 
							{
							temp = nil;
							break;
							}
						[temp appendFormat:@"%c", next]; i++;
						} 
					else 
						{
						[temp appendFormat:@"%c", c];
						if(next == c) i++;
						}
				break;
				}
			} // build temp loop
		if(i == [input length]) 
			{
			return temp;
			}
		} // for each format
	return input;
	}
@end

Sometimes my mom gets confused and doesn’t realize she can scroll a page on her iPhone. She just forgets about scrolling altogether. She’s not dumb, it’s just that virtual user interfaces aren’t her thing.

I was at the Apple store today checking out the new iPad kiosks and noticed this really cool technique for hinting that a page is scrollable. You can see it in the video.

When you display a scrolling page, it first appears below the top. It then scrolls the page to the top effective telling you that you that there’s more to see “below the fold”. Clever.