[core, android] Initial playtime implementation #2535
4 changed files with 205 additions and 70 deletions
|
@ -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
|
||||
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
crueter
commented
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
crueter
commented
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,
|
||||
|
|
49
src/yuzu/set_play_time_dialog.cpp
Normal file
49
src/yuzu/set_play_time_dialog.cpp
Normal 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);
|
||||
}
|
||||
}
|
27
src/yuzu/set_play_time_dialog.h
Normal file
27
src/yuzu/set_play_time_dialog.h
Normal 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;
|
||||
};
|
123
src/yuzu/set_play_time_dialog.ui
Normal file
123
src/yuzu/set_play_time_dialog.ui
Normal 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>
|
Loading…
Add table
Add a link
Reference in a new issue
We can probably make this a .ui file