Show time, date, and recording directory in the info screen

Patch by Igor Poretsky

Change-Id: I5db0d018742c11dd9bf3ca4c9539cd91f94d4c2e
diff --git a/apps/gui/list.c b/apps/gui/list.c
index b0d7829..425cab9 100644
--- a/apps/gui/list.c
+++ b/apps/gui/list.c
@@ -880,6 +880,13 @@
     return gui_synclist_do_button(lists, action, wrap);
 }
 
+bool gui_synclist_item_is_onscreen(struct gui_synclist *lists,
+                                   enum screen_type screen, int item)
+{
+    int nb_lines = list_get_nb_lines(lists, screen);
+    return (unsigned)(item - lists->start_item[screen]) < (unsigned) nb_lines;
+}
+
 /* Simple use list implementation */
 static int simplelist_line_count = 0, simplelist_line_remaining;
 static int simplelist_line_pos;
diff --git a/apps/gui/list.h b/apps/gui/list.h
index ef08a9e..1be9da4 100644
--- a/apps/gui/list.h
+++ b/apps/gui/list.h
@@ -167,6 +167,8 @@
                                    enum themable_icons icon);
 extern void gui_synclist_hide_selection_marker(struct gui_synclist *lists,
                                                 bool hide);
+extern bool gui_synclist_item_is_onscreen(struct gui_synclist *lists,
+                                          enum screen_type screen, int item);
 
 #if CONFIG_CODEC == SWCODEC
 extern bool gui_synclist_keyclick_callback(int action, void* data);
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index e531baf..8aed53f 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -15242,3 +15242,20 @@
     *: "Return"
   </voice>
 </phrase>
+<phrase>
+  id: LANG_REC_DIR
+  desc: used in the info screen to show a recording dir
+  user: core
+  <source>
+    *: none
+    recording: "Recording Directory"
+  </source>
+  <dest>
+    *: none
+    recording: "Recording Directory"
+  </dest>
+  <voice>
+    *: none
+    recording: "Recording Directory"
+  </voice>
+</phrase>
diff --git a/apps/menus/main_menu.c b/apps/menus/main_menu.c
index a519602..00959d0 100644
--- a/apps/menus/main_menu.c
+++ b/apps/menus/main_menu.c
@@ -147,7 +147,14 @@
     INFO_DISK1, /* capacity or internal capacity/free on hotswap */
     INFO_DISK2, /* free space or external capacity/free on hotswap */
     INFO_BUFFER,
+#ifdef HAVE_RECORDING
+    INFO_REC_DIR,
+#endif
     INFO_VERSION,
+#if CONFIG_RTC
+    INFO_DATE,
+    INFO_TIME,
+#endif
     INFO_COUNT
 };
 
@@ -155,6 +162,9 @@
                                 char *buffer, size_t buffer_len)
 {
     struct info_data *info = (struct info_data*)data;
+#if CONFIG_RTC
+    struct tm *tm;
+#endif
     char s1[32];
 #if defined(HAVE_MULTIVOLUME)
     char s2[32];
@@ -179,6 +189,46 @@
                      str(LANG_VERSION), rbversion);
             break;
 
+#if CONFIG_RTC
+        case INFO_TIME:
+            tm = get_time();
+            if (valid_time(tm))
+            {
+                snprintf(buffer, buffer_len, "%02d:%02d:%02d %s",
+                    global_settings.timeformat == 0 ? tm->tm_hour :
+                         ((tm->tm_hour + 11) % 12) + 1,
+                         tm->tm_min,
+                         tm->tm_sec,
+                         global_settings.timeformat == 0 ? "" :
+                         tm->tm_hour>11 ? "P" : "A");
+            }
+            else
+            {
+                snprintf(buffer, buffer_len, "%s", "--:--:--");
+            }
+            break;
+        case INFO_DATE:
+            tm = get_time();
+            if (valid_time(tm))
+            {
+                snprintf(buffer, buffer_len, "%s %d %d",
+                    str(LANG_MONTH_JANUARY + tm->tm_mon),
+                    tm->tm_mday,
+                    tm->tm_year+1900);
+            }
+            else
+            {
+                snprintf(buffer, buffer_len, "%s", str(LANG_UNKNOWN));
+            }
+            break;
+#endif
+
+#ifdef HAVE_RECORDING
+        case INFO_REC_DIR:
+            snprintf(buffer, buffer_len, "%s %s", str(LANG_REC_DIR), global_settings.rec_directory);
+            break;
+#endif
+
         case INFO_BUFFER: /* buffer */
         {
             long kib = audio_buffer_size() >> 10; /* to KiB */
@@ -253,6 +303,22 @@
 {
     struct info_data *info = (struct info_data*)data;
 
+#if CONFIG_RTC
+    struct tm *tm;
+#endif
+
+    if (info->new_data)
+    {
+        volume_size(IF_MV(0,) &info->size, &info->free);
+#ifdef HAVE_MULTIVOLUME
+        if (volume_ismounted(1))
+            volume_size(1, &info->size2, &info->free2);
+        else
+            info->size2 = 0;
+#endif
+        info->new_data = false;
+    }
+
     switch (selected_item)
     {
         case INFO_VERSION: /* version */
@@ -260,6 +326,58 @@
             talk_spell(rbversion, true);
             break;
 
+#if CONFIG_RTC
+        case INFO_TIME:
+            tm = get_time();
+            talk_id(VOICE_CURRENT_TIME, false);
+            if (valid_time(tm))
+            {
+                talk_time(tm, true);
+            }
+            else
+            {
+                talk_id(LANG_UNKNOWN, true);
+            }
+            break;
+        case INFO_DATE:
+            tm = get_time();
+            if (valid_time(tm))
+            {
+                talk_date(get_time(), true);
+            }
+            else
+            {
+                talk_id(LANG_UNKNOWN, true);
+            }
+            break;
+#endif
+
+#ifdef HAVE_RECORDING
+        case INFO_REC_DIR:
+            talk_id(LANG_REC_DIR, false);
+            if (global_settings.rec_directory && global_settings.rec_directory[0])
+            {
+                long *pathsep = NULL;
+                char rec_directory[MAX_PATHNAME+1];
+                char *s;
+                strcpy(rec_directory, global_settings.rec_directory);
+                s = rec_directory;
+                if ((strlen(s) > 1) && (s[strlen(s) - 1] == '/'))
+                    s[strlen(s) - 1] = 0;
+                while (s)
+                {
+                    s = strchr(s + 1, '/');
+                    if (s)
+                        s[0] = 0;
+                    talk_dir_or_spell(rec_directory, pathsep, true);
+                    if (s)
+                        s[0] = '/';
+                    pathsep = TALK_IDARRAY(VOICE_CHAR_SLASH);
+                }
+            }
+            break;
+#endif
+
         case INFO_BUFFER: /* buffer */
         {
             talk_id(LANG_BUFFER_STAT, false);
@@ -271,22 +389,38 @@
 #if CONFIG_CHARGING == CHARGING_SIMPLE
             /* Only know if plugged */
             if (charger_inserted())
+            {
                 talk_id(LANG_BATTERY_CHARGE, true);
+                if (battery_level() >= 0)
+                    talk_value(battery_level(), UNIT_PERCENT, true);
+            }
             else
 #elif CONFIG_CHARGING >= CHARGING_MONITOR
 #ifdef ARCHOS_RECORDER
             /* Report the particular algorithm state */
             if (charge_state == CHARGING)
+            {
                 talk_id(LANG_BATTERY_CHARGE, true);
+                if (battery_level() >= 0)
+                    talk_value(battery_level(), UNIT_PERCENT, true);
+            }
             else if (charge_state == TOPOFF)
                 talk_id(LANG_BATTERY_TOPOFF_CHARGE, true);
             else if (charge_state == TRICKLE)
+            {
                 talk_id(LANG_BATTERY_TRICKLE_CHARGE, true);
+                if (battery_level() >= 0)
+                    talk_value(battery_level(), UNIT_PERCENT, true);
+            }
             else
 #else /* !ARCHOS_RECORDER */
             /* Go by what power management reports */
             if (charging_state())
+            {
                 talk_id(LANG_BATTERY_CHARGE, true);
+                if (battery_level() >= 0)
+                    talk_value(battery_level(), UNIT_PERCENT, true);
+            }
             else
 #endif /* ARCHOS_RECORDER */
 #endif /* CONFIG_CHARGING = */
@@ -349,12 +483,22 @@
         splash(0, ID2P(LANG_SCANNING_DISK));
         for (i = 0; i < NUM_VOLUMES; i++)
             volume_recalc_free(IF_MV(i));
-#else
-        (void) lists;
 #endif
         gui_synclist_speak_item(lists);
         return ACTION_REDRAW;
     }
+#if CONFIG_RTC
+    else if (action == ACTION_NONE)
+    {
+        static int last_redraw = 0;
+        if (gui_synclist_item_is_onscreen(lists, 0, INFO_TIME)
+            && TIME_AFTER(current_tick, last_redraw + HZ*5))
+        {
+            last_redraw = current_tick;
+            return ACTION_REDRAW;
+        }
+    }
+#endif
     return action;
 }
 static int show_info(void)