The decline of Apple

Back in the 90s hardly anyone used Macs or Apple products. They had a small foothold in schools and graphic design shops but that was about it. The iPod was the beginning of their post-millenium rise – the 3rd generation iPod released in 2003 was the first Apple hardware I’d ever wanted, and I eventually purchased a 4th gen iPod in 2004.

ipod
The fourth generation iPod “photo” model

A few years later in 2007 the iPhone came out and completely changed what a smartphone was. Prior the the iPhone the best smartphone was probably a Blackberry, with it’s clunky little keyboard and tiny screen. But the iPhone with it’s giant glass screen and intuitive gestures was revolutionary.

history-of-iphone-3gs-hero
The iPhone 3GS (2009), the first iPhone I owned

There’s hardly any products I can think of that I could afford to purchase the best in the world of. Take cars for example. I can’t afford a brand new Ferrari. Or TVs – I couldn’t afford (or couldn’t justify buying) a top of the line whizz-bang TV. But a phone – yes! The iPhone at the time was the best phone any money could buy. Not that I gave a shit about having an awesome phone, all I wanted at the time was to have wikipedia in my pocket so that I could be a know-all at parties.

Both the iPod and later the iPhone made people, especially us geeks, open our eyes to how good Apple’s products could be. The Macbook Air made us realise that the lightest and sexiest laptop/notebook was also made by Apple. Apple started shipping with Intel processors! Within a couple of years Apple laptops were everywhere, even at conferences for us Windows developers.

I never considered myself an Apple fanboy, but here I am in 2017 typing this on my trusty Macbook Air, with my aging iPhone 5 alongside, and an iPad sitting on the windowsill (which I still never use). At the time of each purchase it wasn’t that I wanted to buy an Apple product, it was just that I wanted the best laptop/phone/tablet on the market at the time, and each of those happened to be made by Apple.

Amongst my geeky friends it was pretty much the same pattern. Mac laptops and iPhones for the most part. Not all though – some swore by Android phones.

In the last couple of years though, Apple have made a few key mistakes with their products which have seen my geek friends desert them, and I think it won’t be long before I too leave Apple products behind.

iWatch sucked

The first big Apple let down was the Apple Watch. Rumours had abounded for years that Apple would be bringing out a smartwatch that would change the world, just like the iPhone did. I was excited about it. Then when it was finally released, it was expensive and gimmicky. Hardly any of my geek friends bought one (hi Andy J, Alan, Alex).

No headphone port

Yep, another mistake was omitting the headphone port from the iPhone 7. Not a single iPhone buyer thought that was a good idea or a step forward. That small error was enough for us geeks to doubt that Apple knew what they were doing, and look at Android phones.

Downgrading the Macbook Pro

The killer mistake though was 2016’s Macbook Pro

  • More expensive
  • No USB 3.0 ports
  • No HDMI port
  • No SD card reader
  • No magsafe power
  • Similar spec CPU, memory and storage to the 2015 model
  • Lame touch bar

Although most users don’t use the F1-F12 keys on the top row of a QWERTY keyboard, us developers DO use them, so getting rid of those keys was a big deal.

See Benjamin Button reviews the new Macbook Pro

Now what?

In summary, Apple haven’t released anything amazing since Steve Jobs died.

So what’s a geek to buy in 2017 then? I don’t know – it’s not as straightforward as a couple of years ago. I usually go on my geek friends recommendations – on the phone front, Google Pixel phones are well regarded. iPhones are hanging on by their fingernails.

On the laptop front, NONE of my friends are buying new Macbooks. Microsoft(!) Surface Books or Surface Pros are looking like a good option. Windows laptops are making a comeback.

What now for Apple

For now, they’ve lost the geek crowd, and in technology where the geeks lead the world follows. Apple needs to release a new killer product to get us back. Or just drop the prices on their bloody phones and make a decent laptop again!

They have enough $$$ in the bank that they’re not gonna die any time soon, but until they win the geek crowd back I predict shrinking profits, maybe even losses, and a dropping share price for Apple (currently USD$132).

Advertisement

On music consumption

This morning I was thinking about how my music listening has changed over the years. The very first album I bought was Guns N’ Roses Appetite for Destruction, which I bought on a cassette tape with my pocket money for something ridiculous like $15 in 1987.

2zgvqex

I didn’t spend too much money over the years on cassettes cos back then we all used to dub them – pretty much everyone had a stereo with 2 tape decks – one for playing and the other for recording.

80s-boom-box-ghetto-blaster-tape-deck

A few years later CDs came out and wow, music got even more expensive. But the quality was worth it – no more tape hiss. However, I still didn’t spend a whole lot on music – I was still at high school, so the tape dubbing continued – except now the source was a digital quality CD instead of a tape :-) I remember getting Guns N’ Roses Use Your Illusion 1 AND 2 off my mate’s older brother (hi Ed!) this way.

Come 1997 (woah, 20 years ago) and I was studying computer science at university, and a friend showed me mp3s (hi Flip!). At first I didn’t get it – because HDD space was expensive, so I was like “nah, I don’t really wanna fill my hard drive with music”. But once I realised how easy it was to share music (no more tape dubbing!) I was sold. So I got me a 2Gb Bigfoot hard drive and I was like – wow, loads of space, bring it on.

2664533936_3a6dfbc8f4
Bigfoot hard drive

This was the start of a period of CD borrowing and ripping – where you’d “rip” a CD on your computer to convert it into mp3s. Back then on our 2x speed CDROM drives and Pentium 1 processors it would take about half an hour to rip the CD and then I think most of the night(!?) to compress the ripped CD to an mp3 album. Playing an mp3 on your computer (using Winamp) was very CPU intensive, it would take pretty much 100% of your CPU to play an mp3 so you couldn’t use it for anything else while playing.

I fleshed out my music collection by borrowing friends’ CDs and ripping them – then you’d meet up with another fellow ripper (hi Trent!) and share mp3s with them, by unplugging the hard drive from your computer, taking it over to their house, and plugging it into their computer. Even though the mp3s were a digital copy so in theory perfect copies, every now and then you’d come across a track with pops and clicks in it – from when someone with a crappy CDROM drive would rip something.

1999 and Napster came along. Peer to peer sharing of music over the Internet! Almost any album you wanted, available to download, for free! Although we only had 56k modems to connect to the Internet, it still meant you could download an entire album in about 2 hours – much quicker and easier than ripping! And then we started running the Linux version of Napster on the University’s computers, so we could pull down an album in about ten or 20 minutes.

A few years later I was working my first post-Uni job so now I had money to spend. I did have a guilty conscience over all that music I’d ripped off so I started buying CDs – which would get converted to mp3s straight away, then the CD would never get played again. I’d moved to Auckland and I started going to concerts – my loose rule was – if I have an album by a band, and they come to Auckland, then I should go see them live. That was my way of supporting an artist.

Anyway, back to the mp3s, in the early 2000s. I was never a straight-up music hoarder. I didn’t want to have any old shite in my collection – it had to be good, memorable music, that I would still like in a few years. I became extremely pedantic with my organising and naming of the mp3s. Every mp3 had to be named correctly, with full metadata (ID3v1 and V2 tags), the correct genre, album art. I used JRiver Media Center software to manage it all. That program could do everything – I even used my newfound VB skills to write a plugin for it.

audio_standard_view
JRiver Media Center

Every time I’d get an album (usually from Napster, or from copying friends music over our corporate network (hi Deano!)), I’d spend ages scrutinizing it – do I like it? Will I still like it a few years from now? If this album came on randomly, would I listen to it? If it came on publicly, would I be embarrased by it? If it met those criteria then it was worthy enough to be added to my library. I’d almost always have to rename it correctly and populate all the metadata. All of which took time and effort.

All this time I was still constrained to listening to these mp3s through a PC – which was OK. I had a PC hooked up to a stereo in my bedroom, and then at work I’d be working on a PC wearing headphones all day. But mp3s on the go wasn’t yet possible for me. Early portable mp3 players were clunky, prone to crashing, had crap interfaces, or just didn’t have the capacity to store my entire collection.

The first game changer that came out was Apple’s iPod in 2001. I remember when it came out – it took the mp3 world by storm, mainly because it was pretty and easy to use. It solved the problem navigating through 1000 songs thanks to its scrollwheel interface. The downside of it was you had to run a Mac computer to use it – and absolutely no one had one of those. Back then Apple was dead. No one had a Mac PC or laptop. The only place I’d seen them was in the Uni’s computer labs.

ipod

If only I’d bought Apple shares back then! I knew the iPod was a hit, but I didn’t think to invest in the company. It turned out to be the beginning of Apple’s turnaround. Back then their shares were around $1.50, now they’re $117.

The first iPod wasn’t big enough for me though – it was 5Gb and I probably had around 20Gb of music by then. But Moore’s law caught up to my music collection, and the 4th generation iPod with 60Gb capacity (and Windows compatibility) was the first one I bought, in 2004. At last, my music everywhere.

In 2010 I moved to the UK and first heard about Spotify, which some of my friends were using. I ignored it for a few years, because I was pretty happy with my mp3 collection, and because I thought they might get shutdown by the music industry (or just go broke), as so many other online music services had.

2014 and I started using Spotify at work, just to try it out. I realised that their playlists solve the problem of what to listen to – when you’ve got hundreds of albums to choose from picking one can be tough. Spotify then became my main source – I installed it on my iPad and that was our main source of music in the house.

So, alas, my carefully curated music collection became obsolete. Here it is, on my laptop right now, still frozen in 2014. The _2014 folder is for new music for curation.

screen-shot-2017-01-08-at-17-22-10

So, I’m a happy Spotify user. Until last week. My girlfriend bought me an Amazon Echo for Christmas, and the voice interface has me sold. I say “Alexa, play music”. And it replies “OK, here’s a station you might like: Adele”. And I’m usually fine with what it (she?) chooses. Alexa has further removed the choice – I don’t even need to think about which playlist to play. I just say “play music” and that’s it. I’ve gone from an avid music collector before to not really caring what I listen to now. Life’s too short to be tagging mp3s.

Anyway, I didn’t intend for this post to be so long – I was just going to write how Alexa has killed my mp3 collection and ended up going on a trip down memory lane. I’ve added a new “Musing” category to this blog as I have a few more topics in mind.

OnePlus 2 = poo

I’ve been a long time iPhone user, first with a 3GS in 2009 and then an iPhone 5 in 2012. So at 3+ years old my iPhone 5 was getting a bit long in tooth. My colleague Nick recently replaced his iPhone 5 with a OnePlus 2 and he was very happy with it. Envious of that big screen and also it’s relatively cheap price, I decided to give it a go. I also wanted to try out Android as I’d heard good things.

DSC04123.0

I wasn’t impressed.

On the phone hardware side: The ringtone was quiet and the vibration unnoticeable when in a pocket. I managed to cause it to crash a few times by accidentally hammering the back button. It would get hot. And battery life wasn’t amazing.

On the Android side: I didn’t like Android’s way of doing notifications. Some web pages would run really slowly, and I don’t tolerate lag in a brand new phone.

As for that big screen – well, the apps didn’t feel optimized it – e.g. Facebook would still only show one news story at a time. Even with the smallest font there wouldn’t be much text on the screen at once, just lots of white space and big buttons. So the big screen felt wasted.

After 5 days I gave up on it and decided to go back to my iPhone 5, so I attempted to return the OnePlus. And that’s where their pathetic support team got involved. I started the returns process on Feb 16, and so far I’ve had 12 messages back and forward confirming my address, and confirming whether or not I want to return the cover, over and over. Finally today, March 11, I received an RMA form. So it’s taken almost a month of backwards and forwards with “Joey” and “Alex”. Let’s see how long it takes to get the money into my account.

Update: it took another month for the RMA to be processed, and I hadn’t heard anything until I chased them, so in total it took 2 months (and 18 emails) just to return the phone and get a refund.

Generating Swagger example requests with Swashbuckle

This is a follow on from my post from last year about Generating example Swagger responses.

Update April 2020: You probably don’t need to do it this way any more. Swashbuckle.AspNetCore supports request examples via XML comments. See my blog post.

Update May 4th 2017: I have created a new NuGet package called Swashbuckle.Examples which contains the functionality I previously described in this blog post. The code lives on GitHub.

I have also created a .NET Standard version of the NuGet package at Swashbuckle.AspNetCore.Filters, which is also on GitHub.

It can also be useful to generate example requests, and in this post I will show you how.

First, install my Swashbuckle.Examples NuGet package, or the .NET Core version Swashbuckle.AspNetCore.Filters

Now decorate your controller methods with the included SwaggerRequestExample attribute:

[Route(RouteTemplates.DeliveryOptionsSearchByAddress)]
[SwaggerRequestExample(typeof(DeliveryOptionsSearchModel), typeof(DeliveryOptionsSearchModelExample))]
[SwaggerResponse(HttpStatusCode.OK, Type = typeof(DeliveryOptionsModel), Description = "Delivery options for the country found and returned successfully")]
[SwaggerResponseExample(tHttpStatusCode.OK, typeof(DeliveryOptionsModelExample))]
[SwaggerResponse(HttpStatusCode.BadRequest, Type = typeof(ErrorsModel), Description = "An invalid or missing input parameter will result in a bad request")]
[SwaggerResponse(HttpStatusCode.InternalServerError, Type = typeof(ErrorsModel), Description = "An unexpected error occurred, should not return sensitive information")]
public async Task<IHttpActionResult> DeliveryOptionsForAddress(DeliveryOptionsSearchModel search)
{

Now implement it, in this case via a DeliveryOptionsSearchModelExample (which should implement IExamplesProvider), which will generate the example data. It should return the type you specified when you specified the [SwaggerRequestExample].

public class DeliveryOptionsSearchModelExample : IExamplesProvider
{
    public object GetExamples()
    {
        return new DeliveryOptionsSearchModel
        {
            Lang = "en-GB",
            Currency = "GBP",
            Address = new AddressModel
            {
                Address1 = "1 Gwalior Road",
                Locality = "London",
                Country = "GB",
                PostalCode = "SW15 1NP"
            },
            Items = new[]
            {
                new ItemModel
                {
                    ItemId = "ABCD",
                    ItemType = ItemType.Product,
                    Price = 20,
                    Quantity = 1,
                    RestrictedCountries = new[] { "US" }
                }
            }
        };
    }

Don’t forget to enable the ExamplesOperationFilter when you enable Swagger, as before:

configuration
    .EnableSwagger(c =>
    {
        c.OperationFilter<ExamplesOperationFilter>();
    })
    .EnableSwaggerUi();

Or if you’re using .NET Core

services.AddSwaggerGen(c =>
   {
        c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
        c.OperationFilter<ExamplesOperationFilter>();

Now that we’ve done all that, we should see the examples output in our swagger.json file, which you can get to by starting your solution and navigating to /swagger/docs/v1.

Capture

And the best part is, when you’re using swagger-ui (at /swagger/ui/index), now when you click the example request in order to populate the form, instead of getting an autogenerated request like this:

Untitled

You’ll get your desired example, like this:

Capture2

I find that having a valid request on hand is useful for smoke testing your API endpoints are working correctly.

Azure Emulator not working with SQL server alias

I just spent a few hours trying to figure out something that had me stumped.

In my local dev environment I’m building a web api which has a SQL database. The connection string for the database is an alias with a named pipe. If I set the web api as StartUp project in Visual Studio it works fine. (See this post for some tips on how to do that). But when I’d instead start the Azure emulator as the StartUp project it wouldn’t connect to the sql server, with the good ol’:

A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 – Error Locating Server/Instance Specified)

Eventually I figured it out. The alias was the problem, because if I changed the connectionstring to .\sqlexpress it worked fine.

Digging deeper, the problem was I had set up the alias on the “SQL Native Client 11.0 Configuration (32bit)” node, but I hadn’t added an alias on the “SQL Native Client 11.0 Configuration” node. So the fix was to create an additional Alias on the “SQL Native Client 11.0 Configuration” node.

sql

So it seems that debugging a web api locally may be a 32 bit process but debugging with the Azure emulator is a 64 bit process. Maybe?

Anyway, hope this helps someone.

Generating Swagger example responses with Swashbuckle

Update April 2020: You probably don’t need to do it this way any more. Swashbuckle.AspNetCore supports request examples via XML comments. See my blog post.

Update May 4th 2017: I have created a new NuGet package called Swashbuckle.Examples which contains the functionality I previously described in this blog post. The code lives on GitHub.

I have also created a .NET Standard version of the NuGet package at Swashbuckle.AspNetCore.Filters, which is also on GitHub.

Swashbuckle is a tool for generating Swagger, the API description language, from your ASP.NET Web Api solution.
Using Swashbuckle, which provides Swagger-UI, you can create pretty living documentation of your web api, like this:
swagger

Documenting the Response

In this post I am going to show you how to document the Response, and a new way to generate some response examples.

You can specify the type of response for Swashbuckle a number of ways. Consider a simple API endpoint which returns a list of Countries:

public class CountriesController : DefaultController
{
    [HttpGet]
    public async Task<HttpResponseMessage> Get()
    {
        var resource = new List<Country>
        {
            new Country {Code = "AR", Name = "Argentina"},
            new Country {Code = "BR", Name = "Brazil"},
            // etc etc omitted for brevity
        };

        return Request.CreateResponse(HttpStatusCode.OK, resource);
    }
}

One way of describing the response code and content for Swashbuckle is using a combination of XML comments, and the ResponseType attribute, like so:

/// <response code="200">Countries returned OK</response>
[HttpGet]
[ResponseType(typeof(IEnumerable<Country>))]
public async Task<HttpResponseMessage> Get()
{

However, this only allows for one type of response.

If your API method can return multiple types, i.e. in the case of an error, then you can use the new SwaggerResponse attribute:

[HttpGet]
[SwaggerResponse(HttpStatusCode.OK, Type=typeof(IEnumerable<Country>))]
[SwaggerResponse(HttpStatusCode.BadRequest, Type = typeof(IEnumerable<ErrorResource>))]
public async Task<HttpResponseMessage> Get(string lang)
{

The Swagger 2.0 spec allows for examples to be added to the Response. However, at time of writing Swashbuckle doesn’t support this. Fortunately Swashbuckle is extendible so here is a way of doing it.

Install my Swashbuckle.Examples NuGet package.

Decorate your methods with the new SwaggerResponseExample attribute:

[SwaggerResponse(HttpStatusCode.OK, Type=typeof(IEnumerable<Country>))]
[SwaggerResponseExample(HttpStatusCode.OK, typeof(CountryExamples))]
[SwaggerResponse(HttpStatusCode.BadRequest, Type = typeof(IEnumerable<ErrorResource>))]
public async Task<HttpResponseMessage> Get(string lang)

Now you’ll need to add an Examples class, which will implement IExamplesProvider to generate the example data

public class CountryExamples : IExamplesProvider
{
    public object GetExamples()
    {
        return new List<Country>
        {
            new Country { Code = "AA", Name = "Test Country" },
            new Country { Code = "BB", Name = "And another" }
        };
    }
}

And finally enable the ExamplesOperationFilter when you configure Swashbuckle’s startup.

configuration
    .EnableSwagger(c =>
    {
        c.OperationFilter<ExamplesOperationFilter>();
    })
    .EnableSwaggerUi();

Now that we’ve done all that, we should see the examples output in our swagger.json file, which you can get to by starting your solution and navigating to /swagger/docs/v1.

response

And then, when you browse the swagger-ui at /swagger/ui/index, instead of an autogenerated example like this:
response old

You’ll see your desired example, like this:
response new

Be sure to check out Part 2, where we again use Swashbuckle to generate example requests.

Run a Windows Azure cloud service locally without the Azure compute emulator

A big bugbear when developing Azure cloud services is the Azure emulator. You make a code change and the write – compile – debug process is slowed down big time because you have to wait for the Azure emulator to start up every time.

One project I worked on had a Web API running in an Azure cloud service and an ASP.NET MVC website running in another cloud service. So in order to develop it locally we had to run 2 instances of Visual Studio 2013 and each of them would fire up an emulator. Needless to say this was quite the resource hog and we’d every now and then see unexpected issues with Visual Studio or the emulators. Oh and the emulators would fight over which ports they would run on so we had to ensure we started debugging the API first so that it would get port 443 and then start the website which would default to 445.

So why can’t we just install our Web API and ASP.NET MVC website into IIS and not use the emulators? Well there are two blockers:

  1. The Azure diagnostics config will throw exceptions if we’re not running in Azure
  2. Settings are read from cloud config values in ServiceConfiguration.cscfg via RoleEnvironment.GetConfigurationSettingValue which needs Azure

My colleague Dylan came up with a solution. Basically, in the Global.asax.cs of both our website and our web api, we need to check if we’re running in Azure or not.

If we are in Azure, then use 1. configure Azure diagnostics config, and 2. read cloud config values using the default RoleEnvironment.GetConfigurationSettingValue.

If we are not in Azure, then 1. don’t configure Azure diagnostics, and 2. read cloud config values from ServiceConfiguration.cscfg manually via XML. parsing.


if (RoleEnvironment.IsAvailable) // we are in Azure
{
    Trace.Listeners.Add(new DiagnosticMonitorTraceListener());
    Trace.AutoFlush = true;
}
else
{
    var di = new DirectoryInfo(HttpContext.Current.Server.MapPath("~"));
    var solutionRoot = di.Parent;

    var xdoc = XDocument.Load(solutionRoot.FullName + @"\Identity.Web.Azure\ServiceConfiguration.cscfg");
    ConfigurationSettingsProvider.Current = new NotInRoleEnvirovmentConfigurationProvider(xdoc, "Identity.Web");
}

Our ConfigurationSettingsProvider.Current is by default a DefaultConfigurationSettingsProvider which uses RoleEnvironment.GetConfigurationSettingValue(key) to read the cloud config – we use one of these when we’re in Azure.

Our NotInRoleEnvirovmentConfigurationProvider reads the .cscfg file using XDocument.

So now I can install our website and web api into IIS locally – and code changes are visible after a compile. No need to run 2 Visual Studios and wait for the memory hungry emulator to startup every time. If I need to debug I can Debug -> Attach to process. Much more productive :-)

Should I cycle: on hold for now

I started building a prototype for Should I cycle on iOS 8 and pretty early on I’ve hit a roadblock. What I wanted was a daily scheduled notification to popup telling me whether conditions were right for cycling or not.

I wanted to use iOS’s local notifications to do this – but I don’t think it can be done. Sure, you can schedule a local notification to popup at say 7:30am, but what’s displayed on the notification has to be set at the time the notification is scheduled. What this means is let’s say at 9pm at night I schedule a notification for 7:30am the next day. And at 9pm the sky is clear and conditions are fine. Then at 7:30am the next day it’s raining. Well, the 7:30am notification popup is going to say “Sky is clear” because that’s what the conditions were like when the notification was scheduled.

So that’s annoying.

What I want to do can be done via remote notifications – i.e. the I would have to schedule on a web server a push notification out to the mobile at 7:30am the next day. But that would be pretty complicated to setup for a prototype.

So I decided I would give up on the push notification for now and instead just check the current weather / cycling conditions whenever the app is started.

But then another thing happened – I gave up cycling to work for various reasons. So for now I have no motivation to work on this app. Maybe one day I’ll pick it up again.

Browse and debug an Azure web role website running locally on a mobile device

So, you’re developing an Azure website using a Web role, and now you want to see what that website looks like on a mobile device.

First, follow my instructions here to set up port forwarding for your website.

Once you’ve done that, assuming your mobile device is on the same network as your PC running the Azure web role, you should just be able to open the URL for the website in your mobile web browser – in my case this https://10.200.34.201:800/

If you need to debug the traffic between your Azure web role and the mobile device, you can do that using Fiddler or Charles proxy. Fiddler instructions here. Charles instructions here. And SSL instructions for Charles here, if your site runs on SSL.

If you need to manipulate the traffic between Azure and the mobile browser, you can use Fiddler’s custom rules to do that – in my case I had to inject a “IsMobile=true” header. Fiddler -> Rules -> Customize Rules. Locate “static function OnBeforeRequest” and add the following line to it. oSession.oRequest[“IsMobile”] = “true”;

Should I cycle: designing the UI

This is the sixth post in my series on building a mobile app, “should I cycle”.

Now that I’ve got my API implemented I’m ready to build the client app.

For my initial prototype I don’t really need any UI at all – I can get away with hard-coding the values I want for my should I cycle alerts particular to my route – e.g. 8am, London, no rain, not easterly winds over 10 mph. However, I haven’t gotten around to implementing that yet for one reason – I can’t decide whether to implement an iPhone or Android (or even Windows Phone) version first. See, I currently have a 2 year old iPhone 5 which is working fine. Just last week the new iPhone 6 was released and I was a bit underwhelmed, so I probably won’t be buying one. So right now I can’t decide whether to stick to my iPhone 5 or jump over to Android and get myself a OnePlus One phone which my flatmate owns and looks pretty good.

In the meantime I started thinking about what the UI for a first version of Should I cycle could look like, and came up with these mockups (using Balsamiq). As you can see I’ve taken iOS’s Alarm app as inspiration and copied much of its UI.

01 Home

02 add alert

03 repeat

04 label

05 city

06 Pollution

07 weather

08 wind direction

09 wind speed

Hmm I guess right now I should just get on with a prototype (with no UI) on iOS for my iPhone 5!