Merge pull request #140 from sudachi-emu/feature-total-times-played
Added total times played support
This commit is contained in:
commit
39f1a62c8d
|
@ -102,7 +102,7 @@ void PushInShowController(Core::System& system, AppletStorageChannel& channel) {
|
||||||
// ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem,
|
// ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem,
|
||||||
// which sets this to the input param
|
// which sets this to the input param
|
||||||
.style_set = Core::HID::NpadStyleSet::None,
|
.style_set = Core::HID::NpadStyleSet::None,
|
||||||
.joy_hold_type = 0,
|
.joy_hold_type = Frontend::NpadJoyDeviceHoldType::Vertical,
|
||||||
};
|
};
|
||||||
std::vector<u8> common_args_data(sizeof(common_args));
|
std::vector<u8> common_args_data(sizeof(common_args));
|
||||||
std::vector<u8> private_args_data(sizeof(private_args));
|
std::vector<u8> private_args_data(sizeof(private_args));
|
||||||
|
|
|
@ -53,6 +53,8 @@ enum class ControllerSupportResult : u32 {
|
||||||
Cancel = 2,
|
Cancel = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class NpadJoyDeviceHoldType : u32 { Vertical = 0, Horizontal = 1 };
|
||||||
|
|
||||||
struct ControllerSupportArgPrivate {
|
struct ControllerSupportArgPrivate {
|
||||||
u32 arg_private_size{};
|
u32 arg_private_size{};
|
||||||
u32 arg_size{};
|
u32 arg_size{};
|
||||||
|
@ -61,7 +63,7 @@ struct ControllerSupportArgPrivate {
|
||||||
ControllerSupportMode mode{};
|
ControllerSupportMode mode{};
|
||||||
ControllerSupportCaller caller{};
|
ControllerSupportCaller caller{};
|
||||||
Core::HID::NpadStyleSet style_set{};
|
Core::HID::NpadStyleSet style_set{};
|
||||||
u32 joy_hold_type{};
|
NpadJoyDeviceHoldType joy_hold_type{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ControllerSupportArgPrivate) == 0x14,
|
static_assert(sizeof(ControllerSupportArgPrivate) == 0x14,
|
||||||
"ControllerSupportArgPrivate has incorrect size.");
|
"ControllerSupportArgPrivate has incorrect size.");
|
||||||
|
|
|
@ -125,6 +125,8 @@ ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent)
|
||||||
connect(ui->show_types, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
|
connect(ui->show_types, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
|
||||||
connect(ui->show_play_time, &QCheckBox::stateChanged, this,
|
connect(ui->show_play_time, &QCheckBox::stateChanged, this,
|
||||||
&ConfigureUi::RequestGameListUpdate);
|
&ConfigureUi::RequestGameListUpdate);
|
||||||
|
connect(ui->show_total_times, &QCheckBox::stateChanged, this,
|
||||||
|
&ConfigureUi::RequestGameListUpdate);
|
||||||
connect(ui->game_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
connect(ui->game_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
&ConfigureUi::RequestGameListUpdate);
|
&ConfigureUi::RequestGameListUpdate);
|
||||||
connect(ui->folder_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
connect(ui->folder_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||||
|
@ -170,6 +172,7 @@ void ConfigureUi::ApplyConfiguration() {
|
||||||
UISettings::values.show_size = ui->show_size->isChecked();
|
UISettings::values.show_size = ui->show_size->isChecked();
|
||||||
UISettings::values.show_types = ui->show_types->isChecked();
|
UISettings::values.show_types = ui->show_types->isChecked();
|
||||||
UISettings::values.show_play_time = ui->show_play_time->isChecked();
|
UISettings::values.show_play_time = ui->show_play_time->isChecked();
|
||||||
|
UISettings::values.show_total_times = ui->show_total_times->isChecked();
|
||||||
UISettings::values.game_icon_size = ui->game_icon_size_combobox->currentData().toUInt();
|
UISettings::values.game_icon_size = ui->game_icon_size_combobox->currentData().toUInt();
|
||||||
UISettings::values.folder_icon_size = ui->folder_icon_size_combobox->currentData().toUInt();
|
UISettings::values.folder_icon_size = ui->folder_icon_size_combobox->currentData().toUInt();
|
||||||
UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
|
UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
|
||||||
|
@ -200,6 +203,7 @@ void ConfigureUi::SetConfiguration() {
|
||||||
ui->show_size->setChecked(UISettings::values.show_size.GetValue());
|
ui->show_size->setChecked(UISettings::values.show_size.GetValue());
|
||||||
ui->show_types->setChecked(UISettings::values.show_types.GetValue());
|
ui->show_types->setChecked(UISettings::values.show_types.GetValue());
|
||||||
ui->show_play_time->setChecked(UISettings::values.show_play_time.GetValue());
|
ui->show_play_time->setChecked(UISettings::values.show_play_time.GetValue());
|
||||||
|
ui->show_total_times->setChecked(UISettings::values.show_total_times.GetValue());
|
||||||
ui->game_icon_size_combobox->setCurrentIndex(
|
ui->game_icon_size_combobox->setCurrentIndex(
|
||||||
ui->game_icon_size_combobox->findData(UISettings::values.game_icon_size.GetValue()));
|
ui->game_icon_size_combobox->findData(UISettings::values.game_icon_size.GetValue()));
|
||||||
ui->folder_icon_size_combobox->setCurrentIndex(
|
ui->folder_icon_size_combobox->setCurrentIndex(
|
||||||
|
@ -262,7 +266,7 @@ void ConfigureUi::InitializeLanguageComboBox() {
|
||||||
#else
|
#else
|
||||||
const QString country = QLocale::countryToString(QLocale(locale).country());
|
const QString country = QLocale::countryToString(QLocale(locale).country());
|
||||||
ui->language_combobox->addItem(QStringLiteral("%1 (%2)").arg(lang, country), locale);
|
ui->language_combobox->addItem(QStringLiteral("%1 (%2)").arg(lang, country), locale);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlike other configuration changes, interface language changes need to be reflected on the
|
// Unlike other configuration changes, interface language changes need to be reflected on the
|
||||||
|
|
|
@ -111,6 +111,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="show_total_times">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show Total Times Column</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="game_icon_size_qhbox_layout_2">
|
<layout class="QHBoxLayout" name="game_icon_size_qhbox_layout_2">
|
||||||
<item>
|
<item>
|
||||||
|
|
|
@ -344,6 +344,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid
|
||||||
tree_view->setColumnHidden(COLUMN_ADD_ONS, !UISettings::values.show_add_ons);
|
tree_view->setColumnHidden(COLUMN_ADD_ONS, !UISettings::values.show_add_ons);
|
||||||
tree_view->setColumnHidden(COLUMN_COMPATIBILITY, !UISettings::values.show_compat);
|
tree_view->setColumnHidden(COLUMN_COMPATIBILITY, !UISettings::values.show_compat);
|
||||||
tree_view->setColumnHidden(COLUMN_PLAY_TIME, !UISettings::values.show_play_time);
|
tree_view->setColumnHidden(COLUMN_PLAY_TIME, !UISettings::values.show_play_time);
|
||||||
|
tree_view->setColumnHidden(COLUMN_TOTAL_TIMES, !UISettings::values.show_total_times);
|
||||||
item_model->setSortRole(GameListItemPath::SortRole);
|
item_model->setSortRole(GameListItemPath::SortRole);
|
||||||
|
|
||||||
connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::OnUpdateThemedIcons);
|
connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::OnUpdateThemedIcons);
|
||||||
|
@ -800,6 +801,7 @@ void GameList::RetranslateUI() {
|
||||||
item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, tr("File type"));
|
item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, tr("File type"));
|
||||||
item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, tr("Size"));
|
item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, tr("Size"));
|
||||||
item_model->setHeaderData(COLUMN_PLAY_TIME, Qt::Horizontal, tr("Play time"));
|
item_model->setHeaderData(COLUMN_PLAY_TIME, Qt::Horizontal, tr("Play time"));
|
||||||
|
item_model->setHeaderData(COLUMN_TOTAL_TIMES, Qt::Horizontal, tr("Total times"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListSearchField::changeEvent(QEvent* event) {
|
void GameListSearchField::changeEvent(QEvent* event) {
|
||||||
|
@ -828,6 +830,7 @@ void GameList::PopulateAsync(QVector<UISettings::GameDir>& game_dirs) {
|
||||||
tree_view->setColumnHidden(COLUMN_FILE_TYPE, !UISettings::values.show_types);
|
tree_view->setColumnHidden(COLUMN_FILE_TYPE, !UISettings::values.show_types);
|
||||||
tree_view->setColumnHidden(COLUMN_SIZE, !UISettings::values.show_size);
|
tree_view->setColumnHidden(COLUMN_SIZE, !UISettings::values.show_size);
|
||||||
tree_view->setColumnHidden(COLUMN_PLAY_TIME, !UISettings::values.show_play_time);
|
tree_view->setColumnHidden(COLUMN_PLAY_TIME, !UISettings::values.show_play_time);
|
||||||
|
tree_view->setColumnHidden(COLUMN_TOTAL_TIMES, !UISettings::values.show_total_times);
|
||||||
|
|
||||||
// Cancel any existing worker.
|
// Cancel any existing worker.
|
||||||
current_worker.reset();
|
current_worker.reset();
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "uisettings.h"
|
|
||||||
#include "sudachi/compatibility_list.h"
|
#include "sudachi/compatibility_list.h"
|
||||||
#include "sudachi/play_time_manager.h"
|
#include "sudachi/play_time_manager.h"
|
||||||
|
#include "uisettings.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
|
@ -77,6 +77,7 @@ public:
|
||||||
COLUMN_FILE_TYPE,
|
COLUMN_FILE_TYPE,
|
||||||
COLUMN_SIZE,
|
COLUMN_SIZE,
|
||||||
COLUMN_PLAY_TIME,
|
COLUMN_PLAY_TIME,
|
||||||
|
COLUMN_TOTAL_TIMES,
|
||||||
COLUMN_COUNT, // Number of columns
|
COLUMN_COUNT, // Number of columns
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -247,6 +247,31 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GameListItem for Play Time values.
|
||||||
|
* This object stores the play time of a game in seconds, and its readable
|
||||||
|
* representation in minutes/hours
|
||||||
|
*/
|
||||||
|
class GameListItemTotalTimes : public GameListItem {
|
||||||
|
public:
|
||||||
|
static constexpr int TotalTimesRole = SortRole;
|
||||||
|
|
||||||
|
GameListItemTotalTimes() = default;
|
||||||
|
explicit GameListItemTotalTimes(const qulonglong times_count) {
|
||||||
|
setData(times_count, TotalTimesRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setData(const QVariant& value, int role) override {
|
||||||
|
qulonglong times_count = value.toULongLong();
|
||||||
|
GameListItem::setData(PlayTime::ReadableTotalTimes(times_count), Qt::DisplayRole);
|
||||||
|
GameListItem::setData(value, TotalTimesRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const QStandardItem& other) const override {
|
||||||
|
return data(TotalTimesRole).toULongLong() < other.data(TotalTimesRole).toULongLong();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class GameListDir : public GameListItem {
|
class GameListDir : public GameListItem {
|
||||||
public:
|
public:
|
||||||
static constexpr int GameDirRole = Qt::UserRole + 2;
|
static constexpr int GameDirRole = Qt::UserRole + 2;
|
||||||
|
|
|
@ -215,7 +215,7 @@ QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::stri
|
||||||
new GameListItem(file_type_string),
|
new GameListItem(file_type_string),
|
||||||
new GameListItemSize(size),
|
new GameListItemSize(size),
|
||||||
new GameListItemPlayTime(play_time_manager.GetPlayTime(program_id)),
|
new GameListItemPlayTime(play_time_manager.GetPlayTime(program_id)),
|
||||||
};
|
new GameListItemTotalTimes(play_time_manager.GetTotalTimes(program_id))};
|
||||||
|
|
||||||
const auto patch_versions = GetGameListCachedObject(
|
const auto patch_versions = GetGameListCachedObject(
|
||||||
fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] {
|
fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] {
|
||||||
|
|
|
@ -18,6 +18,7 @@ void PlayTimeManager::SetProgramId(u64 program_id) {
|
||||||
|
|
||||||
inline void PlayTimeManager::UpdateTimestamp() {
|
inline void PlayTimeManager::UpdateTimestamp() {
|
||||||
this->last_timestamp = std::chrono::steady_clock::now();
|
this->last_timestamp = std::chrono::steady_clock::now();
|
||||||
|
this->last_total_times = GetTotalTimes(this->running_program_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayTimeManager::Start() {
|
void PlayTimeManager::Start() {
|
||||||
|
@ -50,12 +51,12 @@ void PlayTimeManager::Save() {
|
||||||
std::chrono::steady_clock::duration(now - this->last_timestamp))
|
std::chrono::steady_clock::duration(now - this->last_timestamp))
|
||||||
.count());
|
.count());
|
||||||
UpdateTimestamp();
|
UpdateTimestamp();
|
||||||
if (!UpdatePlayTime(running_program_id, duration)) {
|
if (!UpdatePlayTime(running_program_id, duration, 1)) {
|
||||||
LOG_ERROR(Common, "Failed to update play time");
|
LOG_ERROR(Common, "Failed to update play time");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UpdatePlayTime(u64 program_id, u64 add_play_time) {
|
bool UpdatePlayTime(u64 program_id, u64 add_play_time, u64 add_total_times) {
|
||||||
std::vector<PlayTimeElement> play_time_elements;
|
std::vector<PlayTimeElement> play_time_elements;
|
||||||
if (!ReadPlayTimeFile(play_time_elements)) {
|
if (!ReadPlayTimeFile(play_time_elements)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -63,9 +64,11 @@ bool UpdatePlayTime(u64 program_id, u64 add_play_time) {
|
||||||
const auto it = std::find(play_time_elements.begin(), play_time_elements.end(), program_id);
|
const auto it = std::find(play_time_elements.begin(), play_time_elements.end(), program_id);
|
||||||
|
|
||||||
if (it == play_time_elements.end()) {
|
if (it == play_time_elements.end()) {
|
||||||
play_time_elements.push_back({.program_id = program_id, .play_time = add_play_time});
|
play_time_elements.push_back(
|
||||||
|
{.program_id = program_id, .play_time = add_play_time, .total_times = add_total_times});
|
||||||
} else {
|
} else {
|
||||||
play_time_elements.at(it - play_time_elements.begin()).play_time += add_play_time;
|
play_time_elements.at(it - play_time_elements.begin()).play_time += add_play_time;
|
||||||
|
play_time_elements.at(it - play_time_elements.begin()).total_times += add_total_times;
|
||||||
}
|
}
|
||||||
if (!WritePlayTimeFile(play_time_elements)) {
|
if (!WritePlayTimeFile(play_time_elements)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -86,6 +89,19 @@ u64 GetPlayTime(u64 program_id) {
|
||||||
return play_time_elements.at(it - play_time_elements.begin()).play_time;
|
return play_time_elements.at(it - play_time_elements.begin()).play_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 GetTotalTimes(u64 program_id) {
|
||||||
|
std::vector<PlayTimeElement> play_time_elements;
|
||||||
|
|
||||||
|
if (!ReadPlayTimeFile(play_time_elements)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const auto it = std::find(play_time_elements.begin(), play_time_elements.end(), program_id);
|
||||||
|
if (it == play_time_elements.end()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return play_time_elements.at(it - play_time_elements.begin()).total_times;
|
||||||
|
}
|
||||||
|
|
||||||
bool PlayTimeManager::ResetProgramPlayTime(u64 program_id) {
|
bool PlayTimeManager::ResetProgramPlayTime(u64 program_id) {
|
||||||
std::vector<PlayTimeElement> play_time_elements;
|
std::vector<PlayTimeElement> play_time_elements;
|
||||||
|
|
||||||
|
@ -174,4 +190,8 @@ QString ReadablePlayTime(qulonglong time_seconds) {
|
||||||
.arg(QString::fromUtf8(units[unit]));
|
.arg(QString::fromUtf8(units[unit]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ReadableTotalTimes(qulonglong times_count) {
|
||||||
|
return QStringLiteral("%L1").arg((double)times_count, 0, 'f', 0);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace PlayTime
|
} // namespace PlayTime
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace PlayTime {
|
||||||
struct PlayTimeElement {
|
struct PlayTimeElement {
|
||||||
u64 program_id;
|
u64 program_id;
|
||||||
u64 play_time;
|
u64 play_time;
|
||||||
|
u64 total_times;
|
||||||
|
|
||||||
inline bool operator==(const PlayTimeElement& other) const {
|
inline bool operator==(const PlayTimeElement& other) const {
|
||||||
return program_id == other.program_id;
|
return program_id == other.program_id;
|
||||||
|
@ -49,6 +50,7 @@ public:
|
||||||
private:
|
private:
|
||||||
u64 running_program_id;
|
u64 running_program_id;
|
||||||
std::chrono::steady_clock::time_point last_timestamp;
|
std::chrono::steady_clock::time_point last_timestamp;
|
||||||
|
u64 last_total_times;
|
||||||
std::jthread play_time_thread;
|
std::jthread play_time_thread;
|
||||||
void AutoTimestamp(std::stop_token stop_token);
|
void AutoTimestamp(std::stop_token stop_token);
|
||||||
void Save();
|
void Save();
|
||||||
|
@ -56,13 +58,15 @@ private:
|
||||||
|
|
||||||
std::optional<std::filesystem::path> GetCurrentUserPlayTimePath();
|
std::optional<std::filesystem::path> GetCurrentUserPlayTimePath();
|
||||||
|
|
||||||
bool UpdatePlayTime(u64 program_id, u64 add_play_time);
|
bool UpdatePlayTime(u64 program_id, u64 add_play_time, u64 add_total_times);
|
||||||
|
|
||||||
[[nodiscard]] bool ReadPlayTimeFile(std::vector<PlayTimeElement>& out_play_time_elements);
|
[[nodiscard]] bool ReadPlayTimeFile(std::vector<PlayTimeElement>& out_play_time_elements);
|
||||||
[[nodiscard]] bool WritePlayTimeFile(const std::vector<PlayTimeElement>& play_time_elements);
|
[[nodiscard]] bool WritePlayTimeFile(const std::vector<PlayTimeElement>& play_time_elements);
|
||||||
|
|
||||||
u64 GetPlayTime(u64 program_id);
|
u64 GetPlayTime(u64 program_id);
|
||||||
|
u64 GetTotalTimes(u64 program_id);
|
||||||
|
|
||||||
QString ReadablePlayTime(qulonglong time_seconds);
|
QString ReadablePlayTime(qulonglong time_seconds);
|
||||||
|
QString ReadableTotalTimes(qulonglong times_count);
|
||||||
|
|
||||||
} // namespace PlayTime
|
} // namespace PlayTime
|
||||||
|
|
|
@ -18,6 +18,7 @@ namespace {
|
||||||
struct PlayTimeElement {
|
struct PlayTimeElement {
|
||||||
ProgramId program_id;
|
ProgramId program_id;
|
||||||
PlayTime play_time;
|
PlayTime play_time;
|
||||||
|
TotalTimes total_times;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<std::filesystem::path> GetCurrentUserPlayTimePath(
|
std::optional<std::filesystem::path> GetCurrentUserPlayTimePath(
|
||||||
|
@ -57,9 +58,9 @@ std::optional<std::filesystem::path> GetCurrentUserPlayTimePath(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& [program_id, play_time] : elements) {
|
for (const auto& [program_id, play_time, total_times] : elements) {
|
||||||
if (program_id != 0) {
|
if (program_id != 0) {
|
||||||
out_play_time_db[program_id] = play_time;
|
out_play_time_db[program_id] = {play_time, total_times};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,7 +90,7 @@ std::optional<std::filesystem::path> GetCurrentUserPlayTimePath(
|
||||||
|
|
||||||
for (auto& [program_id, play_time] : play_time_db) {
|
for (auto& [program_id, play_time] : play_time_db) {
|
||||||
if (program_id != 0) {
|
if (program_id != 0) {
|
||||||
elements.push_back(PlayTimeElement{program_id, play_time});
|
elements.push_back(PlayTimeElement{program_id, play_time.first, play_time.second});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +140,8 @@ void PlayTimeManager::AutoTimestamp(std::stop_token stop_token) {
|
||||||
while (!stop_token.stop_requested()) {
|
while (!stop_token.stop_requested()) {
|
||||||
Common::StoppableTimedWait(stop_token, 30s);
|
Common::StoppableTimedWait(stop_token, 30s);
|
||||||
|
|
||||||
database[running_program_id] += GetDuration();
|
database[running_program_id].first += GetDuration();
|
||||||
|
database[running_program_id].second += 1;
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,7 +155,16 @@ void PlayTimeManager::Save() {
|
||||||
u64 PlayTimeManager::GetPlayTime(u64 program_id) const {
|
u64 PlayTimeManager::GetPlayTime(u64 program_id) const {
|
||||||
auto it = database.find(program_id);
|
auto it = database.find(program_id);
|
||||||
if (it != database.end()) {
|
if (it != database.end()) {
|
||||||
return it->second;
|
return it->second.first;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 PlayTimeManager::GetTotalTimes(u64 program_id) const {
|
||||||
|
auto it = database.find(program_id);
|
||||||
|
if (it != database.end()) {
|
||||||
|
return it->second.second;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -179,4 +190,12 @@ QString ReadablePlayTime(qulonglong time_seconds) {
|
||||||
.arg(QString::fromUtf8(unit));
|
.arg(QString::fromUtf8(unit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ReadableTotalTimes(qulonglong times_count) {
|
||||||
|
if (times_count == 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return QStringLiteral("%L1").arg((double)times_count, 0, 'f', 0);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace PlayTime
|
} // namespace PlayTime
|
||||||
|
|
|
@ -19,7 +19,8 @@ namespace PlayTime {
|
||||||
|
|
||||||
using ProgramId = u64;
|
using ProgramId = u64;
|
||||||
using PlayTime = u64;
|
using PlayTime = u64;
|
||||||
using PlayTimeDatabase = std::map<ProgramId, PlayTime>;
|
using TotalTimes = u64;
|
||||||
|
using PlayTimeDatabase = std::map<ProgramId, std::pair<PlayTime, TotalTimes>>;
|
||||||
|
|
||||||
class PlayTimeManager {
|
class PlayTimeManager {
|
||||||
public:
|
public:
|
||||||
|
@ -30,6 +31,7 @@ public:
|
||||||
SUDACHI_NON_MOVEABLE(PlayTimeManager);
|
SUDACHI_NON_MOVEABLE(PlayTimeManager);
|
||||||
|
|
||||||
u64 GetPlayTime(u64 program_id) const;
|
u64 GetPlayTime(u64 program_id) const;
|
||||||
|
u64 GetTotalTimes(u64 program_id) const;
|
||||||
void ResetProgramPlayTime(u64 program_id);
|
void ResetProgramPlayTime(u64 program_id);
|
||||||
void SetProgramId(u64 program_id);
|
void SetProgramId(u64 program_id);
|
||||||
void Start();
|
void Start();
|
||||||
|
@ -46,5 +48,6 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
QString ReadablePlayTime(qulonglong time_seconds);
|
QString ReadablePlayTime(qulonglong time_seconds);
|
||||||
|
QString ReadableTotalTimes(qulonglong times_count);
|
||||||
|
|
||||||
} // namespace PlayTime
|
} // namespace PlayTime
|
||||||
|
|
|
@ -212,6 +212,9 @@ struct Values {
|
||||||
// Play time
|
// Play time
|
||||||
Setting<bool> show_play_time{linkage, true, "show_play_time", Category::UiGameList};
|
Setting<bool> show_play_time{linkage, true, "show_play_time", Category::UiGameList};
|
||||||
|
|
||||||
|
// Total times
|
||||||
|
Setting<bool> show_total_times{linkage, true, "show_total_times", Category::UiGameList};
|
||||||
|
|
||||||
bool configuration_applied;
|
bool configuration_applied;
|
||||||
bool reset_to_defaults;
|
bool reset_to_defaults;
|
||||||
bool shortcut_already_warned{false};
|
bool shortcut_already_warned{false};
|
||||||
|
|
Loading…
Reference in New Issue