First foray into phonegap, and Habit Calendar prototype 1

Introduction

I’ve developed some simple apps for iOS using swift in the past, but this is my first experience using JS with phonegap.  The no-brainer question comes up – why would I make an app with JS and phonegap when I can just write native Swift?  Sure, writing an app natively is better for a slew of reasons: including speed, style consistency and deeper access to phone functionality, but I really like Javascript, and the ability to write something once and potentially have it work on both the web and a phone is pretty neat.  I’m sure it’s not as simple as ‘write once, deploy everywhere’, but it’s neat in concept to deepen my skills with JS and also get to prototype some ideas for phone apps.

This idea stems from my lovely girlfriend who every now and again decides to try and form some new habits.  A go to strategy for this is to create a simple ‘yes/no’ calendar.  Set a small goal, then write down, every day, whether you did that thing or not.  Basically it looks like this:

IMG_3633-e1444755430102-768x1024

Small goal? 2 minutes of Planks a day. Check.  Document progress?  Check.  Remarkably successful? Check.

 

Because phones are with us everyday, all the time, what better platform to provide a simple calendar app to log your habit building progress?   Plus, the calendar format adheres to a powerful idea in habit building – ‘Never miss twice’.

never-miss-twice

 

This study, published in the European Journal of Psychology, concludes that while time to form a habit varies wildly between individuals (ranging from 18 – over 200 days), there seemed to be plateau at which a significant majority of people solidify habits.  That mark is 66 days.  The study also looks at the effect of missing days, and concludes that missing one day shows no appreciable decline in the participants ability to form a habit as long as they returned to the habit the following day.  In other words, it’s okay to miss a day as long as you get right back on the horse the next day.

So, my goals for this app are:

  1. Inform the user how to form a new habit
  2. Ensure they understand that small steps are the key to success
  3. Ensure they understand it’s important not to miss twice.
  4. Provide a clean, simple interface to add a habit
  5. Provide a simple ‘yes/no’ interaction scheme to track progress

 

Mock-up

First step – mock up:

homescreen-v1-01

User flow and architecture

The flow is like so:

  • User clicks ‘New’ to create a new habit calender
  • They enter a title (or select a habit from a premade set of options), and they enter a length for how long they’d like to track this habit
  • A new calendar is instantiated and shown in the body of the app, while a reference is kept on the bottom scroll bar
  • As the user enters more habits, they are all stored in the bottom

At first I thought I was going to need an interactive calendar – after all, the app is based on checking off days that you’ve done something.  And there are TONS of Jquery plugins for calendars.  But after mocking it up, what I realized was that I didn’t want a calendar, I just wanted a way to deal with dates, and it would be nice to have a single object containing all the data for any specific calendar, so I figured I’d implement it myself.  Ideally the calendar library would be instantiated with the start date, and the length of the habit, and do all the work itself.  It’ll be re-usable for any and all calendars created by the user.

Library Construction

The calendar lib should be exposed on the global module so I can instantiate new objects with a single line:

var newCal = new HabitCal(length, startDate);

The basic structure is wrapped an immediately invoked function expression (IIFE) to ensure namespace security, and passed the global object.  The object is then exposed to the global object like so:

(function(global) {

    // Constructor function
    var HabitCal = function(elt, startDate, length) {
    
    // Hold reference to parent HTML element
    this.elt = elt;
    this.startDate = startDate;
    
    // Get portions of date
    this.month = cal_months_labels[startDate.getMonth()];
    this.monthLength = cal_days_in_month[startDate.getMonth()];
    this.day = cal_days_labels[startDate.getDay()];
    this.date = startDate.getDate();
    this.year = startDate.getFullYear();

    // Account for leap years
    if (isLeapYear(startDate) && this.month === 'February') this.monthLength = 29;
    
    this.length = length;    
    };

    // Add methods to the prototype object
    HabitCal.prototype = {
        // Returns the length of the habit cal
        getLength: function() {
            return this.length;
        },
    };

    // Helper function to determine if a given year is a leap year - use it to adjust the length of februrary
    function isLeapYear(date) {
        return ((date.getFullYear() % 4 === 0 && date.getFullYear() % 100 !== 0) || date.getFullYear() % 400 === 0);
    }
    
    // Expose HabitCal object on the global object
    global.HabitCal = HabitCal;
}(this));

From here, It’s a matter of adding properties and methods to accomplish the following:

  1. When a new calendar is instantiated, create divs according to the desired length of the habit
  2. Add those divs to the parent element
  3. Create a formatting method to change the visual appearance of the current day, as well as past and future days
  4. Add event listeners to the divs to allow for user interaction
  5. Save a local reference to this habit calendar so it persists across app loads

After a few hours of working on the above problems, I managed to get to this state

More to come as the project progresses!

Leave a Reply

Your email address will not be published. Required fields are marked *