From f66797c5cf9b588f5596e0725225a83fb330c8f0 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Wed, 23 Nov 2022 01:03:36 +1000 Subject: [PATCH] Qt: Add option to reset play time for games --- pcsx2-qt/MainWindow.cpp | 16 +++++++++++++ pcsx2-qt/MainWindow.h | 1 + pcsx2/Frontend/FullscreenUI.cpp | 6 ++++- pcsx2/Frontend/GameList.cpp | 36 ++++++++++++++++++++++++------ pcsx2/Frontend/GameList.h | 1 + pcsx2/Frontend/ImGuiFullscreen.cpp | 2 +- 6 files changed, 53 insertions(+), 9 deletions(-) diff --git a/pcsx2-qt/MainWindow.cpp b/pcsx2-qt/MainWindow.cpp index 4a2f6eaabe..1c9c657519 100644 --- a/pcsx2-qt/MainWindow.cpp +++ b/pcsx2-qt/MainWindow.cpp @@ -1294,6 +1294,9 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point) connect(menu.addAction(tr("Exclude From List")), &QAction::triggered, [this, entry]() { getSettingsDialog()->getGameListSettingsWidget()->addExcludedPath(entry->path); }); + connect(menu.addAction(tr("Reset Play Time")), &QAction::triggered, + [this, entry]() { clearGameListEntryPlayTime(entry); }); + menu.addSeparator(); if (!s_vm_valid) @@ -2374,6 +2377,19 @@ void MainWindow::setGameListEntryCoverImage(const GameList::Entry* entry) m_game_list_widget->refreshGridCovers(); } +void MainWindow::clearGameListEntryPlayTime(const GameList::Entry* entry) +{ + if (QMessageBox::question(this, tr("Confirm Reset"), + tr("Are you sure you want to reset the play time for '%1'?\n\nThis action cannot be undone.") + .arg(QString::fromStdString(entry->title))) != QMessageBox::Yes) + { + return; + } + + GameList::ClearPlayedTimeForSerial(entry->serial); + m_game_list_widget->refresh(false); +} + std::optional MainWindow::promptForResumeState(const QString& save_state_path) { if (save_state_path.isEmpty()) diff --git a/pcsx2-qt/MainWindow.h b/pcsx2-qt/MainWindow.h index c811dd57eb..519b79b5e4 100644 --- a/pcsx2-qt/MainWindow.h +++ b/pcsx2-qt/MainWindow.h @@ -231,6 +231,7 @@ private: void startGameListEntry(const GameList::Entry* entry, std::optional save_slot = std::nullopt, std::optional fast_boot = std::nullopt); void setGameListEntryCoverImage(const GameList::Entry* entry); + void clearGameListEntryPlayTime(const GameList::Entry* entry); std::optional promptForResumeState(const QString& save_state_path); void loadSaveStateSlot(s32 slot); diff --git a/pcsx2/Frontend/FullscreenUI.cpp b/pcsx2/Frontend/FullscreenUI.cpp index 877dbc00f4..7fb235acb2 100644 --- a/pcsx2/Frontend/FullscreenUI.cpp +++ b/pcsx2/Frontend/FullscreenUI.cpp @@ -5142,12 +5142,13 @@ void FullscreenUI::HandleGameListOptions(const GameList::Entry* entry) {ICON_FA_COMPACT_DISC " Default Boot", false}, {ICON_FA_LIGHTBULB " Fast Boot", false}, {ICON_FA_MAGIC " Slow Boot", false}, + {ICON_FA_FOLDER_MINUS " Reset Play Time", false}, {ICON_FA_WINDOW_CLOSE " Close Menu", false}, }; const bool has_resume_state = VMManager::HasSaveStateInSlot(entry->serial.c_str(), entry->crc, -1); OpenChoiceDialog(entry->title.c_str(), false, std::move(options), - [has_resume_state, entry_path = entry->path](s32 index, const std::string& title, bool checked) { + [has_resume_state, entry_path = entry->path, entry_serial = entry->serial](s32 index, const std::string& title, bool checked) { switch (index) { case 0: // Open Game Properties @@ -5168,6 +5169,9 @@ void FullscreenUI::HandleGameListOptions(const GameList::Entry* entry) case 5: // Slow Boot DoStartPath(entry_path, std::nullopt, false); break; + case 6: // Reset Play Time + GameList::ClearPlayedTimeForSerial(entry_serial); + break; default: break; } diff --git a/pcsx2/Frontend/GameList.cpp b/pcsx2/Frontend/GameList.cpp index 39da569fe5..7237318a4f 100644 --- a/pcsx2/Frontend/GameList.cpp +++ b/pcsx2/Frontend/GameList.cpp @@ -883,8 +883,8 @@ GameList::PlayedTimeEntry GameList::UpdatePlayedTimeFile(const std::string& path continue; // found it! - line_entry.last_played_time = last_time; - line_entry.total_played_time += add_time; + line_entry.last_played_time = (last_time != 0) ? last_time : 0; + line_entry.total_played_time = (last_time != 0) ? (line_entry.total_played_time + add_time) : 0; std::string new_line(MakePlayedTimeLine(serial, line_entry)); if (FileSystem::FSeek64(fp.get(), line_pos, SEEK_SET) != 0 || @@ -897,12 +897,15 @@ GameList::PlayedTimeEntry GameList::UpdatePlayedTimeFile(const std::string& path return line_entry; } - // new entry. - std::string new_line(MakePlayedTimeLine(serial, new_entry)); - if (FileSystem::FSeek64(fp.get(), 0, SEEK_END) != 0 || - std::fwrite(new_line.data(), new_line.length(), 1, fp.get()) != 1) + if (last_time != 0) { - Console.Error("Failed to write '%s'.", path.c_str()); + // new entry. + std::string new_line(MakePlayedTimeLine(serial, new_entry)); + if (FileSystem::FSeek64(fp.get(), 0, SEEK_END) != 0 || + std::fwrite(new_line.data(), new_line.length(), 1, fp.get()) != 1) + { + Console.Error("Failed to write '%s'.", path.c_str()); + } } return new_entry; @@ -928,6 +931,25 @@ void GameList::AddPlayedTimeForSerial(const std::string& serial, std::time_t las } } +void GameList::ClearPlayedTimeForSerial(const std::string& serial) +{ + if (serial.empty()) + return; + + UpdatePlayedTimeFile(GetPlayedTimeFile(), serial, 0, 0); + + std::unique_lock lock(s_mutex); + for (GameList::Entry& entry : s_entries) + { + if (entry.serial != serial) + continue; + + entry.last_played_time = 0; + entry.total_played_time = 0; + } +} + + std::time_t GameList::GetCachedPlayedTimeForSerial(const std::string& serial) { if (serial.empty()) diff --git a/pcsx2/Frontend/GameList.h b/pcsx2/Frontend/GameList.h index 91a6795784..09e1b6dd99 100644 --- a/pcsx2/Frontend/GameList.h +++ b/pcsx2/Frontend/GameList.h @@ -124,6 +124,7 @@ namespace GameList /// Add played time for the specified serial. void AddPlayedTimeForSerial(const std::string& serial, std::time_t last_time, std::time_t add_time); + void ClearPlayedTimeForSerial(const std::string& serial); /// Returns the total time played for a game. Requires the game to be scanned in the list. std::time_t GetCachedPlayedTimeForSerial(const std::string& serial); diff --git a/pcsx2/Frontend/ImGuiFullscreen.cpp b/pcsx2/Frontend/ImGuiFullscreen.cpp index 3db138e84c..08b5a0988e 100644 --- a/pcsx2/Frontend/ImGuiFullscreen.cpp +++ b/pcsx2/Frontend/ImGuiFullscreen.cpp @@ -1817,7 +1817,7 @@ void ImGuiFullscreen::DrawChoiceDialog() const float width = LayoutScale(600.0f); const float title_height = g_large_font->FontSize + ImGui::GetStyle().FramePadding.y * 2.0f + ImGui::GetStyle().WindowPadding.y * 2.0f; const float height = std::min( - LayoutScale(400.0f), title_height + LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + (LAYOUT_MENU_BUTTON_Y_PADDING * 2.0f)) * + LayoutScale(450.0f), title_height + LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + (LAYOUT_MENU_BUTTON_Y_PADDING * 2.0f)) * static_cast(s_choice_dialog_options.size())); ImGui::SetNextWindowSize(ImVec2(width, height)); ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));