Initial implementation of a mobile timer page
authorNik Okuntseff <support@anuko.com>
Wed, 16 Mar 2016 01:25:27 +0000 (01:25 +0000)
committerNik Okuntseff <support@anuko.com>
Wed, 16 Mar 2016 01:25:27 +0000 (01:25 +0000)
WEB-INF/lib/form/Combobox.class.php
WEB-INF/lib/ttTimeHelper.class.php
WEB-INF/templates/footer.tpl
WEB-INF/templates/mobile/timer.tpl [new file with mode: 0644]
mobile/timer.php [new file with mode: 0644]

index 7783793..534c8a5 100644 (file)
@@ -87,6 +87,9 @@ class Combobox extends FormElement {
                   
                if ($this->mStyle!="")
                   $html .= " style=\"$this->mStyle\"";
+                
+                if (!$this->isEnable())
+                  $html .= " disabled";
                   
                $html .= ">\n";   
                if (is_array($this->mOptionsEmpty) && (count($this->mOptionsEmpty) > 0))
@@ -112,3 +115,4 @@ class Combobox extends FormElement {
                return $html;
        }
 }
+?>
\ No newline at end of file
index f743e61..e1b2470 100644 (file)
@@ -492,7 +492,7 @@ class ttTimeHelper {
   static function getUncompleted($user_id) {
     $mdb2 = getConnection();
 
-    $sql = "select id from tt_log  
+    $sql = "select id, start from tt_log  
       where user_id = $user_id and start is not null and time_to_sec(duration) = 0 and status = 1";
     $res = $mdb2->query($sql);
     if (!is_a($res, 'PEAR_Error')) {
index f962684..0dd33a8 100644 (file)
@@ -12,7 +12,7 @@
       <br>
       <table cellspacing="0" cellpadding="4" width="100%" border="0">
         <tr>
-          <td align="center">&nbsp;Anuko Time Tracker 1.9.15.3415 | Copyright &copy; <a href="https://www.anuko.com/lp/tt_3.htm" target="_blank">Anuko</a> |
+          <td align="center">&nbsp;Anuko Time Tracker 1.9.16.3417 | Copyright &copy; <a href="https://www.anuko.com/lp/tt_3.htm" target="_blank">Anuko</a> |
             <a href="https://www.anuko.com/lp/tt_4.htm" target="_blank">{$i18n.footer.credits}</a> |
             <a href="https://www.anuko.com/lp/tt_5.htm" target="_blank">{$i18n.footer.license}</a> |
             <a href="https://www.anuko.com/lp/tt_7.htm" target="_blank">{$i18n.footer.improve}</a>
diff --git a/WEB-INF/templates/mobile/timer.tpl b/WEB-INF/templates/mobile/timer.tpl
new file mode 100644 (file)
index 0000000..929d5c2
--- /dev/null
@@ -0,0 +1,302 @@
+<script>
+// We need a few arrays to populate project and task dropdowns.
+// When client selection changes, the project dropdown must be re-populated with only relevant projects.
+// When project selection changes, the task dropdown must be repopulated similarly.
+// Format:
+// project_ids[143] = "325,370,390,400";  // Comma-separated list of project ids for client.
+// project_names[325] = "Time Tracker";   // Project name.
+// task_ids[325] = "100,101,302,303,304"; // Comma-separated list ot task ids for project.
+// task_names[100] = "Coding";            // Task name.
+
+//Prepare an array of projects ids for clients.
+project_ids = new Array();
+{foreach $client_list as $client}
+  project_ids[{$client.id}] = "{$client.projects}";
+{/foreach}
+// Prepare an array of project names.
+project_names = new Array();
+{foreach $project_list as $project}
+  project_names[{$project.id}] = "{$project.name|escape:'javascript'}";
+{/foreach}
+// We'll use this array to populate project dropdown when client is not selected.
+var idx = 0;
+projects = new Array();
+{foreach $project_list as $project}
+  projects[idx] = new Array("{$project.id}", "{$project.name|escape:'javascript'}");
+  idx++;
+{/foreach}
+
+// Prepare an array of task ids for projects.
+task_ids = new Array();
+{foreach $project_list as $project}
+  task_ids[{$project.id}] = "{$project.tasks}";
+{/foreach}
+// Prepare an array of task names.
+task_names = new Array();
+{foreach $task_list as $task}
+  task_names[{$task.id}] = "{$task.name|escape:'javascript'}";
+{/foreach}
+
+// Mandatory top options for project and task dropdowns.
+empty_label_project = '{$i18n.dropdown.select|escape:'javascript'}';
+empty_label_task = '{$i18n.dropdown.select|escape:'javascript'}';
+
+// The populateDropdowns function populates the "project" and "task" dropdown controls
+// with relevant values.
+function fillDropdowns() {
+  if(document.body.contains(document.timeRecordForm.client))
+    fillProjectDropdown(document.timeRecordForm.client.value);
+
+  fillTaskDropdown(document.timeRecordForm.project.value);
+}
+
+// The fillProjectDropdown function populates the project combo box with
+// projects associated with a selected client (client id is passed here as id).    
+function fillProjectDropdown(id) {
+  var str_ids = project_ids[id];
+
+  var dropdown = document.getElementById("project");
+  // Determine previously selected item.
+  var selected_item = dropdown.options[dropdown.selectedIndex].value;
+
+  // Remove existing content.
+  dropdown.length = 0;
+  var project_reset = true;
+  // Add mandatory top option.
+  dropdown.options[0] = new Option(empty_label_project, '', true);
+
+  // Populate project dropdown.
+  if (!id) {
+    // If we are here, client is not selected.
+       var len = projects.length;
+    for (var i = 0; i < len; i++) {
+      dropdown.options[i+1] = new Option(projects[i][1], projects[i][0]);
+      if (dropdown.options[i+1].value == selected_item)  {
+        dropdown.options[i+1].selected = true;
+        project_reset = false;
+      }
+    }
+  } else if (str_ids) {
+    var ids = new Array();
+    ids = str_ids.split(",");
+    var len = ids.length;
+
+    for (var i = 0; i < len; i++) {
+      var p_id = ids[i];
+      dropdown.options[i+1] = new Option(project_names[p_id], p_id);
+      if (dropdown.options[i+1].value == selected_item)  {
+        dropdown.options[i+1].selected = true;
+        project_reset = false;
+      }
+    }
+  }
+
+  // If project selection was reset - clear the tasks dropdown.
+  if (project_reset) {
+    dropdown = document.getElementById("task");
+    dropdown.length = 0;
+    dropdown.options[0] = new Option(empty_label_task, '', true);
+  }
+}
+
+// The fillTaskDropdown function populates the task combo box with
+// tasks associated with a selected project (project id is passed here as id).    
+function fillTaskDropdown(id) {
+  var str_ids = task_ids[id];
+
+  var dropdown = document.getElementById("task");
+  if (dropdown == null) return; // Nothing to do.
+  
+  // Determine previously selected item.
+  var selected_item = dropdown.options[dropdown.selectedIndex].value;
+
+  // Remove existing content.
+  dropdown.length = 0;
+  // Add mandatory top option.
+  dropdown.options[0] = new Option(empty_label_task, '', true);
+
+  // Populate the dropdown from the task_names array.
+  if (str_ids) {
+    var ids = new Array();
+    ids = str_ids.split(",");
+    var len = ids.length;
+
+    var idx = 1;
+    for (var i = 0; i < len; i++) {
+      var t_id = ids[i];
+      if (task_names[t_id]) {
+        dropdown.options[idx] = new Option(task_names[t_id], t_id);
+        idx++;
+      }
+    }
+
+    // If a previously selected item is still in dropdown - select it.
+       if (dropdown.options.length > 0) {
+      for (var i = 0; i < dropdown.options.length; i++) {
+        if (dropdown.options[i].value == selected_item) {
+          dropdown.options[i].selected = true;
+        }
+      }
+    }
+  }
+}
+
+function get_date() {
+  var date = new Date();
+  return date.strftime("%Y-%m-%d");
+}
+
+function get_time() {
+  var date = new Date();
+  return date.strftime("%H:%M");
+}
+</script>
+
+<style>
+.not_billable td {
+       color: #ff6666;
+}
+</style>
+
+<span id="hour">00</span><span id="separator">:</span><span id="min">00</span><!--:<span id="sec">00</span>-->
+
+
+<script>
+var timerID = null;
+var startDate = null;
+var endDate = null;
+var delta = null;
+var separatorVisible = true;
+
+function toggleSeparator() {
+  document.getElementById('separator').style.visibility = separatorVisible ? 'hidden' : 'visible';
+  separatorVisible = !separatorVisible;
+}
+
+function updateTimer() {
+  if (startDate == null) startDate = new Date();
+  endDate = new Date();
+  delta = new Date(endDate - startDate);
+  
+  var hours = delta.getUTCHours();
+  if (hours < 10) hours = '0'+hours;
+  document.getElementById('hour').innerHTML = hours;
+
+  var minutes = delta.getUTCMinutes();
+  if (minutes <  10) minutes = '0'+minutes;
+  document.getElementById('min').innerHTML = minutes;
+
+  // Toggle visibility of separator for 100 ms.
+  toggleSeparator();
+  setTimeout('toggleSeparator()', 100);
+}
+
+function startTimer() {
+  if (timerID) return;
+  
+  updateTimer();
+  timerID = setInterval('updateTimer()', 1000);
+}
+
+function stopTimer() {
+  clearInterval(timerID);
+  timerID = null;
+}
+</script>
+
+{if $uncompleted}
+<script>
+startDate = new Date();
+startDate.setHours({substr($uncompleted['start'], 0, 2)});
+startDate.setMinutes({substr($uncompleted['start'], 3, 2)});
+startDate.setSeconds(0);
+updateTimer();
+startTimer();
+</script>    
+{/if}
+
+<!--
+<table cellspacing="3" cellpadding="0" border="0" width="100%">
+<tr>
+  <td align="center">
+    {if $time_records}
+      <table border='0' cellpadding='4' cellspacing='1' width="100%">
+      {foreach $time_records as $record}
+      <tr bgcolor="{cycle values="#ccccce,#f5f5f5"}" {if !$record.billable} class="not_billable" {/if}>
+{if ($smarty.const.MODE_PROJECTS == $user->tracking_mode || $smarty.const.MODE_PROJECTS_AND_TASKS == $user->tracking_mode)}
+        <td valign='top'>{$record.project|escape:'html'}</td>
+{/if}
+        <td align='right' valign='top'>{if $record.duration == '0:00'}<font color="#ff0000">{/if}{$record.duration}{if $record.duration == '0:00'}</font>{/if}
+        <td align='center'>{if $record.invoice_id}&nbsp;{else}<a href='time_edit.php?id={$record.id}'>{$i18n.label.edit}</a>{/if}</td>
+      </tr>
+      {/foreach}
+         </table>
+         <table border='0'>
+      <tr>
+        <td align='right'>{$i18n.label.day_total}:</td>
+        <td>{$day_total}</td>
+      </tr>
+      </table>
+    {/if}
+  </td>
+</tr>
+</table>
+-->
+
+{$forms.timerRecordForm.open}
+<table cellspacing="4" cellpadding="7" border="0">
+<tr>
+  <td>
+  <table width = "100%">
+  <tr>
+       <td valign="top">
+    <table border="0">
+{if in_array('cl', explode(',', $user->plugins))}
+    <tr><td>{$i18n.label.client}:</td></tr>
+    <tr><td>{$forms.timerRecordForm.client.control}</td></tr>
+{/if}
+{if in_array('iv', explode(',', $user->plugins))}
+    <tr><td><label>{$forms.timerRecordForm.billable.control}{$i18n.form.time.billable}</label></td></tr>
+{/if}
+{if ($custom_fields && $custom_fields->fields[0])}
+      <tr><td>{$custom_fields->fields[0]['label']|escape:'html'}:</td></tr>
+      <tr><td>{$forms.timerRecordForm.cf_1.control}</td></tr>
+{/if}
+{if ($smarty.const.MODE_PROJECTS == $user->tracking_mode || $smarty.const.MODE_PROJECTS_AND_TASKS == $user->tracking_mode)}
+    <tr><td>{$i18n.label.project}:</td></tr>
+    <tr><td>{$forms.timerRecordForm.project.control}</td></tr>
+{/if}
+{if ($smarty.const.MODE_PROJECTS_AND_TASKS == $user->tracking_mode)}
+    <tr><td>{$i18n.label.task}:</td></tr>
+    <tr><td>{$forms.timerRecordForm.task.control}</td></tr>
+{/if}
+    </table>
+    </td>
+  </tr>
+  <tr>
+    <td colspan="2" height="50" align="center">{$forms.timerRecordForm.btn_start.control} {$forms.timerRecordForm.btn_stop.control}</td>
+  </tr>
+  </table>
+  </td>
+</tr>
+</table>
+{$forms.timerRecordForm.close}
+
+<table cellspacing="3" cellpadding="0" border="0" width="100%">
+<tr>
+  <td align="center">
+    {if $time_records}
+    <table border='0'>
+      <tr>
+        <td align='right'>{$i18n.label.day_total}:</td>
+        <td>{$day_total}</td>
+      </tr>
+      <tr>
+        <td align='right'>{$i18n.label.week_total}:</td>
+        <td>{$week_total}</td>
+      </tr>
+    </table>
+    {/if}
+  </td>
+</tr>
+</table>
\ No newline at end of file
diff --git a/mobile/timer.php b/mobile/timer.php
new file mode 100644 (file)
index 0000000..7fde4ea
--- /dev/null
@@ -0,0 +1,313 @@
+<?php
+// +----------------------------------------------------------------------+
+// | Anuko Time Tracker
+// +----------------------------------------------------------------------+
+// | Copyright (c) Anuko International Ltd. (https://www.anuko.com)
+// +----------------------------------------------------------------------+
+// | LIBERAL FREEWARE LICENSE: This source code document may be used
+// | by anyone for any purpose, and freely redistributed alone or in
+// | combination with other software, provided that the license is obeyed.
+// |
+// | There are only two ways to violate the license:
+// |
+// | 1. To redistribute this code in source form, with the copyright
+// |    notice or license removed or altered. (Distributing in compiled
+// |    forms without embedded copyright notices is permitted).
+// |
+// | 2. To redistribute modified versions of this code in *any* form
+// |    that bears insufficient indications that the modifications are
+// |    not the work of the original author(s).
+// |
+// | This license applies to this document only, not any other software
+// | that it may be combined with.
+// |
+// +----------------------------------------------------------------------+
+// | Contributors:
+// | https://www.anuko.com/time_tracker/credits.htm
+// +----------------------------------------------------------------------+
+
+require_once('../initialize.php');
+import('form.Form');
+import('ttUserHelper');
+import('ttTeamHelper');
+import('ttClientHelper');
+import('ttTimeHelper');
+import('DateAndTime');
+
+// Access check.
+if (!ttAccessCheck(right_data_entry)) {
+  header('Location: access_denied.php');
+  exit();
+}
+
+// Initialize and store date in session.
+$cl_date  = $request->getParameter('date', @$_SESSION['date']);
+$selected_date = new DateAndTime(DB_DATEFORMAT, $cl_date);
+if($selected_date->isError())
+  $selected_date = new DateAndTime(DB_DATEFORMAT);
+if(!$cl_date)
+  $cl_date = $selected_date->toString(DB_DATEFORMAT);
+$_SESSION['date'] = $cl_date;
+// TODO: for time page we may limit the day to today only.
+  
+// Use custom fields plugin if it is enabled.
+if (in_array('cf', explode(',', $user->plugins))) {
+  require_once('../plugins/CustomFields.class.php');
+  $custom_fields = new CustomFields($user->team_id);
+  $smarty->assign('custom_fields', $custom_fields);
+}
+
+// Initialize variables.
+$cl_start = trim($request->getParameter('browser_time'));
+$cl_finish = trim($request->getParameter('browser_time'));
+// Custom field.
+$cl_cf_1 = trim($request->getParameter('cf_1', ($request->getMethod()=='POST'? null : @$_SESSION['cf_1'])));
+$_SESSION['cf_1'] = $cl_cf_1;
+$cl_billable = 1;
+if (in_array('iv', explode(',', $user->plugins))) {
+  if ($request->getMethod() == 'POST') {
+    $cl_billable = $request->getParameter('billable');
+    $_SESSION['billable'] = (int) $cl_billable;
+  } else 
+    if (isset($_SESSION['billable']))
+      $cl_billable = $_SESSION['billable'];
+}
+$cl_client = $request->getParameter('client', @$_SESSION['client']);
+$_SESSION['client'] = $cl_client;
+$cl_project = $request->getParameter('project', @$_SESSION['project']);
+$_SESSION['project'] = $cl_project;
+$cl_task = $request->getParameter('task', @$_SESSION['task']);
+$_SESSION['task'] = $cl_task;
+
+// Obtain uncompleted record. Assumtion is that only 1 uncompleted record is allowed.
+$uncompleted = ttTimeHelper::getUncompleted($user->getActiveUser());
+$enable_controls = ($uncompleted == null);
+
+// Elements of timeRecordForm.
+$form = new Form('timerRecordForm');
+
+// Dropdown for clients in MODE_TIME. Use all active clients.
+if (MODE_TIME == $user->tracking_mode && in_array('cl', explode(',', $user->plugins))) {
+    $active_clients = ttTeamHelper::getActiveClients($user->team_id, true);
+    $form->addInput(array('type'=>'combobox',
+      'onchange'=>'fillProjectDropdown(this.value);',
+      'name'=>'client',
+      'style'=>'width: 250px;',
+      'enable'=>$enable_controls,
+      'value'=>$cl_client,
+      'data'=>$active_clients,
+      'datakeys'=>array('id', 'name'),
+      'empty'=>array(''=>$i18n->getKey('dropdown.select'))
+    ));
+  // Note: in other modes the client list is filtered to relevant clients only. See below.
+}
+
+if (MODE_PROJECTS == $user->tracking_mode || MODE_PROJECTS_AND_TASKS == $user->tracking_mode) {
+  // Dropdown for projects assigned to user.
+  $project_list = $user->getAssignedProjects();
+  $form->addInput(array('type'=>'combobox',
+    'onchange'=>'fillTaskDropdown(this.value);',
+    'name'=>'project',
+    'style'=>'width: 250px;',
+    'enable'=>$enable_controls,
+    'value'=>$cl_project,
+    'data'=>$project_list,
+    'datakeys'=>array('id','name'),
+    'empty'=>array(''=>$i18n->getKey('dropdown.select'))
+  ));
+
+  // Dropdown for clients if the clients plugin is enabled.
+  if (in_array('cl', explode(',', $user->plugins))) {
+    $active_clients = ttTeamHelper::getActiveClients($user->team_id, true);
+    // We need an array of assigned project ids to do some trimming. 
+    foreach($project_list as $project)
+      $projects_assigned_to_user[] = $project['id'];
+
+    // Build a client list out of active clients. Use only clients that are relevant to user.
+    // Also trim their associated project list to only assigned projects (to user).
+    foreach($active_clients as $client) {
+         $projects_assigned_to_client = explode(',', $client['projects']);
+         $intersection = array_intersect($projects_assigned_to_client, $projects_assigned_to_user);
+         if ($intersection) {
+           $client['projects'] = implode(',', $intersection);
+           $client_list[] = $client;
+         }
+    }
+    $form->addInput(array('type'=>'combobox',
+      'onchange'=>'fillProjectDropdown(this.value);',
+      'name'=>'client',
+      'style'=>'width: 250px;',
+      'enable'=>$enable_controls,
+      'value'=>$cl_client,
+      'data'=>$client_list,
+      'datakeys'=>array('id', 'name'),
+      'empty'=>array(''=>$i18n->getKey('dropdown.select'))
+    ));
+  }
+}
+
+if (MODE_PROJECTS_AND_TASKS == $user->tracking_mode) {
+  $task_list = ttTeamHelper::getActiveTasks($user->team_id);
+  $form->addInput(array('type'=>'combobox',
+    'name'=>'task',
+    'style'=>'width: 250px;',
+    'enable'=>$enable_controls,
+    'value'=>$cl_task,
+    'data'=>$task_list,
+    'datakeys'=>array('id','name'),
+    'empty'=>array(''=>$i18n->getKey('dropdown.select'))
+  ));
+}
+if (in_array('iv', explode(',', $user->plugins)))
+  $form->addInput(array('type'=>'checkbox','name'=>'billable','data'=>1,'value'=>$cl_billable,'enable'=>$enable_controls));
+$form->addInput(array('type'=>'hidden','name'=>'browser_today','value'=>'')); // User current date, which gets filled in on button click.
+$form->addInput(array('type'=>'hidden','name'=>'browser_time','value'=>''));  // User current time, which gets filled in on button click.
+$enable_start = $uncompleted ? false : true;
+$enable_stop = $uncompleted ? true : false;
+$form->addInput(array('type'=>'submit','name'=>'btn_start','onclick'=>'browser_time.value=get_time()','value'=>$i18n->getKey('label.start'),'enable'=>$enable_start));
+$form->addInput(array('type'=>'submit','name'=>'btn_stop','onclick'=>'browser_time.value=get_time()','value'=>$i18n->getKey('label.finish'),'enable'=>$enable_stop));
+  
+// If we have custom fields - add controls for them.
+if ($custom_fields && $custom_fields->fields[0]) {
+  // Only one custom field is supported at this time.
+  if ($custom_fields->fields[0]['type'] == CustomFields::TYPE_TEXT) {
+    $form->addInput(array('type'=>'text','name'=>'cf_1','value'=>$cl_cf_1));
+  } else if ($custom_fields->fields[0]['type'] == CustomFields::TYPE_DROPDOWN) {
+    $form->addInput(array('type'=>'combobox','name'=>'cf_1',
+      'style'=>'width: 250px;',
+      'value'=>$cl_cf_1,
+      'data'=>$custom_fields->options,
+      'empty'=>array(''=>$i18n->getKey('dropdown.select'))
+    ));
+  }
+}
+
+// Determine lock date. Time entries earlier than lock date cannot be created or modified. 
+$lock_interval = $user->lock_interval;
+$lockdate = 0;
+if ($lock_interval > 0) {
+  $lockdate = new DateAndTime();
+  $lockdate->decDay($lock_interval);
+}
+
+// Submit.
+if ($request->getMethod() == 'POST') {
+  if ($request->getParameter('btn_start')) {
+    // Start button clicked. We need to create a new uncompleted record with only the start time.
+    $cl_finish = null;
+
+    // Validate user input.
+    if (in_array('cl', explode(',', $user->plugins)) && in_array('cm', explode(',', $user->plugins)) && !$cl_client)
+      $errors->add($i18n->getKey('error.client'));
+    if ($custom_fields) {
+      if (!ttValidString($cl_cf_1, !$custom_fields->fields[0]['required'])) $errors->add($i18n->getKey('error.field'), $custom_fields->fields[0]['label']);
+    }
+    if (MODE_PROJECTS == $user->tracking_mode || MODE_PROJECTS_AND_TASKS == $user->tracking_mode) {
+      if (!$cl_project) $errors->add($i18n->getKey('error.project'));
+    }
+    if (MODE_PROJECTS_AND_TASKS == $user->tracking_mode) {
+      if (!$cl_task) $errors->add($i18n->getKey('error.task'));
+    }
+    // Finished validating user input.
+    
+    // Prohibit creating entries in future.
+    if (defined('FUTURE_ENTRIES') && !isTrue(FUTURE_ENTRIES)) {
+      $browser_today = new DateAndTime(DB_DATEFORMAT, $request->getParameter('browser_today', null));
+      if ($selected_date->after($browser_today))
+        $errors->add($i18n->getKey('error.future_date'));
+    }
+    
+    // Prohibit creating time entries in locked interval.
+    if($lockdate && $selected_date->before($lockdate))
+      $errors->add($i18n->getKey('error.period_locked'));
+
+    // Prohibit creating another uncompleted record.
+    if ($errors->isEmpty() && $uncompleted) {
+      $errors->add($i18n->getKey('error.uncompleted_exists')." <a href = 'time_edit.php?id=".$not_completed_rec['id']."'>".$i18n->getKey('error.goto_uncompleted')."</a>");
+    }
+    
+    // Prohibit creating an overlapping record.
+    if ($errors->isEmpty()) {
+      if (ttTimeHelper::overlaps($user->getActiveUser(), $cl_date, $cl_start, $cl_finish))
+        $errors->add($i18n->getKey('error.overlap'));
+    }  
+    
+    if ($errors->isEmpty()) {
+      $id = ttTimeHelper::insert(array(
+        'date' => $cl_date,
+        'user_id' => $user->getActiveUser(),
+        'client' => $cl_client,
+        'project' => $cl_project,
+        'task' => $cl_task,
+        'start' => $cl_start,
+        'finish' => $cl_finish,
+        'duration' => $cl_duration,
+        'note' => $cl_note,
+        'billable' => $cl_billable));
+               
+      // Insert a custom field if we have it.
+      $result = true;
+      if ($id && $custom_fields && $cl_cf_1) {
+        if ($custom_fields->fields[0]['type'] == CustomFields::TYPE_TEXT)
+          $result = $custom_fields->insert($id, $custom_fields->fields[0]['id'], null, $cl_cf_1);
+        else if ($custom_fields->fields[0]['type'] == CustomFields::TYPE_DROPDOWN)
+          $result = $custom_fields->insert($id, $custom_fields->fields[0]['id'], $cl_cf_1, null);
+      }
+
+      if ($id && $result) {
+        header('Location: timer.php');
+        exit();
+      }
+      $errors->add($i18n->getKey('error.db'));
+    }
+  }
+  if ($request->getParameter('btn_stop')) {
+    // Stop button clicked. We need to finish an uncompleted record in progress.
+    $record = ttTimeHelper::getRecord($uncompleted['id'], $user->getActiveUser());
+
+    // Can we complete this record?
+    if (ttTimeHelper::isValidInterval($record['start'], $cl_finish) // finish time is greater than start time
+      && !ttTimeHelper::overlaps($user->getActiveUser(), $cl_date, $record['start'], $cl_finish)) { // no overlap
+      $res = ttTimeHelper::update(array(
+        'id'=>$record['id'],  
+        'date'=>$cl_date,  
+        'user_id'=>$user->getActiveUser(),
+        'client'=>$record['client_id'],  
+        'project'=>$record['project_id'],  
+        'task'=>$record['task_id'],  
+        'start'=>$record['start'],  
+        'finish'=>$cl_finish,
+        'note'=>$record['comment'],
+        'billable'=>$record['billable']));
+      if ($res) {
+        header('Location: timer.php');
+        exit();
+      } else
+        $errors->add($i18n->getKey('error.db'));
+    } else {
+      // Cannot complete, redirect for manual edit.
+      header('Location: time_edit.php?id='.$record['id']);
+      exit();          
+    }
+  }
+}
+
+$week_total = ttTimeHelper::getTimeForWeek($user->getActiveUser(), $cl_date);
+$smarty->assign('week_total', $week_total);
+
+$smarty->assign('uncompleted', $uncompleted);
+
+
+
+$smarty->assign('time_records', ttTimeHelper::getRecords($user->getActiveUser(), $cl_date));
+$smarty->assign('day_total', ttTimeHelper::getTimeForDay($user->getActiveUser(), $cl_date));
+$smarty->assign('client_list', $client_list);
+$smarty->assign('project_list', $project_list);
+$smarty->assign('task_list', $task_list);
+$smarty->assign('forms', array($form->getName()=>$form->toArray()));
+$smarty->assign('onload', 'onLoad="fillDropdowns()"');
+$smarty->assign('timestring', $selected_date->toString($user->date_format));
+$smarty->assign('title', $i18n->getKey('title.time'));
+$smarty->assign('content_page_name', 'mobile/timer.tpl');
+$smarty->display('mobile/index.tpl');
+?>
\ No newline at end of file