From fa2d06e7a4d503f8aeefbe81ca3f0b642b2d3869 Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Sat, 20 Jun 2015 19:37:36 -0400 Subject: [PATCH 1/3] Android: Switch all activities to AppCompat-based Material themes, and use Support Library version of Floating Action Button. --- Source/Android/app/build.gradle | 9 ++-- .../Android/app/src/main/AndroidManifest.xml | 2 +- .../activities/AddDirectoryActivity.java | 6 +-- .../activities/EmulationActivity.java | 5 +- .../activities/GameGridActivity.java | 8 ++-- .../activities/OverlayConfigActivity.java | 3 +- .../activities/SettingsActivity.java | 4 +- .../dolphinemu/dialogs/GameDetailsDialog.java | 4 +- .../main/res/drawable/oval_ripple_accent.xml | 8 ---- .../main/res/layout/activity_game_grid.xml | 10 ++-- .../main/res/layout/dialog_game_details.xml | 10 ++-- .../app/src/main/res/values/styles.xml | 48 +++++++++---------- 12 files changed, 58 insertions(+), 59 deletions(-) delete mode 100644 Source/Android/app/src/main/res/drawable/oval_ripple_accent.xml diff --git a/Source/Android/app/build.gradle b/Source/Android/app/build.gradle index 1fe1039f89..b936e0604d 100644 --- a/Source/Android/app/build.gradle +++ b/Source/Android/app/build.gradle @@ -75,11 +75,10 @@ android { } dependencies { - - compile 'com.android.support:support-v4:22.1.1' - compile 'com.android.support:support-v13:22.0.0' - compile 'com.android.support:cardview-v7:21.0.3' - compile 'com.android.support:recyclerview-v7:21.0.3' + compile 'com.android.support:support-v13:22.2.0' + compile 'com.android.support:cardview-v7:22.2.0' + compile 'com.android.support:recyclerview-v7:22.2.0' + compile 'com.android.support:design:22.2.0' // For showing the banner as a circle a-la Material Design Guidelines compile 'de.hdodenhof:circleimageview:1.2.2' diff --git a/Source/Android/app/src/main/AndroidManifest.xml b/Source/Android/app/src/main/AndroidManifest.xml index 7e57b6cb3f..ad63dcd0c2 100644 --- a/Source/Android/app/src/main/AndroidManifest.xml +++ b/Source/Android/app/src/main/AndroidManifest.xml @@ -54,7 +54,7 @@ + android:theme="@style/DolphinSettingsGamecube"/> diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java index 1cbc30e7e5..f9308fc80e 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java @@ -1,12 +1,12 @@ package org.dolphinemu.dolphinemu.activities; -import android.app.Activity; import android.content.AsyncQueryHandler; import android.content.ContentValues; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Environment; +import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.Menu; @@ -24,7 +24,7 @@ import org.dolphinemu.dolphinemu.model.GameProvider; * An Activity that shows a list of files and folders, allowing the user to tell the app which folder(s) * contains the user's games. */ -public class AddDirectoryActivity extends Activity implements FileAdapter.FileClickListener +public class AddDirectoryActivity extends AppCompatActivity implements FileAdapter.FileClickListener { public static final String KEY_CURRENT_PATH = BuildConfig.APPLICATION_ID + ".path"; @@ -97,8 +97,6 @@ public class AddDirectoryActivity extends Activity implements FileAdapter.FileCl /** * Add a directory to the library, and if successful, end the activity. - * - * @param path The target directory's path. */ @Override public void addDirectory() diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index 19d4a8b3aa..cb6b17c3d5 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -1,10 +1,13 @@ package org.dolphinemu.dolphinemu.activities; +import android.app.AlertDialog; +import android.content.DialogInterface; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.InputDevice; import android.view.KeyEvent; @@ -19,7 +22,7 @@ import org.dolphinemu.dolphinemu.fragments.EmulationFragment; import java.util.List; -public final class EmulationActivity extends Activity +public final class EmulationActivity extends AppCompatActivity { private View mDecorView; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/GameGridActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/GameGridActivity.java index d431f6c981..ef8dc870d5 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/GameGridActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/GameGridActivity.java @@ -1,6 +1,5 @@ package org.dolphinemu.dolphinemu.activities; -import android.app.Activity; import android.app.LoaderManager; import android.content.CursorLoader; import android.content.Intent; @@ -9,6 +8,8 @@ import android.content.SharedPreferences; import android.database.Cursor; import android.os.Bundle; import android.preference.PreferenceManager; +import android.support.design.widget.FloatingActionButton; +import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; @@ -16,7 +17,6 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.widget.ImageButton; import android.widget.Toolbar; import org.dolphinemu.dolphinemu.NativeLibrary; @@ -30,7 +30,7 @@ import org.dolphinemu.dolphinemu.services.AssetCopyService; * The main Activity of the Lollipop style UI. Shows a grid of games on tablets & landscape phones, * shows a list of games on portrait phones. */ -public final class GameGridActivity extends Activity implements LoaderManager.LoaderCallbacks +public final class GameGridActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks { private static final int REQUEST_ADD_DIRECTORY = 1; @@ -48,7 +48,7 @@ public final class GameGridActivity extends Activity implements LoaderManager.Lo Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_game_list); setActionBar(toolbar); - ImageButton buttonAddDirectory = (ImageButton) findViewById(R.id.button_add_directory); + FloatingActionButton buttonAddDirectory = (FloatingActionButton) findViewById(R.id.button_add_directory); RecyclerView recyclerView = (RecyclerView) findViewById(R.id.grid_games); // TODO Rather than calling into native code, this should use the commented line below. diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/OverlayConfigActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/OverlayConfigActivity.java index 41202000ec..78e93677ea 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/OverlayConfigActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/OverlayConfigActivity.java @@ -8,6 +8,7 @@ package org.dolphinemu.dolphinemu.activities; import android.app.Activity; import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; import android.widget.RelativeLayout; import org.dolphinemu.dolphinemu.R; @@ -16,7 +17,7 @@ import org.dolphinemu.dolphinemu.overlay.OverlayConfigButton; /** * {@link Activity} used for configuring the input overlay. */ -public final class OverlayConfigActivity extends Activity +public final class OverlayConfigActivity extends AppCompatActivity { @Override public void onCreate(Bundle savedInstanceState) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/SettingsActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/SettingsActivity.java index fe1ddd14d4..a595cdeb0f 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/SettingsActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/SettingsActivity.java @@ -1,15 +1,15 @@ package org.dolphinemu.dolphinemu.activities; -import android.app.Activity; import android.content.Intent; import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; import android.util.Log; import org.dolphinemu.dolphinemu.fragments.SettingsFragment; import org.dolphinemu.dolphinemu.services.SettingsSaveService; -public final class SettingsActivity extends Activity +public final class SettingsActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java index 04c7253cb5..ac193c9fb1 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java @@ -6,9 +6,9 @@ import android.app.Dialog; import android.app.DialogFragment; import android.content.Intent; import android.os.Bundle; +import android.support.design.widget.FloatingActionButton; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; @@ -61,7 +61,7 @@ public final class GameDetailsDialog extends DialogFragment TextView textCountry = (TextView) contents.findViewById(R.id.text_country); TextView textDate = (TextView) contents.findViewById(R.id.text_date); - ImageButton buttonLaunch = (ImageButton) contents.findViewById(R.id.button_launch); + FloatingActionButton buttonLaunch = (FloatingActionButton) contents.findViewById(R.id.button_launch); int countryIndex = getArguments().getInt(ARGUMENT_GAME_COUNTRY); String country = getResources().getStringArray(R.array.country_names)[countryIndex]; diff --git a/Source/Android/app/src/main/res/drawable/oval_ripple_accent.xml b/Source/Android/app/src/main/res/drawable/oval_ripple_accent.xml deleted file mode 100644 index fbdfec87f5..0000000000 --- a/Source/Android/app/src/main/res/drawable/oval_ripple_accent.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/Source/Android/app/src/main/res/layout/activity_game_grid.xml b/Source/Android/app/src/main/res/layout/activity_game_grid.xml index 53ac5d614e..cf91a6dac6 100644 --- a/Source/Android/app/src/main/res/layout/activity_game_grid.xml +++ b/Source/Android/app/src/main/res/layout/activity_game_grid.xml @@ -1,5 +1,6 @@ - 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 1d7b63468b..ca33e56007 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 @@ -1,5 +1,6 @@ - + app:rippleColor="?android:colorPrimaryDark" + app:borderWidth="0dp" + app:elevation="6dp" + app:pressedTranslationZ="12dp" + /> diff --git a/Source/Android/app/src/main/res/values/styles.xml b/Source/Android/app/src/main/res/values/styles.xml index bec7fc0035..374ec4d628 100644 --- a/Source/Android/app/src/main/res/values/styles.xml +++ b/Source/Android/app/src/main/res/values/styles.xml @@ -1,83 +1,83 @@ - - - - \ No newline at end of file From 8b5b83c29ae2ee00e96b454238e554ff475fb747 Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Sun, 21 Jun 2015 15:43:28 -0400 Subject: [PATCH 2/3] Android Refactor: GameGridActivity is now MainActivity, and uses a Toolbar that reacts to the game grid scrolling. --- .../Android/app/src/main/AndroidManifest.xml | 2 +- ...ameGridActivity.java => MainActivity.java} | 16 +++---- .../main/res/layout/activity_game_grid.xml | 46 ------------------- .../app/src/main/res/layout/activity_main.xml | 44 ++++++++++++++++++ .../app/src/main/res/menu/menu_game_grid.xml | 7 +-- .../app/src/main/res/values/dimens.xml | 2 + 6 files changed, 59 insertions(+), 58 deletions(-) rename Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/{GameGridActivity.java => MainActivity.java} (92%) delete mode 100644 Source/Android/app/src/main/res/layout/activity_game_grid.xml create mode 100644 Source/Android/app/src/main/res/layout/activity_main.xml diff --git a/Source/Android/app/src/main/AndroidManifest.xml b/Source/Android/app/src/main/AndroidManifest.xml index ad63dcd0c2..30fffd11e9 100644 --- a/Source/Android/app/src/main/AndroidManifest.xml +++ b/Source/Android/app/src/main/AndroidManifest.xml @@ -26,7 +26,7 @@ android:banner="@drawable/banner_tv"> diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/GameGridActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/MainActivity.java similarity index 92% rename from Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/GameGridActivity.java rename to Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/MainActivity.java index ef8dc870d5..bb65b855be 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/GameGridActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/MainActivity.java @@ -12,12 +12,12 @@ import android.support.design.widget.FloatingActionButton; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.widget.Toolbar; import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; @@ -27,10 +27,10 @@ import org.dolphinemu.dolphinemu.model.GameProvider; import org.dolphinemu.dolphinemu.services.AssetCopyService; /** - * The main Activity of the Lollipop style UI. Shows a grid of games on tablets & landscape phones, - * shows a list of games on portrait phones. + * The main Activity of the Lollipop style UI. Manages several PlatformGamesFragments, which + * individually display a grid of available games for each Fragment, in a tabbed layout. */ -public final class GameGridActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks +public final class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks { private static final int REQUEST_ADD_DIRECTORY = 1; @@ -43,10 +43,10 @@ public final class GameGridActivity extends AppCompatActivity implements LoaderM protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_game_grid); + setContentView(R.layout.activity_main); - Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_game_list); - setActionBar(toolbar); + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_main); + setSupportActionBar(toolbar); FloatingActionButton buttonAddDirectory = (FloatingActionButton) findViewById(R.id.button_add_directory); RecyclerView recyclerView = (RecyclerView) findViewById(R.id.grid_games); @@ -73,7 +73,7 @@ public final class GameGridActivity extends AppCompatActivity implements LoaderM @Override public void onClick(View view) { - Intent fileChooser = new Intent(GameGridActivity.this, AddDirectoryActivity.class); + Intent fileChooser = new Intent(MainActivity.this, AddDirectoryActivity.class); // The second argument to this method is read below in onActivityResult(). startActivityForResult(fileChooser, REQUEST_ADD_DIRECTORY); diff --git a/Source/Android/app/src/main/res/layout/activity_game_grid.xml b/Source/Android/app/src/main/res/layout/activity_game_grid.xml deleted file mode 100644 index cf91a6dac6..0000000000 --- a/Source/Android/app/src/main/res/layout/activity_game_grid.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/Source/Android/app/src/main/res/layout/activity_main.xml b/Source/Android/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000000..8ebddcc5d5 --- /dev/null +++ b/Source/Android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Android/app/src/main/res/menu/menu_game_grid.xml b/Source/Android/app/src/main/res/menu/menu_game_grid.xml index ca0f117e4f..5b6bf23ac0 100644 --- a/Source/Android/app/src/main/res/menu/menu_game_grid.xml +++ b/Source/Android/app/src/main/res/menu/menu_game_grid.xml @@ -1,14 +1,15 @@ - + + app:showAsAction="ifRoom"/> + app:showAsAction="ifRoom"/> \ No newline at end of file diff --git a/Source/Android/app/src/main/res/values/dimens.xml b/Source/Android/app/src/main/res/values/dimens.xml index 72b7d0fcaf..986b230792 100644 --- a/Source/Android/app/src/main/res/values/dimens.xml +++ b/Source/Android/app/src/main/res/values/dimens.xml @@ -7,4 +7,6 @@ 1dp 4dp 16dp + + 128dp From 6b24b604e5cc55caface9abc861554fd084eb2ab Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Sun, 21 Jun 2015 19:22:12 -0400 Subject: [PATCH 3/3] Android: MainActivity now contains a tab switcher separating games by platform. --- .../dolphinemu/activities/MainActivity.java | 144 ++++++++++++++---- .../adapters/PlatformPagerAdapter.java | 61 ++++++++ .../fragments/PlatformGamesFragment.java | 110 +++++++++++++ .../dolphinemu/model/GameDatabase.java | 9 +- .../app/src/main/res/layout/activity_main.xml | 23 +-- .../app/src/main/res/layout/fragment_grid.xml | 15 ++ .../app/src/main/res/values/styles.xml | 7 + 7 files changed, 326 insertions(+), 43 deletions(-) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/PlatformPagerAdapter.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/PlatformGamesFragment.java create mode 100644 Source/Android/app/src/main/res/layout/fragment_grid.xml diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/MainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/MainActivity.java index bb65b855be..7812e6ead5 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/MainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/MainActivity.java @@ -8,10 +8,11 @@ import android.content.SharedPreferences; import android.database.Cursor; import android.os.Bundle; import android.preference.PreferenceManager; +import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; +import android.support.design.widget.TabLayout; +import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; @@ -21,7 +22,9 @@ import android.view.View; import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; -import org.dolphinemu.dolphinemu.adapters.GameAdapter; +import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter; +import org.dolphinemu.dolphinemu.fragments.PlatformGamesFragment; +import org.dolphinemu.dolphinemu.model.Game; import org.dolphinemu.dolphinemu.model.GameDatabase; import org.dolphinemu.dolphinemu.model.GameProvider; import org.dolphinemu.dolphinemu.services.AssetCopyService; @@ -34,10 +37,17 @@ public final class MainActivity extends AppCompatActivity implements LoaderManag { private static final int REQUEST_ADD_DIRECTORY = 1; - private static final int LOADER_ID_GAMES = 1; - // TODO When each platform has its own tab, there should be a LOADER_ID for each platform. + /** + * It is important to keep track of loader ID separately from platform ID (see Game.java) + * because we could potentially have Loaders that load things other than Games. + */ + public static final int LOADER_ID_ALL = 100; // TODO + public static final int LOADER_ID_GAMECUBE = 0; + public static final int LOADER_ID_WII = 1; + public static final int LOADER_ID_WIIWARE = 2; - private GameAdapter mAdapter; + private ViewPager mViewPager; + private PlatformPagerAdapter mPlatformPagerAdapter; @Override protected void onCreate(Bundle savedInstanceState) @@ -45,29 +55,26 @@ public final class MainActivity extends AppCompatActivity implements LoaderManag super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + // Set up the Toolbar. Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_main); setSupportActionBar(toolbar); - FloatingActionButton buttonAddDirectory = (FloatingActionButton) findViewById(R.id.button_add_directory); - RecyclerView recyclerView = (RecyclerView) findViewById(R.id.grid_games); - // TODO Rather than calling into native code, this should use the commented line below. // String versionName = BuildConfig.VERSION_NAME; String versionName = NativeLibrary.GetVersionString(); toolbar.setSubtitle(versionName); - // Specifying the LayoutManager determines how the RecyclerView arranges views. - RecyclerView.LayoutManager layoutManager = new GridLayoutManager(this, - getResources().getInteger(R.integer.game_grid_columns)); - recyclerView.setLayoutManager(layoutManager); + // Set up the Tab bar. + mViewPager = (ViewPager) findViewById(R.id.pager_platforms); - recyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8)); + mPlatformPagerAdapter = new PlatformPagerAdapter(getFragmentManager(), this); + mViewPager.setAdapter(mPlatformPagerAdapter); - // Create an adapter that will relate the dataset to the views on-screen. - getLoaderManager().initLoader(LOADER_ID_GAMES, null, this); - mAdapter = new GameAdapter(); - recyclerView.setAdapter(mAdapter); + TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs_platforms); + tabLayout.setupWithViewPager(mViewPager); + // Set up the FAB. + FloatingActionButton buttonAddDirectory = (FloatingActionButton) findViewById(R.id.button_add_directory); buttonAddDirectory.setOnClickListener(new View.OnClickListener() { @Override @@ -115,7 +122,7 @@ public final class MainActivity extends AppCompatActivity implements LoaderManag // other activities might use this callback in the future (don't forget to change Javadoc!) if (requestCode == REQUEST_ADD_DIRECTORY) { - getLoaderManager().restartLoader(LOADER_ID_GAMES, null, this); + refreshFragment(); } } } @@ -147,7 +154,7 @@ public final class MainActivity extends AppCompatActivity implements LoaderManag case R.id.menu_refresh: getContentResolver().insert(GameProvider.URI_REFRESH, null); - getLoaderManager().restartLoader(LOADER_ID_GAMES, null, this); + refreshFragment(); return true; } @@ -155,6 +162,15 @@ public final class MainActivity extends AppCompatActivity implements LoaderManag return false; } + public void refreshFragment() + { + PlatformGamesFragment fragment = getPlatformFragment(mViewPager.getCurrentItem()); + if (fragment != null) + { + fragment.refresh(); + } + } + /** * Callback that's invoked when the system has initialized the Loader and @@ -173,16 +189,30 @@ public final class MainActivity extends AppCompatActivity implements LoaderManag // Take action based on the ID of the Loader that's being created. switch (id) { - case LOADER_ID_GAMES: + case LOADER_ID_ALL: // TODO Play some sort of load-starting animation; maybe fade the list out. return new CursorLoader( - this, // Parent activity context - GameProvider.URI_GAME, // URI of table to query - null, // Return all columns - null, // No selection clause - null, // No selection arguments - GameDatabase.KEY_GAME_TITLE + " asc" // Sort by game name, ascending order + this, // Parent activity context + GameProvider.URI_GAME, // URI of table to query + null, // Return all columns + null, // No selection clause + null, // No selection arguments + GameDatabase.KEY_GAME_TITLE + " asc" // Sort by game name, ascending order + ); + + case LOADER_ID_GAMECUBE: + case LOADER_ID_WII: + case LOADER_ID_WIIWARE: + // TODO Play some sort of load-starting animation; maybe fade the list out. + + return new CursorLoader( + this, // Parent activity context + GameProvider.URI_GAME, // URI of table to query + null, // Return all columns + GameDatabase.KEY_GAME_PLATFORM + " = ?", // Select by platform + new String[]{Integer.toString(id)}, // Platform id is Loader id minus 1 + GameDatabase.KEY_GAME_TITLE + " asc" // Sort by game name, ascending order ); default: @@ -205,25 +235,73 @@ public final class MainActivity extends AppCompatActivity implements LoaderManag int id = loader.getId(); Log.d("DolphinEmu", "Loader finished with id: " + id); - // TODO When each platform has its own tab, this should just call into those tabs instead. + PlatformGamesFragment fragment = null; switch (id) { - case LOADER_ID_GAMES: - mAdapter.swapCursor(data); - // TODO Play some sort of load-finished animation; maybe fade the list in. + case LOADER_ID_GAMECUBE: + fragment = getPlatformFragment(Game.PLATFORM_GC); break; + case LOADER_ID_WII: + fragment = getPlatformFragment(Game.PLATFORM_WII); + break; + + case LOADER_ID_WIIWARE: + fragment = getPlatformFragment(Game.PLATFORM_WII_WARE); + break; + + // TODO case LOADER_ID_ALL: + default: Log.e("DolphinEmu", "Bad ID passed in."); + break; } + if (fragment != null) + { + fragment.onLoadFinished(loader, data); + } } @Override public void onLoaderReset(Loader loader) { - Log.d("DolphinEmu", "Loader resetting."); + int id = loader.getId(); + Log.e("DolphinEmu", "Loader resetting with id: " + id); - // TODO ¯\_(ツ)_/¯ + PlatformGamesFragment fragment = null; + switch (id) + { + case LOADER_ID_GAMECUBE: + fragment = getPlatformFragment(Game.PLATFORM_GC); + break; + + case LOADER_ID_WII: + fragment = getPlatformFragment(Game.PLATFORM_WII); + break; + + case LOADER_ID_WIIWARE: + fragment = getPlatformFragment(Game.PLATFORM_WII_WARE); + break; + + // TODO case LOADER_ID_ALL: + + default: + Log.e("DolphinEmu", "Bad ID passed in."); + break; + } + + if (fragment != null) + { + fragment.onLoaderReset(); + } + } + + @Nullable + public PlatformGamesFragment getPlatformFragment(int platform) + { + String fragmentTag = "android:switcher:" + mViewPager.getId() + ":" + platform; + + return (PlatformGamesFragment) getFragmentManager().findFragmentByTag(fragmentTag); } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/PlatformPagerAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/PlatformPagerAdapter.java new file mode 100644 index 0000000000..feeb9ee50f --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/PlatformPagerAdapter.java @@ -0,0 +1,61 @@ +package org.dolphinemu.dolphinemu.adapters; + + +import android.app.Fragment; +import android.app.FragmentManager; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.v13.app.FragmentPagerAdapter; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.ImageSpan; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.fragments.PlatformGamesFragment; + +public class PlatformPagerAdapter extends FragmentPagerAdapter +{ + private Context mContext; + + private final static int[] TAB_ICONS = { + R.drawable.ic_gamecube, + R.drawable.ic_wii, + R.drawable.ic_folder// wiiware TODO Have an icon here. + }; + + public PlatformPagerAdapter(FragmentManager fm, Context context) + { + super(fm); + mContext = context; + } + + @Override + public Fragment getItem(int position) + { + return PlatformGamesFragment.newInstance(position); + } + + @Override + public int getCount() + { + return TAB_ICONS.length; + } + + @Override + public CharSequence getPageTitle(int position) + { + // Hax from https://guides.codepath.com/android/Google-Play-Style-Tabs-using-TabLayout#design-support-library + // Apparently a workaround for TabLayout not supporting icons. + // TODO This workaround will eventually not be necessary; switch to more legit methods when that is the case + // TODO Also remove additional hax from styles.xml + Drawable drawable = mContext.getResources().getDrawable(TAB_ICONS[position]); + drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); + + ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM); + + SpannableString sb = new SpannableString(" "); + sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + + return sb; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/PlatformGamesFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/PlatformGamesFragment.java new file mode 100644 index 0000000000..4957090ed3 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/PlatformGamesFragment.java @@ -0,0 +1,110 @@ +package org.dolphinemu.dolphinemu.fragments; + +import android.app.Activity; +import android.app.Fragment; +import android.app.LoaderManager; +import android.content.Loader; +import android.database.Cursor; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.dolphinemu.dolphinemu.BuildConfig; +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.adapters.GameAdapter; + +public class PlatformGamesFragment extends Fragment +{ + private static final String ARG_PLATFORM = BuildConfig.APPLICATION_ID + ".PLATFORM"; + + private int mPlatform; + + private GameAdapter mAdapter; + + public static PlatformGamesFragment newInstance(int platform) + { + PlatformGamesFragment fragment = new PlatformGamesFragment(); + + Bundle args = new Bundle(); + args.putInt(ARG_PLATFORM, platform); + + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + mPlatform = getArguments().getInt(ARG_PLATFORM); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) + { + View rootView = inflater.inflate(R.layout.fragment_grid, container, false); + RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.grid_games); + + // Specifying the LayoutManager determines how the RecyclerView arranges views. + + RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), + getResources().getInteger(R.integer.game_grid_columns)); + recyclerView.setLayoutManager(layoutManager); + + recyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8)); + + // Create an adapter that will relate the dataset to the views on-screen. +1 because of LOADER_ID_ALL + getLoaderManager().initLoader(mPlatform, null, + (LoaderManager.LoaderCallbacks) getActivity()); + + mAdapter = new GameAdapter(); + recyclerView.setAdapter(mAdapter); + + return rootView; + } + + @Override + public void onAttach(Activity activity) + { + super.onAttach(activity); + } + + public void refresh() + { + Log.d("DolphinEmu", "[PlatformGamesFragment] " + mPlatform + ": Refreshing..."); + // +1 because of LOADER_ID_ALL + getLoaderManager().restartLoader(mPlatform, null, (LoaderManager.LoaderCallbacks) getActivity()); + } + + public void onLoadFinished(Loader loader, Cursor data) + { + // TODO Play some sort of load-finished animation; maybe fade the list in. + + Log.d("DolphinEmu", "[PlatformGamesFragment] " + mPlatform + ": Load finished, swapping cursor..."); + Log.d("DolphinEmu", "[PlatformGamesFragment] " + mPlatform + ": Cursor size: " + data.getCount()); + if (mAdapter != null) + { + mAdapter.swapCursor(data); + } + else + { + Log.e("DolphinEmu", "[PlatformGamesFragment] " + mPlatform + ": No adapter available."); + } + } + + public void onLoaderReset() + { + Log.e("DolphinEmu", "[PlatformGamesFragment] " + mPlatform + ": Loader reset; clearing data from view."); + if (mAdapter != null) + { + mAdapter.swapCursor(null); + } + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameDatabase.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameDatabase.java index 28ef08f32e..6aaee3ae16 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameDatabase.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameDatabase.java @@ -196,7 +196,14 @@ public final class GameDatabase extends SQLiteOpenHelper gameId = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.lastIndexOf(".")); } - ContentValues game = Game.asContentValues(NativeLibrary.GetPlatform(filePath), + // If the game's platform field is empty, file under Wiiware. // TODO Something less dum + int platform = NativeLibrary.GetPlatform(filePath); + if (platform == -1) + { + platform = Game.PLATFORM_WII_WARE; + } + + ContentValues game = Game.asContentValues(platform, name, NativeLibrary.GetDescription(filePath).replace("\n", " "), NativeLibrary.GetCountry(filePath), diff --git a/Source/Android/app/src/main/res/layout/activity_main.xml b/Source/Android/app/src/main/res/layout/activity_main.xml index 8ebddcc5d5..53d4de6e72 100644 --- a/Source/Android/app/src/main/res/layout/activity_main.xml +++ b/Source/Android/app/src/main/res/layout/activity_main.xml @@ -1,7 +1,6 @@ + + + - \ No newline at end of file diff --git a/Source/Android/app/src/main/res/layout/fragment_grid.xml b/Source/Android/app/src/main/res/layout/fragment_grid.xml new file mode 100644 index 0000000000..eb46ff8458 --- /dev/null +++ b/Source/Android/app/src/main/res/layout/fragment_grid.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/Source/Android/app/src/main/res/values/styles.xml b/Source/Android/app/src/main/res/values/styles.xml index 374ec4d628..98cf984807 100644 --- a/Source/Android/app/src/main/res/values/styles.xml +++ b/Source/Android/app/src/main/res/values/styles.xml @@ -80,4 +80,11 @@ + + + + + \ No newline at end of file