Nick Harris

Glassboard 2.0… Sorry I didn’t mention it… It’s kind of Private

But it got good press :-)

http://daringfireball.net/linked/2012/05/15/glassboard-2

http://thenextweb.com/apps/2012/05/15/brent-simmons-talks-glassboard-2-0-making-a-path-for-work-and-doing-cross-platform-right/
http://www.loopinsight.com/2012/05/15/glassboard-2-0/
http://appadvice.com/appnn/2012/05/glassboard-2-0-introduces-new-navigation-and-news-feed-experience-across-the-board
http://verynicewebsite.net/2012/05/glassboard-2-0/
http://sparkspring.com/post/23166016772/simple-but-smart
http://inessential.com/2012/05/15/glassboard_2_0
http://walkerfenton.blogspot.com/2012/05/glassboard-20-launches.html
http://www.android4schools.com/2012/01/17/glassboard-offers-private-mobile-group-messaging/
http://beakerbrain.blogspot.com/2012/05/wheres-beakers-brain-been.html
http://www.informationweek.com/byte/news/personal-tech/mobile-apps/240000450
http://collindonnell.com/2012/05/15/glassboard-2-0/
http://alexking.org/blog/2012/05/15/glassboard-2-0-and-glassbot
http://alexking.org/blog/2012/05/16/glassboard-2-0
http://www.expeditionportal.com/forum/threads/78362-Glassboard-app-for-iOS-Android
http://www.rassoc.com/gregr/weblog/2012/05/15/glassboard-2-0-and-glassbot/
http://www.macworld.com/article/1166864/the_week_in_ios_apps_hear_hear_.html
http://arstechnica.com/apple/2012/05/hands-on-with-glassboard-2-0-for-ios-simple-private-group-sharing/
http://www.iphoneclub.nl/184125/glassboard-voor-iphone-chatten-en-samenwerken-in-besloten-groep/
http://www.rexblog.com/2012/05/20/47694
http://frankthuss.wordpress.com/2012/05/24/glassboard-mobiel-samenwerken-in-besloten-groepen-yam-hanicto/
http://www.computerwoche.de/netzwerke/mobile-wireless/2512883/
http://www.onemorething.nl/2012/05/omts-wekelijkse-app-update-week-21/
http://www.cmswire.com/cms/social-business/glassboard-20-private-boards-now-offer-desktop-blackberry-access-015820.php
http://web.appstorm.net/reviews/file-management/share-ideas-and-files-privately-on-glassboard/

 

Written by Nick Harris

June 6, 2012 at 4:28 am

Posted in Uncategorized

Ze Frank

I’m a huge fan of Ze Frank  (http://www.zefrank.com/).

Ze had “The Show” for a year – I loved it!

A few years later he made this song as a request for a fan:

Chill Out

When I had the opportunity to give back this is what I received in return:

Thanks Ze!

Written by Nick Harris

April 22, 2012 at 7:57 am

Posted in Uncategorized

iOS Slide-out Navigation Code

Ken Yarmosh has a great post entitled New iOS Design Pattern: Slide-out Navigation in which he does a great job describing this new design pattern and how different applications are using it.

I personally like the approach so I decided to figure out how I would implement it.  I have no idea if any of the apps mentioned in Ken’s post actually do it this way, but it works.

Slide-out Navigation

The idea here is use the Application Delegate as the controller between the current content view of the application and the menu view.  When a view in the application needs to show the navigation menu, it can call a method on the App Delegate that handles all the work of showing and restoring the menu and content views.

The “illusion” of the content view sliding off to reveal the menu view is done by first grabbing a screenshot of the current content view and passing that off to the MenuViewController.  The MenuViewController has a UIImageView that it populates with that screenshot.  Its this UIImageView that acts as the content view overlay. It makes animation smooth using a single flat image rather then trying to animate an actual view back and forth.

AppDelegate

The AppDelegate acts as the central controller whenever any views need to show the menu view. It gets two new properties:

@property (strong, nonatomic) ContentViewController *contentViewController;

@property (strong, nonatomic) MenuViewController *menuViewController;

 

The contentViewController gets used as a temp holding place while the menuViewController is visible.  Having the two of them in the app delegate makes switching the window.rootViewController easier.  I do this in two new methods on the AppDelegate:

-(void)showSideMenu

{

// before swaping the views, we'll take a "screenshot" of the current view

// by rendering its CALayer into the an ImageContext then saving that off to a UIImage

CGSize viewSize = self.contentViewController.view.bounds.size;

UIGraphicsBeginImageContextWithOptions(viewSize, NO, 1.0);

[self.contentViewController.view.layer renderInContext:UIGraphicsGetCurrentContext()];

 

// Read the UIImage object

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

 

// pass this image off to the MenuViewController then swap it in as the rootViewController

self.menuViewController.screenShotImage = image;

self.window.rootViewController = self.menuViewController;

}

 

-(void)hideSideMenu

{

// all animation takes place elsewhere. When this gets called just swap the contentViewController in

self.window.rootViewController = self.contentViewController;

}

 

MenuViewController

The MenuViewController handles all the animation and touch gestures that make the slide-out navigation feel real.  It has two important properties:

@property (strong, nonatomic) IBOutlet UIImageView *screenShotImageView;

@property (strong, nonatomic) UIImage *screenShotImage;

 

Using the viewWillAppear:animated method we can reset the menu view, covering the entire view with the screenShotImageView whose image has been set using the screenshot taken by the app delegate of the currentContentViewController.  It’s then just animated to the right.

-(void)viewWillAppear:(BOOL)animated

{

[super viewWillAppear:animated];

 

// when the menu view appears, it will create the illusion that the other view has slide to the side

// what its actually doing is sliding the screenShotImage passed in off to the side

// to start this, we always want the image to be the entire screen, so set it there

[screenShotImageView setImage:self.screenShotImage];

[screenShotImageView setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];

 

// now we'll animate it across to the right over 0.2 seconds with an Ease In and Out curve

// this uses blocks to do the animation. Inside the block the frame of the UIImageView has its

// x value changed to where it will end up with the animation is complete.

// this animation doesn't require any action when completed so the block is left empty

[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{

[screenShotImageView setFrame:CGRectMake(265, 0, self.view.frame.size.width, self.view.frame.size.height)];

}

completion:^(BOOL finished){  }];

}

 

The easy part of the MenuViewController is if the user selects a new view.  Simply set the currentViewController on the AppDelegate with the new view, then call the slideThenHide method which animates the screenshot back over the entire screen completing the illusion.

-(IBAction)showLogoExpandingViewController

{

// this sets the currentViewController on the app_delegate to the expanding view controller

// then slides the screenshot back over

[app_delegate setContentViewController:[[LogoExpandingViewController alloc] initWithNibName:@"LogoExpandingViewController" bundle:nil]];

[self slideThenHide];

}

 

-(void) slideThenHide

{

// this animates the screenshot back to the left before telling the app delegate to swap out the MenuViewController

// it tells the app delegate using the completion block of the animation

[UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{

[screenShotImageView setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];

}

completion:^(BOOL finished){ [app_delegate hideSideMenu]; }];

}

 

The more difficult part is detecting when the user interacts with the screenshot.  If they touch it, the end result should be the menu hiding and the content view becoming active again.  So it needs a UITapGestureRecognizer.

It also needs to be user interactive.  If they touch and drag the screenshot it should respond by moving. So it also needs a UIPanGestureRecognizer.

I wasn’t up to speed with dragging using Gestures so after a little searching I found this post by Soo How Ng which made it pretty simple:

- (void)viewDidLoad

{

[super viewDidLoad];

 

// create a UITapGestureRecognizer to detect when the screenshot recieves a single tap

tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapScreenShot:)];

[screenShotImageView addGestureRecognizer:tapGesture];

 

// create a UIPanGestureRecognizer to detect when the screenshot is touched and dragged

panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureMoveAround:)];

[panGesture setMaximumNumberOfTouches:2];

[panGesture setDelegate:self];

[screenShotImageView addGestureRecognizer:panGesture];

}

 

- (void)viewDidUnload

{

[super viewDidUnload];

 

// remove the gesture recognizers

[self.screenShotImageView removeGestureRecognizer:self.tapGesture];

[self.screenShotImageView removeGestureRecognizer:self.panGesture];

}

 

- (void)singleTapScreenShot:(UITapGestureRecognizer *)gestureRecognizer

{

// on a single tap of the screenshot, assume the user is done viewing the menu

// and call the slideThenHide function

[self slideThenHide];

}

 

/* The following is from http://blog.shoguniphicus.com/2011/06/15/working-with-uigesturerecognizers-uipangesturerecognizer-uipinchgesturerecognizer/ */

-(void)panGestureMoveAround:(UIPanGestureRecognizer *)gesture;

{

UIView *piece = [gesture view];

[self adjustAnchorPointForGestureRecognizer:gesture];

 

if ([gesture state] == UIGestureRecognizerStateBegan || [gesture state] == UIGestureRecognizerStateChanged) {

 

CGPoint translation = [gesture translationInView:[piece superview]];

 

// I edited this line so that the image view cannont move vertically

[piece setCenter:CGPointMake([piece center].x + translation.x, [piece center].y)];

[gesture setTranslation:CGPointZero inView:[piece superview]];

}

else if ([gesture state] == UIGestureRecognizerStateEnded)

[self slideThenHide];

}

 

- (void)adjustAnchorPointForGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {

if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {

UIView *piece = gestureRecognizer.view;

CGPoint locationInView = [gestureRecognizer locationInView:piece];

CGPoint locationInSuperview = [gestureRecognizer locationInView:piece.superview];

 

piece.layer.anchorPoint = CGPointMake(locationInView.x / piece.bounds.size.width, locationInView.y / piece.bounds.size.height);

piece.center = locationInSuperview;

}

}

 

Sample

 

Source Code

https://bitbucket.org/nh129096/slideoutnavigationsample/src

 

Written by Nick Harris

February 5, 2012 at 3:53 am

Posted in Uncategorized

Our Language

Brent recently chimed in on the age old argument of which language is the best.

I’m always disheartened by these arguments.

In the end we flick bits off and on.

Those bits flicker into the most beautiful things the mind has only begun to imagine.

Lets make beautiful things.

Written by Nick Harris

November 8, 2011 at 7:11 am

Posted in Uncategorized

iPhone 4 Pictures

Reasons why I love this picture:

1. It was there
2. I get to share what I saw
3. S
4. Symmetry
5. Red / Blue
6. Engineering (built for semi-trucks at high speeds)
7. My shadow
8. Snow capped peaks

Written by Nick Harris

July 9, 2011 at 5:16 am

Posted in Uncategorized

Sports Thoughts – 6/18/2011

Going on vacation with my family this weekend.  Need to get brushed up on all my sports related thoughts so I don’t get out maned by my sister…

LeBron James

I was happy Dirk Nowitzki, Jason Kidd and Mark Cuban won a championship.  I thought LeBron’s post game interviews and tweets were funny – but I agree that he needs a strong mentor – a Chris Carter type – to help him get to his next level.  He’s not there yet.  He will be.

Mark Cuban

Blog Maverick was one of the first blogs I subscribed to when I started at NewsGator 6 years ago.  Mark is a polarizing figure.  I fall on the “love him” side.  His handling of the playoff interviews this year was incredible, but him deferring the acceptance of the trophy to the original owner of the Mavs was one of the classiest things I’ve ever seen in sports.  The biggest FUCK YOU to all his haters.  Well done sir.

Vancouver

The city is overreacting.  We get it that it was just a few idiots.  We’re Americans.  We deal with those kind of people everyday.  I think it got so much coverage here cause we assumed you didn’t have those idiots too.

Boston

One of the most important cities in America’s history is also currently the best sports city in the world.  7 championships in all major American sports leagues in the past decade.  Kudos Boston!

Packers Ring Ceremony

The maturity of my favorite players on the team continues.  Arron Rodgers, Clay Matthews, Greg Jennings – all class acts.  It was fun to watch them post all their pictures on Twitter last night as they got their rings.

Tim Tebow

I won’t buy his jersey but I’m proud to have him in Denver.  I’m no Broncos fan, but players who reach out and make a positive impact on the community get my admiration.  Tebow’s partnership with Denver Mattress for his foundation to help orphans is just the latest example.  John Lynch was one of the greatest persons I think Denver had the pleasure of have play for a team.  Class act all the way.  Tebow I think has that same draw.. even if he’s never a starter here.

Roy McIlroy

I’m cheering for him.  His post-Masters-collapse interview was one of the most refreshing takes on ones personal faults I’ve heard from an athlete in a long time.

Ohio State Football

Looks more and more like Pryor is going to be portrayed as the poison pill.  Is it fair?  No.  It’s obvious for anyone who follows college football.  But the effort to help Tressels image by doing so doesn’t bother me much.  I think Tressel is one of the finest coaches in college football.  I wasn’t happy to see him go, though I was one who thought he should be fired to save the reputation of OSU.  His reputation was fairly safe no matter what.

Written by Nick Harris

June 18, 2011 at 7:45 am

Posted in Uncategorized

Let them have feedback!

I’ve written and tweeted before about webservice API’s that make it difficult to figure out what you’re doing wrong… but at least those gave me some kind of feedback that something was wrong.  The worst are services that give you no feedback what-so-ever.  If anything my name is attached to ever does this to you, let me know immediately!

My Latest Experience

We use SendGrid to send emails from our platform.  Could we have done it ourselves?  Of course.  But reliably delivering emails is a lot more complicated then you would think, so we decided to go with a trusted company.  We’ve been using them for months and honestly they’ve been terrific!

This week I was tasked with estimating a solution for our users to be able to reply to emails we send.  My first thought was our own SMTP server since we have the code in the NewsGator platform.  But moving an SMTP service in your own datacenter to Azure turned out to be more difficult than I wanted.

My former CTO (who actually wrote the SMTP code I was working with) pointed out to me that SendGrid had its own solution for email replies.  I was pleasantly surprised with how easy it looked – and its SendGrid… they’ve been great!  They even had step-by-step instructions on how to get everything configured.  This included writing and deploying our own REST endpoint as well as DNS/MX configuration stuff.  Not a trivial task but it looked so easy I went for it.

About 6 hours later I had talked to the right people in our company to get the DNS/MX setup correctly, rolled my own endpoint, unit tested it and deployed it to our production environment. Now for the big test… send an email to our MX domain and watch it get parsed by SendGrid and passed to my endpoint.  I sent the first email.  Then the second.  Then the third, fourth, fifth and sixth.  Nothing.

OK – what’s going wrong?  My emails aren’t bouncing (I tested. GMail bounces invalid DNS lookups almost instantly).  My unit tests work so my endpoint is correct.  So I logged into the SendGrid dashboard to see if it would tell me what’s wrong.  Nothing.

Ugh!!!

Finally it hit me – what account type do we have and what’s supported with it?  I didn’t setup our account so I honestly didn’t know the differences.

On the dashboard our account is listed as a “Recurring Account”.  Cool.  So I went to the pricing matrix - no “Recurring Account” type there.

Well shit.  Back to our account page.  Clicked the “Upgrade Account” button.  Ah!  ”Current Package: BasicPlan: $9.95″.

Back to the pricing matrix.  No “Basic Plan”.

Oh for fucks’ sake.

Well the “Bronze” plan is $9.95… and there it is… the red X in the column for Parse API.

I had to sign into our SendGrid account to configure it correctly to use the Parse API.  Presumably it knew at that point what account type we had.  It should have never let me go ahead with configuring this feature.  At the very least it should have told me when I was done that it wouldn’t be enabled until we upgraded our account.  Instead I got nothing but an hour of detective work to figure out it wasn’t a problem with my code.

**Have we upgraded?  No.  $9.95 vs. $79.95 isn’t a small upgrade.

The Point

My point here is that if you offer a tiered service plan, make it EXPLICITLY CLEAR EVERYWHERE what options are available and which aren’t.  Hide them or disable them (which is better is a whole different UX discussion… but choose one!).  Not giving feedback anywhere along the way is a horrible experience!

My guess is that I’m the first to stumble upon this with SendGrid and based on our experience with them they will rectify this as soon as they can.  They have been a great service to us.  I hope they’ll do the right thing and I’ll still recommend SendGrid for anyone who needs to send email via Azure or for any other situation where you need your email delivered reliably.  But hopefully if you’re creating one of these services you’ll remember my story :-)

** I don’t have the authorization to upgrade our account.  I’ll revisit if we do.

Written by Nick Harris

June 16, 2011 at 4:19 am

Posted in Uncategorized

Follow

Get every new post delivered to your Inbox.