item.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. #include <furi.h>
  2. #include <storage/storage.h>
  3. #include <toolbox/dir_walk.h>
  4. #include <toolbox/path.h>
  5. #include "quac.h"
  6. #include "item.h"
  7. #include <m-array.h>
  8. ARRAY_DEF(FileArray, FuriString*, FURI_STRING_OPLIST);
  9. ItemsView* item_get_items_view_from_path(void* context, const FuriString* input_path) {
  10. App* app = context;
  11. // Handle the app start condition
  12. FuriString* in_path;
  13. if(input_path == NULL) {
  14. in_path = furi_string_alloc_set_str(APP_DATA_PATH(""));
  15. } else {
  16. in_path = furi_string_alloc_set(input_path);
  17. }
  18. if(furi_string_get_char(in_path, furi_string_size(in_path) - 1) == '/') {
  19. furi_string_left(in_path, furi_string_size(in_path) - 1);
  20. }
  21. const char* cpath = furi_string_get_cstr(in_path);
  22. FURI_LOG_I(TAG, "Reading items from path: %s", cpath);
  23. ItemsView* iview = malloc(sizeof(ItemsView));
  24. iview->path = furi_string_alloc_set(in_path);
  25. iview->name = furi_string_alloc();
  26. if(app->depth == 0) {
  27. furi_string_set_str(iview->name, QUAC_NAME);
  28. } else {
  29. path_extract_basename(cpath, iview->name);
  30. item_prettify_name(iview->name);
  31. }
  32. DirWalk* dir_walk = dir_walk_alloc(app->storage);
  33. dir_walk_set_recursive(dir_walk, false);
  34. FuriString* path = furi_string_alloc();
  35. FileArray_t flist;
  36. FileArray_init(flist);
  37. FuriString* filename_tmp;
  38. filename_tmp = furi_string_alloc();
  39. // Walk the directory and store all file names in sorted order
  40. if(dir_walk_open(dir_walk, cpath)) {
  41. while(dir_walk_read(dir_walk, path, NULL) == DirWalkOK) {
  42. // FURI_LOG_I(TAG, "> dir_walk: %s", furi_string_get_cstr(path));
  43. const char* cpath = furi_string_get_cstr(path);
  44. path_extract_filename(path, filename_tmp, false);
  45. // Always skip our .quac.conf file!
  46. if(!furi_string_cmp_str(filename_tmp, QUAC_SETTINGS_FILENAME)) {
  47. continue;
  48. }
  49. // Skip "hidden" files
  50. char first_char = furi_string_get_char(filename_tmp, 0);
  51. if(first_char == '.' && !app->settings.show_hidden) {
  52. // FURI_LOG_I(TAG, ">> skipping hidden file: %s", furi_string_get_cstr(filename_tmp));
  53. continue;
  54. }
  55. // Insert the new file path in sorted order to flist
  56. uint32_t i = 0;
  57. FileArray_it_t it;
  58. for(FileArray_it(it, flist); !FileArray_end_p(it); FileArray_next(it), ++i) {
  59. if(strcmp(cpath, furi_string_get_cstr(*FileArray_ref(it))) > 0) {
  60. continue;
  61. }
  62. // FURI_LOG_I(TAG, ">> Inserting at %lu", i);
  63. FileArray_push_at(flist, i, path);
  64. break;
  65. }
  66. if(i == FileArray_size(flist)) {
  67. // FURI_LOG_I(TAG, "Couldn't insert, so adding at the end!");
  68. FileArray_push_back(flist, path);
  69. }
  70. }
  71. }
  72. furi_string_free(filename_tmp);
  73. furi_string_free(path);
  74. // Generate our Item list
  75. FileArray_it_t iter;
  76. ItemArray_init(iview->items);
  77. for(FileArray_it(iter, flist); !FileArray_end_p(iter); FileArray_next(iter)) {
  78. path = *FileArray_ref(iter);
  79. Item* item = ItemArray_push_new(iview->items);
  80. item->is_link = false;
  81. item->name = furi_string_alloc();
  82. FileInfo fileinfo;
  83. if(storage_common_stat(app->storage, furi_string_get_cstr(path), &fileinfo) == FSE_OK &&
  84. file_info_is_dir(&fileinfo)) {
  85. item->type = Item_Group;
  86. path_extract_filename(path, item->name, false);
  87. } else {
  88. // Action files have extensions, which determine their type
  89. item->ext[0] = 0;
  90. item_path_extract_filename(path, item->name, &(item->ext), &(item->is_link));
  91. item->type = item_get_item_type_from_extension(item->ext);
  92. }
  93. // FURI_LOG_I(TAG, "Basename: %s", furi_string_get_cstr(item->name));
  94. item_prettify_name(item->name);
  95. item->path = furi_string_alloc_set(path);
  96. // FURI_LOG_I(TAG, "Path: %s", furi_string_get_cstr(item->path));
  97. }
  98. furi_string_free(in_path);
  99. FileArray_clear(flist);
  100. dir_walk_free(dir_walk);
  101. return iview;
  102. }
  103. void item_items_view_free(ItemsView* items_view) {
  104. furi_string_free(items_view->name);
  105. furi_string_free(items_view->path);
  106. ItemArray_it_t iter;
  107. for(ItemArray_it(iter, items_view->items); !ItemArray_end_p(iter); ItemArray_next(iter)) {
  108. furi_string_free(ItemArray_ref(iter)->name);
  109. furi_string_free(ItemArray_ref(iter)->path);
  110. }
  111. ItemArray_clear(items_view->items);
  112. free(items_view);
  113. }
  114. void item_prettify_name(FuriString* name) {
  115. // FURI_LOG_I(TAG, "Converting %s to...", furi_string_get_cstr(name));
  116. if(furi_string_size(name) > 3) {
  117. char c = furi_string_get_char(name, 2);
  118. if(c == '_') {
  119. char a = furi_string_get_char(name, 0);
  120. char b = furi_string_get_char(name, 1);
  121. if(a >= '0' && a <= '9' && b >= '0' && b <= '9') {
  122. furi_string_right(name, 3);
  123. }
  124. }
  125. }
  126. furi_string_replace_all_str(name, "_", " ");
  127. // FURI_LOG_I(TAG, "... %s", furi_string_get_cstr(name));
  128. }
  129. ItemType item_get_item_type_from_extension(const char* ext) {
  130. ItemType type = Item_Unknown;
  131. if(!strcmp(ext, ".sub")) {
  132. type = Item_SubGhz;
  133. } else if(!strcmp(ext, ".rfid")) {
  134. type = Item_RFID;
  135. } else if(!strcmp(ext, ".ir")) {
  136. type = Item_IR;
  137. } else if(!strcmp(ext, ".nfc")) {
  138. type = Item_NFC;
  139. } else if(!strcmp(ext, ".ibtn")) {
  140. type = Item_iButton;
  141. } else if(!strcmp(ext, ".qpl")) {
  142. type = Item_Playlist;
  143. }
  144. return type;
  145. }
  146. void item_path_extract_filename(
  147. FuriString* path,
  148. FuriString* name,
  149. char (*ext)[MAX_EXT_LEN],
  150. bool* is_link) {
  151. furi_check(ext);
  152. furi_check(is_link);
  153. FuriString* temp = furi_string_alloc_set(path);
  154. *is_link = furi_string_end_withi_str(temp, ".ql");
  155. if(*is_link) {
  156. furi_string_left(temp, furi_string_size(temp) - 3);
  157. }
  158. path_extract_extension(temp, *ext, MAX_EXT_LEN);
  159. path_extract_filename(temp, name, true);
  160. furi_string_free(temp);
  161. }