diff --git a/firmware/application/apps/ui_fileman.cpp b/firmware/application/apps/ui_fileman.cpp index d2d0ab84..2ad716ad 100644 --- a/firmware/application/apps/ui_fileman.cpp +++ b/firmware/application/apps/ui_fileman.cpp @@ -146,22 +146,89 @@ namespace ui { /* FileManBaseView ***********************************************************/ -void FileManBaseView::load_directory_contents(const fs::path& dir_path) { +void FileManBaseView::load_directory_contents_unordered(const fs::path& dir_path, size_t file_cnt) { + current_path = dir_path; + entry_list.clear(); + menu_view.clear(); + auto filtering = !extension_filter.empty(); + bool cxx_file = path_iequal(cxx_ext, extension_filter); + + text_current.set(dir_path.empty() ? "(sd root)" : truncate(dir_path, 24)); + + nb_pages = 1 + (file_cnt / items_per_page); + size_t start = pagination * items_per_page; + size_t stop = start + items_per_page; + if (file_cnt < stop) stop = file_cnt; + if (start > file_cnt) start = 0; // shouldn't hapen but check against it won't hurt + + size_t curr = 0; + + for (const auto& entry : fs::directory_iterator(dir_path, u"*")) { + if (entry_list.size() >= items_per_page) { + break; + } + // Hide files starting with '.' (hidden / tmp). + if (!show_hidden_files && is_hidden_file(entry.path())) + continue; + + if (fs::is_regular_file(entry.status())) { + if (!filtering || path_iequal(entry.path().extension(), extension_filter) || (cxx_file && is_cxx_capture_file(entry.path()))) { + curr++; + if (curr >= start) insert_sorted(entry_list, {entry.path().string(), (uint32_t)entry.size(), false}); + } + + } else if (fs::is_directory(entry.status())) { + curr++; + if (curr >= start) insert_sorted(entry_list, {entry.path().string(), 0, true}); + } + } + + // Add "parent" directory if not at the root. + if (!dir_path.empty() && pagination == 0) + entry_list.insert(entry_list.begin(), {parent_dir_path.string(), 0, true}); + + // add next page + if (file_cnt > start + items_per_page) { + entry_list.push_back({str_next, (uint32_t)pagination + 1, true}); + } + + // add prev page + if (pagination > 0) { + entry_list.insert(entry_list.begin(), {str_back, (uint32_t)pagination - 1, true}); + } +} + +int FileManBaseView::file_count_filtered(const fs::path& directory) { + int count{0}; + auto filtering = !extension_filter.empty(); + bool cxx_file = path_iequal(cxx_ext, extension_filter); + + for (auto& entry : std::filesystem::directory_iterator(directory, (const TCHAR*)u"*")) { + if (fs::is_regular_file(entry.status())) { + if (!filtering || path_iequal(entry.path().extension(), extension_filter) || (cxx_file && is_cxx_capture_file(entry.path()))) + ++count; + } else + ++count; + } + return count; +} + +void FileManBaseView::load_directory_contents(const fs::path& dir_path) { + size_t file_cnt = file_count_filtered(dir_path); + if (file_cnt >= max_items_loaded) { + load_directory_contents_unordered(dir_path, file_cnt); + return; + } current_path = dir_path; entry_list.clear(); menu_view.clear(); auto filtering = !extension_filter.empty(); bool cxx_file = path_iequal(cxx_ext, extension_filter); - bool wasfull = false; // reached the limit or not text_current.set(dir_path.empty() ? "(sd root)" : truncate(dir_path, 24)); for (const auto& entry : fs::directory_iterator(dir_path, u"*")) { // Hide files starting with '.' (hidden / tmp). - if (entry_list.size() >= max_items_loaded) { - wasfull = true; - break; // hard limit. size() complexyt constant in list from c++11, and for vector it constant. - } if (!show_hidden_files && is_hidden_file(entry.path())) continue; @@ -192,11 +259,6 @@ void FileManBaseView::load_directory_contents(const fs::path& dir_path) { // add next page if (list_size > start + items_per_page) { entry_list.push_back({str_next, (uint32_t)pagination + 1, true}); - } else { - // add warning if reached limit - if (wasfull) { - entry_list.push_back({str_full, max_items_loaded, true}); - } } // add prev page diff --git a/firmware/application/apps/ui_fileman.hpp b/firmware/application/apps/ui_fileman.hpp index 18c25d1f..0bbb5e78 100644 --- a/firmware/application/apps/ui_fileman.hpp +++ b/firmware/application/apps/ui_fileman.hpp @@ -65,7 +65,7 @@ class FileManBaseView : public View { uint8_t pagination = 0; uint8_t nb_pages = 1; static constexpr size_t max_filename_length = 20; - static constexpr size_t max_items_loaded = 75; // too memory hungry, so won't load more + static constexpr size_t max_items_loaded = 75; // too memory hungry, so won't sort it static constexpr size_t items_per_page = 20; struct file_assoc_t { @@ -89,10 +89,12 @@ class FileManBaseView : public View { std::filesystem::path get_selected_full_path() const; const fileman_entry& get_selected_entry() const; + int file_count_filtered(const std::filesystem::path& directory); void pop_dir(); void refresh_list(); void reload_current(bool reset_pagination = false); void load_directory_contents(const std::filesystem::path& dir_path); + void load_directory_contents_unordered(const std::filesystem::path& dir_path, size_t file_cnt); const file_assoc_t& get_assoc(const std::filesystem::path& ext) const; NavigationView& nav_;