Ketelet


Ketelet is an iOS and Android Application that calculates your ideal body weight.

This project was born as a component of Meals App. This app had a section where users calculated their Ideal Body Weight. Most users were mostly engaged with this section so we extracted it and created its own application.



Design

For the design of Ketelet we went with a simple flat UI. Big buttons and easy interactions.

Development

The first version of this app was created using Rubymotion for iOS. We then created the Android version a couple of months ago.

class IdealBodyWeightCalculator
  attr_accessor :range_absolute_height, :range_absolute_weight, :absolute_height, :absolute_weight
  attr_accessor :settings

  def initialize
    locale = NSLocale.currentLocale
    locale.objectForKey(NSLocaleUsesMetricSystem) ? self.set_metric_system : set_imperial_system
  end

  def calculate
    result = ( sex_base_weigth + ( constant * inches_over_5_ft)).round(2)
    imperial_system? ? kgs_to_lbs(result).to_i : result.to_i
  end

  def data
    {:ideal => calculate, :current => weight}
  end

  def constant ; 2.3 ; end

  def sex_base_weigth 
    male? ? 50.0 : 45.5
  end

  def inches_over_5_ft
    if imperial_system?
      result = feet_to_inch(height)
    else 
      result = meter_to_inch(height)
    end    
    result -= feet_to_inch(5)
  end

  def set_height_absolute(range)
    @range_absolute_height = range
  end

  def set_weight_absolute(range)
    @range_absolute_weight = range
  end

  def height
    sprintf('%.2f', total_height(@absolute_height,range_height))
  end

  def weight
    total_weight(@absolute_weight,range_weight).to_i
  end

  def range_height
    imperial_system? ? range_height_in_feet : range_height_in_meters
  end

  def range_weight
    imperial_system? ? range_weight_in_lbs : range_weight_in_kgs
  end

  def range_height_in_meters
     {min: 1.52, max: 2.40 }
  end

  def range_height_in_feet
    hash = {}
    range_height_in_meters.each{ |key,value| hash[key] = meter_to_feet(value)}
    hash
  end

  def range_weight_in_kgs
     {min: 40 ,max: 250 }
  end

  def range_weight_in_lbs
    hash = {}
    range_weight_in_kgs.each{ |key,value| hash[key] = kgs_to_lbs(value).to_i}
    hash
  end

  def male?
    @gender == "male"
  end

  def female?
    @gender = "female"
  end

  def set_female
    @gender = "female"
  end

  def set_male
    @gender = "male"
  end


  def set_imperial_system
    @system = {height: 'ft.', weight: 'lbs.'}
  end

  def set_metric_system
    @system = {height: 'mts.', weight: 'kgs.'}
  end

  def height_units
    @system[:height]
  end

  def weight_units
    @system[:weight]
  end

  private

  def imperial_system?
    @system == {height: 'ft.', weight: 'lbs.'}
  end

  def meter_to_feet(meters)
    (meters.to_f * 3.2808399).round(2)
  end

  def kgs_to_lbs(kgs)
    (kgs * 2.20462262).round(2)
  end

  def feet_to_inch(feet)
    (feet.to_f * 12).round(2)
  end

  def meter_to_inch(meters)
    feet_to_inch(meter_to_feet(meters))
  end

  def total_height(value,range_unit)
    percent = percent_height_absolute(value)
    convert_to_units(value,range_unit,percent)
  end

  def total_weight(value,range_unit)    
    percent = percent_weight_absolute(value)
    convert_to_units(value,range_unit,percent)
  end

  def convert_to_units(value,range_unit,percent)
   difference = (range_unit[:max] - range_unit[:min])
   range_unit[:min] + (difference * percent)
  end

  def percent_height_absolute(value)
    percent_absolute(value,range_absolute_height)
  end

  def percent_weight_absolute(value)
    percent_absolute(value,range_absolute_weight)
  end

  def percent_absolute(value,range)
    (value - range[:max].to_f) / (range[:min] - range[:max])
  end

end
describe IdealBodyWeightCalculator do
  before { @calculator = IdealBodyWeightCalculator.new }

  it "ranges values for meters" do
    range = @calculator.range_height_in_meters
    range.should == {min: 1.52 ,max: 2.40 }
  end

  it "ranges values for feet" do
    range = @calculator.range_height_in_feet
    range.should == {min: (4.99).round(2) ,max: 7.87.round(2)}
    # tuve que hacerlo... colocar sin el round lo convierte a un numero diferente
  end

  it "ranges values for kgs" do
    range = @calculator.range_weight_in_kgs
    range.should == {min: 40 ,max: 250 }
  end

  it "ranges values for lbs" do
    range = @calculator.range_weight_in_lbs
    range.should == {min: 88 ,max: 551}
  end

  it "Get units for height in metric system" do
    @calculator.set_metric_system
    @calculator.height_units.should == "mts."
  end
  it "Get units for weight in metric system" do
    @calculator.set_metric_system
    @calculator.weight_units.should == "kgs."
  end
    it "Get units for height in imperial system" do
    @calculator.set_imperial_system
    @calculator.height_units.should == "ft."
  end
  it "Get units for weight in imperial system" do
    @calculator.set_imperial_system
    @calculator.weight_units.should == "lbs."
  end

  it "convert ranges absolutes to valid range min value" do
    @calculator.set_metric_system
    @calculator.set_height_absolute(min: 0, max: 10)
    @calculator.absolute_height = 0
    @calculator.height.should == 2.40.round(2)
  end

  it "convert ranges absolutes to valid range max value" do
    @calculator.set_metric_system
    @calculator.set_height_absolute(min: 0, max: 10)
    @calculator.absolute_height = 10
    @calculator.height.should == 1.52.round(2)
  end
  it "convert ranges absolutes to valid range mid value" do
    @calculator.set_metric_system
    @calculator.set_height_absolute(min: 0, max: 10)
    @calculator.absolute_height = 5
    @calculator.height.should == 1.96.round(2)
  end

  it "convert ranges absolutes to valid range min value for weight" do
    @calculator.set_metric_system
    @calculator.set_weight_absolute(min: 0, max: 1000)
    @calculator.absolute_weight = 0
    @calculator.weight.should == 250
  end

  it "convert ranges absolutes to valid range max value for weight" do
    @calculator.set_metric_system
    @calculator.set_weight_absolute(min: 0, max: 1000)
    @calculator.absolute_weight = 1000
    @calculator.weight.should == 40
  end
  it "convert ranges absolutes to valid range mid value for weight" do
    @calculator.set_metric_system
    @calculator.set_weight_absolute(min: 0, max: 1000)
    @calculator.absolute_weight = 500
    @calculator.weight.should == 145
  end

  it "ideal weight in kgs" do
    @calculator.set_metric_system
    @calculator.set_height_absolute(min: 0, max: 10)
    @calculator.absolute_height = 5
    @calculator.calculate.should == 84
  end

end

Our Process

Meetings

We have weekly calls where we discuss progress. We use Skype, Google Hangouts or GotoMeeting.

We agreed on a day and time that worked for everyone.

Planning

In the beginning we send a timeline specifying the planning and tasks for that week.

These tasks are the same cards we have planned in Trello.

Trello

We translate all requirements into stories in Trello Cards.

Trello is the place to add any specification, ask questions or comments to the team.

Deliveries

Once the tasks are done they go through a testing process and we pass them for your approval.

Every week we will pass cards onto the client list for you to give us feedback.

Quality Assurance

Once the functionality is completed one of our functional testers will try to break the feature.

We either move it to Needs Improvement or pass it to you for feedback.

Feedback

We need the support from you to review the cards and Approve them or tell us how to improve it.

This is key to meet goals and being on time in the development of the application.