diff --git a/rpcs3/rpcs3qt/game_list_frame.cpp b/rpcs3/rpcs3qt/game_list_frame.cpp index 8111932b09..528e889abd 100644 --- a/rpcs3/rpcs3qt/game_list_frame.cpp +++ b/rpcs3/rpcs3qt/game_list_frame.cpp @@ -106,6 +106,8 @@ game_list_frame::game_list_frame(std::shared_ptr guiSettings, std: AddColumn(gui::column_resolution, tr("Supported Resolutions"), tr("Show Supported Resolutions")); AddColumn(gui::column_sound, tr("Sound Formats"), tr("Show Sound Formats")); AddColumn(gui::column_parental, tr("Parental Level"), tr("Show Parental Levels")); + AddColumn(gui::column_last_play, tr("Last Played"), tr("Show Last Played")); + AddColumn(gui::column_playtime, tr("Time Played"), tr("Show Time Played")); AddColumn(gui::column_compat, tr("Compatibility"), tr("Show Compatibility")); // Events @@ -363,6 +365,48 @@ void game_list_frame::SortGameList() m_gameList->resizeColumnToContents(gui::column_count - 1); } +QString game_list_frame::GetLastPlayedBySerial(const QString& serial) +{ + return m_gui_settings->GetLastPlayed(serial); +} + +QString game_list_frame::GetPlayTimeBySerial(const QString& serial) +{ + const qint64 elapsed_ms = m_gui_settings->GetPlaytime(serial); + + if (elapsed_ms <= 0) + { + return ""; + } + + const qint64 elapsed_seconds = (elapsed_ms / 1000) + ((elapsed_ms % 1000) > 0 ? 1 : 0); + const qint64 hours_played = elapsed_seconds / 3600; + const qint64 minutes_played = (elapsed_seconds % 3600) / 60; + const qint64 seconds_played = (elapsed_seconds % 3600) % 60; + + if (hours_played <= 0) + { + if (minutes_played <= 0) + { + return tr("%0 seconds").arg(seconds_played); + } + + if (seconds_played <= 0) + { + return tr("%0 minutes").arg(minutes_played); + } + + return tr("%0 minutes and %1 seconds").arg(minutes_played).arg(seconds_played); + } + + if (minutes_played <= 0) + { + return tr("%0 hours").arg(hours_played); + } + + return tr("%0 hours and %1 minutes").arg(hours_played).arg(minutes_played); +} + std::string game_list_frame::GetCacheDirBySerial(const std::string& serial) { return fs::get_cache_dir() + "cache/" + serial; @@ -499,6 +543,8 @@ void game_list_frame::Refresh(const bool fromDrive, const bool scrollAfter) QString serial = qstr(game.serial); m_notes[serial] = m_gui_settings->GetValue(gui::notes, serial, "").toString(); m_titles[serial] = m_gui_settings->GetValue(gui::titles, serial, "").toString().simplified(); + m_gui_settings->SetLastPlayed(serial, m_gui_settings->GetValue(gui::last_played, serial, "").toString()); + m_gui_settings->SetPlaytime(serial, m_gui_settings->GetValue(gui::playtime, serial, 0).toInt()); serials.insert(serial); auto cat = category::cat_boot.find(game.category); @@ -1859,6 +1905,8 @@ int game_list_frame::PopulateGameList() m_gameList->setItem(row, gui::column_resolution, new custom_table_widget_item(GetStringFromU32(game->info.resolution, resolution::mode, true))); m_gameList->setItem(row, gui::column_sound, new custom_table_widget_item(GetStringFromU32(game->info.sound_format, sound::format, true))); m_gameList->setItem(row, gui::column_parental, new custom_table_widget_item(GetStringFromU32(game->info.parental_lvl, parental::level), Qt::UserRole, game->info.parental_lvl)); + m_gameList->setItem(row, gui::column_last_play, new custom_table_widget_item(GetLastPlayedBySerial(serial))); + m_gameList->setItem(row, gui::column_playtime, new custom_table_widget_item(GetPlayTimeBySerial(serial))); m_gameList->setItem(row, gui::column_compat, compat_item); if (selected_item == game->info.icon_path) diff --git a/rpcs3/rpcs3qt/game_list_frame.h b/rpcs3/rpcs3qt/game_list_frame.h index a39991abf0..31e82346a8 100644 --- a/rpcs3/rpcs3qt/game_list_frame.h +++ b/rpcs3/rpcs3qt/game_list_frame.h @@ -253,6 +253,8 @@ private: bool RemoveSPUCache(const std::string& base_dir, bool is_interactive = false); bool CreatePPUCache(const game_info& game); + QString GetLastPlayedBySerial(const QString& serial); + QString GetPlayTimeBySerial(const QString& serial); std::string GetCacheDirBySerial(const std::string& serial); std::string GetDataDirBySerial(const std::string& serial); std::string CurrentSelectionIconPath(); diff --git a/rpcs3/rpcs3qt/gui_application.cpp b/rpcs3/rpcs3qt/gui_application.cpp index 349135bc80..77752a4809 100644 --- a/rpcs3/rpcs3qt/gui_application.cpp +++ b/rpcs3/rpcs3qt/gui_application.cpp @@ -75,6 +75,11 @@ void gui_application::Init() void gui_application::InitializeConnects() { + connect(this, &gui_application::OnEmulatorRun, this, &gui_application::StartPlaytime); + connect(this, &gui_application::OnEmulatorStop, this, &gui_application::StopPlaytime); + connect(this, &gui_application::OnEmulatorPause, this, &gui_application::StopPlaytime); + connect(this, &gui_application::OnEmulatorResume, this, &gui_application::StartPlaytime); + if (m_main_window) { connect(m_main_window, &main_window::RequestGlobalStylesheetChange, this, &gui_application::OnChangeStyleSheetRequest); @@ -201,6 +206,25 @@ void gui_application::InitializeCallbacks() Emu.SetCallbacks(std::move(callbacks)); } +void gui_application::StartPlaytime() +{ + const QString serial = qstr(Emu.GetTitleID()); + m_gui_settings->SetLastPlayed(serial, QDate::currentDate().toString("MMMM d yyyy")); + m_timer_playtime.start(); +} + +void gui_application::StopPlaytime() +{ + if (!m_timer_playtime.isValid()) + return; + + const QString serial = qstr(Emu.GetTitleID()); + const qint64 playtime = m_gui_settings->GetPlaytime(serial) + m_timer_playtime.elapsed(); + m_gui_settings->SetPlaytime(serial, playtime); + m_gui_settings->SetLastPlayed(serial, QDate::currentDate().toString("MMMM d yyyy")); + m_timer_playtime.invalidate(); +} + /* * Handle a request to change the stylesheet. May consider adding reporting of errors in future. * Empty string means default. diff --git a/rpcs3/rpcs3qt/gui_application.h b/rpcs3/rpcs3qt/gui_application.h index a63ab205d2..5a87fb3ac2 100644 --- a/rpcs3/rpcs3qt/gui_application.h +++ b/rpcs3/rpcs3qt/gui_application.h @@ -49,6 +49,11 @@ private: void InitializeCallbacks(); void InitializeConnects(); + void StartPlaytime(); + void StopPlaytime(); + + QElapsedTimer m_timer_playtime; + std::shared_ptr m_emu_settings; std::shared_ptr m_gui_settings; diff --git a/rpcs3/rpcs3qt/gui_settings.cpp b/rpcs3/rpcs3qt/gui_settings.cpp index e399691622..b41814deb8 100644 --- a/rpcs3/rpcs3qt/gui_settings.cpp +++ b/rpcs3/rpcs3qt/gui_settings.cpp @@ -157,6 +157,28 @@ void gui_settings::SetValue(const QString& key, const QString& name, const QVari m_settings.endGroup(); } +void gui_settings::SetPlaytime(const QString& serial, const qint64& elapsed) +{ + m_playtime[serial] = elapsed; + SetValue(gui::playtime, serial, elapsed); +} + +qint64 gui_settings::GetPlaytime(const QString& serial) +{ + return m_playtime[serial]; +} + +void gui_settings::SetLastPlayed(const QString& serial, const QString& date) +{ + m_last_played[serial] = date; + SetValue(gui::last_played, serial, date); +} + +QString gui_settings::GetLastPlayed(const QString& serial) +{ + return m_last_played[serial]; +} + QStringList gui_settings::GetGameListCategoryFilters() { QStringList filterList; diff --git a/rpcs3/rpcs3qt/gui_settings.h b/rpcs3/rpcs3qt/gui_settings.h index b3855f284c..2329487d75 100644 --- a/rpcs3/rpcs3qt/gui_settings.h +++ b/rpcs3/rpcs3qt/gui_settings.h @@ -57,6 +57,8 @@ namespace gui column_resolution, column_sound, column_parental, + column_last_play, + column_playtime, column_compat, column_count @@ -88,6 +90,10 @@ namespace gui return "column_sound"; case column_parental: return "column_parental"; + case column_last_play: + return "column_last_play"; + case column_playtime: + return "column_playtime"; case column_compat: return "column_compat"; case column_count: @@ -131,6 +137,8 @@ namespace gui const QString users = "Users"; const QString notes = "Notes"; const QString titles = "Titles"; + const QString playtime = "Playtime"; + const QString last_played = "LastPlayed"; const QColor gl_icon_color = QColor(240, 240, 240, 255); @@ -189,9 +197,9 @@ namespace gui const gui_save fs_dev_flash_list = gui_save(fs, "dev_flash_list", QStringList()); const gui_save fs_dev_usb000_list = gui_save(fs, "dev_usb000_list", QStringList()); - const gui_save l_tty = gui_save(logger, "TTY", true); - const gui_save l_level = gui_save(logger, "level", (uint)(logs::level::success)); - const gui_save l_stack = gui_save(logger, "stack", true); + const gui_save l_tty = gui_save(logger, "TTY", true); + const gui_save l_level = gui_save(logger, "level", (uint)(logs::level::success)); + const gui_save l_stack = gui_save(logger, "stack", true); const gui_save l_stack_tty = gui_save(logger, "TTY stack", false); const gui_save d_splitterState = gui_save(debugger, "splitterState", QByteArray()); @@ -207,7 +215,7 @@ namespace gui const gui_save m_enableUIColors = gui_save(meta, "enableUIColors", false); const gui_save m_richPresence = gui_save(meta, "useRichPresence", true); const gui_save m_discordState = gui_save(meta, "discordState", ""); - const gui_save m_check_upd_start = gui_save(meta, "checkUpdateStart", true); + const gui_save m_check_upd_start = gui_save(meta, "checkUpdateStart", true); const gui_save gs_disableMouse = gui_save(gs_frame, "disableMouse", false); const gui_save gs_resize = gui_save(gs_frame, "resize", false); @@ -280,6 +288,12 @@ public Q_SLOTS: void SetValue(const gui_save& entry, const QVariant& value); void SetValue(const QString& key, const QString& name, const QVariant& value); + void SetPlaytime(const QString& serial, const qint64& elapsed); + qint64 GetPlaytime(const QString& serial); + + void SetLastPlayed(const QString& serial, const QString& date); + QString GetLastPlayed(const QString& serial); + /** Sets the visibility of the chosen category. */ void SetCategoryVisibility(int cat, const bool& val); @@ -300,4 +314,6 @@ private: QSettings m_settings; QDir m_settingsDir; QString m_current_name; + QMap m_playtime; + QMap m_last_played; }; diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 79c0ec36bc..58146e01db 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -851,6 +851,12 @@ void main_window::OnEmuPause() ui->toolbar_start->setIcon(m_icon_play); ui->toolbar_start->setText(tr("Play")); ui->toolbar_start->setToolTip(tr("Resume emulation")); + + // Refresh game list in order to update time played + if (m_gameListFrame) + { + m_gameListFrame->Refresh(); + } } void main_window::OnEmuStop() @@ -883,6 +889,12 @@ void main_window::OnEmuStop() ui->toolbar_start->setToolTip(Emu.IsReady() ? tr("Start emulation") : tr("Resume emulation")); } ui->actionManage_Users->setEnabled(true); + + // Refresh game list in order to update time played + if (m_gameListFrame) + { + m_gameListFrame->Refresh(); + } } void main_window::OnEmuReady()