From bfe9368f1386254b5d84ded17361fe9e27342398 Mon Sep 17 00:00:00 2001 From: Zangetsu38 Date: Thu, 10 Oct 2024 15:16:37 +0200 Subject: [PATCH] gui: Refactor notice handling and app selection. - Switch from opening app to selecting it for newly installed apps. - Implement erase app notice when corresponding app is deleted. - Refactor structures to remove redundant variables. --- vita3k/gui/include/gui/functions.h | 2 + vita3k/gui/src/app_context_menu.cpp | 3 + vita3k/gui/src/archive_install_dialog.cpp | 3 +- vita3k/gui/src/home_screen.cpp | 42 +++++++---- vita3k/gui/src/information_bar.cpp | 88 ++++++++++++++--------- vita3k/gui/src/pkg_install_dialog.cpp | 1 + 6 files changed, 93 insertions(+), 46 deletions(-) diff --git a/vita3k/gui/include/gui/functions.h b/vita3k/gui/include/gui/functions.h index 0cb5576e80..33a28ae45d 100644 --- a/vita3k/gui/include/gui/functions.h +++ b/vita3k/gui/include/gui/functions.h @@ -45,6 +45,7 @@ void close_and_run_new_app(GuiState &gui, EmuEnvState &emuenv, const std::string void close_live_area_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); void close_system_app(GuiState &gui, EmuEnvState &emuenv); void delete_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); +void erase_app_notice(GuiState &gui, const std::string &title_id); void get_app_info(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); size_t get_app_size(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); App *get_app_index(GuiState &gui, const std::string &app_path); @@ -101,6 +102,7 @@ void pre_run_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path void reset_controller_binding(EmuEnvState &emuenv); void save_apps_cache(GuiState &gui, EmuEnvState &emuenv); void save_user(GuiState &gui, EmuEnvState &emuenv, const std::string &user_id); +void select_app(GuiState &gui, const std::string &title_id); void set_config(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); void set_shaders_compiled_display(GuiState &gui, EmuEnvState &emuenv); void update_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path); diff --git a/vita3k/gui/src/app_context_menu.cpp b/vita3k/gui/src/app_context_menu.cpp index e86fd6bece..c38e512ddf 100644 --- a/vita3k/gui/src/app_context_menu.cpp +++ b/vita3k/gui/src/app_context_menu.cpp @@ -262,6 +262,9 @@ void delete_app(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) save_time_apps(gui, emuenv); } + erase_app_notice(gui, title_id); + save_notice_list(emuenv); + LOG_INFO("Application successfully deleted '{} [{}]'.", title_id, APP_INDEX->title); gui.app_selector.user_apps.erase(gui.app_selector.user_apps.begin() + (APP_INDEX - &gui.app_selector.user_apps[0])); diff --git a/vita3k/gui/src/archive_install_dialog.cpp b/vita3k/gui/src/archive_install_dialog.cpp index 03635cac88..a4ad96c6dc 100644 --- a/vita3k/gui/src/archive_install_dialog.cpp +++ b/vita3k/gui/src/archive_install_dialog.cpp @@ -259,9 +259,10 @@ void draw_archive_install_dialog(GuiState &gui, EmuEnvState &emuenv) { emuenv.app_info.app_content_id = content.content_id; if (emuenv.app_info.app_category != "theme") update_notice_info(gui, emuenv, "content"); - if (content.category == "gd") { + if ((content.category.find("gd") != std::string::npos) || (content.category.find("gp") != std::string::npos)) { init_user_app(gui, emuenv, content.title_id); save_apps_cache(gui, emuenv); + select_app(gui, content.title_id); } } } diff --git a/vita3k/gui/src/home_screen.cpp b/vita3k/gui/src/home_screen.cpp index e169588ec7..65c6dd5bb2 100644 --- a/vita3k/gui/src/home_screen.cpp +++ b/vita3k/gui/src/home_screen.cpp @@ -419,7 +419,9 @@ static std::string get_label_name(GuiState &gui, const SortType &type) { return label; } -static int32_t first_visible_app_index = -4, current_selected_app_index = -5; +static constexpr int32_t INVALID_APP_INDEX = -5; +static int32_t first_visible_app_index = INVALID_APP_INDEX, current_selected_app_index = INVALID_APP_INDEX; + static std::vector apps_list_filtered; void browse_home_apps_list(GuiState &gui, EmuEnvState &emuenv, const uint32_t button) { if (apps_list_filtered.empty()) @@ -430,7 +432,7 @@ void browse_home_apps_list(GuiState &gui, EmuEnvState &emuenv, const uint32_t bu gui.is_nav_button = true; // When the current selected app index have not any selected, set it to the first visible app index - if (current_selected_app_index < -4) + if (current_selected_app_index <= INVALID_APP_INDEX) current_selected_app_index = first_visible_app_index; return; @@ -505,6 +507,22 @@ void browse_home_apps_list(GuiState &gui, EmuEnvState &emuenv, const uint32_t bu } } +static int selected_app_index = INVALID_APP_INDEX; +void select_app(GuiState &gui, const std::string &title_id) { + // Find the app in the user apps list + auto app_it = std::find_if(gui.app_selector.user_apps.begin(), gui.app_selector.user_apps.end(), [&](const App &app) { + return app.title_id == title_id; + }); + + // Check if the app was found + if (app_it != gui.app_selector.user_apps.end()) { + // Set the selected app index + current_selected_app_index = selected_app_index = std::distance(gui.app_selector.user_apps.begin(), app_it); + gui.is_nav_button = true; + } else + LOG_ERROR("App with title id {} not found", title_id); +} + static constexpr ImU32 ARROW_COLOR = 0xFFFFFFFF; // White static float scroll_type, current_scroll_pos, max_scroll_pos; @@ -757,7 +775,6 @@ void draw_home_screen(GuiState &gui, EmuEnvState &emuenv) { const auto display_app = [&](const std::vector &apps_list, std::map &apps_icon) { for (const auto &app : apps_list) { - bool selected = false; const auto is_sys = app.path.starts_with("NPXS") && (app.path != "NPXS10007"); if (!is_sys) { @@ -784,18 +801,19 @@ void draw_home_screen(GuiState &gui, EmuEnvState &emuenv) { ImGui::SetCursorPosX(GRID_ICON_POS); // Get the current app index off the apps list. - const auto app_index = static_cast(&app - &apps_list[0]); + const auto app_index = static_cast(&app - apps_list.data()); const auto current_app_index = !is_sys ? app_index : app_index - 4; apps_list_filtered.push_back(current_app_index); // Check if the current app is selected. - const auto is_app_selected = gui.is_nav_button && (current_selected_app_index == current_app_index); - + const auto is_current_app_selected = gui.is_nav_button && (current_selected_app_index == current_app_index); const auto icon_flags = emuenv.cfg.apps_list_grid ? ImGuiSelectableFlags_None : ImGuiSelectableFlags_SpanAllColumns; - if (ImGui::Selectable("##icon", selected || is_app_selected, icon_flags, SELECTABLE_APP_SIZE)) - selected = true; + if (ImGui::Selectable("##icon", is_current_app_selected || (selected_app_index == current_app_index), icon_flags, SELECTABLE_APP_SIZE)) { + selected_app_index = INVALID_APP_INDEX; + pre_load_app(gui, emuenv, emuenv.cfg.show_live_area_screen, app.path); + } - if (!gui.configuration_menu.custom_settings_dialog && (ImGui::IsItemHovered() || is_app_selected)) + if (!gui.configuration_menu.custom_settings_dialog && (ImGui::IsItemHovered() || is_current_app_selected)) emuenv.app_path = app.path; if (emuenv.app_path == app.path) draw_app_context_menu(gui, emuenv, app.path); @@ -813,7 +831,7 @@ void draw_home_screen(GuiState &gui, EmuEnvState &emuenv) { const auto element_is_within_visible_area = (MIN_ITEM_RECT_MAX >= POS_APP_LIST.y) && (item_rect_min <= MAX_LIST_POS); // When the app is selected. - if (is_app_selected) { + if (is_current_app_selected) { // Scroll to the app position when it is not visible. if (item_rect_min < POS_APP_LIST.y) ImGui::SetScrollHereY(0.f); @@ -859,7 +877,7 @@ void draw_home_screen(GuiState &gui, EmuEnvState &emuenv) { } } else if (!gui.is_nav_button && (current_selected_app_index == current_app_index)) { // When the app is selected but not visible, reset the current selected app index. - current_selected_app_index = -5; + current_selected_app_index = INVALID_APP_INDEX; } if (!emuenv.cfg.apps_list_grid) @@ -912,8 +930,6 @@ void draw_home_screen(GuiState &gui, EmuEnvState &emuenv) { ImGui::PopTextWrapPos(); } ImGui::NextColumn(); - if (selected) - pre_load_app(gui, emuenv, emuenv.cfg.show_live_area_screen, app.path); ImGui::PopID(); } }; diff --git a/vita3k/gui/src/information_bar.cpp b/vita3k/gui/src/information_bar.cpp index 4c557ac42b..9301f4a9e2 100644 --- a/vita3k/gui/src/information_bar.cpp +++ b/vita3k/gui/src/information_bar.cpp @@ -37,31 +37,57 @@ namespace gui { -struct NoticeInfo { +struct NoticeList { std::string id; std::string content_id; std::string group; std::string type; time_t time; - std::string name; - std::string msg; + bool is_new; }; -struct NoticeList { - std::string id; - std::string content_id; - std::string group; - std::string type; - time_t time; +struct NoticeInfo : NoticeList { + std::string name; + std::string msg; }; static std::map> notice_list; static std::map notice_list_count_new; -static std::map> notice_list_new; -static std::map notice_info_new; static int notice_info_count_new = 0; static std::vector notice_info; +void erase_app_notice(GuiState &gui, const std::string &title_id) { + auto ¬ice_global = notice_list["global"]; + + // Check if the notice list is empty + if (notice_global.empty()) { + LOG_WARN("Notice list is empty."); + return; + } + + auto notice_list_it = notice_global.begin(); + while (notice_list_it != notice_global.end()) { + if (notice_list_it->id == title_id) { + // Find and erase the corresponding entry in notice_info + const auto notice_info_it = std::find_if(notice_info.begin(), notice_info.end(), [&](const NoticeInfo &n) { + return n.time == notice_list_it->time; + }); + if (notice_info_it != notice_info.end()) + notice_info.erase(notice_info_it); // Erase the entry from notice_info + + // Erase the entry from notice_info_icon if it exists + if (gui.notice_info_icon.contains(notice_list_it->time)) + gui.notice_info_icon.erase(notice_list_it->time); + + // Erase the item from notice_general and update the iterator + notice_list_it = notice_global.erase(notice_list_it); + + LOG_INFO("Notice content with title id: {} has been erased.", title_id); + } else + ++notice_list_it; + } +} + static bool init_notice_icon(GuiState &gui, EmuEnvState &emuenv, const fs::path &content_path, const NoticeList &info) { gui.notice_info_icon[info.time] = {}; int32_t width = 0; @@ -162,7 +188,7 @@ static bool set_notice_info(GuiState &gui, EmuEnvState &emuenv, const NoticeList return false; } - notice_info.push_back({ info.id, info.content_id, info.group, info.type, info.time, name, msg }); + notice_info.push_back({ info, name, msg }); return true; } @@ -171,10 +197,7 @@ void init_notice_info(GuiState &gui, EmuEnvState &emuenv) { if (!notice_info.empty()) { notice_info.clear(); notice_info_count_new = 0; - for (auto ¬ice : gui.notice_info_icon) - notice.second = {}; gui.notice_info_icon.clear(); - notice_info_new.clear(); } if (!notice_list.empty()) { @@ -185,10 +208,8 @@ void init_notice_info(GuiState &gui, EmuEnvState &emuenv) { if (!set_notice_info(gui, emuenv, *notice_it)) { notice_it = user.second.erase(notice_it); save_notice_list(emuenv); - } else { - notice_info_new[notice_it->time] = notice_list_new[user.first][notice_it->time]; + } else ++notice_it; - } } } } @@ -205,7 +226,6 @@ void init_notice_info(GuiState &gui, EmuEnvState &emuenv) { void get_notice_list(EmuEnvState &emuenv) { notice_list.clear(); notice_list_count_new.clear(); - notice_list_new.clear(); const auto notice_path{ emuenv.pref_path / "ux0/user/notice.xml" }; if (fs::exists(notice_path)) { @@ -224,7 +244,7 @@ void get_notice_list(EmuEnvState &emuenv) { noticeList.group = notice.attribute("group").as_string(); noticeList.type = notice.attribute("type").as_string(); noticeList.time = !notice.attribute("time").empty() ? notice.attribute("time").as_llong() : (notice.attribute("date").as_llong() * 1000); // Backward Compat - notice_list_new[user_id][noticeList.time] = notice.attribute("new").as_bool(); + noticeList.is_new = notice.attribute("new").as_bool(); notice_list[user_id].push_back(noticeList); } } @@ -261,7 +281,7 @@ void save_notice_list(EmuEnvState &emuenv) { info_child.append_attribute("group") = notice.group.c_str(); info_child.append_attribute("type") = notice.type.c_str(); info_child.append_attribute("time") = notice.time; - info_child.append_attribute("new") = notice_list_new[user.first][notice.time]; + info_child.append_attribute("new") = notice.is_new; } } @@ -286,12 +306,11 @@ void update_notice_info(GuiState &gui, EmuEnvState &emuenv, const std::string &t } info.type = type; info.time = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - notice_info_new[info.time] = true; - notice_list_new[user_id][info.time] = true; + info.is_new = true; notice_list[user_id].push_back(info); if (set_notice_info(gui, emuenv, info)) { - ++notice_info_count_new; ++notice_list_count_new[user_id]; + ++notice_info_count_new; std::sort(notice_info.begin(), notice_info.end(), [&](const NoticeInfo &na, const NoticeInfo &nb) { return na.time > nb.time; }); @@ -302,11 +321,16 @@ void update_notice_info(GuiState &gui, EmuEnvState &emuenv, const std::string &t static void clean_notice_info_new(const std::string &user_id) { notice_info_count_new = 0; - notice_info_new.clear(); notice_list_count_new["global"] = 0; notice_list_count_new[user_id] = 0; - notice_list_new["global"].clear(); - notice_list_new[user_id].clear(); + for (auto ¬ice : notice_info) + notice.is_new = false; + for (auto ¬ice : notice_list) { + if ((notice.first == "global") || (notice.first == user_id)) { + for (auto &list : notice.second) + list.is_new = false; + } + } } static std::string get_notice_time(GuiState &gui, EmuEnvState &emuenv, const time_t &time) { @@ -379,7 +403,7 @@ static void draw_notice_info(GuiState &gui, EmuEnvState &emuenv) { } if (ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow) && !ImGui::IsAnyItemHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { - if (notice_info_state) { + if (notice_info_state && (notice_info_count_new > 0)) { clean_notice_info_new(emuenv.io.user_id); save_notice_list(emuenv); } @@ -395,6 +419,7 @@ static void draw_notice_info(GuiState &gui, EmuEnvState &emuenv) { ImGui::PushStyleColor(ImGuiCol_Border, GUI_COLOR_TEXT); ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.f * SCALE.x); ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, notice_info.empty() ? 0.f : 8.0f * SCALE.x); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.f, 0.f)); ImGui::SetNextWindowPos(POPUP_POS, ImGuiCond_Always); ImGui::BeginChild("##notice_info_child", POPUP_SIZE, ImGuiChildFlags_Borders, ImGuiWindowFlags_NoSavedSettings); auto &lang = gui.lang.indicator; @@ -426,14 +451,14 @@ static void draw_notice_info(GuiState &gui, EmuEnvState &emuenv) { ImGui::PushStyleColor(ImGuiCol_Header, SELECT_COLOR); ImGui::PushStyleColor(ImGuiCol_HeaderHovered, SELECT_COLOR_HOVERED); ImGui::PushStyleColor(ImGuiCol_HeaderActive, SELECT_COLOR_ACTIVE); - if (ImGui::Selectable("##icon", notice_info_new[notice.time], ImGuiSelectableFlags_SpanAllColumns, SELECT_SIZE)) { + if (ImGui::Selectable("##icon", notice.is_new, ImGuiSelectableFlags_SpanAllColumns, SELECT_SIZE)) { clean_notice_info_new(emuenv.io.user_id); save_notice_list(emuenv); if (notice.type == "content") { if (notice.group == "theme") pre_load_app(gui, emuenv, false, "NPXS10015"); else - pre_load_app(gui, emuenv, emuenv.cfg.show_live_area_screen, notice.id); + select_app(gui, notice.id); } else { pre_load_app(gui, emuenv, false, "NPXS10008"); open_trophy_unlocked(gui, emuenv, notice.id, notice.content_id); @@ -459,7 +484,7 @@ static void draw_notice_info(GuiState &gui, EmuEnvState &emuenv) { } ImGui::EndChild(); ImGui::PopStyleColor(2); - ImGui::PopStyleVar(2); + ImGui::PopStyleVar(3); if (!notice_info.empty()) { const auto DELETE_POPUP_SIZE = ImVec2(756.0f * SCALE.x, 436.0f * SCALE.y); @@ -494,7 +519,6 @@ static void draw_notice_info(GuiState &gui, EmuEnvState &emuenv) { gui.notice_info_icon.clear(); notice_list["global"].clear(); notice_list[emuenv.io.user_id].clear(); - clean_notice_info_new(emuenv.io.user_id); save_notice_list(emuenv); notice_info_state = false; ImGui::CloseCurrentPopup(); diff --git a/vita3k/gui/src/pkg_install_dialog.cpp b/vita3k/gui/src/pkg_install_dialog.cpp index 3d32843ed6..7148f00a55 100644 --- a/vita3k/gui/src/pkg_install_dialog.cpp +++ b/vita3k/gui/src/pkg_install_dialog.cpp @@ -175,6 +175,7 @@ void draw_pkg_install_dialog(GuiState &gui, EmuEnvState &emuenv) { if ((emuenv.app_info.app_category.find("gd") != std::string::npos) || (emuenv.app_info.app_category.find("gp") != std::string::npos)) { init_user_app(gui, emuenv, emuenv.app_info.app_title_id); save_apps_cache(gui, emuenv); + select_app(gui, emuenv.app_info.app_title_id); } update_notice_info(gui, emuenv, "content"); pkg_path = "";