summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorSolomon Peachy <pizza@shaftnet.org>2019-07-24 14:09:52 -0400
committerSolomon Peachy <pizza@shaftnet.org>2019-08-05 04:10:25 +0200
commit701bf06b2655ab659621ae603fb4de784b660db2 (patch)
treeaf682a351a9a625acafda7c6f3da6db8e01a5871 /apps
parent2a737d3e6f028c68b9c97723f4f14025d74860af (diff)
downloadrockbox-701bf06b2655ab659621ae603fb4de784b660db2.tar.gz
rockbox-701bf06b2655ab659621ae603fb4de784b660db2.zip
Voice enable properties plugin
Patch by Igor Poretsky Updated by Solomon Peachy Change-Id: Ia2adf4a65723b08d6c438f836e3e811cba3dced0
Diffstat (limited to 'apps')
-rw-r--r--apps/lang/english.lang196
-rw-r--r--apps/plugins/properties.c146
2 files changed, 307 insertions, 35 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index da0f21b9c7..075272ef09 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -15723,3 +15723,199 @@ id: VOICE_BAT_BENCH_KEYS
15723 *: "" 15723 *: ""
15724 </voice> 15724 </voice>
15725</phrase> 15725</phrase>
15726<phrase>
15727 id: LANG_PROPERTIES_PATH
15728 desc: in properties plugin
15729 user: core
15730 <source>
15731 *: "[Path]"
15732 </source>
15733 <dest>
15734 *: "[Path]"
15735 </dest>
15736 <voice>
15737 *: "Path"
15738 </voice>
15739</phrase>
15740<phrase>
15741 id: LANG_PROPERTIES_FILENAME
15742 desc: in properties plugin
15743 user: core
15744 <source>
15745 *: "[Filename]"
15746 </source>
15747 <dest>
15748 *: "[Filename]"
15749 </dest>
15750 <voice>
15751 *: "Filename"
15752 </voice>
15753</phrase>
15754<phrase>
15755 id: LANG_PROPERTIES_SIZE
15756 desc: in properties plugin
15757 user: core
15758 <source>
15759 *: "[Size]"
15760 </source>
15761 <dest>
15762 *: "[Size]"
15763 </dest>
15764 <voice>
15765 *: "Size"
15766 </voice>
15767</phrase>
15768<phrase>
15769 id: LANG_PROPERTIES_DATE
15770 desc: in properties plugin
15771 user: core
15772 <source>
15773 *: "[Date]"
15774 </source>
15775 <dest>
15776 *: "[Date]"
15777 </dest>
15778 <voice>
15779 *: "Date"
15780 </voice>
15781</phrase>
15782<phrase>
15783 id: LANG_PROPERTIES_TIME
15784 desc: in properties plugin
15785 user: core
15786 <source>
15787 *: "[Time]"
15788 </source>
15789 <dest>
15790 *: "[Time]"
15791 </dest>
15792 <voice>
15793 *: "Time"
15794 </voice>
15795</phrase>
15796<phrase>
15797 id: LANG_PROPERTIES_ARTIST
15798 desc: in properties plugin
15799 user: core
15800 <source>
15801 *: "[Artist]"
15802 </source>
15803 <dest>
15804 *: "[Artist]"
15805 </dest>
15806 <voice>
15807 *: "Artist"
15808 </voice>
15809</phrase>
15810<phrase>
15811 id: LANG_PROPERTIES_TITLE
15812 desc: in properties plugin
15813 user: core
15814 <source>
15815 *: "[Title]"
15816 </source>
15817 <dest>
15818 *: "[Title]"
15819 </dest>
15820 <voice>
15821 *: "Title"
15822 </voice>
15823</phrase>
15824<phrase>
15825 id: LANG_PROPERTIES_ALBUM
15826 desc: in properties plugin
15827 user: core
15828 <source>
15829 *: "[Album]"
15830 </source>
15831 <dest>
15832 *: "[Album]"
15833 </dest>
15834 <voice>
15835 *: "Album"
15836 </voice>
15837</phrase>
15838<phrase>
15839 id: LANG_PROPERTIES_DURATION
15840 desc: in properties plugin
15841 user: core
15842 <source>
15843 *: "[Duration]"
15844 </source>
15845 <dest>
15846 *: "[Duration]"
15847 </dest>
15848 <voice>
15849 *: "Duration"
15850 </voice>
15851</phrase>
15852<phrase>
15853 id: LANG_PROPERTIES_SUBDIRS
15854 desc: in properties plugin
15855 user: core
15856 <source>
15857 *: "[Subdirs]"
15858 </source>
15859 <dest>
15860 *: "[Subdirs]"
15861 </dest>
15862 <voice>
15863 *: "Subdirs"
15864 </voice>
15865</phrase>
15866<phrase>
15867 id: LANG_PROPERTIES_FILES
15868 desc: in properties plugin
15869 user: core
15870 <source>
15871 *: "[Files]"
15872 </source>
15873 <dest>
15874 *: "[Files]"
15875 </dest>
15876 <voice>
15877 *: "Files"
15878 </voice>
15879</phrase>
15880<phrase>
15881 id: LANG_PROPERTIES_DIRECTORY_PROPERTIES
15882 desc: in properties plugin
15883 user: core
15884 <source>
15885 *: "Directory properties"
15886 </source>
15887 <dest>
15888 *: "Directory properties"
15889 </dest>
15890 <voice>
15891 *: ""
15892 </voice>
15893</phrase>
15894<phrase>
15895 id: LANG_PROPERTIES_FILE_PROPERTIES
15896 desc: in properties plugin
15897 user: core
15898 <source>
15899 *: "File properties"
15900 </source>
15901 <dest>
15902 *: "File properties"
15903 </dest>
15904 <voice>
15905 *: ""
15906 </voice>
15907</phrase>
15908<phrase>
15909 id: LANG_PROPERTIES_FAIL
15910 desc: in properties plugin
15911 user: core
15912 <source>
15913 *: "Failed to gather information"
15914 </source>
15915 <dest>
15916 *: "Failed to gather information"
15917 </dest>
15918 <voice>
15919 *: "Failed to gather information"
15920 </voice>
15921</phrase>
diff --git a/apps/plugins/properties.c b/apps/plugins/properties.c
index 3bddc24d69..686b4d6d1a 100644
--- a/apps/plugins/properties.c
+++ b/apps/plugins/properties.c
@@ -37,32 +37,44 @@ char str_artist[MAX_PATH];
37char str_album[MAX_PATH]; 37char str_album[MAX_PATH];
38char str_duration[32]; 38char str_duration[32];
39 39
40unsigned nseconds;
41unsigned long nsize;
42int32_t size_unit;
43struct tm tm;
44
40int num_properties; 45int num_properties;
41 46
42static const char* props_file[] = 47static const unsigned char* const props_file[] =
43{ 48{
44 "[Path]", str_dirname, 49 ID2P(LANG_PROPERTIES_PATH), str_dirname,
45 "[Filename]", str_filename, 50 ID2P(LANG_PROPERTIES_FILENAME), str_filename,
46 "[Size]", str_size, 51 ID2P(LANG_PROPERTIES_SIZE), str_size,
47 "[Date]", str_date, 52 ID2P(LANG_PROPERTIES_DATE), str_date,
48 "[Time]", str_time, 53 ID2P(LANG_PROPERTIES_TIME), str_time,
49 "[Artist]", str_artist, 54 ID2P(LANG_PROPERTIES_ARTIST), str_artist,
50 "[Title]", str_title, 55 ID2P(LANG_PROPERTIES_TITLE), str_title,
51 "[Album]", str_album, 56 ID2P(LANG_PROPERTIES_ALBUM), str_album,
52 "[Duration]", str_duration, 57 ID2P(LANG_PROPERTIES_DURATION), str_duration,
53}; 58};
54static const char* props_dir[] = 59static const unsigned char* const props_dir[] =
55{ 60{
56 "[Path]", str_dirname, 61 ID2P(LANG_PROPERTIES_PATH), str_dirname,
57 "[Subdirs]", str_dircount, 62 ID2P(LANG_PROPERTIES_SUBDIRS), str_dircount,
58 "[Files]", str_filecount, 63 ID2P(LANG_PROPERTIES_FILES), str_filecount,
59 "[Size]", str_size, 64 ID2P(LANG_PROPERTIES_SIZE), str_size,
65};
66
67static const int32_t units[] =
68{
69 LANG_BYTE,
70 LANG_KIBIBYTE,
71 LANG_MEBIBYTE,
72 LANG_GIBIBYTE
60}; 73};
61 74
62static const char human_size_prefix[4] = { '\0', 'K', 'M', 'G' };
63static unsigned human_size_log(unsigned long long size) 75static unsigned human_size_log(unsigned long long size)
64{ 76{
65 const size_t n = sizeof(human_size_prefix)/sizeof(human_size_prefix[0]); 77 const size_t n = sizeof(units)/sizeof(units[0]);
66 78
67 unsigned i; 79 unsigned i;
68 /* margin set at 10K boundary: 10239 B +1 => 10 KB */ 80 /* margin set at 10K boundary: 10239 B +1 => 10 KB */
@@ -89,9 +101,9 @@ static bool file_properties(const char* selected_file)
89 { 101 {
90 unsigned log; 102 unsigned log;
91 log = human_size_log((unsigned long)info.size); 103 log = human_size_log((unsigned long)info.size);
92 rb->snprintf(str_size, sizeof str_size, "%lu %cB", 104 nsize = ((unsigned long)info.size) >> (log*10);
93 ((unsigned long)info.size) >> (log*10), human_size_prefix[log]); 105 size_unit = units[log];
94 struct tm tm; 106 rb->snprintf(str_size, sizeof str_size, "%lu %s", nsize, rb->str(size_unit));
95 rb->gmtime_r(&info.mtime, &tm); 107 rb->gmtime_r(&info.mtime, &tm);
96 rb->snprintf(str_date, sizeof str_date, "%04d/%02d/%02d", 108 rb->snprintf(str_date, sizeof str_date, "%04d/%02d/%02d",
97 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); 109 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
@@ -119,6 +131,7 @@ static bool file_properties(const char* selected_file)
119 131
120 if (dur > 0) 132 if (dur > 0)
121 { 133 {
134 nseconds = dur;
122 if (dur < 3600) 135 if (dur < 3600)
123 rb->snprintf(str_duration, sizeof str_duration, 136 rb->snprintf(str_duration, sizeof str_duration,
124 "%d:%02d", (int)(dur / 60), 137 "%d:%02d", (int)(dur / 60),
@@ -181,8 +194,6 @@ static bool _dir_properties(DPS *dps)
181 194
182 if (info.attribute & ATTR_DIRECTORY) 195 if (info.attribute & ATTR_DIRECTORY)
183 { 196 {
184 unsigned log;
185
186 if (!rb->strcmp((char *)entry->d_name, ".") || 197 if (!rb->strcmp((char *)entry->d_name, ".") ||
187 !rb->strcmp((char *)entry->d_name, "..")) 198 !rb->strcmp((char *)entry->d_name, ".."))
188 continue; /* skip these */ 199 continue; /* skip these */
@@ -190,16 +201,16 @@ static bool _dir_properties(DPS *dps)
190 dps->dc++; /* new directory */ 201 dps->dc++; /* new directory */
191 if (*rb->current_tick - lasttick > (HZ/8)) 202 if (*rb->current_tick - lasttick > (HZ/8))
192 { 203 {
204 unsigned log = human_size_log(dps->bc);
193 lasttick = *rb->current_tick; 205 lasttick = *rb->current_tick;
194 rb->lcd_clear_display(); 206 rb->lcd_clear_display();
195 rb->lcd_puts(0,0,"SCANNING..."); 207 rb->lcd_puts(0,0,"SCANNING...");
196 rb->lcd_puts(0,1,dps->dirname); 208 rb->lcd_puts(0,1,dps->dirname);
197 rb->lcd_puts(0,2,entry->d_name); 209 rb->lcd_putsf(0,2,"Directories: %d", dps->dc);
198 rb->lcd_putsf(0,3,"Directories: %d", dps->dc); 210 rb->lcd_putsf(0,3,"Files: %d", dps->fc);
199 rb->lcd_putsf(0,4,"Files: %d", dps->fc);
200 log = human_size_log(dps->bc); 211 log = human_size_log(dps->bc);
201 rb->lcd_putsf(0,5,"Size: %lu %cB", (unsigned long)(dps->bc >> (10*log)), 212 rb->lcd_putsf(0,4,"Size: %lu %cB", (unsigned long)(dps->bc >> (10*log)),
202 human_size_prefix[log]); 213 rb->str(units[log]));
203 rb->lcd_update(); 214 rb->lcd_update();
204 } 215 }
205 216
@@ -245,12 +256,19 @@ static bool dir_properties(const char* selected_file, DPS *dps)
245 rb->snprintf(str_dircount, sizeof str_dircount, "%d", dps->dc); 256 rb->snprintf(str_dircount, sizeof str_dircount, "%d", dps->dc);
246 rb->snprintf(str_filecount, sizeof str_filecount, "%d", dps->fc); 257 rb->snprintf(str_filecount, sizeof str_filecount, "%d", dps->fc);
247 log = human_size_log(dps->bc); 258 log = human_size_log(dps->bc);
248 rb->snprintf(str_size, sizeof str_size, "%ld %cB", 259 nsize = (long) (dps->bc >> (log*10));
249 (long) (dps->bc >> (log*10)), human_size_prefix[log]); 260 size_unit = units[log];
261 rb->snprintf(str_size, sizeof str_size, "%ld %s", nsize, rb->str(size_unit));
250 num_properties = 4; 262 num_properties = 4;
251 return true; 263 return true;
252} 264}
253 265
266static const unsigned char* p2str(const unsigned char* p)
267{
268 int id = P2ID(p);
269 return (id != -1) ? rb->str(id) : p;
270}
271
254static const char * get_props(int selected_item, void* data, 272static const char * get_props(int selected_item, void* data,
255 char *buffer, size_t buffer_len) 273 char *buffer, size_t buffer_len)
256{ 274{
@@ -263,7 +281,7 @@ static const char * get_props(int selected_item, void* data,
263 } 281 }
264 else 282 else
265 { 283 {
266 rb->strlcpy(buffer, props_dir[selected_item], buffer_len); 284 rb->strlcpy(buffer, p2str(props_dir[selected_item]), buffer_len);
267 } 285 }
268 } 286 }
269 else 287 else
@@ -274,12 +292,69 @@ static const char * get_props(int selected_item, void* data,
274 } 292 }
275 else 293 else
276 { 294 {
277 rb->strlcpy(buffer, props_file[selected_item], buffer_len); 295 rb->strlcpy(buffer, p2str(props_file[selected_item]), buffer_len);
278 } 296 }
279 } 297 }
280 return buffer; 298 return buffer;
281} 299}
282 300
301static int speak_property_selection(int selected_item, void *data)
302{
303 DPS *dps = data;
304 int32_t id = P2ID((its_a_dir ? props_dir : props_file)[selected_item]);
305 rb->talk_id(id, false);
306 switch (id)
307 {
308 case LANG_PROPERTIES_PATH:
309 if (str_dirname[0] == '/')
310 {
311 char *start = str_dirname;
312 char *ptr;
313 while (0 != (ptr = rb->strchr(start, '/')))
314 {
315 *ptr = '\0';
316 rb->talk_dir_or_spell(str_dirname, NULL, true);
317 *ptr = '/';
318 rb->talk_id(VOICE_CHAR_SLASH, true);
319 start = ptr + 1;
320 }
321 if (*start)
322 rb->talk_dir_or_spell(str_dirname, NULL, true);
323 }
324 else
325 {
326 rb->talk_spell(str_dirname, true);
327 }
328 break;
329 case LANG_PROPERTIES_FILENAME:
330 rb->talk_file_or_spell(str_dirname, str_filename, NULL, true);
331 break;
332 case LANG_PROPERTIES_SIZE:
333 rb->talk_number(nsize, true);
334 rb->talk_id(size_unit, true);
335 break;
336 case LANG_PROPERTIES_DATE:
337 rb->talk_date(&tm, true);
338 break;
339 case LANG_PROPERTIES_TIME:
340 rb->talk_time(&tm, true);
341 break;
342 case LANG_PROPERTIES_DURATION:
343 rb->talk_value(nseconds, UNIT_TIME, true);
344 break;
345 case LANG_PROPERTIES_SUBDIRS:
346 rb->talk_number(dps->dc, true);
347 break;
348 case LANG_PROPERTIES_FILES:
349 rb->talk_number(dps->fc, true);
350 break;
351 default:
352 rb->talk_spell(props_file[selected_item + 1], true);
353 break;
354 }
355 return 0;
356}
357
283enum plugin_status plugin_start(const void* parameter) 358enum plugin_status plugin_start(const void* parameter)
284{ 359{
285 struct gui_synclist properties_lists; 360 struct gui_synclist properties_lists;
@@ -337,7 +412,7 @@ enum plugin_status plugin_start(const void* parameter)
337 if(!(its_a_dir ? dir_properties(file, &dps) : file_properties(file))) 412 if(!(its_a_dir ? dir_properties(file, &dps) : file_properties(file)))
338 { 413 {
339 /* something went wrong (to do: tell user what it was (nesting,...) */ 414 /* something went wrong (to do: tell user what it was (nesting,...) */
340 rb->splash(0, "Failed to gather information"); 415 rb->splash(0, ID2P(LANG_PROPERTIES_FAIL));
341 rb->action_userabort(TIMEOUT_BLOCK); 416 rb->action_userabort(TIMEOUT_BLOCK);
342 return PLUGIN_OK; 417 return PLUGIN_OK;
343 } 418 }
@@ -348,14 +423,15 @@ enum plugin_status plugin_start(const void* parameter)
348#endif 423#endif
349 424
350 rb->gui_synclist_init(&properties_lists, &get_props, &dps, false, 2, NULL); 425 rb->gui_synclist_init(&properties_lists, &get_props, &dps, false, 2, NULL);
351 rb->gui_synclist_set_title(&properties_lists, its_a_dir ? 426 rb->gui_synclist_set_title(&properties_lists, rb->str(its_a_dir ? LANG_PROPERTIES_DIRECTORY_PROPERTIES : LANG_PROPERTIES_FILE_PROPERTIES), NOICON);
352 "Directory properties" :
353 "File properties", NOICON);
354 rb->gui_synclist_set_icon_callback(&properties_lists, NULL); 427 rb->gui_synclist_set_icon_callback(&properties_lists, NULL);
428 if (rb->global_settings->talk_menu)
429 rb->gui_synclist_set_voice_callback(&properties_lists, speak_property_selection);
355 rb->gui_synclist_set_nb_items(&properties_lists, num_properties * 2); 430 rb->gui_synclist_set_nb_items(&properties_lists, num_properties * 2);
356 rb->gui_synclist_limit_scroll(&properties_lists, true); 431 rb->gui_synclist_limit_scroll(&properties_lists, true);
357 rb->gui_synclist_select_item(&properties_lists, 0); 432 rb->gui_synclist_select_item(&properties_lists, 0);
358 rb->gui_synclist_draw(&properties_lists); 433 rb->gui_synclist_draw(&properties_lists);
434 rb->gui_synclist_speak_item(&properties_lists);
359 435
360 while(!quit) 436 while(!quit)
361 { 437 {