From bb1e3a0692e960afbb0ab6592a60985ce1d4e018 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sat, 28 Nov 2020 00:11:20 +1000 Subject: [PATCH] Android: Display covers in game list --- .../app/src/cpp/android_host_interface.cpp | 6 ++-- .../stenzek/duckstation/GameListEntry.java | 15 ++++++--- .../stenzek/duckstation/ImageLoadTask.java | 32 +++++++++++++++++++ .../main/res/layout/game_list_view_entry.xml | 2 +- 4 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 android/app/src/main/java/com/github/stenzek/duckstation/ImageLoadTask.java diff --git a/android/app/src/cpp/android_host_interface.cpp b/android/app/src/cpp/android_host_interface.cpp index adb3c8393..61f9b3682 100644 --- a/android/app/src/cpp/android_host_interface.cpp +++ b/android/app/src/cpp/android_host_interface.cpp @@ -930,7 +930,7 @@ DEFINE_JNI_ARGS_METHOD(jarray, AndroidHostInterface_getGameListEntries, jobject jmethodID entry_constructor = env->GetMethodID(entry_class, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JLjava/lang/" - "String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + "String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); Assert(entry_constructor != nullptr); AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj); @@ -943,6 +943,7 @@ DEFINE_JNI_ARGS_METHOD(jarray, AndroidHostInterface_getGameListEntries, jobject const Timestamp modified_ts( Timestamp::FromUnixTimestamp(static_cast(entry.last_modified_time))); const std::string file_title_str(System::GetTitleForPath(entry.path.c_str())); + const std::string cover_path_str(hi->GetGameList()->GetCoverImagePathForEntry(&entry)); jstring path = env->NewStringUTF(entry.path.c_str()); jstring code = env->NewStringUTF(entry.code.c_str()); @@ -952,11 +953,12 @@ DEFINE_JNI_ARGS_METHOD(jarray, AndroidHostInterface_getGameListEntries, jobject jstring type = env->NewStringUTF(GameList::EntryTypeToString(entry.type)); jstring compatibility_rating = env->NewStringUTF(GameList::EntryCompatibilityRatingToString(entry.compatibility_rating)); + jstring cover_path = (cover_path_str.empty()) ? nullptr : env->NewStringUTF(cover_path_str.c_str()); jstring modified_time = env->NewStringUTF(modified_ts.ToString("%Y/%m/%d, %H:%M:%S")); jlong size = entry.total_size; jobject entry_jobject = env->NewObject(entry_class, entry_constructor, path, code, title, file_title, size, - modified_time, region, type, compatibility_rating); + modified_time, region, type, compatibility_rating, cover_path); env->SetObjectArrayElement(entry_array, counter++, entry_jobject); } diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/GameListEntry.java b/android/app/src/main/java/com/github/stenzek/duckstation/GameListEntry.java index f1e1e77ff..7f78e369c 100644 --- a/android/app/src/main/java/com/github/stenzek/duckstation/GameListEntry.java +++ b/android/app/src/main/java/com/github/stenzek/duckstation/GameListEntry.java @@ -1,5 +1,7 @@ package com.github.stenzek.duckstation; +import android.net.Uri; +import android.os.AsyncTask; import android.view.View; import android.widget.ImageView; import android.widget.TextView; @@ -31,16 +33,17 @@ public class GameListEntry { private DiscRegion mRegion; private EntryType mType; private CompatibilityRating mCompatibilityRating; - + private String mCoverPath; public GameListEntry(String path, String code, String title, String fileTitle, long size, String modifiedTime, String region, - String type, String compatibilityRating) { + String type, String compatibilityRating, String coverPath) { mPath = path; mCode = code; mTitle = title; mFileTitle = fileTitle; mSize = size; mModifiedTime = modifiedTime; + mCoverPath = coverPath; try { mRegion = DiscRegion.valueOf(region); @@ -144,8 +147,12 @@ public class GameListEntry { break; } - ((ImageView) view.findViewById(R.id.game_list_view_entry_type_icon)) - .setImageDrawable(ContextCompat.getDrawable(view.getContext(), typeDrawableId)); + ImageView icon = ((ImageView) view.findViewById(R.id.game_list_view_entry_type_icon)); + icon.setImageDrawable(ContextCompat.getDrawable(view.getContext(), typeDrawableId)); + + if (mCoverPath != null) { + new ImageLoadTask(icon).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mCoverPath); + } int compatibilityDrawableId; switch (mCompatibilityRating) diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/ImageLoadTask.java b/android/app/src/main/java/com/github/stenzek/duckstation/ImageLoadTask.java new file mode 100644 index 000000000..447a4c87c --- /dev/null +++ b/android/app/src/main/java/com/github/stenzek/duckstation/ImageLoadTask.java @@ -0,0 +1,32 @@ +package com.github.stenzek.duckstation; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.widget.ImageView; + +import java.lang.ref.WeakReference; + +public class ImageLoadTask extends AsyncTask { + private WeakReference mView; + + public ImageLoadTask(ImageView view) { + mView = new WeakReference<>(view); + } + + @Override + protected Bitmap doInBackground(String... strings) { + try { + return BitmapFactory.decodeFile(strings[0]); + } catch (Exception e) { + return null; + } + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + ImageView iv = mView.get(); + if (iv != null) + iv.setImageBitmap(bitmap); + } +} diff --git a/android/app/src/main/res/layout/game_list_view_entry.xml b/android/app/src/main/res/layout/game_list_view_entry.xml index 0dc1ac201..4753f5f75 100644 --- a/android/app/src/main/res/layout/game_list_view_entry.xml +++ b/android/app/src/main/res/layout/game_list_view_entry.xml @@ -63,7 +63,7 @@ android:id="@+id/game_list_view_entry_region_icon" android:layout_width="32dp" android:layout_height="28dp" - android:layout_marginTop="8dp" + android:layout_marginTop="4dp" android:layout_marginEnd="24dp" android:focusable="false" android:focusableInTouchMode="false"