Browse Source
[core, android] Initial playtime implementation (#2535)
[core, android] Initial playtime implementation (#2535)
So firstly, playtime code is moved to src/common and qt specific code to yuzu/utils.cpp. The dependency on ProfileManager was removed because it was working properly on Android, and I think a shared playtime is better behavior. Now, playtime is stored in a file called "playtime.bin". JNI code is from Azahar although modified by me, as well as that I added code to reset the game's playtime which was missing for some reason on there. Before this gets merged, I plan to add the ability to manually edit the database as well. Note: Code still needs a bit of cleanup. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2535 Reviewed-by: CamilleLaVey <camillelavey99@gmail.com> Reviewed-by: Lizzie <lizzie@eden-emu.dev> Reviewed-by: crueter <crueter@eden-emu.dev> Reviewed-by: MaranBr <maranbr@eden-emu.dev> Co-authored-by: inix <Nixy01@proton.me> Co-committed-by: inix <Nixy01@proton.me>pull/2761/head
committed by
crueter
No known key found for this signature in database
GPG Key ID: 425ACD2D4830EBC6
23 changed files with 587 additions and 46 deletions
-
11src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
-
1src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt
-
8src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
-
2src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
-
135src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt
-
54src/android/app/src/main/jni/native.cpp
-
10src/android/app/src/main/res/layout-w600dp/fragment_game_properties.xml
-
59src/android/app/src/main/res/layout/dialog_edit_playtime.xml
-
12src/android/app/src/main/res/layout/fragment_game_properties.xml
-
12src/android/app/src/main/res/values/strings.xml
-
2src/frontend_common/CMakeLists.txt
-
75src/frontend_common/play_time_manager.cpp
-
12src/frontend_common/play_time_manager.h
-
4src/yuzu/CMakeLists.txt
-
6src/yuzu/game_list.cpp
-
3src/yuzu/game_list.h
-
4src/yuzu/game_list_p.h
-
2src/yuzu/game_list_worker.h
-
21src/yuzu/main.cpp
-
1src/yuzu/main.h
-
49src/yuzu/set_play_time_dialog.cpp
-
27src/yuzu/set_play_time_dialog.h
-
123src/yuzu/set_play_time_dialog.ui
@ -0,0 +1,59 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:orientation="horizontal" |
|||
android:padding="16dp"> |
|||
|
|||
<com.google.android.material.textfield.TextInputLayout |
|||
android:id="@+id/layout_hours" |
|||
android:layout_width="0dp" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="1" |
|||
android:layout_marginEnd="8dp" |
|||
android:hint="@string/hours" |
|||
app:boxBackgroundMode="outline"> |
|||
|
|||
<com.google.android.material.textfield.TextInputEditText |
|||
android:id="@+id/input_hours" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:inputType="number" |
|||
android:maxLength="4" /> |
|||
</com.google.android.material.textfield.TextInputLayout> |
|||
|
|||
<com.google.android.material.textfield.TextInputLayout |
|||
android:id="@+id/layout_minutes" |
|||
android:layout_width="0dp" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="1" |
|||
android:layout_marginEnd="8dp" |
|||
android:hint="@string/minutes" |
|||
app:boxBackgroundMode="outline"> |
|||
|
|||
<com.google.android.material.textfield.TextInputEditText |
|||
android:id="@+id/input_minutes" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:inputType="number" |
|||
android:maxLength="2" /> |
|||
</com.google.android.material.textfield.TextInputLayout> |
|||
|
|||
<com.google.android.material.textfield.TextInputLayout |
|||
android:id="@+id/layout_seconds" |
|||
android:layout_width="0dp" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="1" |
|||
android:hint="@string/seconds" |
|||
app:boxBackgroundMode="outline"> |
|||
|
|||
<com.google.android.material.textfield.TextInputEditText |
|||
android:id="@+id/input_seconds" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:inputType="number" |
|||
android:maxLength="2" /> |
|||
</com.google.android.material.textfield.TextInputLayout> |
|||
|
|||
</LinearLayout> |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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; |
|||
}; |
|||
@ -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> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue