diff options
| author | JosJuice <josjuice@gmail.com> | 2025-04-12 14:27:09 +0200 |
|---|---|---|
| committer | JosJuice <josjuice@gmail.com> | 2025-04-19 14:34:49 +0200 |
| commit | b8e70df413ddd4663aa8e65a6f9d8a1e059c64c7 (patch) | |
| tree | b537d6552b2383bed599fad32f46efe8d7156122 /Source/Android | |
| parent | 3eee52cb6bbebfc6b44b43aa85cd22b17b27aca5 (diff) | |
Android: Show time played in game details
Unlike in DolphinQt, there isn't much space to show playtimes directly in
the game list, so I've put it in the game details dialog instead.
Diffstat (limited to 'Source/Android')
7 files changed, 83 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/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 aa0266968f..22cd5c4a34 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -519,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) { |
