Game List: Improve dialog for Reset Play Time

This commit is contained in:
TheTechnician27 2025-10-20 18:17:20 -05:00 committed by GovanifY
parent c96607fe37
commit 7db487a49b
7 changed files with 54 additions and 25 deletions

View File

@ -271,15 +271,18 @@ int GameListModel::columnCount(const QModelIndex& parent) const
return Column_Count;
}
QString GameListModel::formatTimespan(time_t timespan)
QString GameListModel::formatTimespan(const time_t timespan)
{
// avoid an extra string conversion
// Avoid an extra string conversion over calling QString::fromStdString(GameList::FormatTimespan).
const u32 hours = static_cast<u32>(timespan / 3600);
const u32 minutes = static_cast<u32>((timespan % 3600) / 60);
if (hours > 0)
return qApp->translate("GameList", "%n hours", "", hours);
else
const u32 minutes = static_cast<u32>((timespan % 3600) / 60);
if (minutes > 0)
return qApp->translate("GameList", "%n minutes", "", minutes);
else
return qApp->translate("GameList", "%n seconds", "", static_cast<u32>((timespan % 3600) % 60));
}
QVariant GameListModel::data(const QModelIndex& index, int role) const

View File

@ -84,7 +84,7 @@ private:
void loadOrGenerateCover(const GameList::Entry* ge);
void invalidateCoverForPath(const std::string& path);
static QString formatTimespan(time_t timespan);
static QString formatTimespan(const time_t timespan);
float m_cover_scale = 0.0f;
std::atomic<u32> m_cover_scale_counter{0};

View File

@ -1455,12 +1455,15 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
connect(menu.addAction(tr("Exclude From List")), &QAction::triggered,
[this, entry]() { getSettingsWindow()->getGameListSettingsWidget()->addExcludedPath(entry->path); });
connect(menu.addAction(tr("Reset Play Time")), &QAction::triggered, [this, entry]() { clearGameListEntryPlayTime(entry); });
const time_t entry_played_time = GameList::GetCachedPlayedTimeForSerial(entry->serial);
// Best two options given zero play time are to grey this out or to not show it at all.
if (entry_played_time)
connect(menu.addAction(tr("Reset Play Time")), &QAction::triggered, [this, entry, entry_played_time]()
{ clearGameListEntryPlayTime(entry, entry_played_time); });
// Check Wiki Page functionality is based on a serial redirect.
if (!entry->serial.empty())
{
connect(menu.addAction(tr("Check Wiki Page")), &QAction::triggered, [this, entry]() { goToWikiPage(entry); });
}
action = menu.addAction(tr("Open Screenshots Folder"));
connect(action, &QAction::triggered, [this, entry]() { openScreenshotsFolderForGame(entry); });
@ -2901,17 +2904,18 @@ void MainWindow::setGameListEntryCoverImage(const GameList::Entry* entry)
m_game_list_widget->refreshGridCovers();
}
void MainWindow::clearGameListEntryPlayTime(const GameList::Entry* entry)
void MainWindow::clearGameListEntryPlayTime(const GameList::Entry* entry, const time_t entry_played_time)
{
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)
tr("Are you sure you want to reset the play time for '%1' (%2)?\n\nYour current play time is %3.\n\nThis action cannot be undone.")
.arg(entry->title.empty() ? tr("empty title") : QString::fromStdString(entry->title),
entry->serial.empty() ? tr("no serial") : QString::fromStdString(entry->serial),
QString::fromStdString(GameList::FormatTimespan(entry_played_time, true))),
(QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes)
{
return;
GameList::ClearPlayedTimeForSerial(entry->serial);
m_game_list_widget->refresh(false);
}
GameList::ClearPlayedTimeForSerial(entry->serial);
m_game_list_widget->refresh(false);
}
void MainWindow::goToWikiPage(const GameList::Entry* entry)

View File

@ -273,7 +273,7 @@ private:
void startGameListEntry(
const GameList::Entry* entry, std::optional<s32> save_slot = std::nullopt, std::optional<bool> fast_boot = std::nullopt, bool load_backup = false);
void setGameListEntryCoverImage(const GameList::Entry* entry);
void clearGameListEntryPlayTime(const GameList::Entry* entry);
void clearGameListEntryPlayTime(const GameList::Entry* entry, const time_t entry_played_time);
void goToWikiPage(const GameList::Entry* entry);
void openScreenshotsFolderForGame(const GameList::Entry* entry);

View File

@ -1174,7 +1174,7 @@ std::string GameList::FormatTimestamp(std::time_t timestamp)
return ret;
}
std::string GameList::FormatTimespan(std::time_t timespan, bool long_format)
std::string GameList::FormatTimespan(const std::time_t timespan, const bool long_format)
{
const u32 hours = static_cast<u32>(timespan / 3600);
const u32 minutes = static_cast<u32>((timespan % 3600) / 60);
@ -1198,8 +1198,10 @@ std::string GameList::FormatTimespan(std::time_t timespan, bool long_format)
{
if (hours > 0)
ret.assign(TRANSLATE_PLURAL_STR("GameList", "%n hours", "", hours));
else
else if (minutes > 0)
ret.assign(TRANSLATE_PLURAL_STR("GameList", "%n minutes", "", minutes));
else
ret.assign(TRANSLATE_PLURAL_STR("GameList", "%n seconds", "", seconds));
}
return ret;

View File

@ -145,7 +145,7 @@ namespace GameList
std::string FormatTimestamp(std::time_t timestamp);
/// Formats a timespan to something human readable (e.g. 1h2m3s or 1 hour).
std::string FormatTimespan(std::time_t timespan, bool long_format = false);
std::string FormatTimespan(const std::time_t timespan, const bool long_format = false);
std::string GetCoverImagePathForEntry(const Entry* entry);
std::string GetNewCoverImagePathForEntry(const Entry* entry, const char* new_filename, bool use_serial = false);

View File

@ -7880,13 +7880,17 @@ void FullscreenUI::HandleGameListOptions(const GameList::Entry* entry)
{FSUI_ICONSTR(ICON_PF_STAR, "Default Boot"), false},
{FSUI_ICONSTR(ICON_FA_FORWARD_FAST, "Fast Boot"), false},
{FSUI_ICONSTR(ICON_FA_COMPACT_DISC, "Full Boot"), false},
{FSUI_ICONSTR(ICON_FA_STOPWATCH, "Reset Play Time"), false},
{FSUI_ICONSTR(ICON_FA_SQUARE_XMARK, "Close Menu"), false},
};
const time_t entry_played_time = GameList::GetCachedPlayedTimeForSerial(entry->serial);
if (entry_played_time)
options.emplace_back(FSUI_ICONSTR(ICON_FA_STOPWATCH, "Reset Play Time"), false);
options.emplace_back(FSUI_ICONSTR(ICON_FA_SQUARE_XMARK, "Close Menu"), false);
const bool has_resume_state = VMManager::HasSaveStateInSlot(entry->serial.c_str(), entry->crc, -1);
OpenChoiceDialog(entry->GetTitle(true).c_str(), false, std::move(options),
[has_resume_state, entry_path = entry->path, entry_serial = entry->serial](s32 index, const std::string& title, bool checked) {
[has_resume_state, entry_path = entry->path, entry_serial = entry->serial, entry_title = entry->title, entry_played_time]
(s32 index, const std::string& title, bool checked) {
switch (index)
{
case 0: // Open Game Properties
@ -7907,10 +7911,26 @@ void FullscreenUI::HandleGameListOptions(const GameList::Entry* entry)
case 5: // Full Boot
DoStartPath(entry_path, std::nullopt, false);
break;
case 6: // Reset Play Time
GameList::ClearPlayedTimeForSerial(entry_serial);
case 6:
{
// Close Menu
if (!entry_played_time)
break;
// Reset Play Time
OpenConfirmMessageDialog(FSUI_ICONSTR(ICON_FA_STOPWATCH, "Confirm Reset"),
fmt::format(FSUI_FSTR("Are you sure you want to reset the play time for '{}' ({})?\n\n"
"Your current play time is {}.\n\nThis action cannot be undone."),
entry_title.empty() ? FSUI_STR("empty title") : entry_title,
entry_serial.empty() ? FSUI_STR("no serial") : entry_serial,
GameList::FormatTimespan(entry_played_time, true)),
[entry_serial](bool result) {
if (result)
GameList::ClearPlayedTimeForSerial(entry_serial);
}, false);
}
break;
default:
default: // Close Menu
break;
}