Thursday 14 August 2014

Simple clock app

I had need of a simple clock app to show the time and speak it to me every 5 minutes.

It took very little time to pull that together but getting it to be configurable by other people on various different devices was a nightmare.

The answers I came up with in the end were much simpler than anything else I tried.

If anyone wants to take a look at it, there is an spk at http://hudl.sgarman.net/public/spk/SJGclock001.spk

The code looks like
//global
var lastMinute;
var granularity = app.LoadNumber("granularity", 99);
var alarmHour = app.LoadNumber("alarmHour", 99);
var alarmMin = app.LoadNumber("alarmMin", 0);
var alarmOn = app.LoadBoolean("alarmOn", false);
var timout;// for use with clearTimeout

//Called when application is started 
function OnStart() {
    app.EnableBackKey(false);
  //Create a layout with objects vertically centered.
   lay = app.CreateLayout("linear", "VCenter,FillX");
  // add top bar
    lay_bar = app.CreateLayout("Linear", "Horizontal,Left, FillX");
    lay_bar.SetBackColor("#222222");
    speakTxt = app.CreateText(gran_message(granularity));
    speakTxt.SetTextSize(16);
    speakTxt.SetTextColor("#00ffff");
    speakTxt.SetPadding(0.01, 0, 0.01, 0);
    speakTxt.SetOnTouchUp(speakTxt_OnTouchUp);
    lay_bar.AddChild(speakTxt);
    
    msgTxt = app.CreateText("Alarm time");
    msgTxt.SetTextSize(16);
    // msgTxt.SetTextColor( "#ff00ff" );
    msgTxt.SetPadding(0.01, 0, 0.01, 0);
    lay_bar.AddChild(msgTxt);
    txtAlarm = app.CreateText(populate_alarm());
    txtAlarm.SetTextSize(16);
    txtAlarm.SetTextColor("#ffff00");
    txtAlarm.SetPadding(0.01, 0, 0.01, 0);
    txtAlarm.SetOnTouchUp(txtAlarm_OnTouchUp);
    lay_bar.AddChild(txtAlarm);

    chkAlarm = app.CreateCheckBox("Alarm on");
    chkAlarm.SetChecked(alarmOn);
    lay_bar.AddChild(chkAlarm);

    lay.AddChild(lay_bar); 

    //Create a text label and add it to layout.
    txt = app.CreateText("");
    txt.SetTextSize(64);
    lay.AddChild(txt);

    //Add layout to app.    
    app.AddLayout(lay);
    pause = createAskDialog();
    displayTime();
}

function displayTime() {
    var d = new Date();
    var minute = d.getMinutes();
    //if no change, do nothing
    if (minute != lastMinute) {
        var hr = d.getHours();
        var min = (("0" + minute).slice(-2));
        txt.SetText(hr + ":" + min);
        //speak as often as required
        if ((granularity < 61) && (minute % granularity == 0)) {
            app.TextToSpeech(hr + ". " + min);
        }
        lastMinute = minute;
        if ((chkAlarm.GetChecked()) && (minute == alarmMin)
                && (hr == alarmHour)) {
            app.TextToSpeech("Alarm sounding");
        }
    }
    setTimeout(displayTime, 3000);
}

function speakTxt_OnTouchUp() {
    //lstGran.SetVisibility("Show");
   switch (granularity){
   case 99: granularity=1;break;
   case 1: granularity=5;break;
   case 5: granularity=15;break;
   case 15: granularity=30;break;
   case 30: granularity=60;break;
   case 60: granularity=99;break;
  }
  speakTxt.SetText(gran_message(granularity));
}

function gran_message() {
    switch (granularity) {
    case 60:
        return "Speak every hour";
        break;
    case 30:
        return "Speak at 30 mins";
        break;
    case 15:
        return "Speak at 15 mins";
        break;
    case 5:
        return "Speak at 5 mins";
        break;
    case 1:
        return "Speak every minute";
        break;
    case 99:
        return "No speech";
        break;
    }
}

//////
function populate_alarm() {
    if (alarmHour > 24) {
        var d = new Date();
        alarmHour = d.getHours();
        alarmMin = d.getMinutes();
    }
    return alarmHour + ":" + (("0" + alarmMin).slice(-2));
}

function txtAlarm_OnTouchUp() {
  ask("Type a time (hh:mm)", txtAlarm.GetText());    
}

function OnBack() {
  //save current settings
    app.SaveNumber("granularity", granularity);
    app.SaveNumber("alarmHour", alarmHour);
    app.SaveNumber("alarmMin", alarmMin);
    app.SaveBoolean("alarmOn", chkAlarm.GetChecked());
  //only exit if user presses Back again
  //within 4 seconds
    doubleBackKeyExit(4000);
}

function doubleBackKeyExit(millisecs) {
    app.EnableBackKey(true);
    app.ShowPopup("Press Back again to exit", "Bottom");
    setTimeout(disableBackKey, millisecs);
}
function disableBackKey() {
    app.EnableBackKey(false);
}

//Called when user touches Ok button.
function btnAskOk_OnTouch(){
  tmp = edtAsk.GetText().split( ":");
  if( tmp.length == 2 ){
    tmphr = parseInt((tmp[0]).trim());
    tmpmin = parseInt((tmp[1]).trim());
    if( isFinite(tmphr) && isFinite(tmpmin)
      && (tmphr > -1) && (tmphr < 24) 
      && (tmpmin > -1) && (tmpmin < 60) ){
        alarmHour = tmphr;
        alarmMin = tmpmin;
        txtAlarm.SetText(populate_alarm());
    }   
  }
  unAsk();
}
/////////
//ask functionality
function createAskDialog( ){
  //Create a layout for Ask dialog
  layAsk = app.CreateLayout( "Linear", "FillXY" );
  layAsk.SetPadding( 0, 0.1, 0, 0 ); 
  layAsk.SetBackColor( "#dd008800" );
  layAsk.SetPosition(0, 0, 0.5, 0.5);
  layAsk.SetVisibility( "Hide" );
    
  txtAsk = app.CreateText("");
  layAsk.AddChild(txtAsk);
  txtAsk.SetTextSize(12);
  txtAsk.SetMargins( 0, 0, 0, 0.05 );
  edtAsk = app.CreateTextEdit("");
  edtAsk.SetMargins( 0, 0, 0, 0.05 )
  layAsk.AddChild(edtAsk);
  //Create button and add to  layout.
  btnAskOk = app.CreateButton( "Ok", 0.3, 0.06, "gray" );
  btnAskOk.SetOnTouch( btnAskOk_OnTouch );
  layAsk.AddChild( btnAskOk );

  app.AddLayout(layAsk);
  return true;
}
function ask(msg, dflt){
  //open dialog
  txtAsk.SetText( msg );
  edtAsk.SetText( dflt );
  layAsk.Animate("SlideFromTop");
}
function unAsk(){
  //close dialog
  app.HideKeyboard();//just in case
  layAsk.Animate("SlideToTop");
}
////////

No comments:

Post a Comment