mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-12-23 22:39:22 -05:00
Fileman memory opt (#2076)
* paginator * fixes * string instead of path, so saves ram. * fix FileLoadView * pagination list number * pagination "size" test * added detection of special folder name to display page numbers instead of (0 or a number of byte) * order of things: only one directory '..', only on first page Co-authored-by: gullradriel <gullradriel@no-mail.com>
This commit is contained in:
parent
56303eb385
commit
a30875b582
@ -62,7 +62,7 @@ std::string truncate(const fs::path& path, size_t max_length) {
|
||||
}
|
||||
|
||||
// Inserts the entry into the entry list sorted directories first then by file name.
|
||||
void insert_sorted(std::vector<fileman_entry>& entries, fileman_entry&& entry) {
|
||||
void insert_sorted(std::list<fileman_entry>& entries, fileman_entry&& entry) {
|
||||
auto it = std::lower_bound(
|
||||
std::begin(entries), std::end(entries), entry,
|
||||
[](const fileman_entry& lhs, const fileman_entry& rhs) {
|
||||
@ -149,31 +149,64 @@ namespace ui {
|
||||
void FileManBaseView::load_directory_contents(const fs::path& dir_path) {
|
||||
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;
|
||||
|
||||
if (fs::is_regular_file(entry.status())) {
|
||||
if (!filtering || path_iequal(entry.path().extension(), extension_filter) || (cxx_file && is_cxx_capture_file(entry.path())))
|
||||
insert_sorted(entry_list, {entry.path(), (uint32_t)entry.size(), false});
|
||||
insert_sorted(entry_list, {entry.path().string(), (uint32_t)entry.size(), false});
|
||||
} else if (fs::is_directory(entry.status())) {
|
||||
insert_sorted(entry_list, {entry.path(), 0, true});
|
||||
insert_sorted(entry_list, {entry.path().string(), 0, true});
|
||||
}
|
||||
}
|
||||
|
||||
// paginating
|
||||
auto list_size = entry_list.size();
|
||||
nb_pages = 1 + (list_size / items_per_page);
|
||||
size_t start = pagination * items_per_page;
|
||||
size_t stop = start + items_per_page;
|
||||
if (list_size > start) {
|
||||
if (list_size < stop)
|
||||
stop = list_size;
|
||||
entry_list.erase(std::next(entry_list.begin(), stop), entry_list.end());
|
||||
entry_list.erase(entry_list.begin(), std::next(entry_list.begin(), start));
|
||||
}
|
||||
|
||||
// Add "parent" directory if not at the root.
|
||||
if (!dir_path.empty())
|
||||
entry_list.insert(entry_list.begin(), {parent_dir_path, 0, true});
|
||||
if (!dir_path.empty() && pagination == 0)
|
||||
entry_list.insert(entry_list.begin(), {parent_dir_path.string(), 0, true});
|
||||
|
||||
// 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
|
||||
if (pagination > 0) {
|
||||
entry_list.insert(entry_list.begin(), {str_back, (uint32_t)pagination - 1, true});
|
||||
}
|
||||
}
|
||||
|
||||
fs::path FileManBaseView::get_selected_full_path() const {
|
||||
if (get_selected_entry().path == parent_dir_path)
|
||||
if (get_selected_entry().path == parent_dir_path.string())
|
||||
return current_path.parent_path();
|
||||
|
||||
return current_path / get_selected_entry().path;
|
||||
@ -181,7 +214,10 @@ fs::path FileManBaseView::get_selected_full_path() const {
|
||||
|
||||
const fileman_entry& FileManBaseView::get_selected_entry() const {
|
||||
// TODO: return reference to an "empty" entry on OOB?
|
||||
return entry_list[menu_view.highlighted_index()];
|
||||
auto it = entry_list.begin();
|
||||
if (menu_view.highlighted_index() >= 1) std::advance(it, menu_view.highlighted_index());
|
||||
return *it;
|
||||
// return entry_list[menu_view.highlighted_index()];
|
||||
}
|
||||
|
||||
FileManBaseView::FileManBaseView(
|
||||
@ -230,7 +266,7 @@ void FileManBaseView::push_dir(const fs::path& path) {
|
||||
current_path /= path;
|
||||
saved_index_stack.push_back(menu_view.highlighted_index());
|
||||
menu_view.set_highlighted(0);
|
||||
reload_current();
|
||||
reload_current(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,29 +275,56 @@ void FileManBaseView::pop_dir() {
|
||||
return;
|
||||
|
||||
current_path = current_path.parent_path();
|
||||
reload_current();
|
||||
reload_current(true);
|
||||
menu_view.set_highlighted(saved_index_stack.back());
|
||||
saved_index_stack.pop_back();
|
||||
}
|
||||
|
||||
std::string get_extension(std::string t) {
|
||||
const auto index = t.find_last_of(u'.');
|
||||
if (index == t.npos) {
|
||||
return {};
|
||||
} else {
|
||||
return t.substr(index);
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_stem(std::string t) {
|
||||
const auto index = t.find_last_of(u'.');
|
||||
if (index == t.npos) {
|
||||
return t;
|
||||
} else {
|
||||
return t.substr(0, index);
|
||||
}
|
||||
}
|
||||
std::string get_filename(std::string _s) {
|
||||
const auto index = _s.find_last_of("/");
|
||||
if (index == _s.npos) {
|
||||
return _s;
|
||||
} else {
|
||||
return _s.substr(index + 1);
|
||||
}
|
||||
}
|
||||
void FileManBaseView::refresh_list() {
|
||||
if (on_refresh_widgets)
|
||||
on_refresh_widgets(false);
|
||||
|
||||
auto prev_highlight = menu_view.highlighted_index();
|
||||
prev_highlight = menu_view.highlighted_index();
|
||||
menu_view.clear();
|
||||
|
||||
for (const auto& entry : entry_list) {
|
||||
auto entry_name = truncate(entry.path, 20);
|
||||
auto entry_name = std::string{entry.path.length() <= 20 ? entry.path : entry.path.substr(0, 20)};
|
||||
|
||||
if (entry.is_directory) {
|
||||
auto size_str =
|
||||
(entry.path == parent_dir_path)
|
||||
? ""
|
||||
: to_string_dec_uint(file_count(current_path / entry.path));
|
||||
std::string size_str{};
|
||||
if (entry.path == str_next || entry.path == str_back) {
|
||||
size_str = to_string_dec_uint(1 + entry.size) + "/" + to_string_dec_uint(nb_pages); // show computed number of pages
|
||||
} else {
|
||||
size_str = (entry.path == parent_dir_path.string()) ? "" : to_string_dec_uint(file_count(current_path / entry.path));
|
||||
}
|
||||
|
||||
menu_view.add_item(
|
||||
{entry_name + std::string(21 - entry_name.length(), ' ') + size_str,
|
||||
{entry_name.substr(0, max_filename_length) + std::string(21 - entry_name.length(), ' ') + size_str,
|
||||
ui::Color::yellow(),
|
||||
&bitmap_icon_dir,
|
||||
[this](KeyEvent key) {
|
||||
@ -270,11 +333,11 @@ void FileManBaseView::refresh_list() {
|
||||
}});
|
||||
|
||||
} else {
|
||||
const auto& assoc = get_assoc(entry.path.extension());
|
||||
const auto& assoc = get_assoc(get_extension(entry.path));
|
||||
auto size_str = to_string_file_size(entry.size);
|
||||
|
||||
menu_view.add_item(
|
||||
{entry_name + std::string(21 - entry_name.length(), ' ') + size_str,
|
||||
{entry_name.substr(0, max_filename_length) + std::string(21 - entry_name.length(), ' ') + size_str,
|
||||
assoc.color,
|
||||
assoc.icon,
|
||||
[this](KeyEvent key) {
|
||||
@ -282,16 +345,13 @@ void FileManBaseView::refresh_list() {
|
||||
on_select_entry(key);
|
||||
}});
|
||||
}
|
||||
|
||||
// HACK: Should page menu items instead of limiting the number.
|
||||
if (menu_view.item_count() >= max_items_shown)
|
||||
break;
|
||||
}
|
||||
|
||||
menu_view.set_highlighted(prev_highlight);
|
||||
}
|
||||
|
||||
void FileManBaseView::reload_current() {
|
||||
void FileManBaseView::reload_current(bool reset_pagination) {
|
||||
if (reset_pagination) pagination = 0;
|
||||
load_directory_contents(current_path);
|
||||
refresh_list();
|
||||
}
|
||||
@ -327,6 +387,21 @@ FileLoadView::FileLoadView(
|
||||
|
||||
on_select_entry = [this](KeyEvent) {
|
||||
if (get_selected_entry().is_directory) {
|
||||
if (get_selected_entry().path == str_full) {
|
||||
return;
|
||||
}
|
||||
if (get_selected_entry().path == str_back) {
|
||||
pagination--;
|
||||
menu_view.set_highlighted(0);
|
||||
reload_current(false);
|
||||
return;
|
||||
}
|
||||
if (get_selected_entry().path == str_next) {
|
||||
pagination++;
|
||||
menu_view.set_highlighted(0);
|
||||
reload_current(false);
|
||||
return;
|
||||
}
|
||||
push_dir(get_selected_entry().path);
|
||||
} else {
|
||||
if (on_changed)
|
||||
@ -416,10 +491,10 @@ void FileManagerView::on_rename(std::string_view hint) {
|
||||
auto& entry = get_selected_entry();
|
||||
|
||||
// Append the hint to the filename stem as a rename suggestion.
|
||||
name_buffer = entry.path.stem().string();
|
||||
name_buffer = get_stem(entry.path);
|
||||
if (!hint.empty())
|
||||
name_buffer += "_" + std::string{hint};
|
||||
name_buffer += entry.path.extension().string();
|
||||
name_buffer += get_extension(entry.path);
|
||||
|
||||
// Set the rename cursor to before the extension to make renaming simpler.
|
||||
uint32_t cursor_pos = (uint32_t)name_buffer.length();
|
||||
@ -440,11 +515,11 @@ void FileManagerView::on_rename(std::string_view hint) {
|
||||
auto new_name = renamed_path.replace_extension(partner.extension());
|
||||
rename_file(partner, current_path / new_name);
|
||||
}
|
||||
reload_current();
|
||||
reload_current(false);
|
||||
});
|
||||
|
||||
if (!has_partner)
|
||||
reload_current();
|
||||
reload_current(false);
|
||||
});
|
||||
}
|
||||
|
||||
@ -454,7 +529,7 @@ void FileManagerView::on_delete() {
|
||||
return;
|
||||
}
|
||||
|
||||
auto name = get_selected_entry().path.filename().string();
|
||||
auto name = get_filename(get_selected_entry().path);
|
||||
nav_.push<ModalMessageView>(
|
||||
"Delete", "Delete " + name + "\nAre you sure?", YESNO,
|
||||
[this](bool choice) {
|
||||
@ -466,11 +541,11 @@ void FileManagerView::on_delete() {
|
||||
[this](const fs::path& partner, bool should_delete) {
|
||||
if (should_delete)
|
||||
delete_file(partner);
|
||||
reload_current();
|
||||
reload_current(true);
|
||||
});
|
||||
|
||||
if (!has_partner)
|
||||
reload_current();
|
||||
reload_current(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -495,7 +570,7 @@ void FileManagerView::on_clean() {
|
||||
std::filesystem::path current_full_path = path_name / file_name;
|
||||
delete_file(current_full_path);
|
||||
}
|
||||
reload_current();
|
||||
reload_current(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -504,7 +579,7 @@ void FileManagerView::on_new_dir() {
|
||||
name_buffer = "";
|
||||
text_prompt(nav_, name_buffer, max_filename_length, [this](std::string& dir_name) {
|
||||
make_new_directory(current_path / dir_name);
|
||||
reload_current();
|
||||
reload_current(true);
|
||||
});
|
||||
}
|
||||
|
||||
@ -528,14 +603,14 @@ void FileManagerView::on_paste() {
|
||||
clipboard_path = fs::path{};
|
||||
clipboard_mode = ClipboardMode::None;
|
||||
menu_view.focus();
|
||||
reload_current();
|
||||
reload_current(true);
|
||||
}
|
||||
|
||||
void FileManagerView::on_new_file() {
|
||||
name_buffer = "";
|
||||
text_prompt(nav_, name_buffer, max_filename_length, [this](std::string& file_name) {
|
||||
make_new_file(current_path / file_name);
|
||||
reload_current();
|
||||
reload_current(true);
|
||||
});
|
||||
}
|
||||
|
||||
@ -558,7 +633,7 @@ bool FileManagerView::handle_file_open() {
|
||||
return true;
|
||||
} else if (path_iequal(bmp_ext, ext)) {
|
||||
nav_.push<SplashViewer>(path);
|
||||
reload_current();
|
||||
reload_current(false);
|
||||
return true;
|
||||
} else if (path_iequal(rem_ext, ext)) {
|
||||
nav_.push<RemoteView>(path);
|
||||
@ -570,7 +645,7 @@ bool FileManagerView::handle_file_open() {
|
||||
|
||||
bool FileManagerView::selected_is_valid() const {
|
||||
return !entry_list.empty() &&
|
||||
get_selected_entry().path != parent_dir_path;
|
||||
get_selected_entry().path != parent_dir_path.string();
|
||||
}
|
||||
|
||||
FileManagerView::FileManagerView(
|
||||
@ -602,7 +677,7 @@ FileManagerView::FileManagerView(
|
||||
});
|
||||
|
||||
menu_view.on_highlight = [this]() {
|
||||
if (menu_view.highlighted_index() >= max_items_shown - 1) {
|
||||
if (menu_view.highlighted_index() >= max_items_loaded - 1) { // todo check this if correct
|
||||
text_date.set_style(&Styles::red);
|
||||
text_date.set("Too many files!");
|
||||
} else {
|
||||
@ -617,13 +692,30 @@ FileManagerView::FileManagerView(
|
||||
refresh_list();
|
||||
|
||||
on_select_entry = [this](KeyEvent key) {
|
||||
if (key == KeyEvent::Select && get_selected_entry().is_directory) {
|
||||
push_dir(get_selected_entry().path);
|
||||
} else if (key == KeyEvent::Select && handle_file_open()) {
|
||||
return;
|
||||
} else {
|
||||
button_rename.focus();
|
||||
if (key == KeyEvent::Select) {
|
||||
if (get_selected_entry().is_directory) {
|
||||
if (get_selected_entry().path == str_full) {
|
||||
return;
|
||||
}
|
||||
if (get_selected_entry().path == str_back) {
|
||||
pagination--;
|
||||
menu_view.set_highlighted(0);
|
||||
reload_current(false);
|
||||
return;
|
||||
}
|
||||
if (get_selected_entry().path == str_next) {
|
||||
pagination++;
|
||||
menu_view.set_highlighted(0);
|
||||
reload_current(false);
|
||||
return;
|
||||
}
|
||||
push_dir(get_selected_entry().path);
|
||||
return;
|
||||
} else if (handle_file_open()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
button_rename.focus();
|
||||
};
|
||||
|
||||
button_rename.on_select = [this]() {
|
||||
|
@ -31,7 +31,7 @@
|
||||
namespace ui {
|
||||
|
||||
struct fileman_entry {
|
||||
std::filesystem::path path{};
|
||||
std::string path{};
|
||||
uint32_t size{};
|
||||
bool is_directory{};
|
||||
};
|
||||
@ -61,8 +61,12 @@ class FileManBaseView : public View {
|
||||
void push_dir(const std::filesystem::path& path);
|
||||
|
||||
protected:
|
||||
static constexpr size_t max_filename_length = 64;
|
||||
static constexpr size_t max_items_shown = 100;
|
||||
uint32_t prev_highlight = 0;
|
||||
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 items_per_page = 20;
|
||||
|
||||
struct file_assoc_t {
|
||||
std::filesystem::path extension;
|
||||
@ -87,7 +91,7 @@ class FileManBaseView : public View {
|
||||
|
||||
void pop_dir();
|
||||
void refresh_list();
|
||||
void reload_current();
|
||||
void reload_current(bool reset_pagination = false);
|
||||
void load_directory_contents(const std::filesystem::path& dir_path);
|
||||
const file_assoc_t& get_assoc(const std::filesystem::path& ext) const;
|
||||
|
||||
@ -97,11 +101,14 @@ class FileManBaseView : public View {
|
||||
std::function<void(KeyEvent)> on_select_entry{nullptr};
|
||||
std::function<void(bool)> on_refresh_widgets{nullptr};
|
||||
|
||||
const std::string str_back{"<--"};
|
||||
const std::string str_next{"-->"};
|
||||
const std::string str_full{"Can't load more.."};
|
||||
const std::filesystem::path parent_dir_path{u".."};
|
||||
std::filesystem::path current_path{u""};
|
||||
std::filesystem::path extension_filter{u""};
|
||||
|
||||
std::vector<fileman_entry> entry_list{};
|
||||
std::list<fileman_entry> entry_list{};
|
||||
std::vector<uint32_t> saved_index_stack{};
|
||||
|
||||
bool show_hidden_files{false};
|
||||
|
Loading…
Reference in New Issue
Block a user