archive_browser.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. #include "archive_browser.h"
  2. #include "math.h"
  3. void archive_update_offset(ArchiveBrowserView* browser) {
  4. furi_assert(browser);
  5. with_view_model(
  6. browser->view, (ArchiveBrowserViewModel * model) {
  7. size_t array_size = files_array_size(model->files);
  8. uint16_t bounds = array_size > 3 ? 2 : array_size;
  9. if(array_size > 3 && model->idx >= array_size - 1) {
  10. model->list_offset = model->idx - 3;
  11. } else if(
  12. model->last_offset && model->last_offset != model->list_offset &&
  13. model->tab_idx == model->last_tab) {
  14. model->list_offset = model->last_offset;
  15. model->last_offset = !model->last_offset;
  16. } else if(model->list_offset < model->idx - bounds) {
  17. model->list_offset = CLAMP(model->idx - 2, array_size - bounds, 0);
  18. } else if(model->list_offset > model->idx - bounds) {
  19. model->list_offset = CLAMP(model->idx - 1, array_size - bounds, 0);
  20. }
  21. return true;
  22. });
  23. }
  24. void archive_update_focus(ArchiveBrowserView* browser, const char* target) {
  25. furi_assert(browser);
  26. furi_assert(target);
  27. archive_get_filenames(browser, string_get_cstr(browser->path));
  28. if(!archive_file_array_size(browser) && !archive_get_depth(browser)) {
  29. archive_switch_tab(browser, DEFAULT_TAB_DIR);
  30. } else {
  31. with_view_model(
  32. browser->view, (ArchiveBrowserViewModel * model) {
  33. uint16_t idx = 0;
  34. while(idx < files_array_size(model->files)) {
  35. ArchiveFile_t* current = files_array_get(model->files, idx);
  36. if(!string_search(current->name, target)) {
  37. model->idx = idx;
  38. break;
  39. }
  40. ++idx;
  41. }
  42. return false;
  43. });
  44. archive_update_offset(browser);
  45. }
  46. }
  47. size_t archive_file_array_size(ArchiveBrowserView* browser) {
  48. uint16_t size = 0;
  49. with_view_model(
  50. browser->view, (ArchiveBrowserViewModel * model) {
  51. size = files_array_size(model->files);
  52. return false;
  53. });
  54. return size;
  55. }
  56. void archive_file_array_rm_selected(ArchiveBrowserView* browser) {
  57. with_view_model(
  58. browser->view, (ArchiveBrowserViewModel * model) {
  59. files_array_remove_v(model->files, model->idx, model->idx + 1);
  60. model->idx = CLAMP(model->idx, files_array_size(model->files) - 1, 0);
  61. return false;
  62. });
  63. if(!archive_file_array_size(browser) && !archive_get_depth(browser)) {
  64. archive_switch_tab(browser, DEFAULT_TAB_DIR);
  65. }
  66. archive_update_offset(browser);
  67. }
  68. void archive_file_array_swap(ArchiveBrowserView* browser, int8_t d) {
  69. with_view_model(
  70. browser->view, (ArchiveBrowserViewModel * model) {
  71. ArchiveFile_t temp;
  72. size_t array_size = files_array_size(model->files) - 1;
  73. uint8_t swap_idx = CLAMP(model->idx + d, array_size, 0);
  74. if(model->idx == 0 && d < 0) {
  75. ArchiveFile_t_init(&temp);
  76. files_array_pop_at(&temp, model->files, array_size);
  77. files_array_push_at(model->files, model->idx, temp);
  78. ArchiveFile_t_clear(&temp);
  79. } else if(model->idx == array_size && d > 0) {
  80. ArchiveFile_t_init(&temp);
  81. files_array_pop_at(&temp, model->files, model->last_idx);
  82. files_array_push_at(model->files, array_size, temp);
  83. ArchiveFile_t_clear(&temp);
  84. } else {
  85. files_array_swap_at(model->files, model->idx, swap_idx);
  86. }
  87. return false;
  88. });
  89. }
  90. void archive_file_array_rm_all(ArchiveBrowserView* browser) {
  91. with_view_model(
  92. browser->view, (ArchiveBrowserViewModel * model) {
  93. files_array_reset(model->files);
  94. return false;
  95. });
  96. }
  97. ArchiveFile_t* archive_get_current_file(ArchiveBrowserView* browser) {
  98. ArchiveFile_t* selected;
  99. with_view_model(
  100. browser->view, (ArchiveBrowserViewModel * model) {
  101. selected = files_array_size(model->files) ? files_array_get(model->files, model->idx) :
  102. NULL;
  103. return false;
  104. });
  105. return selected;
  106. }
  107. ArchiveFile_t* archive_get_file_at(ArchiveBrowserView* browser, size_t idx) {
  108. ArchiveFile_t* selected;
  109. idx = CLAMP(idx, archive_file_array_size(browser), 0);
  110. with_view_model(
  111. browser->view, (ArchiveBrowserViewModel * model) {
  112. selected = files_array_size(model->files) ? files_array_get(model->files, idx) : NULL;
  113. return false;
  114. });
  115. return selected;
  116. }
  117. ArchiveTabEnum archive_get_tab(ArchiveBrowserView* browser) {
  118. ArchiveTabEnum tab_id;
  119. with_view_model(
  120. browser->view, (ArchiveBrowserViewModel * model) {
  121. tab_id = model->tab_idx;
  122. return false;
  123. });
  124. return tab_id;
  125. }
  126. uint8_t archive_get_depth(ArchiveBrowserView* browser) {
  127. uint8_t depth;
  128. with_view_model(
  129. browser->view, (ArchiveBrowserViewModel * model) {
  130. depth = model->depth;
  131. return false;
  132. });
  133. return depth;
  134. }
  135. const char* archive_get_path(ArchiveBrowserView* browser) {
  136. return string_get_cstr(browser->path);
  137. }
  138. const char* archive_get_name(ArchiveBrowserView* browser) {
  139. ArchiveFile_t* selected = archive_get_current_file(browser);
  140. return string_get_cstr(selected->name);
  141. }
  142. void archive_set_tab(ArchiveBrowserView* browser, ArchiveTabEnum tab) {
  143. with_view_model(
  144. browser->view, (ArchiveBrowserViewModel * model) {
  145. model->tab_idx = tab;
  146. return false;
  147. });
  148. }
  149. void archive_set_last_tab(ArchiveBrowserView* browser, ArchiveTabEnum tab) {
  150. with_view_model(
  151. browser->view, (ArchiveBrowserViewModel * model) {
  152. model->last_tab = model->tab_idx;
  153. return false;
  154. });
  155. }
  156. void archive_add_item(ArchiveBrowserView* browser, FileInfo* file_info, const char* name) {
  157. furi_assert(browser);
  158. furi_assert(file_info);
  159. furi_assert(name);
  160. ArchiveFile_t item;
  161. if(filter_by_extension(file_info, get_tab_ext(archive_get_tab(browser)), name)) {
  162. ArchiveFile_t_init(&item);
  163. string_init_set_str(item.name, name);
  164. set_file_type(&item, file_info);
  165. with_view_model(
  166. browser->view, (ArchiveBrowserViewModel * model) {
  167. files_array_push_back(model->files, item);
  168. return false;
  169. });
  170. ArchiveFile_t_clear(&item);
  171. }
  172. }
  173. void archive_show_file_menu(ArchiveBrowserView* browser, bool show) {
  174. furi_assert(browser);
  175. with_view_model(
  176. browser->view, (ArchiveBrowserViewModel * model) {
  177. model->menu = show;
  178. model->menu_idx = 0;
  179. if(show) {
  180. ArchiveFile_t* selected = files_array_get(model->files, model->idx);
  181. selected->fav = archive_is_favorite(
  182. "%s/%s", string_get_cstr(browser->path), string_get_cstr(selected->name));
  183. }
  184. return true;
  185. });
  186. }
  187. void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active) {
  188. with_view_model(
  189. browser->view, (ArchiveBrowserViewModel * model) {
  190. model->move_fav = active;
  191. return true;
  192. });
  193. }
  194. void archive_switch_dir(ArchiveBrowserView* browser, const char* path) {
  195. furi_assert(browser);
  196. furi_assert(path);
  197. string_set(browser->path, path);
  198. archive_get_filenames(browser, string_get_cstr(browser->path));
  199. archive_update_offset(browser);
  200. }
  201. void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
  202. furi_assert(browser);
  203. ArchiveTabEnum tab = archive_get_tab(browser);
  204. if(key == InputKeyLeft) {
  205. tab = ((tab - 1) + ArchiveTabTotal) % ArchiveTabTotal;
  206. } else if(key == InputKeyRight) {
  207. tab = (tab + 1) % ArchiveTabTotal;
  208. }
  209. archive_set_tab(browser, tab);
  210. if((tab != ArchiveTabFavorites &&
  211. !archive_dir_empty(browser, archive_get_default_path(tab))) ||
  212. (tab == ArchiveTabFavorites && !archive_favorites_count(browser))) {
  213. if(tab != ArchiveTabBrowser) {
  214. archive_switch_tab(browser, key);
  215. }
  216. } else {
  217. with_view_model(
  218. browser->view, (ArchiveBrowserViewModel * model) {
  219. if(model->last_tab != model->tab_idx) {
  220. model->idx = 0;
  221. model->depth = 0;
  222. }
  223. return false;
  224. });
  225. archive_switch_dir(browser, archive_get_default_path(tab));
  226. }
  227. archive_set_last_tab(browser, tab);
  228. }
  229. void archive_enter_dir(ArchiveBrowserView* browser, string_t name) {
  230. furi_assert(browser);
  231. furi_assert(name);
  232. with_view_model(
  233. browser->view, (ArchiveBrowserViewModel * model) {
  234. model->last_idx = model->idx;
  235. model->last_offset = model->list_offset;
  236. model->idx = 0;
  237. model->depth = CLAMP(model->depth + 1, MAX_DEPTH, 0);
  238. return false;
  239. });
  240. string_cat(browser->path, "/");
  241. string_cat(browser->path, name);
  242. archive_switch_dir(browser, string_get_cstr(browser->path));
  243. }
  244. void archive_leave_dir(ArchiveBrowserView* browser) {
  245. furi_assert(browser);
  246. const char* path = archive_get_path(browser);
  247. char* last_char_ptr = strrchr(path, '/');
  248. if(last_char_ptr) {
  249. size_t pos = last_char_ptr - path;
  250. string_left(browser->path, pos);
  251. }
  252. with_view_model(
  253. browser->view, (ArchiveBrowserViewModel * model) {
  254. model->depth = CLAMP(model->depth - 1, MAX_DEPTH, 0);
  255. model->idx = model->last_idx;
  256. return false;
  257. });
  258. archive_switch_dir(browser, path);
  259. }