From fa2d06e7a4d503f8aeefbe81ca3f0b642b2d3869 Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Sat, 20 Jun 2015 19:37:36 -0400 Subject: Android: Switch all activities to AppCompat-based Material themes, and use Support Library version of Floating Action Button. --- .../dolphinemu/dolphinemu/activities/AddDirectoryActivity.java | 6 ++---- .../org/dolphinemu/dolphinemu/activities/EmulationActivity.java | 5 ++++- .../org/dolphinemu/dolphinemu/activities/GameGridActivity.java | 8 ++++---- .../dolphinemu/dolphinemu/activities/OverlayConfigActivity.java | 3 ++- .../org/dolphinemu/dolphinemu/activities/SettingsActivity.java | 4 ++-- .../java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java | 4 ++-- 6 files changed, 16 insertions(+), 14 deletions(-) (limited to 'Source/Android/app/src/main/java/org') 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]; -- cgit v1.2.3 From 8b5b83c29ae2ee00e96b454238e554ff475fb747 Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Sun, 21 Jun 2015 15:43:28 -0400 Subject: Android Refactor: GameGridActivity is now MainActivity, and uses a Toolbar that reacts to the game grid scrolling. --- .../dolphinemu/activities/GameGridActivity.java | 229 --------------------- .../dolphinemu/activities/MainActivity.java | 229 +++++++++++++++++++++ 2 files changed, 229 insertions(+), 229 deletions(-) delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/GameGridActivity.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/MainActivity.java (limited to 'Source/Android/app/src/main/java/org') 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 deleted file mode 100644 index ef8dc870d5..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/GameGridActivity.java +++ /dev/null @@ -1,229 +0,0 @@ -package org.dolphinemu.dolphinemu.activities; - -import android.app.LoaderManager; -import android.content.CursorLoader; -import android.content.Intent; -import android.content.Loader; -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; -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; -import org.dolphinemu.dolphinemu.adapters.GameAdapter; -import org.dolphinemu.dolphinemu.model.GameDatabase; -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. - */ -public final class GameGridActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks -{ - 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. - - private GameAdapter mAdapter; - - @Override - protected void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_game_grid); - - Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_game_list); - setActionBar(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); - - recyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8)); - - // 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); - - buttonAddDirectory.setOnClickListener(new View.OnClickListener() - { - @Override - public void onClick(View view) - { - Intent fileChooser = new Intent(GameGridActivity.this, AddDirectoryActivity.class); - - // The second argument to this method is read below in onActivityResult(). - startActivityForResult(fileChooser, REQUEST_ADD_DIRECTORY); - } - }); - - // Stuff in this block only happens when this activity is newly created (i.e. not a rotation) - if (savedInstanceState == null) - { - NativeLibrary.SetUserDirectory(""); // Auto-Detect - - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - boolean assetsCopied = preferences.getBoolean("assetsCopied", false); - - // Only perform these extensive copy operations once. - if (!assetsCopied) - { - // Copy assets into appropriate locations. - Intent copyAssets = new Intent(this, AssetCopyService.class); - startService(copyAssets); - } - } - } - - /** - * Callback from AddDirectoryActivity. Applies any changes necessary to the GameGridActivity. - * - * @param requestCode An int describing whether the Activity that is returning did so successfully. - * @param resultCode An int describing what Activity is giving us this callback. - * @param result The information the returning Activity is providing us. - */ - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent result) - { - // If the user picked a file, as opposed to just backing out. - if (resultCode == RESULT_OK) - { - // Sanity check to make sure the Activity that just returned was the AddDirectoryActivity; - // 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); - } - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) - { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.menu_game_grid, menu); - return true; - } - - /** - * Called by the framework whenever any actionbar/toolbar icon is clicked. - * - * @param item The icon that was clicked on. - * @return True if the event was handled, false to bubble it up to the OS. - */ - @Override - public boolean onOptionsItemSelected(MenuItem item) - { - switch (item.getItemId()) - { - case R.id.menu_settings: - // Launch the Settings Actvity. - Intent settings = new Intent(this, SettingsActivity.class); - startActivity(settings); - return true; - - case R.id.menu_refresh: - getContentResolver().insert(GameProvider.URI_REFRESH, null); - getLoaderManager().restartLoader(LOADER_ID_GAMES, null, this); - - return true; - } - - return false; - } - - - /** - * Callback that's invoked when the system has initialized the Loader and - * is ready to start the query. This usually happens when initLoader() is - * called. Here, we use it to make a DB query for games. - * - * @param id The ID value passed to the initLoader() call that triggered this. - * @param args The args bundle supplied by the caller. - * @return A new Loader instance that is ready to start loading. - */ - @Override - public Loader onCreateLoader(int id, Bundle args) - { - Log.d("DolphinEmu", "Creating loader with id: " + id); - - // Take action based on the ID of the Loader that's being created. - switch (id) - { - case LOADER_ID_GAMES: - // 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 - ); - - default: - Log.e("DolphinEmu", "Bad ID passed in."); - return null; - } - } - - /** - * Callback that's invoked when the Loader returned in onCreateLoader is finished - * with its task. In this case, the game DB query is finished, so we should put the results - * on screen. - * - * @param loader The loader that finished. - * @param data The data the Loader loaded. - */ - @Override - public void onLoadFinished(Loader loader, Cursor data) - { - 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. - switch (id) - { - case LOADER_ID_GAMES: - mAdapter.swapCursor(data); - // TODO Play some sort of load-finished animation; maybe fade the list in. - break; - - default: - Log.e("DolphinEmu", "Bad ID passed in."); - } - - } - - @Override - public void onLoaderReset(Loader loader) - { - Log.d("DolphinEmu", "Loader resetting."); - - // TODO ¯\_(ツ)_/¯ - } -} 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 new file mode 100644 index 0000000000..bb65b855be --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/MainActivity.java @@ -0,0 +1,229 @@ +package org.dolphinemu.dolphinemu.activities; + +import android.app.LoaderManager; +import android.content.CursorLoader; +import android.content.Intent; +import android.content.Loader; +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.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 org.dolphinemu.dolphinemu.NativeLibrary; +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.adapters.GameAdapter; +import org.dolphinemu.dolphinemu.model.GameDatabase; +import org.dolphinemu.dolphinemu.model.GameProvider; +import org.dolphinemu.dolphinemu.services.AssetCopyService; + +/** + * 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 MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks +{ + 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. + + private GameAdapter mAdapter; + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + 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); + + recyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8)); + + // 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); + + buttonAddDirectory.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View view) + { + Intent fileChooser = new Intent(MainActivity.this, AddDirectoryActivity.class); + + // The second argument to this method is read below in onActivityResult(). + startActivityForResult(fileChooser, REQUEST_ADD_DIRECTORY); + } + }); + + // Stuff in this block only happens when this activity is newly created (i.e. not a rotation) + if (savedInstanceState == null) + { + NativeLibrary.SetUserDirectory(""); // Auto-Detect + + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + boolean assetsCopied = preferences.getBoolean("assetsCopied", false); + + // Only perform these extensive copy operations once. + if (!assetsCopied) + { + // Copy assets into appropriate locations. + Intent copyAssets = new Intent(this, AssetCopyService.class); + startService(copyAssets); + } + } + } + + /** + * Callback from AddDirectoryActivity. Applies any changes necessary to the GameGridActivity. + * + * @param requestCode An int describing whether the Activity that is returning did so successfully. + * @param resultCode An int describing what Activity is giving us this callback. + * @param result The information the returning Activity is providing us. + */ + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent result) + { + // If the user picked a file, as opposed to just backing out. + if (resultCode == RESULT_OK) + { + // Sanity check to make sure the Activity that just returned was the AddDirectoryActivity; + // 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); + } + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) + { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.menu_game_grid, menu); + return true; + } + + /** + * Called by the framework whenever any actionbar/toolbar icon is clicked. + * + * @param item The icon that was clicked on. + * @return True if the event was handled, false to bubble it up to the OS. + */ + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + switch (item.getItemId()) + { + case R.id.menu_settings: + // Launch the Settings Actvity. + Intent settings = new Intent(this, SettingsActivity.class); + startActivity(settings); + return true; + + case R.id.menu_refresh: + getContentResolver().insert(GameProvider.URI_REFRESH, null); + getLoaderManager().restartLoader(LOADER_ID_GAMES, null, this); + + return true; + } + + return false; + } + + + /** + * Callback that's invoked when the system has initialized the Loader and + * is ready to start the query. This usually happens when initLoader() is + * called. Here, we use it to make a DB query for games. + * + * @param id The ID value passed to the initLoader() call that triggered this. + * @param args The args bundle supplied by the caller. + * @return A new Loader instance that is ready to start loading. + */ + @Override + public Loader onCreateLoader(int id, Bundle args) + { + Log.d("DolphinEmu", "Creating loader with id: " + id); + + // Take action based on the ID of the Loader that's being created. + switch (id) + { + case LOADER_ID_GAMES: + // 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 + ); + + default: + Log.e("DolphinEmu", "Bad ID passed in."); + return null; + } + } + + /** + * Callback that's invoked when the Loader returned in onCreateLoader is finished + * with its task. In this case, the game DB query is finished, so we should put the results + * on screen. + * + * @param loader The loader that finished. + * @param data The data the Loader loaded. + */ + @Override + public void onLoadFinished(Loader loader, Cursor data) + { + 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. + switch (id) + { + case LOADER_ID_GAMES: + mAdapter.swapCursor(data); + // TODO Play some sort of load-finished animation; maybe fade the list in. + break; + + default: + Log.e("DolphinEmu", "Bad ID passed in."); + } + + } + + @Override + public void onLoaderReset(Loader loader) + { + Log.d("DolphinEmu", "Loader resetting."); + + // TODO ¯\_(ツ)_/¯ + } +} -- cgit v1.2.3 From 6b24b604e5cc55caface9abc861554fd084eb2ab Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Sun, 21 Jun 2015 19:22:12 -0400 Subject: Android: MainActivity now contains a tab switcher separating games by platform. --- .../dolphinemu/activities/MainActivity.java | 144 ++++++++++++++++----- .../dolphinemu/adapters/PlatformPagerAdapter.java | 61 +++++++++ .../fragments/PlatformGamesFragment.java | 110 ++++++++++++++++ .../dolphinemu/dolphinemu/model/GameDatabase.java | 9 +- 4 files changed, 290 insertions(+), 34 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 (limited to 'Source/Android/app/src/main/java/org') 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 + ); + + 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 - 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 + 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); + + 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; - // TODO ¯\_(ツ)_/¯ + 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), -- cgit v1.2.3