[core, android] Initial playtime implementation #2535

Open
inix wants to merge 10 commits from inix/eden:playtime-android into master
4 changed files with 205 additions and 70 deletions
Showing only changes of commit 0636f93e16 - Show all commits

View file

@ -15,6 +15,8 @@
#include <memory>
#include <thread>
#include "set_play_time_dialog.h"
#ifdef __APPLE__
#include <unistd.h> // 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);
crueter marked this conversation as resolved

We can probably make this a .ui file

We can probably make this a .ui file
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<u64>(hours) * 3600 + static_cast<u64>(minutes) * 60 + static_cast<u64>(seconds);
if (dialog.exec() == QDialog::Accepted) {
const u64 total_seconds = dialog.GetTotalSeconds();
play_time_manager->SetPlayTime(program_id, total_seconds);
crueter marked this conversation as resolved

These can be spin boxes

These can be spin boxes
game_list->PopulateAsync(UISettings::values.game_dirs);
dialog.accept();
});
connect(button_box, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
dialog.exec();
}
}
crueter marked this conversation as resolved

And if we do go with QSpinBox you can just set the range and this won't be necessary

And if we do go with QSpinBox you can just set the range and this won't be necessary
void GMainWindow::OnGameListRemovePlayTimeData(u64 program_id) {
if (QMessageBox::question(this, tr("Remove Play Time Data"), tr("Reset play time?"),
QMessageBox::Yes | QMessageBox::No,

View file

@ -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::SetPlayTimeDialog>()} {
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<int>::of(&QSpinBox::valueChanged), this,
&SetPlayTimeDialog::OnValueChanged);
connect(ui->minutesSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this,
&SetPlayTimeDialog::OnValueChanged);
connect(ui->secondsSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this,
&SetPlayTimeDialog::OnValueChanged);
}
SetPlayTimeDialog::~SetPlayTimeDialog() = default;
u64 SetPlayTimeDialog::GetTotalSeconds() const {
const u64 hours = static_cast<u64>(ui->hoursSpinBox->value());
const u64 minutes = static_cast<u64>(ui->minutesSpinBox->value());
const u64 seconds = static_cast<u64>(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);
}
}

View file

@ -0,0 +1,27 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QDialog>
#include <memory>
#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::SetPlayTimeDialog> ui;
};

View file

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SetPlayTimeDialog</class>
<widget class="QDialog" name="SetPlayTimeDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>150</height>
</rect>
</property>
<property name="windowTitle">
<string>Set Play Time Data</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="inputLayout">
<item>
<widget class="QLabel" name="labelHours">
<property name="text">
<string>Hours:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="hoursSpinBox">
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelMinutes">
<property name="text">
<string>Minutes:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="minutesSpinBox">
<property name="maximum">
<number>59</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelSeconds">
<property name="text">
<string>Seconds:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="secondsSpinBox">
<property name="maximum">
<number>59</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="errorLabel">
<property name="styleSheet">
<string notr="true">QLabel { color : red; }</string>
</property>
<property name="text">
<string/>
</property>
<property name="visible">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SetPlayTimeDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>199</x>
<y>129</y>
</hint>
<hint type="destinationlabel">
<x>199</x>
<y>74</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SetPlayTimeDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>199</x>
<y>129</y>
</hint>
<hint type="destinationlabel">
<x>199</x>
<y>74</y>
</hint>
</hints>
</connection>
</connections>
</ui>