From 81657b6710aeadaa694ff947595263b8ff0f922a Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Sat, 9 Jan 2016 18:08:04 -0500 Subject: [PATCH 1/3] Refactor MainActivity to MVP architecture --- .../Android/app/src/main/AndroidManifest.xml | 2 +- .../dolphinemu/activities/MainActivity.java | 173 ----------------- .../dolphinemu/activities/TvMainActivity.java | 12 +- .../dolphinemu/adapters/GameAdapter.java | 5 +- .../dolphinemu/ui/main/MainActivity.java | 174 ++++++++++++++++++ .../dolphinemu/ui/main/MainPresenter.java | 68 +++++++ .../dolphinemu/ui/main/MainView.java | 15 ++ 7 files changed, 266 insertions(+), 183 deletions(-) delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/MainActivity.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java diff --git a/Source/Android/app/src/main/AndroidManifest.xml b/Source/Android/app/src/main/AndroidManifest.xml index adfda3d0cec3..0d83b3a37d21 100644 --- a/Source/Android/app/src/main/AndroidManifest.xml +++ b/Source/Android/app/src/main/AndroidManifest.xml @@ -27,7 +27,7 @@ android:banner="@drawable/banner_tv"> 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 deleted file mode 100644 index 5dc3bbd9831b..000000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/MainActivity.java +++ /dev/null @@ -1,173 +0,0 @@ -package org.dolphinemu.dolphinemu.activities; - -import android.content.Intent; -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.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.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; -import org.dolphinemu.dolphinemu.utils.StartupHandler; - -/** - * 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 -{ - public static final int REQUEST_ADD_DIRECTORY = 1; - public static final int REQUEST_EMULATE_GAME = 2; - - private ViewPager mViewPager; - private PlatformPagerAdapter mPlatformPagerAdapter; - - @Override - protected void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - // Set up the Toolbar. - Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_main); - setSupportActionBar(toolbar); - - // 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); - - // Set up the Tab bar. - mViewPager = (ViewPager) findViewById(R.id.pager_platforms); - - mPlatformPagerAdapter = new PlatformPagerAdapter(getFragmentManager(), this); - mViewPager.setAdapter(mPlatformPagerAdapter); - - 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 - 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) - StartupHandler.HandleInit(this); - } - - /** - * 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) - { - switch (requestCode) - { - case REQUEST_ADD_DIRECTORY: - // 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) - { - refreshFragment(); - } - } - break; - - case REQUEST_EMULATE_GAME: - // Invalidate Picasso image so that the new screenshot is animated in. - PlatformGamesFragment fragment = getPlatformFragment(mViewPager.getCurrentItem()); - - if (fragment != null) - { - fragment.refreshScreenshotAtPosition(resultCode); - } - break; - } - } - - @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); - refreshFragment(); - - return true; - } - - return false; - } - - public void refreshFragment() - { - PlatformGamesFragment fragment = getPlatformFragment(mViewPager.getCurrentItem()); - if (fragment != null) - { - fragment.refresh(); - } - } - - @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/activities/TvMainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/TvMainActivity.java index a01e080549d7..c7724519541c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/TvMainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/TvMainActivity.java @@ -4,10 +4,8 @@ import android.app.ActivityOptions; import android.app.FragmentManager; import android.content.Intent; -import android.content.SharedPreferences; import android.database.Cursor; import android.os.Bundle; -import android.preference.PreferenceManager; import android.support.v17.leanback.app.BrowseFragment; import android.support.v17.leanback.database.CursorMapper; import android.support.v17.leanback.widget.ArrayObjectAdapter; @@ -21,7 +19,6 @@ import android.support.v17.leanback.widget.RowPresenter; import android.widget.Toast; -import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.adapters.GameRowPresenter; import org.dolphinemu.dolphinemu.adapters.SettingsRowPresenter; @@ -29,7 +26,8 @@ import org.dolphinemu.dolphinemu.model.GameDatabase; import org.dolphinemu.dolphinemu.model.GameProvider; import org.dolphinemu.dolphinemu.model.TvSettingsItem; -import org.dolphinemu.dolphinemu.services.AssetCopyService; +import org.dolphinemu.dolphinemu.ui.main.MainActivity; +import org.dolphinemu.dolphinemu.ui.main.MainPresenter; import org.dolphinemu.dolphinemu.utils.StartupHandler; import org.dolphinemu.dolphinemu.viewholders.TvGameViewHolder; @@ -88,7 +86,7 @@ public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowP Intent fileChooser = new Intent(TvMainActivity.this, AddDirectoryActivity.class); // The second argument to this method is read below in onActivityResult(). - startActivityForResult(fileChooser, MainActivity.REQUEST_ADD_DIRECTORY); + startActivityForResult(fileChooser, MainPresenter.REQUEST_ADD_DIRECTORY); break; @@ -134,13 +132,13 @@ protected void onActivityResult(int requestCode, int resultCode, Intent result) { switch (requestCode) { - case MainActivity.REQUEST_ADD_DIRECTORY: + case MainPresenter.REQUEST_ADD_DIRECTORY: // 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 == MainActivity.REQUEST_ADD_DIRECTORY) + if (requestCode == MainPresenter.REQUEST_ADD_DIRECTORY) { // TODO Let the Activity know the data is refreshed in some other, better way. recreate(); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java index e74bd6f96d77..2a0b0783c047 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java @@ -17,9 +17,10 @@ import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.activities.EmulationActivity; -import org.dolphinemu.dolphinemu.activities.MainActivity; +import org.dolphinemu.dolphinemu.ui.main.MainActivity; import org.dolphinemu.dolphinemu.dialogs.GameDetailsDialog; import org.dolphinemu.dolphinemu.model.GameDatabase; +import org.dolphinemu.dolphinemu.ui.main.MainPresenter; import org.dolphinemu.dolphinemu.viewholders.GameViewHolder; /** @@ -231,7 +232,7 @@ public void onClick(View view) "image_game_screenshot"); ((Activity) view.getContext()).startActivityForResult(intent, - MainActivity.REQUEST_EMULATE_GAME, + MainPresenter.REQUEST_EMULATE_GAME, options.toBundle()); } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java new file mode 100644 index 000000000000..ac2bfe525865 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java @@ -0,0 +1,174 @@ +package org.dolphinemu.dolphinemu.ui.main; + +import android.content.Intent; +import android.os.Bundle; +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.Toolbar; +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.activities.AddDirectoryActivity; +import org.dolphinemu.dolphinemu.activities.SettingsActivity; +import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter; +import org.dolphinemu.dolphinemu.fragments.PlatformGamesFragment; +import org.dolphinemu.dolphinemu.model.GameProvider; +import org.dolphinemu.dolphinemu.utils.StartupHandler; + +/** + * 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 MainView +{ + private ViewPager mViewPager; + private Toolbar mToolbar; + private TabLayout mTabLayout; + private FloatingActionButton mFab; + + private MainPresenter mPresenter = new MainPresenter(this); + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + findViews(); + + setSupportActionBar(mToolbar); + + PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(getFragmentManager(), this); + + mViewPager.setAdapter(platformPagerAdapter); + mTabLayout.setupWithViewPager(mViewPager); + + // Set up the FAB. + mFab.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View view) + { + mPresenter.onFabClick(); + } + }); + + mPresenter.onCreate(); + + // Stuff in this block only happens when this activity is newly created (i.e. not a rotation) + // TODO Split some of this stuff into Application.onCreate() + if (savedInstanceState == null) + StartupHandler.HandleInit(this); + } + + // TODO: Replace with a ButterKnife injection. + private void findViews() + { + mToolbar = (Toolbar) findViewById(R.id.toolbar_main); + mViewPager = (ViewPager) findViewById(R.id.pager_platforms); + mTabLayout = (TabLayout) findViewById(R.id.tabs_platforms); + mFab = (FloatingActionButton) findViewById(R.id.button_add_directory); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) + { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.menu_game_grid, menu); + return true; + } + + /** + * MainView + */ + + @Override + public void setSubtitle(String subtitle) + { + mToolbar.setSubtitle(subtitle); + } + + @Override + public void refresh() + { + getContentResolver().insert(GameProvider.URI_REFRESH, null); + refreshFragment(); + } + + @Override + public void refreshFragmentScreenshot(int fragmentPosition) + { + // Invalidate Picasso image so that the new screenshot is animated in. + PlatformGamesFragment fragment = getPlatformFragment(mViewPager.getCurrentItem()); + + if (fragment != null) + { + fragment.refreshScreenshotAtPosition(fragmentPosition); + } + } + + @Override + public void launchSettingsActivity() + { + Intent settings = new Intent(this, SettingsActivity.class); + startActivity(settings); + } + + @Override + public void launchFileListActivity() + { + Intent fileChooser = new Intent(MainActivity.this, AddDirectoryActivity.class); + + // The second argument to this method is read below in onActivityResult(). + startActivityForResult(fileChooser, MainPresenter.REQUEST_ADD_DIRECTORY); + } + + /** + * 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) + { + mPresenter.handleActivityResult(requestCode, resultCode); + } + + /** + * 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) + { + return mPresenter.handleOptionSelection(item.getItemId()); + } + + private void refreshFragment() + { + PlatformGamesFragment fragment = getPlatformFragment(mViewPager.getCurrentItem()); + if (fragment != null) + { + fragment.refresh(); + } + } + + @Nullable + private 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/ui/main/MainPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java new file mode 100644 index 000000000000..992b242d881c --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java @@ -0,0 +1,68 @@ +package org.dolphinemu.dolphinemu.ui.main; + + +import android.content.Intent; + +import org.dolphinemu.dolphinemu.NativeLibrary; +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.activities.SettingsActivity; +import org.dolphinemu.dolphinemu.fragments.PlatformGamesFragment; +import org.dolphinemu.dolphinemu.model.GameProvider; +import org.dolphinemu.dolphinemu.ui.main.MainView; + +public class MainPresenter +{ + public static final int REQUEST_ADD_DIRECTORY = 1; + public static final int REQUEST_EMULATE_GAME = 2; + + private final MainView mView; + + public MainPresenter(MainView view) + { + mView = view; + } + + public void onCreate() + { + // TODO Rather than calling into native code, this should use the commented line below. + // String versionName = BuildConfig.VERSION_NAME; + String versionName = NativeLibrary.GetVersionString(); + mView.setSubtitle(versionName); + } + + public void onFabClick() { + mView.launchFileListActivity(); + } + + public boolean handleOptionSelection(int itemId) { + switch (itemId) + { + case R.id.menu_settings: + mView.launchSettingsActivity(); + return true; + + case R.id.menu_refresh: + mView.refresh(); + return true; + } + + return false; + } + + public void handleActivityResult(int requestCode, int resultCode) { + switch (requestCode) + { + case REQUEST_ADD_DIRECTORY: + // If the user picked a file, as opposed to just backing out. + if (resultCode == MainActivity.RESULT_OK) + { + mView.refresh(); + } + break; + + case REQUEST_EMULATE_GAME: + mView.refreshFragmentScreenshot(resultCode); + break; + } + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java new file mode 100644 index 000000000000..4c8b26f306ba --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java @@ -0,0 +1,15 @@ +package org.dolphinemu.dolphinemu.ui.main; + + +public interface MainView +{ + void setSubtitle(String subtitle); + + void refresh(); + + void refreshFragmentScreenshot(int fragmentPosition); + + void launchSettingsActivity(); + + void launchFileListActivity(); +} From 24efce4cea12ff8b7934464814e601b8eab3d18b Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Sat, 9 Jan 2016 20:32:10 -0500 Subject: [PATCH 2/3] Refactor TvMainActivity to MVP architecture --- .../dolphinemu/activities/TvMainActivity.java | 142 ++++++++---------- .../dolphinemu/ui/main/MainActivity.java | 9 +- .../dolphinemu/ui/main/MainPresenter.java | 31 ++++ .../dolphinemu/ui/main/MainView.java | 4 + 4 files changed, 105 insertions(+), 81 deletions(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/TvMainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/TvMainActivity.java index c7724519541c..23ad7230da47 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/TvMainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/TvMainActivity.java @@ -28,12 +28,15 @@ import org.dolphinemu.dolphinemu.model.TvSettingsItem; import org.dolphinemu.dolphinemu.ui.main.MainActivity; import org.dolphinemu.dolphinemu.ui.main.MainPresenter; +import org.dolphinemu.dolphinemu.ui.main.MainView; import org.dolphinemu.dolphinemu.utils.StartupHandler; import org.dolphinemu.dolphinemu.viewholders.TvGameViewHolder; -public final class TvMainActivity extends Activity +public final class TvMainActivity extends Activity implements MainView { - protected BrowseFragment mBrowseFragment; + private MainPresenter mPresenter = new MainPresenter(this); + + private BrowseFragment mBrowseFragment; private ArrayObjectAdapter mRowsAdapter; @@ -56,6 +59,8 @@ protected void onCreate(Bundle savedInstanceState) buildRowsAdapter(); + mPresenter.onCreate(); + mBrowseFragment.setOnItemViewClickedListener( new OnItemViewClickedListener() { @@ -66,34 +71,7 @@ public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowP if (item instanceof TvSettingsItem) { TvSettingsItem settingsItem = (TvSettingsItem) item; - - switch (settingsItem.getItemId()) - { - case R.id.menu_refresh: - getContentResolver().insert(GameProvider.URI_REFRESH, null); - - // TODO Let the Activity know the data is refreshed in some other, better way. - recreate(); - break; - - case R.id.menu_settings: - // Launch the Settings Actvity. - Intent settings = new Intent(TvMainActivity.this, SettingsActivity.class); - startActivity(settings); - break; - - case R.id.button_add_directory: - Intent fileChooser = new Intent(TvMainActivity.this, AddDirectoryActivity.class); - - // The second argument to this method is read below in onActivityResult(). - startActivityForResult(fileChooser, MainPresenter.REQUEST_ADD_DIRECTORY); - - break; - - default: - Toast.makeText(TvMainActivity.this, "Unimplemented menu option.", Toast.LENGTH_SHORT).show(); - break; - } + mPresenter.handleOptionSelection(settingsItem.getItemId()); } else { @@ -120,6 +98,56 @@ public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowP StartupHandler.HandleInit(this); } + /** + * MainView + */ + + @Override + public void setSubtitle(String subtitle) + { + // No-op + } + + @Override + public void refresh() + { + recreate(); + } + + @Override + public void refreshFragmentScreenshot(int fragmentPosition) + { + // No-op (For now) + } + + @Override + public void launchSettingsActivity() + { + Intent settings = new Intent(this, SettingsActivity.class); + startActivity(settings); + } + + @Override + public void launchFileListActivity() + { + Intent fileChooser = new Intent(this, AddDirectoryActivity.class); + + // The second argument to this method is read below in onActivityResult(). + startActivityForResult(fileChooser, MainPresenter.REQUEST_ADD_DIRECTORY); + } + + @Override + public void showGames(int platformIndex, Cursor games) + { + ListRow row = buildGamesRow(platformIndex, games); + + // Add row to the adapter only if it is not empty. + if (row != null) + { + mRowsAdapter.add(row); + } + } + /** * Callback from AddDirectoryActivity. Applies any changes necessary to the GameGridActivity. * @@ -130,22 +158,7 @@ public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowP @Override protected void onActivityResult(int requestCode, int resultCode, Intent result) { - switch (requestCode) - { - case MainPresenter.REQUEST_ADD_DIRECTORY: - // 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 == MainPresenter.REQUEST_ADD_DIRECTORY) - { - // TODO Let the Activity know the data is refreshed in some other, better way. - recreate(); - } - } - break; - } + mPresenter.handleActivityResult(requestCode, resultCode); } private void buildRowsAdapter() @@ -155,50 +168,19 @@ private void buildRowsAdapter() // For each platform for (int platformIndex = 0; platformIndex <= Game.PLATFORM_ALL; ++platformIndex) { - ListRow row = buildGamesRow(platformIndex); - - // Add row to the adapter only if it is not empty. - if (row != null) - { - mRowsAdapter.add(row); - } + mPresenter.loadGames(platformIndex); } - ListRow settingsRow = buildSettingsRow(); - mRowsAdapter.add(settingsRow); + mRowsAdapter.add(buildSettingsRow()); mBrowseFragment.setAdapter(mRowsAdapter); } - private ListRow buildGamesRow(int platform) + private ListRow buildGamesRow(int platform, Cursor games) { // Create an adapter for this row. CursorObjectAdapter row = new CursorObjectAdapter(new GameRowPresenter()); - Cursor games; - if (platform == Game.PLATFORM_ALL) - { - // Get all games. - games = getContentResolver().query( - GameProvider.URI_GAME, // URI of table to query - null, // Return all columns - null, // Return all games - null, // Return all games - GameDatabase.KEY_GAME_TITLE + " asc" // Sort by game name, ascending order - ); - } - else - { - // Get games for this particular platform. - games = getContentResolver().query( - GameProvider.URI_GAME, // URI of table to query - null, // Return all columns - GameDatabase.KEY_GAME_PLATFORM + " = ?", // Select by platform - new String[]{Integer.toString(platform)}, // Platform id - GameDatabase.KEY_GAME_TITLE + " asc" // Sort by game name, ascending order - ); - } - // If cursor is empty, don't return a Row. if (!games.moveToFirst()) { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java index ac2bfe525865..1044266acf32 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java @@ -1,6 +1,7 @@ package org.dolphinemu.dolphinemu.ui.main; import android.content.Intent; +import android.database.Cursor; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; @@ -124,12 +125,18 @@ public void launchSettingsActivity() @Override public void launchFileListActivity() { - Intent fileChooser = new Intent(MainActivity.this, AddDirectoryActivity.class); + Intent fileChooser = new Intent(this, AddDirectoryActivity.class); // The second argument to this method is read below in onActivityResult(). startActivityForResult(fileChooser, MainPresenter.REQUEST_ADD_DIRECTORY); } + @Override + public void showGames(int platformIndex, Cursor games) + { + // no-op. Handled by PlatformGamesFragment. + } + /** * Callback from AddDirectoryActivity. Applies any changes necessary to the GameGridActivity. * diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java index 992b242d881c..d744d06f1b64 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java @@ -2,14 +2,23 @@ import android.content.Intent; +import android.database.Cursor; +import android.util.Log; +import org.dolphinemu.dolphinemu.DolphinApplication; import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity; import org.dolphinemu.dolphinemu.activities.SettingsActivity; import org.dolphinemu.dolphinemu.fragments.PlatformGamesFragment; +import org.dolphinemu.dolphinemu.model.GameDatabase; import org.dolphinemu.dolphinemu.model.GameProvider; import org.dolphinemu.dolphinemu.ui.main.MainView; +import rx.android.schedulers.AndroidSchedulers; +import rx.functions.Action1; +import rx.schedulers.Schedulers; + public class MainPresenter { public static final int REQUEST_ADD_DIRECTORY = 1; @@ -44,6 +53,10 @@ public boolean handleOptionSelection(int itemId) { case R.id.menu_refresh: mView.refresh(); return true; + + case R.id.button_add_directory: + mView.launchFileListActivity(); + return true; } return false; @@ -65,4 +78,22 @@ public void handleActivityResult(int requestCode, int resultCode) { break; } } + + public void loadGames(final int platformIndex) + { + GameDatabase databaseHelper = DolphinApplication.databaseHelper; + + databaseHelper.getGamesForPlatform(platformIndex) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Action1() + { + @Override + public void call(Cursor games) + { + mView.showGames(platformIndex, games); + } + } + ); + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java index 4c8b26f306ba..a29150f207f9 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java @@ -1,6 +1,8 @@ package org.dolphinemu.dolphinemu.ui.main; +import android.database.Cursor; + public interface MainView { void setSubtitle(String subtitle); @@ -12,4 +14,6 @@ public interface MainView void launchSettingsActivity(); void launchFileListActivity(); + + void showGames(int platformIndex, Cursor games); } From a455305c23fba35b8da57515072ab707f777d7ac Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Sat, 9 Jan 2016 20:52:59 -0500 Subject: [PATCH 3/3] Refactor AddDirectoryActivity and SettingsActivity to be launched exclusively via their own launcher method --- .../activities/AddDirectoryActivity.java | 8 +++++ .../activities/SettingsActivity.java | 7 ++++ .../dolphinemu/activities/TvMainActivity.java | 14 ++------ .../dolphinemu/adapters/GameAdapter.java | 1 - .../dolphinemu/ui/main/MainActivity.java | 13 +++----- .../dolphinemu/ui/main/MainPresenter.java | 20 +++++------- .../dolphinemu/ui/main/MainView.java | 32 +++++++++++++++++-- 7 files changed, 60 insertions(+), 35 deletions(-) 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 f9308fc80e17..09e833d1addb 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,5 +1,6 @@ package org.dolphinemu.dolphinemu.activities; +import android.app.Activity; import android.content.AsyncQueryHandler; import android.content.ContentValues; import android.content.Intent; @@ -19,6 +20,7 @@ import org.dolphinemu.dolphinemu.adapters.FileAdapter; import org.dolphinemu.dolphinemu.model.GameDatabase; import org.dolphinemu.dolphinemu.model.GameProvider; +import org.dolphinemu.dolphinemu.ui.main.MainPresenter; /** * An Activity that shows a list of files and folders, allowing the user to tell the app which folder(s) @@ -131,4 +133,10 @@ public void updateSubtitle(String path) { mToolbar.setSubtitle(path); } + + public static void launch(Activity activity) + { + Intent fileChooser = new Intent(activity, AddDirectoryActivity.class); + activity.startActivityForResult(fileChooser, MainPresenter.REQUEST_ADD_DIRECTORY); + } } 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 a595cdeb0f25..c6ce27acfeaa 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,6 +1,7 @@ package org.dolphinemu.dolphinemu.activities; +import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; @@ -38,4 +39,10 @@ protected void onStop() Intent settingsSaver = new Intent(this, SettingsSaveService.class); startService(settingsSaver); } + + public static void launch(Context context) + { + Intent settings = new Intent(context, SettingsActivity.class); + context.startActivity(settings); + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/TvMainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/TvMainActivity.java index 23ad7230da47..6d580eaafb82 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/TvMainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/TvMainActivity.java @@ -17,16 +17,12 @@ import android.support.v17.leanback.widget.Presenter; import android.support.v17.leanback.widget.Row; import android.support.v17.leanback.widget.RowPresenter; -import android.widget.Toast; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.adapters.GameRowPresenter; import org.dolphinemu.dolphinemu.adapters.SettingsRowPresenter; import org.dolphinemu.dolphinemu.model.Game; -import org.dolphinemu.dolphinemu.model.GameDatabase; -import org.dolphinemu.dolphinemu.model.GameProvider; import org.dolphinemu.dolphinemu.model.TvSettingsItem; -import org.dolphinemu.dolphinemu.ui.main.MainActivity; import org.dolphinemu.dolphinemu.ui.main.MainPresenter; import org.dolphinemu.dolphinemu.ui.main.MainView; import org.dolphinemu.dolphinemu.utils.StartupHandler; @@ -103,7 +99,7 @@ public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowP */ @Override - public void setSubtitle(String subtitle) + public void setVersionString(String version) { // No-op } @@ -123,17 +119,13 @@ public void refreshFragmentScreenshot(int fragmentPosition) @Override public void launchSettingsActivity() { - Intent settings = new Intent(this, SettingsActivity.class); - startActivity(settings); + SettingsActivity.launch(this); } @Override public void launchFileListActivity() { - Intent fileChooser = new Intent(this, AddDirectoryActivity.class); - - // The second argument to this method is read below in onActivityResult(). - startActivityForResult(fileChooser, MainPresenter.REQUEST_ADD_DIRECTORY); + AddDirectoryActivity.launch(this); } @Override diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java index 2a0b0783c047..205447e0543a 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java @@ -17,7 +17,6 @@ import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.activities.EmulationActivity; -import org.dolphinemu.dolphinemu.ui.main.MainActivity; import org.dolphinemu.dolphinemu.dialogs.GameDetailsDialog; import org.dolphinemu.dolphinemu.model.GameDatabase; import org.dolphinemu.dolphinemu.ui.main.MainPresenter; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java index 1044266acf32..372edd324942 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java @@ -14,7 +14,6 @@ import android.view.MenuItem; import android.view.View; -import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity; import org.dolphinemu.dolphinemu.activities.SettingsActivity; @@ -91,9 +90,9 @@ public boolean onCreateOptionsMenu(Menu menu) */ @Override - public void setSubtitle(String subtitle) + public void setVersionString(String version) { - mToolbar.setSubtitle(subtitle); + mToolbar.setSubtitle(version); } @Override @@ -118,17 +117,13 @@ public void refreshFragmentScreenshot(int fragmentPosition) @Override public void launchSettingsActivity() { - Intent settings = new Intent(this, SettingsActivity.class); - startActivity(settings); + SettingsActivity.launch(this); } @Override public void launchFileListActivity() { - Intent fileChooser = new Intent(this, AddDirectoryActivity.class); - - // The second argument to this method is read below in onActivityResult(). - startActivityForResult(fileChooser, MainPresenter.REQUEST_ADD_DIRECTORY); + AddDirectoryActivity.launch(this); } @Override diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java index d744d06f1b64..97b7a39f25ef 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java @@ -1,25 +1,18 @@ package org.dolphinemu.dolphinemu.ui.main; -import android.content.Intent; import android.database.Cursor; -import android.util.Log; import org.dolphinemu.dolphinemu.DolphinApplication; import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; -import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity; -import org.dolphinemu.dolphinemu.activities.SettingsActivity; -import org.dolphinemu.dolphinemu.fragments.PlatformGamesFragment; import org.dolphinemu.dolphinemu.model.GameDatabase; -import org.dolphinemu.dolphinemu.model.GameProvider; -import org.dolphinemu.dolphinemu.ui.main.MainView; import rx.android.schedulers.AndroidSchedulers; import rx.functions.Action1; import rx.schedulers.Schedulers; -public class MainPresenter +public final class MainPresenter { public static final int REQUEST_ADD_DIRECTORY = 1; public static final int REQUEST_EMULATE_GAME = 2; @@ -36,14 +29,16 @@ public void onCreate() // TODO Rather than calling into native code, this should use the commented line below. // String versionName = BuildConfig.VERSION_NAME; String versionName = NativeLibrary.GetVersionString(); - mView.setSubtitle(versionName); + mView.setVersionString(versionName); } - public void onFabClick() { + public void onFabClick() + { mView.launchFileListActivity(); } - public boolean handleOptionSelection(int itemId) { + public boolean handleOptionSelection(int itemId) + { switch (itemId) { case R.id.menu_settings: @@ -62,7 +57,8 @@ public boolean handleOptionSelection(int itemId) { return false; } - public void handleActivityResult(int requestCode, int resultCode) { + public void handleActivityResult(int requestCode, int resultCode) + { switch (requestCode) { case REQUEST_ADD_DIRECTORY: diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java index a29150f207f9..1d286bebf3d2 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java @@ -3,17 +3,45 @@ import android.database.Cursor; +/** + * Abstraction for the screen that shows on application launch. + * Implementations will differ primarily to target touch-screen + * or non-touch screen devices. + */ public interface MainView { - void setSubtitle(String subtitle); - + /** + * Pass the view the native library's version string. Displaying + * it is optional. + * + * @param version A string pulled from native code. + */ + void setVersionString(String version); + + /** + * Tell the view to refresh its contents. + */ void refresh(); + /** + * Tell the view to tell the currently displayed {@link android.support.v4.app.Fragment} + * to refresh the screenshot at the given position in its list of games. + * + * @param fragmentPosition An index corresponding to the list or grid of games. + */ void refreshFragmentScreenshot(int fragmentPosition); + void launchSettingsActivity(); void launchFileListActivity(); + /** + * To be called when an asynchronous database read completes. Passes the + * result, in this case a {@link Cursor} to the view. + * + * @param platformIndex Which platform contains these games. + * @param games A Cursor containing the games read from the database. + */ void showGames(int platformIndex, Cursor games); }