diff --git a/Android/res/layout/gallery_item_adapter.xml b/Android/res/layout/gallery_item_adapter.xml index aa90bdb50..a55c20c86 100644 --- a/Android/res/layout/gallery_item_adapter.xml +++ b/Android/res/layout/gallery_item_adapter.xml @@ -11,7 +11,7 @@ Copyleft © 1998–2016 by Project64.\n Zilmar, Jabo, Smiff, Gent, Jahra!n, Witten, RadeonUser, Trotterwatch, pixi, Azimer, Gonetz, cxd4, AmbientMalice, LegendOfDragoon, Nekokabu, Lithium64, death-droid, LuigiBlood, dsx. + + Recently played + Games + Settings Settings diff --git a/Android/src/emu/project64/GalleryActivity.java b/Android/src/emu/project64/GalleryActivity.java index 8f26f9d4d..296980b2b 100644 --- a/Android/src/emu/project64/GalleryActivity.java +++ b/Android/src/emu/project64/GalleryActivity.java @@ -28,6 +28,7 @@ import emu.project64.inAppPurchase.Purchase; import emu.project64.jni.NativeExports; import emu.project64.jni.SettingsID; import emu.project64.jni.SystemEvent; +import emu.project64.jni.UISettingID; import emu.project64.settings.GameSettingsActivity; import emu.project64.settings.SettingsActivity; import emu.project64.util.Utility; @@ -83,6 +84,7 @@ public class GalleryActivity extends AppCompatActivity implements IabBroadcastLi // Misc. private static List mGalleryItems = new ArrayList(); + private static List mRecentItems = new ArrayList(); private static GalleryActivity mActiveGalleryActivity = null; // The IAB helper object @@ -256,7 +258,7 @@ public class GalleryActivity extends AppCompatActivity implements IabBroadcastLi Log.d("GalleryActivity", "Purchased save support " + (SaveSupportPurchase!= null ? "Yes" : "No")); if (SaveSupportPurchase != null) { - mHasSaveSupport = true; + mHasSaveSupport = true; } setWaitScreen(false); @@ -519,8 +521,8 @@ public class GalleryActivity extends AppCompatActivity implements IabBroadcastLi //Purchase save support try { - String payload = NativeExports.appVersion(); - mIabHelper.launchPurchaseFlow(finalActivity, SKU_SAVESUPPORT, RC_REQUEST, mPurchaseFinishedListener, payload); + String payload = NativeExports.appVersion(); + mIabHelper.launchPurchaseFlow(finalActivity, SKU_SAVESUPPORT, RC_REQUEST, mPurchaseFinishedListener, payload); } catch (IabAsyncInProgressException e) { @@ -634,21 +636,36 @@ public class GalleryActivity extends AppCompatActivity implements IabBroadcastLi // billing... super.onActivityResult(requestCode, resultCode, data); } - } void refreshGrid( ) { - mGridView.setAdapter( new GalleryItem.Adapter( this, mGalleryItems ) ); + List items; + items = new ArrayList(); + + if (mRecentItems.size() > 0) + { + items.add( new GalleryItem( this, getString( R.string.galleryRecentlyPlayed ) ) ); + items.addAll( mRecentItems ); + + items.add( new GalleryItem( this, getString( R.string.galleryLibrary ) ) ); + } + items.addAll( mGalleryItems ); + + mGridView.setAdapter( new GalleryItem.Adapter( this, items ) ); // Allow the headings to take up the entire width of the layout - //final List finalItems = mGalleryItems; + final List finalItems = items; GridLayoutManager layoutManager = new GridLayoutManager( this, galleryColumns ); layoutManager.setSpanSizeLookup( new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize( int position ) { + // Headings will take up every span (column) in the grid + if( finalItems.get( position ).isHeading ) + return galleryColumns; + // Games will fit in a single column return 1; } @@ -752,6 +769,27 @@ public class GalleryActivity extends AppCompatActivity implements IabBroadcastLi public static void RomListLoadDone() { + mRecentItems = new ArrayList(); + + Log.d("GalleryActivity","File_RecentGameFileCount = " + NativeExports.UISettingsLoadDword(UISettingID.File_RecentGameFileCount.getValue())); + + for (int i = 0, n = NativeExports.UISettingsLoadDword(UISettingID.File_RecentGameFileCount.getValue()); i < n; i++) + { + String RecentFile = NativeExports.UISettingsLoadStringIndex(UISettingID.File_RecentGameFileIndex.getValue(), i); + if (RecentFile.length() == 0) + { + break; + } + for (int z = 0; z < mGalleryItems.size(); z++) + { + if (RecentFile.equals(mGalleryItems.get(z).romFile.getAbsolutePath())) + { + mRecentItems.add(mGalleryItems.get(z)); + break; + } + } + } + if (mActiveGalleryActivity != null && mActiveGalleryActivity.mProgress != null) { Handler h = new Handler(Looper.getMainLooper()); diff --git a/Android/src/emu/project64/GalleryItem.java b/Android/src/emu/project64/GalleryItem.java index e900464b2..c2f85a942 100644 --- a/Android/src/emu/project64/GalleryItem.java +++ b/Android/src/emu/project64/GalleryItem.java @@ -35,6 +35,7 @@ public class GalleryItem public final File romFile; public final int textColor; public final Context context; + public final boolean isHeading; public GalleryItem( Context context, String goodName, String fileName, String romPath, int textColor ) { @@ -42,9 +43,20 @@ public class GalleryItem this.fileName = fileName; this.context = context; this.textColor = textColor; + this.isHeading = false; this.romFile = TextUtils.isEmpty( romPath ) ? null : new File( romPath ); } + public GalleryItem( Context context, String headingName ) + { + this.goodName = headingName; + this.fileName = null; + this.context = context; + this.isHeading = true; + this.romFile = null; + this.textColor = 0; + } + @Override public String toString() { @@ -139,7 +151,7 @@ public class GalleryItem @Override public int getItemViewType( int position ) { - return 0; + return mObjects.get( position ).isHeading ? 1 : 0; } public void onBindViewHolder( ViewHolder holder, int position ) @@ -158,14 +170,24 @@ public class GalleryItem LinearLayout linearLayout = (LinearLayout) view.findViewById( R.id.galleryItem ); GalleryActivity activity = (GalleryActivity) item.context; - view.setClickable( true ); - view.setLongClickable( true ); - linearLayout.setPadding( activity.galleryHalfSpacing, - activity.galleryHalfSpacing, activity.galleryHalfSpacing, - activity.galleryHalfSpacing ); - tv1.setPadding( 0, 0, 0, 0 ); - tv1.setTextSize( TypedValue.COMPLEX_UNIT_DIP, 13.0f ); - + if( item.isHeading ) + { + view.setClickable( false ); + view.setLongClickable( false ); + linearLayout.setPadding( 0, 0, 0, 0 ); + tv1.setPadding( 5, 10, 0, 0 ); + tv1.setTextSize( TypedValue.COMPLEX_UNIT_DIP, 18.0f ); + } + else + { + view.setClickable( true ); + view.setLongClickable( true ); + linearLayout.setPadding( activity.galleryHalfSpacing, + activity.galleryHalfSpacing, activity.galleryHalfSpacing, + activity.galleryHalfSpacing ); + tv1.setPadding( 0, 0, 0, 0 ); + tv1.setTextSize( TypedValue.COMPLEX_UNIT_DIP, 13.0f ); + } LinearLayout layout = (LinearLayout) view.findViewById( R.id.info ); layout.getLayoutParams().width = activity.galleryWidth; } diff --git a/Android/src/emu/project64/jni/NativeExports.java b/Android/src/emu/project64/jni/NativeExports.java index 12b4e0938..6fd7f89fd 100644 --- a/Android/src/emu/project64/jni/NativeExports.java +++ b/Android/src/emu/project64/jni/NativeExports.java @@ -47,4 +47,5 @@ public class NativeExports public static native boolean UISettingsLoadBool(int Type); public static native int UISettingsLoadDword(int Type); + public static native String UISettingsLoadStringIndex(int Type, int Index); } diff --git a/Android/src/emu/project64/jni/UISettingID.java b/Android/src/emu/project64/jni/UISettingID.java index 209ad6e5b..29b23d7fe 100644 --- a/Android/src/emu/project64/jni/UISettingID.java +++ b/Android/src/emu/project64/jni/UISettingID.java @@ -14,6 +14,10 @@ public enum UISettingID { Asserts_Version, Screen_Orientation, + + //Recent Game + File_RecentGameFileCount, + File_RecentGameFileIndex, ; private int value; diff --git a/Source/Android/Bridge/UISettings.cpp b/Source/Android/Bridge/UISettings.cpp index eccdbbbff..fc17ae098 100644 --- a/Source/Android/Bridge/UISettings.cpp +++ b/Source/Android/Bridge/UISettings.cpp @@ -10,12 +10,15 @@ ****************************************************************************/ #include #include +#include #include "UISettings.h" void RegisterUISettings(void) { g_Settings->AddHandler((SettingID)(FirstUISettings + Asserts_Version), new CSettingTypeApplication("", "Asserts Version", (uint32_t)0)); g_Settings->AddHandler((SettingID)(FirstUISettings + Screen_Orientation), new CSettingTypeApplication("", "Screen Orientation", (uint32_t)0)); + g_Settings->AddHandler((SettingID)(FirstUISettings + File_RecentGameFileCount), new CSettingTypeApplication("", "Remembered Rom Files", (uint32_t)10)); + g_Settings->AddHandler((SettingID)(FirstUISettings + File_RecentGameFileIndex), new CSettingTypeApplicationIndex("Recent File", "Recent Rom", Default_None)); } void UISettingsSaveBool(UISettingID Type, bool Value) @@ -39,4 +42,3 @@ uint32_t UISettingsLoadDword(UISettingID Type) { return g_Settings->LoadDword((SettingID)(FirstUISettings + Type)); } - diff --git a/Source/Android/Bridge/UISettings.h b/Source/Android/Bridge/UISettings.h index e5bb4d61a..4efc2c4bf 100644 --- a/Source/Android/Bridge/UISettings.h +++ b/Source/Android/Bridge/UISettings.h @@ -16,6 +16,10 @@ enum UISettingID { Asserts_Version, Screen_Orientation, + + //Recent Game + File_RecentGameFileCount, + File_RecentGameFileIndex, }; void RegisterUISettings(void); diff --git a/Source/Android/Bridge/jniBridge.cpp b/Source/Android/Bridge/jniBridge.cpp index 4cd360054..af1a30700 100644 --- a/Source/Android/Bridge/jniBridge.cpp +++ b/Source/Android/Bridge/jniBridge.cpp @@ -90,6 +90,68 @@ EXPORT jint CALL JNI_OnLoad(JavaVM* vm, void* reserved) return JNI_VERSION_1_4; } +std::string UISettingsLoadStringIndex(UISettingID Type, int32_t index) +{ + return g_Settings->LoadStringIndex((SettingID)(FirstUISettings + Type), index); +} + +void UISettingsSaveStringIndex(UISettingID Type, int32_t index, const std::string & Value) +{ + g_Settings->SaveStringIndex((SettingID)(FirstUISettings + Type), index, Value); +} + +void AddRecentRom(const char * ImagePath) +{ + if (ImagePath == NULL) { return; } + WriteTrace(TraceUserInterface, TraceDebug, "Start (ImagePath: %s)",ImagePath); + + //Get Information about the stored rom list + size_t MaxRememberedFiles = UISettingsLoadDword(File_RecentGameFileCount); + strlist RecentGames; + size_t i; + for (i = 0; i < MaxRememberedFiles; i++) + { + stdstr RecentGame = UISettingsLoadStringIndex(File_RecentGameFileIndex, i); + if (RecentGame.empty()) + { + break; + } + RecentGames.push_back(RecentGame); + } + + //See if the dir is already in the list if so then move it to the top of the list + strlist::iterator iter; + for (iter = RecentGames.begin(); iter != RecentGames.end(); iter++) + { + if (_stricmp(ImagePath, iter->c_str()) != 0) + { + continue; + } + RecentGames.erase(iter); + break; + } + RecentGames.push_front(ImagePath); + if (RecentGames.size() > MaxRememberedFiles) + { + RecentGames.pop_back(); + } + + for (i = 0, iter = RecentGames.begin(); iter != RecentGames.end(); iter++, i++) + { + UISettingsSaveStringIndex(File_RecentGameFileIndex, i, *iter); + } + WriteTrace(TraceUserInterface, TraceDebug, "Done"); +} + +void GameLoaded(void * /*NotUsed*/) +{ + stdstr FileLoc = g_Settings->LoadStringVal(Game_File); + if (FileLoc.length() > 0) + { + AddRecentRom(FileLoc.c_str()); + } +} + void GameCpuRunning(void * /*NotUsed*/) { WriteTrace(TraceUserInterface, TraceDebug, "Start"); @@ -169,6 +231,7 @@ EXPORT jboolean CALL Java_emu_project64_jni_NativeExports_appInit(JNIEnv* env, j RegisterUISettings(); g_Settings->RegisterChangeCB(GameRunning_CPU_Running, NULL, (CSettings::SettingChangedFunc)GameCpuRunning); + g_Settings->RegisterChangeCB(Game_File, NULL, (CSettings::SettingChangedFunc)GameLoaded); } else { @@ -348,6 +411,11 @@ EXPORT int CALL Java_emu_project64_jni_NativeExports_UISettingsLoadDword(JNIEnv* return UISettingsLoadDword((UISettingID)Type); } +EXPORT jstring CALL Java_emu_project64_jni_NativeExports_UISettingsLoadStringIndex(JNIEnv* env, jclass cls, jint Type, jint Index) +{ + return env->NewStringUTF(UISettingsLoadStringIndex((UISettingID)Type, Index).c_str()); +} + EXPORT void CALL Java_emu_project64_jni_NativeExports_StopEmulation(JNIEnv* env, jclass cls) { WriteTrace(TraceUserInterface, TraceDebug, "Start");