diff --git a/bin/resources/icons/ra-icon.svg b/bin/resources/icons/ra-icon.svg new file mode 100644 index 0000000000..a423507a83 --- /dev/null +++ b/bin/resources/icons/ra-icon.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcsx2/ImGui/FullscreenUI.cpp b/pcsx2/ImGui/FullscreenUI.cpp index 88e10e1011..57551b3b45 100644 --- a/pcsx2/ImGui/FullscreenUI.cpp +++ b/pcsx2/ImGui/FullscreenUI.cpp @@ -255,6 +255,13 @@ namespace FullscreenUI static bool s_was_paused_on_quick_menu_open = false; static bool s_about_window_open = false; + // achievements login dialog state + static bool s_achievements_login_open = false; + static bool s_achievements_login_logging_in = false; + static char s_achievements_login_username[256] = {}; + static char s_achievements_login_password[256] = {}; + static Achievements::LoginRequestReason s_achievements_login_reason = Achievements::LoginRequestReason::UserInitiated; + // local copies of the currently-running game static std::string s_current_game_title; static std::string s_current_game_subtitle; @@ -493,6 +500,7 @@ namespace FullscreenUI ////////////////////////////////////////////////////////////////////////// static void SwitchToAchievementsWindow(); static void SwitchToLeaderboardsWindow(); + static void DrawAchievementsLoginWindow(); } // namespace FullscreenUI ////////////////////////////////////////////////////////////////////////// @@ -1034,6 +1042,9 @@ void FullscreenUI::Render() if (s_about_window_open) DrawAboutWindow(); + if (s_achievements_login_open) + DrawAchievementsLoginWindow(); + if (s_input_binding_type != InputBindingInfo::Type::Unknown) DrawInputBindingWindow(); @@ -7207,6 +7218,229 @@ bool FullscreenUI::OpenAchievementsWindow() return true; } +void FullscreenUI::DrawAchievementsLoginWindow() +{ + ImGui::SetNextWindowSize(LayoutScale(400.0f, 330.0f)); + ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(12.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(24.0f, 24.0f)); + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0.13f, 0.13f, 0.13f, 0.95f)); + + if (ImGui::BeginPopupModal("RetroAchievements", &s_achievements_login_open, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar)) + { + const float content_width = ImGui::GetContentRegionAvail().x; + + ImGui::PushFont(g_large_font); + + const float icon_height = LayoutScale(24.0f); + const float icon_width = icon_height * (500.0f / 275.0f); + GSTexture* ra_icon = GetCachedSvgTextureAsync("icons/ra-icon.svg", ImVec2(icon_width, icon_height)); + const float title_width = ImGui::CalcTextSize("RetroAchievements").x; + const float header_width = (ra_icon ? icon_width + LayoutScale(10.0f) : 0.0f) + title_width; + const float header_start = (content_width - header_width) * 0.5f; + + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + header_start); + + if (ra_icon) + { + ImGui::Image(reinterpret_cast(ra_icon->GetNativeHandle()), + ImVec2(icon_width, icon_height)); + ImGui::SameLine(); + } + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + LayoutScale(1.0f)); + ImGui::TextUnformatted(FSUI_CSTR("RetroAchievements")); + ImGui::PopFont(); + + ImGui::Spacing(); + ImGui::Spacing(); + + ImGui::PushTextWrapPos(content_width); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8f, 0.8f, 0.8f, 1.0f)); + ImGui::TextWrapped(FSUI_CSTR("Please enter your user name and password for retroachievements.org below. Your password will not be saved in PCSX2, an access token will be generated and used instead.")); + ImGui::PopStyleColor(); + ImGui::PopTextWrapPos(); + + ImGui::Spacing(); + ImGui::Spacing(); + + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, LayoutScale(6.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(12.0f, 10.0f)); + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.2f, 0.2f, 0.2f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.25f, 0.25f, 0.25f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.3f, 0.3f, 0.3f, 1.0f)); + + if (s_achievements_login_logging_in) + ImGui::BeginDisabled(); + + ImGui::SetNextItemWidth(content_width); + ImGui::InputTextWithHint("##username", FSUI_CSTR("Username"), s_achievements_login_username, sizeof(s_achievements_login_username)); + + ImGui::Spacing(); + + ImGui::SetNextItemWidth(content_width); + ImGui::InputTextWithHint("##password", FSUI_CSTR("Password"), s_achievements_login_password, sizeof(s_achievements_login_password), ImGuiInputTextFlags_Password); + + ImGui::PopStyleColor(3); + ImGui::PopStyleVar(2); + + if (s_achievements_login_logging_in) + ImGui::EndDisabled(); + + ImGui::Spacing(); + ImGui::Spacing(); + + if (s_achievements_login_logging_in) + { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.7f, 0.7f, 0.7f, 1.0f)); + const float status_width = ImGui::CalcTextSize("Logging in...").x; + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (content_width - status_width) * 0.5f); + ImGui::TextUnformatted(FSUI_CSTR("Logging in...")); + ImGui::PopStyleColor(); + ImGui::Spacing(); + } + + const float button_height = LayoutScale(36.0f); + const float button_width = LayoutScale(100.0f); + const float button_spacing = LayoutScale(12.0f); + const float total_width = (button_width * 2) + button_spacing; + const float start_x = (content_width - total_width) * 0.5f; + + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + start_x); + + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, LayoutScale(6.0f)); + + const bool can_login = !s_achievements_login_logging_in && + strlen(s_achievements_login_username) > 0 && + strlen(s_achievements_login_password) > 0; + + if (can_login) + { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.5f, 0.9f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.3f, 0.6f, 1.0f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.1f, 0.4f, 0.8f, 1.0f)); + } + else + { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.3f, 0.3f, 0.3f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.3f, 0.3f, 0.3f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.3f, 0.3f, 0.3f, 1.0f)); + } + + if (ImGui::Button(FSUI_CSTR("Login"), ImVec2(button_width, button_height)) && can_login) + { + s_achievements_login_logging_in = true; + + Host::RunOnCPUThread([username = std::string(s_achievements_login_username), + password = std::string(s_achievements_login_password)]() { + Error error; + const bool result = Achievements::Login(username.c_str(), password.c_str(), &error); + + s_achievements_login_logging_in = false; + + if (!result) + { + ShowToast(std::string(), fmt::format(FSUI_FSTR("Login failed.\nError: {}\n\nPlease check your username and password, and try again."), + error.GetDescription())); + return; + } + + ImGui::CloseCurrentPopup(); + s_achievements_login_open = false; + + s_achievements_login_username[0] = '\0'; + s_achievements_login_password[0] = '\0'; + + if (s_achievements_login_reason == Achievements::LoginRequestReason::UserInitiated) + { + if (!Host::GetBaseBoolSettingValue("Achievements", "Enabled", false)) + { + OpenConfirmMessageDialog(FSUI_STR("Enable Achievements"), + FSUI_STR("Achievement tracking is not currently enabled. Your login will have no effect until " + "after tracking is enabled.\n\nDo you want to enable tracking now?"), + [](bool result) { + if (result) + { + Host::SetBaseBoolSettingValue("Achievements", "Enabled", true); + Host::CommitBaseSettingChanges(); + VMManager::ApplySettings(); + } + }); + } + + if (!Host::GetBaseBoolSettingValue("Achievements", "ChallengeMode", false)) + { + OpenConfirmMessageDialog(FSUI_STR("Enable Hardcore Mode"), + FSUI_STR("Hardcore mode is not currently enabled. Enabling hardcore mode allows you to set times, scores, and " + "participate in game-specific leaderboards.\n\nHowever, hardcore mode also prevents the usage of save " + "states, cheats and slowdown functionality.\n\nDo you want to enable hardcore mode?"), + [](bool result) { + if (result) + { + Host::SetBaseBoolSettingValue("Achievements", "ChallengeMode", true); + Host::CommitBaseSettingChanges(); + VMManager::ApplySettings(); + + bool has_active_game; + { + auto lock = Achievements::GetLock(); + has_active_game = Achievements::HasActiveGame(); + } + + if (has_active_game) + { + OpenConfirmMessageDialog(FSUI_STR("Reset System"), + FSUI_STR("Hardcore mode will not be enabled until the system is reset. Do you want to reset the system now?"), + [](bool reset) { + if (reset && VMManager::HasValidVM()) + RequestReset(); + }); + } + } + }); + } + } + }); + } + + ImGui::PopStyleColor(3); + + ImGui::SameLine(0, button_spacing); + + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.4f, 0.4f, 0.4f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.5f, 0.5f, 0.5f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.3f, 0.3f, 0.3f, 1.0f)); + + if (ImGui::Button(FSUI_CSTR("Cancel"), ImVec2(button_width, button_height)) && !s_achievements_login_logging_in) + { + if (s_achievements_login_reason == Achievements::LoginRequestReason::TokenInvalid) + { + if (VMManager::HasValidVM() && !Achievements::HasActiveGame()) + Achievements::DisableHardcoreMode(); + } + + ImGui::CloseCurrentPopup(); + s_achievements_login_open = false; + s_achievements_login_logging_in = false; + + s_achievements_login_username[0] = '\0'; + s_achievements_login_password[0] = '\0'; + } + + ImGui::PopStyleColor(3); + ImGui::PopStyleVar(); + + ImGui::EndPopup(); + } + + ImGui::PopStyleColor(); + ImGui::PopStyleVar(2); + + if (!ImGui::IsPopupOpen("RetroAchievements")) + ImGui::OpenPopup("RetroAchievements"); +} + bool FullscreenUI::IsAchievementsWindowOpen() { return (s_current_main_window == MainWindowType::Achievements); @@ -7414,7 +7648,10 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock& se ActiveButton(FSUI_ICONSTR(ICON_FA_USER, "Not Logged In"), false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); if (MenuButton(FSUI_ICONSTR(ICON_FA_KEY, "Login"), FSUI_CSTR("Logs in to RetroAchievements."))) - Host::OnAchievementsLoginRequested(Achievements::LoginRequestReason::UserInitiated); + { + s_achievements_login_reason = Achievements::LoginRequestReason::UserInitiated; + s_achievements_login_open = true; + } } MenuHeading(FSUI_CSTR("Current Game")); @@ -8363,5 +8600,13 @@ TRANSLATE_NOOP("FullscreenUI", "Game not loaded or no RetroAchievements availabl TRANSLATE_NOOP("FullscreenUI", "Card Enabled"); TRANSLATE_NOOP("FullscreenUI", "Card Name"); TRANSLATE_NOOP("FullscreenUI", "Eject Card"); +TRANSLATE_NOOP("FullscreenUI", "Username"); +TRANSLATE_NOOP("FullscreenUI", "Password"); +TRANSLATE_NOOP("FullscreenUI", "Please enter your user name and password for retroachievements.org below. Your password will not be saved in PCSX2, an access token will be generated and used instead."); +TRANSLATE_NOOP("FullscreenUI", "Login failed.\nError: {}\n\nPlease check your username and password, and try again."); +TRANSLATE_NOOP("FullscreenUI", "Achievement tracking is not currently enabled. Your login will have no effect until after tracking is enabled.\n\nDo you want to enable tracking now?"); +TRANSLATE_NOOP("FullscreenUI", "Hardcore mode is not currently enabled. Enabling hardcore mode allows you to set times, scores, and participate in game-specific leaderboards.\n\nHowever, hardcore mode also prevents the usage of save states, cheats and slowdown functionality.\n\nDo you want to enable hardcore mode?"); +TRANSLATE_NOOP("FullscreenUI", "Logging in..."); // TRANSLATION-STRING-AREA-END #endif +