diff --git a/src/frontend_common/play_time_manager.cpp b/src/frontend_common/play_time_manager.cpp index b506cd5ae0..782433392f 100644 --- a/src/frontend_common/play_time_manager.cpp +++ b/src/frontend_common/play_time_manager.cpp @@ -13,6 +13,9 @@ #include "core/hle/service/acc/profile_manager.h" #include "play_time_manager.h" +#include +#include + namespace PlayTime { namespace { @@ -164,4 +167,37 @@ void PlayTimeManager::ResetProgramPlayTime(u64 program_id) { Save(); } +std::string PlayTimeManager::GetReadablePlayTime(u64 time_seconds) { + if (time_seconds == 0) { + return {}; + } + + const auto time_minutes = std::max(static_cast(time_seconds) / 60.0, 1.0); + const auto time_hours = static_cast(time_seconds) / 3600.0; + const bool is_minutes = time_minutes < 60.0; + + if (is_minutes) { + return fmt::format("{:.0f} m", time_minutes); + } else { + const bool has_remainder = time_seconds % 60 != 0; + if (has_remainder) { + return fmt::format("{:.1f} h", time_hours); + } else { + return fmt::format("{:.0f} h", time_hours); + } + } +} + +std::string PlayTimeManager::GetPlayTimeHours(u64 time_seconds) { + return fmt::format("{}", time_seconds / 3600); +} + +std::string PlayTimeManager::GetPlayTimeMinutes(u64 time_seconds) { + return fmt::format("{}", (time_seconds % 3600) / 60); +} + +std::string PlayTimeManager::GetPlayTimeSeconds(u64 time_seconds) { + return fmt::format("{}", time_seconds % 60); +} + } // namespace PlayTime diff --git a/src/frontend_common/play_time_manager.h b/src/frontend_common/play_time_manager.h index 1a46d17e1f..a99ccebb1e 100644 --- a/src/frontend_common/play_time_manager.h +++ b/src/frontend_common/play_time_manager.h @@ -38,6 +38,11 @@ public: void Start(); void Stop(); + static std::string GetReadablePlayTime(u64 time_seconds); + static std::string GetPlayTimeHours(u64 time_seconds); + static std::string GetPlayTimeMinutes(u64 time_seconds); + static std::string GetPlayTimeSeconds(u64 time_seconds); + private: void AutoTimestamp(std::stop_token stop_token); void Save(); diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index 7c4c7e4321..25469a351b 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -27,9 +27,6 @@ add_library(qt_common STATIC qt_rom_util.h qt_rom_util.cpp qt_applet_util.h qt_applet_util.cpp qt_progress_dialog.h qt_progress_dialog.cpp - qt_playtime_manager.cpp - qt_playtime_manager.h - ) create_target_directory_groups(qt_common) diff --git a/src/qt_common/qt_playtime_manager.cpp b/src/qt_common/qt_playtime_manager.cpp deleted file mode 100644 index 9000a285fa..0000000000 --- a/src/qt_common/qt_playtime_manager.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "qt_playtime_manager.h" - -namespace QtCommon::PlayTimeManager { - -QString ReadablePlayTime(qulonglong time_seconds) { - if (time_seconds == 0) { - return {}; - } - const auto time_minutes = std::max(static_cast(time_seconds) / 60, 1.0); - const auto time_hours = static_cast(time_seconds) / 3600; - const bool is_minutes = time_minutes < 60; - const char* unit = is_minutes ? "m" : "h"; - const auto value = is_minutes ? time_minutes : time_hours; - - return QStringLiteral("%L1 %2") - .arg(value, 0, 'f', !is_minutes && time_seconds % 60 != 0) - .arg(QString::fromUtf8(unit)); -} - -QString GetPlayTimeUnit(qulonglong time_seconds, TimeUnit unit) { - switch (unit) { - case TimeUnit::Hours: { - const qulonglong hours = time_seconds / 3600; - return QString::number(hours); - } - case TimeUnit::Minutes: { - const qulonglong minutes = (time_seconds % 3600) / 60; - return QString::number(minutes); - } - case TimeUnit::Seconds: { - const qulonglong seconds = time_seconds % 60; - return QString::number(seconds); - } - default: - return QStringLiteral("0"); - } -} - -} // namespace QtCommon::PlayTimeManager \ No newline at end of file diff --git a/src/qt_common/qt_playtime_manager.h b/src/qt_common/qt_playtime_manager.h deleted file mode 100644 index d58793d694..0000000000 --- a/src/qt_common/qt_playtime_manager.h +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include - -namespace QtCommon::PlayTimeManager { - -enum class TimeUnit { - Hours, - Minutes, - Seconds -}; - -// Converts a length of time in seconds into a readable format -QString ReadablePlayTime(qulonglong time_seconds); - -// Returns play time hours/minutes/seconds as a string -QString GetPlayTimeUnit(qulonglong time_seconds, TimeUnit unit); - -} // namespace QtCommon::PlayTimeManager \ No newline at end of file diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 1edc01e540..f14b48a0c7 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -201,6 +201,8 @@ add_executable(yuzu precompiled_headers.h startup_checks.cpp startup_checks.h + set_play_time_dialog.cpp + set_play_time_dialog.h util/clickable_label.cpp util/clickable_label.h util/controller_navigation.cpp diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index 806fffc292..e22f920e3e 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -21,7 +21,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/string_util.h" -#include "qt_common/qt_playtime_manager.h" +#include "frontend_common/play_time_manager.h" #include "qt_common/uisettings.h" #include "yuzu/util/util.h" @@ -241,7 +241,7 @@ public: void setData(const QVariant& value, int role) override { qulonglong time_seconds = value.toULongLong(); - GameListItem::setData(QtCommon::PlayTimeManager::ReadablePlayTime(time_seconds), Qt::DisplayRole); + GameListItem::setData(QString::fromStdString(PlayTime::PlayTimeManager::GetReadablePlayTime(time_seconds)), Qt::DisplayRole); GameListItem::setData(value, PlayTimeRole); } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 2111060a6f..a3d6e0a085 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -15,6 +15,8 @@ #include #include +#include "set_play_time_dialog.h" + #ifdef __APPLE__ #include // for chdir #endif @@ -2637,84 +2639,18 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListR } void GMainWindow::OnGameListSetPlayTime(u64 program_id) { - QDialog dialog(this); - dialog.setWindowTitle(tr("Set Play Time Data")); - dialog.setModal(true); - - auto* layout = new QVBoxLayout(&dialog); - auto* input_layout = new QHBoxLayout(); - auto* hours_edit = new QLineEdit(&dialog); - auto* minutes_edit = new QLineEdit(&dialog); - auto* seconds_edit = new QLineEdit(&dialog); - - hours_edit->setValidator(new QIntValidator(0, 9999, hours_edit)); - minutes_edit->setValidator(new QIntValidator(0, 59, minutes_edit)); - seconds_edit->setValidator(new QIntValidator(0, 59, seconds_edit)); - - using QtCommon::PlayTimeManager::TimeUnit; const u64 current_play_time = play_time_manager->GetPlayTime(program_id); - auto getTimeUnit = [current_play_time](TimeUnit unit) { - return QtCommon::PlayTimeManager::GetPlayTimeUnit(current_play_time, unit); - }; - hours_edit->setText(getTimeUnit(TimeUnit::Hours)); - minutes_edit->setText(getTimeUnit(TimeUnit::Minutes)); - seconds_edit->setText(getTimeUnit(TimeUnit::Seconds)); + SetPlayTimeDialog dialog(this, current_play_time); - input_layout->addWidget(new QLabel(tr("Hours:"), &dialog)); - input_layout->addWidget(hours_edit); - input_layout->addWidget(new QLabel(tr("Minutes:"), &dialog)); - input_layout->addWidget(minutes_edit); - input_layout->addWidget(new QLabel(tr("Seconds:"), &dialog)); - input_layout->addWidget(seconds_edit); - - layout->addLayout(input_layout); - - auto* error_label = new QLabel(&dialog); - error_label->setStyleSheet(QStringLiteral("QLabel { color : red; }")); - error_label->setVisible(false); - layout->addWidget(error_label); - - auto* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog); - layout->addWidget(button_box); - - connect(button_box, &QDialogButtonBox::accepted, [&]() { - const int hours = hours_edit->text().toInt(); - const int minutes = minutes_edit->text().toInt(); - const int seconds = seconds_edit->text().toInt(); - - if (hours < 0 || hours > 9999) { - error_label->setText(tr("Hours must be between 0 and 9999.")); - error_label->setVisible(true); - return; - } - - if (minutes < 0 || minutes > 59) { - error_label->setText(tr("Minutes must be between 0 and 59.")); - error_label->setVisible(true); - return; - } - - if (seconds < 0 || seconds > 59) { - error_label->setText(tr("Seconds must be between 0 and 59.")); - error_label->setVisible(true); - return; - } - - u64 total_seconds = static_cast(hours) * 3600 + static_cast(minutes) * 60 + static_cast(seconds); + if (dialog.exec() == QDialog::Accepted) { + const u64 total_seconds = dialog.GetTotalSeconds(); play_time_manager->SetPlayTime(program_id, total_seconds); game_list->PopulateAsync(UISettings::values.game_dirs); - - dialog.accept(); - }); - - connect(button_box, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); - - dialog.exec(); + } } - void GMainWindow::OnGameListRemovePlayTimeData(u64 program_id) { if (QMessageBox::question(this, tr("Remove Play Time Data"), tr("Reset play time?"), QMessageBox::Yes | QMessageBox::No, diff --git a/src/yuzu/set_play_time_dialog.cpp b/src/yuzu/set_play_time_dialog.cpp new file mode 100644 index 0000000000..c0f1f0be22 --- /dev/null +++ b/src/yuzu/set_play_time_dialog.cpp @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "yuzu/set_play_time_dialog.h" +#include "frontend_common/play_time_manager.h" +#include "ui_set_play_time_dialog.h" + +SetPlayTimeDialog::SetPlayTimeDialog(QWidget* parent, u64 current_play_time) + : QDialog(parent), ui{std::make_unique()} { + ui->setupUi(this); + + ui->hoursSpinBox->setValue( + QString::fromStdString(PlayTime::PlayTimeManager::GetPlayTimeHours(current_play_time)).toInt()); + ui->minutesSpinBox->setValue( + QString::fromStdString(PlayTime::PlayTimeManager::GetPlayTimeMinutes(current_play_time)).toInt()); + ui->secondsSpinBox->setValue( + QString::fromStdString(PlayTime::PlayTimeManager::GetPlayTimeSeconds(current_play_time)).toInt()); + + connect(ui->hoursSpinBox, QOverload::of(&QSpinBox::valueChanged), this, + &SetPlayTimeDialog::OnValueChanged); + connect(ui->minutesSpinBox, QOverload::of(&QSpinBox::valueChanged), this, + &SetPlayTimeDialog::OnValueChanged); + connect(ui->secondsSpinBox, QOverload::of(&QSpinBox::valueChanged), this, + &SetPlayTimeDialog::OnValueChanged); +} + +SetPlayTimeDialog::~SetPlayTimeDialog() = default; + +u64 SetPlayTimeDialog::GetTotalSeconds() const { + const u64 hours = static_cast(ui->hoursSpinBox->value()); + const u64 minutes = static_cast(ui->minutesSpinBox->value()); + const u64 seconds = static_cast(ui->secondsSpinBox->value()); + + return hours * 3600 + minutes * 60 + seconds; +} + +void SetPlayTimeDialog::OnValueChanged() { + if (ui->errorLabel->isVisible()) { + ui->errorLabel->setVisible(false); + } + + const u64 total_seconds = GetTotalSeconds(); + constexpr u64 max_reasonable_time = 9999ULL * 3600; + + if (total_seconds > max_reasonable_time) { + ui->errorLabel->setText(tr("Total play time reached maximum.")); + ui->errorLabel->setVisible(true); + } +} diff --git a/src/yuzu/set_play_time_dialog.h b/src/yuzu/set_play_time_dialog.h new file mode 100644 index 0000000000..75513539e5 --- /dev/null +++ b/src/yuzu/set_play_time_dialog.h @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include "common/common_types.h" + +namespace Ui { +class SetPlayTimeDialog; +} + +class SetPlayTimeDialog : public QDialog { + Q_OBJECT + +public: + explicit SetPlayTimeDialog(QWidget* parent, u64 current_play_time); + ~SetPlayTimeDialog() override; + + u64 GetTotalSeconds() const; + +private: + void OnValueChanged(); + + std::unique_ptr ui; +}; diff --git a/src/yuzu/set_play_time_dialog.ui b/src/yuzu/set_play_time_dialog.ui new file mode 100644 index 0000000000..dca1c7f1a7 --- /dev/null +++ b/src/yuzu/set_play_time_dialog.ui @@ -0,0 +1,123 @@ + + + SetPlayTimeDialog + + + + 0 + 0 + 400 + 150 + + + + Set Play Time Data + + + true + + + + + + + + Hours: + + + + + + + 9999 + + + + + + + Minutes: + + + + + + + 59 + + + + + + + Seconds: + + + + + + + 59 + + + + + + + + + QLabel { color : red; } + + + + + + false + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SetPlayTimeDialog + accept() + + + 199 + 129 + + + 199 + 74 + + + + + buttonBox + rejected() + SetPlayTimeDialog + reject() + + + 199 + 129 + + + 199 + 74 + + + + +