summaryrefslogtreecommitdiff
path: root/Source/Android
diff options
context:
space:
mode:
authorTilka <tilkax@gmail.com>2025-04-25 01:43:53 +0100
committerGitHub <noreply@github.com>2025-04-25 01:43:53 +0100
commita95779add09bf24002ba9e5d0d5987d2c6945e47 (patch)
tree7ce613c858dd5d1f0a492019b7e99c427c87fe59 /Source/Android
parent5523b9a01b5e2628b3b22a5b97cb78aac0cd83f6 (diff)
parentb8e70df413ddd4663aa8e65a6f9d8a1e059c64c7 (diff)
Merge pull request #13506 from JosJuice/android-time-played
Android: Show time played in game details
Diffstat (limited to 'Source/Android')
-rw-r--r--Source/Android/app/build.gradle.kts2
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.kt31
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.kt7
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt8
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.kt11
-rw-r--r--Source/Android/app/src/main/res/layout/dialog_game_details.xml17
-rw-r--r--Source/Android/app/src/main/res/layout/dialog_game_details_tv.xml18
-rw-r--r--Source/Android/app/src/main/res/values/strings.xml3
-rw-r--r--Source/Android/jni/GameList/GameFile.cpp9
9 files changed, 100 insertions, 6 deletions
diff --git a/Source/Android/app/build.gradle.kts b/Source/Android/app/build.gradle.kts
index 0ed29fde4b..00db541705 100644
--- a/Source/Android/app/build.gradle.kts
+++ b/Source/Android/app/build.gradle.kts
@@ -153,6 +153,8 @@ dependencies {
// For loading custom GPU drivers
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
+
implementation("com.nononsenseapps:filepicker:4.2.1")
}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.kt
index 53b1467bbc..0384da89c0 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.kt
@@ -19,6 +19,7 @@ import kotlinx.coroutines.launch
import org.dolphinemu.dolphinemu.NativeLibrary
import org.dolphinemu.dolphinemu.databinding.DialogGameDetailsBinding
import org.dolphinemu.dolphinemu.databinding.DialogGameDetailsTvBinding
+import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting
import org.dolphinemu.dolphinemu.model.GameFile
class GameDetailsDialog : DialogFragment() {
@@ -35,6 +36,21 @@ class GameDetailsDialog : DialogFragment() {
if (requireActivity() is AppCompatActivity) {
binding = DialogGameDetailsBinding.inflate(layoutInflater)
binding.apply {
+ if (BooleanSetting.MAIN_TIME_TRACKING.boolean) {
+ lifecycleScope.launch {
+ val totalMs = gameFile.getTimePlayedMs()
+ val totalMinutes = totalMs / 60000
+ val totalHours = totalMinutes / 60
+ textTimePlayed.text = resources.getString(
+ R.string.game_details_time_played,
+ totalHours,
+ totalMinutes % 60
+ )
+ }
+ } else {
+ textTimePlayed.visibility = View.GONE
+ }
+
textGameTitle.text = gameFile.getTitle()
textDescription.text = gameFile.getDescription()
if (gameFile.getDescription().isEmpty()) {
@@ -87,6 +103,21 @@ class GameDetailsDialog : DialogFragment() {
} else {
tvBinding = DialogGameDetailsTvBinding.inflate(layoutInflater)
tvBinding.apply {
+ if (BooleanSetting.MAIN_TIME_TRACKING.boolean) {
+ lifecycleScope.launch {
+ val totalMs = gameFile.getTimePlayedMs()
+ val totalMinutes = totalMs / 60000
+ val totalHours = totalMinutes / 60
+ textTimePlayed.text = resources.getString(
+ R.string.game_details_time_played,
+ totalHours,
+ totalMinutes % 60
+ )
+ }
+ } else {
+ textTimePlayed.visibility = View.GONE
+ }
+
textGameTitle.text = gameFile.getTitle()
textDescription.text = gameFile.getDescription()
if (gameFile.getDescription().isEmpty()) {
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.kt
index 16ee12e307..afe48b86d7 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/BooleanSetting.kt
@@ -132,6 +132,12 @@ enum class BooleanSetting(
),
MAIN_WII_WIILINK_ENABLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "EnableWiiLink", false),
MAIN_DSP_JIT(Settings.FILE_DOLPHIN, Settings.SECTION_INI_DSP, "EnableJIT", true),
+ MAIN_TIME_TRACKING(
+ Settings.FILE_DOLPHIN,
+ Settings.SECTION_INI_GENERAL,
+ "EnablePlayTimeTracking",
+ true
+ ),
MAIN_EXPAND_TO_CUTOUT_AREA(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_INTERFACE,
@@ -916,6 +922,7 @@ enum class BooleanSetting(
MAIN_RAM_OVERRIDE_ENABLE,
MAIN_CUSTOM_RTC_ENABLE,
MAIN_DSP_JIT,
+ MAIN_TIME_TRACKING,
MAIN_EMULATE_SKYLANDER_PORTAL,
MAIN_EMULATE_INFINITY_BASE
)
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt
index ff82f4c63c..e0aa32e15c 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.kt
@@ -344,6 +344,14 @@ class SettingsFragmentPresenter(
R.string.osd_messages_description
)
)
+ sl.add(
+ SwitchSetting(
+ context,
+ BooleanSetting.MAIN_TIME_TRACKING,
+ R.string.time_tracking,
+ R.string.time_tracking_description
+ )
+ )
val appTheme: AbstractIntSetting = object : AbstractIntSetting {
override val isOverridden: Boolean
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.kt
index 347433f552..26da174285 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.kt
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.kt
@@ -3,6 +3,8 @@
package org.dolphinemu.dolphinemu.model
import androidx.annotation.Keep
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
@Keep
class GameFile private constructor(private val pointer: Long) {
@@ -54,6 +56,15 @@ class GameFile private constructor(private val pointer: Long) {
external fun getBannerHeight(): Int
+ suspend fun getTimePlayedMs(): Long {
+ // getTimePlayedMsInternal reads from disk, so let's use coroutines.
+ return withContext(Dispatchers.IO) {
+ getTimePlayedMsInternal()
+ }
+ }
+
+ external private fun getTimePlayedMsInternal(): Long
+
val customCoverPath: String
get() = "${getPath().substring(0, getPath().lastIndexOf("."))}.cover.png"
diff --git a/Source/Android/app/src/main/res/layout/dialog_game_details.xml b/Source/Android/app/src/main/res/layout/dialog_game_details.xml
index 57a8530134..79825825f3 100644
--- a/Source/Android/app/src/main/res/layout/dialog_game_details.xml
+++ b/Source/Android/app/src/main/res/layout/dialog_game_details.xml
@@ -42,12 +42,23 @@
android:id="@+id/banner"
android:layout_width="144dp"
android:layout_height="48dp"
- android:layout_marginTop="20dp"
- android:layout_marginBottom="16dp"
+ android:layout_marginTop="16dp"
tools:src="@drawable/no_banner"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_description" />
+ <TextView
+ android:id="@+id/text_time_played"
+ style="@android:style/TextAppearance.Material.Caption"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:textAlignment="viewStart"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/banner"
+ tools:text="Played for 1h 23m" />
+
<com.google.android.material.divider.MaterialDivider
android:id="@+id/divider_1"
android:layout_width="0dp"
@@ -55,7 +66,7 @@
android:layout_marginTop="24dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@id/banner" />
+ app:layout_constraintTop_toBottomOf="@id/text_time_played" />
<TextView
android:id="@+id/label_country"
diff --git a/Source/Android/app/src/main/res/layout/dialog_game_details_tv.xml b/Source/Android/app/src/main/res/layout/dialog_game_details_tv.xml
index 7146565357..82b03c4a30 100644
--- a/Source/Android/app/src/main/res/layout/dialog_game_details_tv.xml
+++ b/Source/Android/app/src/main/res/layout/dialog_game_details_tv.xml
@@ -44,12 +44,24 @@
android:id="@+id/banner"
android:layout_width="144dp"
android:layout_height="48dp"
- android:layout_marginTop="20dp"
- android:layout_marginBottom="16dp"
+ android:layout_marginTop="16dp"
tools:src="@drawable/no_banner"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_description" />
+ <TextView
+ android:id="@+id/text_time_played"
+ style="@android:style/TextAppearance.Material.Caption"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:textColor="@color/dolphin_onSurface"
+ android:textAlignment="viewStart"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/banner"
+ tools:text="Played for 1h 23m" />
+
<View
android:id="@+id/divider_1"
android:layout_width="0dp"
@@ -58,7 +70,7 @@
android:background="@color/dolphin_onSurfaceVariant"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@id/banner" />
+ app:layout_constraintTop_toBottomOf="@id/text_time_played" />
<TextView
android:id="@+id/label_country"
diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml
index 1b08fc6475..22cd5c4a34 100644
--- a/Source/Android/app/src/main/res/values/strings.xml
+++ b/Source/Android/app/src/main/res/values/strings.xml
@@ -153,6 +153,8 @@
<string name="panic_handlers_description">Show a message box when a potentially serious error has occurred. Disabling this may avoid annoying and non-fatal messages, but it may result in major crashes having no explanation at all.</string>
<string name="osd_messages">Show On-Screen Display Messages</string>
<string name="osd_messages_description">Display messages over the emulation screen area. These messages include memory card writes, video backend and CPU information, and JIT cache clearing.</string>
+ <string name="time_tracking">Enable Play Time Tracking</string>
+ <string name="time_tracking_description">Tracks the time you spend playing games and shows it in the game details.</string>
<string name="download_game_covers">Download Game Covers from GameTDB.com</string>
<string name="show_titles_in_game_list">Show Titles</string>
<string name="change_theme">Change App Theme</string>
@@ -517,6 +519,7 @@
<string name="game_ini_junk_question">The settings file for this game contains extraneous data added by an old version of Dolphin. This will likely prevent global settings from working as intended.\n\nWould you like to fix this by deleting the settings file for this game? All game-specific settings and cheats that you have added will be removed. This cannot be undone.</string>
<!-- Game Details Screen -->
+ <string name="game_details_time_played">Played for %1$dh %2$dm</string>
<string name="game_details_country">Country</string>
<string name="game_details_company">Company</string>
<string name="game_details_game_id">Game ID</string>
diff --git a/Source/Android/jni/GameList/GameFile.cpp b/Source/Android/jni/GameList/GameFile.cpp
index 3bf60beb28..dc922d701c 100644
--- a/Source/Android/jni/GameList/GameFile.cpp
+++ b/Source/Android/jni/GameList/GameFile.cpp
@@ -3,12 +3,14 @@
#include "jni/GameList/GameFile.h"
+#include <chrono>
#include <memory>
#include <utility>
#include <vector>
#include <jni.h>
+#include "Core/TimePlayed.h"
#include "DiscIO/Blob.h"
#include "DiscIO/Enums.h"
#include "UICommon/GameFile.h"
@@ -190,6 +192,13 @@ JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getBannerHe
return static_cast<jint>(GetRef(env, obj)->GetBannerImage().height);
}
+JNIEXPORT jlong JNICALL
+Java_org_dolphinemu_dolphinemu_model_GameFile_getTimePlayedMsInternal(JNIEnv* env, jobject obj)
+{
+ const std::chrono::milliseconds time = TimePlayed().GetTimePlayed(GetRef(env, obj)->GetGameID());
+ return time.count();
+}
+
JNIEXPORT jobject JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_parse(JNIEnv* env, jclass,
jstring path)
{