From a4395ecd75e52756bb3c6db9f991e8ab2305df35 Mon Sep 17 00:00:00 2001 From: Eder Bastos Date: Fri, 8 May 2015 19:54:56 -0400 Subject: Have Picasso load images into memory at the size they will be displayed. --- .../src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java | 2 ++ .../main/java/org/dolphinemu/dolphinemu/dialogs/GameDetailsDialog.java | 2 ++ 2 files changed, 4 insertions(+) (limited to 'Source/Android/app/src/main/java') 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 30bc9daad6..d868ed46de 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 @@ -64,6 +64,8 @@ public class GameAdapter extends RecyclerView.Adapter // Fill in the view contents. Picasso.with(holder.imageScreenshot.getContext()) .load(game.getScreenPath()) + .fit() + .centerCrop() .error(R.drawable.no_banner) .into(holder.imageScreenshot); 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 19c6621345..e22b30ea18 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 @@ -84,6 +84,8 @@ public class GameDetailsDialog extends DialogFragment // Fill in the view contents. Picasso.with(imageGameScreen.getContext()) .load(getArguments().getString(ARGUMENT_GAME_SCREENSHOT_PATH)) + .fit() + .centerCrop() .noFade() .noPlaceholder() .into(imageGameScreen); -- cgit v1.2.3 From 24c6be9d0f8dfddc84898cd02c2b98c34f444712 Mon Sep 17 00:00:00 2001 From: Eder Bastos Date: Sat, 9 May 2015 12:36:17 -0400 Subject: Add File Browser screen to new UI. --- .../activities/AddDirectoryActivity.java | 96 ++++++++++++ .../dolphinemu/activities/GameGridActivity.java | 118 +++++++++------ .../dolphinemu/adapters/FileAdapter.java | 161 +++++++++++++++++++++ .../dolphinemu/adapters/GameAdapter.java | 7 +- .../dolphinemu/dolphinemu/model/FileListItem.java | 81 +++++++++++ .../dolphinemu/viewholders/FileViewHolder.java | 27 ++++ 6 files changed, 448 insertions(+), 42 deletions(-) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/FileListItem.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/viewholders/FileViewHolder.java (limited to 'Source/Android/app/src/main/java') 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 new file mode 100644 index 0000000000..3a282f6433 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java @@ -0,0 +1,96 @@ +package org.dolphinemu.dolphinemu.activities; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.os.Environment; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.widget.Toolbar; + +import org.dolphinemu.dolphinemu.BuildConfig; +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.adapters.FileAdapter; + +public class AddDirectoryActivity extends Activity implements FileAdapter.FileClickListener +{ + public static final String KEY_CURRENT_PATH = BuildConfig.APPLICATION_ID + ".path"; + + private FileAdapter mAdapter; + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_add_directory); + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_folder_list); + setActionBar(toolbar); + + RecyclerView recyclerView = (RecyclerView) findViewById(R.id.list_files); + + // Specifying the LayoutManager determines how the RecyclerView arranges views. + RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); + recyclerView.setLayoutManager(layoutManager); + + String path; + // Stuff in this block only happens when this activity is newly created (i.e. not a rotation) + if (savedInstanceState == null) + { + path = Environment.getExternalStorageDirectory().getPath(); + } else + { + // Get the path we were looking at before we rotated. + path = savedInstanceState.getString(KEY_CURRENT_PATH); + } + + mAdapter = new FileAdapter(path, this); + recyclerView.setAdapter(mAdapter); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) + { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.menu_add_directory, menu); + + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + switch (item.getItemId()) + { + case R.id.menu_up_one_level: + mAdapter.setPath(mAdapter.getPath() + "/.."); + break; + } + + return super.onOptionsItemSelected(item); + } + + @Override + protected void onSaveInstanceState(Bundle outState) + { + super.onSaveInstanceState(outState); + + // Save the path we're looking at so when rotation is done, we start from same folder. + outState.putString(KEY_CURRENT_PATH, mAdapter.getPath()); + } + + @Override + public void finishSuccessfully() + { + Intent resultData = new Intent(); + + resultData.putExtra(KEY_CURRENT_PATH, mAdapter.getPath()); + setResult(RESULT_OK, resultData); + + finish(); + } +} 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 be0fbbed1a..14633d1277 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 @@ -2,13 +2,21 @@ package org.dolphinemu.dolphinemu.activities; import android.app.Activity; import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.net.Uri; import android.os.Bundle; import android.os.Environment; +import android.preference.PreferenceManager; +import android.provider.DocumentsContract; +import android.provider.OpenableColumns; 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.View; +import android.widget.ImageButton; import android.widget.Toolbar; import org.dolphinemu.dolphinemu.AssetCopyService; @@ -24,11 +32,11 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; -public class GameGridActivity extends Activity +public final class GameGridActivity extends Activity { - private RecyclerView mRecyclerView; - private RecyclerView.Adapter mAdapter; - private RecyclerView.LayoutManager mLayoutManager; + private static final int REQUEST_ADD_DIRECTORY = 1; + + private GameAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) @@ -39,21 +47,32 @@ public class GameGridActivity extends Activity Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_game_list); setActionBar(toolbar); - mRecyclerView = (RecyclerView) findViewById(R.id.grid_games); + ImageButton buttonAddDirectory = (ImageButton) findViewById(R.id.button_add_directory); + RecyclerView recyclerView = (RecyclerView) findViewById(R.id.grid_games); // use this setting to improve performance if you know that changes // in content do not change the layout size of the RecyclerView //mRecyclerView.setHasFixedSize(true); // Specifying the LayoutManager determines how the RecyclerView arranges views. - mLayoutManager = new GridLayoutManager(this, 4); - mRecyclerView.setLayoutManager(mLayoutManager); + RecyclerView.LayoutManager layoutManager = new GridLayoutManager(this, 4); + recyclerView.setLayoutManager(layoutManager); - mRecyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8)); + recyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8)); // Create an adapter that will relate the dataset to the views on-screen. mAdapter = new GameAdapter(getGameList()); - mRecyclerView.setAdapter(mAdapter); + recyclerView.setAdapter(mAdapter); + + buttonAddDirectory.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View view) + { + Intent fileChooser = new Intent(GameGridActivity.this, AddDirectoryActivity.class); + 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) @@ -64,11 +83,33 @@ public class GameGridActivity extends Activity } } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent result) + { + if (resultCode == RESULT_OK) + { + if (requestCode == REQUEST_ADD_DIRECTORY) + { + String path = result.getStringExtra(AddDirectoryActivity.KEY_CURRENT_PATH); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + SharedPreferences.Editor editor = prefs.edit(); + + editor.putString(AddDirectoryActivity.KEY_CURRENT_PATH, path); + + // Using commit in order to block so the next method has the correct data to load. + editor.commit(); + + mAdapter.setGameList(getGameList()); + } + } + } + @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.gamelist_menu, menu); + inflater.inflate(R.menu.menu_game_grid, menu); return true; } @@ -82,48 +123,43 @@ public class GameGridActivity extends Activity NativeLibrary.SetUserDirectory(DefaultDir); - String Directories = NativeLibrary.GetConfig("Dolphin.ini", "General", "ISOPaths", "0"); - Log.v("DolphinEmu", "Directories: " + Directories); - int intDirectories = Integer.parseInt(Directories); - // Extensions to filter by. Set exts = new HashSet(Arrays.asList(".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".wad", ".wbfs")); - for (int a = 0; a < intDirectories; ++a) - { - String BrowseDir = NativeLibrary.GetConfig("Dolphin.ini", "General", "ISOPath" + a, ""); - Log.v("DolphinEmu", "Directory " + a + ": " + BrowseDir); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + + String path = prefs.getString(AddDirectoryActivity.KEY_CURRENT_PATH, "/"); - File currentDir = new File(BrowseDir); - File[] dirs = currentDir.listFiles(); - try + File currentDir = new File(path); + File[] dirs = currentDir.listFiles(); + try + { + for (File entry : dirs) { - for (File entry : dirs) + if (!entry.isHidden() && !entry.isDirectory()) { - if (!entry.isHidden() && !entry.isDirectory()) - { - String entryName = entry.getName(); - - // Check that the file has an appropriate extension before trying to read out of it. - if (exts.contains(entryName.toLowerCase().substring(entryName.lastIndexOf('.')))) - { - GcGame game = new GcGame(NativeLibrary.GetTitle(entry.getAbsolutePath()), - NativeLibrary.GetDescription(entry.getAbsolutePath()).replace("\n", " "), - // TODO Some games might actually not be from this region, believe it or not. - "United States", - entry.getAbsolutePath(), - NativeLibrary.GetGameId(entry.getAbsolutePath()), - NativeLibrary.GetDate(entry.getAbsolutePath())); - - gameList.add(game); - } + String entryName = entry.getName(); + // Check that the file has an appropriate extension before trying to read out of it. + if (exts.contains(entryName.toLowerCase().substring(entryName.lastIndexOf('.')))) + { + GcGame game = new GcGame(NativeLibrary.GetTitle(entry.getAbsolutePath()), + NativeLibrary.GetDescription(entry.getAbsolutePath()).replace("\n", " "), + // TODO Some games might actually not be from this region, believe it or not. + "United States", + entry.getAbsolutePath(), + NativeLibrary.GetGameId(entry.getAbsolutePath()), + NativeLibrary.GetDate(entry.getAbsolutePath())); + + gameList.add(game); } } - } catch (Exception ignored) - { + } + } catch (Exception ignored) + { + } return gameList; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java new file mode 100644 index 0000000000..7f4acf6abe --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java @@ -0,0 +1,161 @@ +package org.dolphinemu.dolphinemu.adapters; + +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.model.FileListItem; +import org.dolphinemu.dolphinemu.viewholders.FileViewHolder; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; + +public class FileAdapter extends RecyclerView.Adapter implements View.OnClickListener +{ + private ArrayList mFileList; + + private String mPath; + + private FileClickListener mListener; + + /** + * Initializes the dataset to be displayed, and associates the Adapter with the + * Activity as an event listener. + * + * @param gameList + */ + public FileAdapter(String path, FileClickListener listener) + { + mFileList = generateFileList(new File(path)); + mListener = listener; + } + + /** + * Called by the LayoutManager when it is necessary to create a new view. + * + * @param parent The RecyclerView (I think?) the created view will be thrown into. + * @param viewType Not used here, but useful when more than one type of child will be used in the RecyclerView. + * @return The created ViewHolder with references to all the child view's members. + */ + @Override + public FileViewHolder onCreateViewHolder(ViewGroup parent, int viewType) + { + // Create a new view. + View listItem = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.list_item_file, parent, false); + + listItem.setOnClickListener(this); + + // Use that view to create a ViewHolder. + return new FileViewHolder(listItem); + } + + /** + * Called by the LayoutManager when a new view is not necessary because we can recycle + * an existing one (for example, if a view just scrolled onto the screen from the bottom, we + * can use the view that just scrolled off the top instead of inflating a new one.) + * + * @param holder A ViewHolder representing the view we're recycling. + * @param position The position of the 'new' view in the dataset. + */ + @Override + public void onBindViewHolder(FileViewHolder holder, int position) + { + // Get a reference to the item from the dataset; we'll use this to fill in the view contents. + final FileListItem file = mFileList.get(position); + + // Fill in the view contents. + switch (file.getType()) + { + case FileListItem.TYPE_FOLDER: + holder.imageType.setImageResource(R.drawable.ic_folder); + break; + + case FileListItem.TYPE_GC: + holder.imageType.setImageResource(R.drawable.ic_gamecube); + break; + + case FileListItem.TYPE_WII: + holder.imageType.setImageResource(R.drawable.ic_wii); + break; + + case FileListItem.TYPE_OTHER: + holder.imageType.setImageResource(android.R.color.transparent); + break; + } + + holder.textFileName.setText(file.getFilename()); + holder.itemView.setTag(file.getPath()); + } + + /** + * Called by the LayoutManager to find out how much data we have. + * + * @return Size of the dataset. + */ + @Override + public int getItemCount() + { + return mFileList.size(); + } + + @Override + public void onClick(View view) + { + String path = (String) view.getTag(); + + File clickedFile = new File(path); + + if (clickedFile.isDirectory()) + { + mFileList = generateFileList(clickedFile); + notifyDataSetChanged(); + } else + { + // Pass the activity the path of the parent directory of the clicked file. + mListener.finishSuccessfully(); + } + } + + private ArrayList generateFileList(File directory) + { + File[] children = directory.listFiles(); + ArrayList fileList = new ArrayList(children.length); + + for (File child : children) + { + if (!child.isHidden()) + { + FileListItem item = new FileListItem(child); + fileList.add(item); + } + } + + mPath = directory.getAbsolutePath(); + + Collections.sort(fileList); + return fileList; + } + + public String getPath() + { + return mPath; + } + + public void setPath(String path) + { + mPath = path; + File parentDirectory = new File(path); + + mFileList = generateFileList(parentDirectory); + notifyDataSetChanged(); + } + + public static interface FileClickListener + { + public void finishSuccessfully(); + } +} 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 d868ed46de..bf7bf435b7 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 @@ -79,7 +79,6 @@ public class GameAdapter extends RecyclerView.Adapter holder.path = game.getPath(); holder.screenshotPath = game.getScreenPath(); holder.game = game; - } /** @@ -112,4 +111,10 @@ public class GameAdapter extends RecyclerView.Adapter } } + + public void setGameList(ArrayList gameList) + { + mGameList = gameList; + notifyDataSetChanged(); + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/FileListItem.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/FileListItem.java new file mode 100644 index 0000000000..e15516dbaf --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/FileListItem.java @@ -0,0 +1,81 @@ +package org.dolphinemu.dolphinemu.model; + + +import org.dolphinemu.dolphinemu.NativeLibrary; + +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class FileListItem implements Comparable +{ + public static final int TYPE_FOLDER = 0; + public static final int TYPE_GC = 1; + public static final int TYPE_WII = 2; + public static final int TYPE_OTHER = 3; + + private int mType; + private String mFilename; + private String mPath; + + public FileListItem(File file) + { + mPath = file.getAbsolutePath(); + + if (file.isDirectory()) + { + mType = TYPE_FOLDER; + } else + { + String fileExtension = mPath.substring(mPath.lastIndexOf('.')); + + // Extensions to filter by. + Set allowedExtensions = new HashSet(Arrays.asList(".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".wad", ".wbfs")); + + // Check that the file has an appropriate extension before trying to read out of it. + if (allowedExtensions.contains(fileExtension)) + { + mType = NativeLibrary.IsWiiTitle(mPath) ? TYPE_WII : TYPE_GC; + } else + { + mType = TYPE_OTHER; + } + } + + mFilename = file.getName(); + } + + public int getType() + { + return mType; + } + + public String getFilename() + { + return mFilename; + } + + public String getPath() + { + return mPath; + } + + @Override + public int compareTo(FileListItem theOther) + { + if (theOther.getType() == getType()) + { + return getFilename().toLowerCase().compareTo(theOther.getFilename().toLowerCase()); + } else + { + if (getType() > theOther.getType()) + { + return 1; + } else + { + return -1; + } + } + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/viewholders/FileViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/viewholders/FileViewHolder.java new file mode 100644 index 0000000000..79acc8400b --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/viewholders/FileViewHolder.java @@ -0,0 +1,27 @@ +package org.dolphinemu.dolphinemu.viewholders; + +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import org.dolphinemu.dolphinemu.R; + + +public class FileViewHolder extends RecyclerView.ViewHolder +{ + public View itemView; + + public TextView textFileName; + public ImageView imageType; + + public FileViewHolder(View itemView) + { + super(itemView); + + this.itemView = itemView; + + textFileName = (TextView) itemView.findViewById(R.id.text_file_name); + imageType = (ImageView) itemView.findViewById(R.id.image_type); + } +} -- cgit v1.2.3 From 3f1465196c7ea13a99517ddcdcd56f75d4359f99 Mon Sep 17 00:00:00 2001 From: Eder Bastos Date: Sun, 10 May 2015 10:29:29 -0400 Subject: Add touch feedback to GameGridActivity and AddDirectoryActivity. --- .../dolphinemu/adapters/FileAdapter.java | 50 ++++++++++++++++++--- .../dolphinemu/adapters/GameAdapter.java | 52 ++++++++++++++++++++-- .../dolphinemu/viewholders/GameViewHolder.java | 47 +------------------ 3 files changed, 95 insertions(+), 54 deletions(-) (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java index 7f4acf6abe..2414883279 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java @@ -4,6 +4,7 @@ import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Toast; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.model.FileListItem; @@ -102,8 +103,14 @@ public class FileAdapter extends RecyclerView.Adapter implements return mFileList.size(); } + /** + * When a file is clicked, determine if it is a directory; if it is, show that new directory's + * contents. If it is not, end the activity successfully. + * + * @param view + */ @Override - public void onClick(View view) + public void onClick(final View view) { String path = (String) view.getTag(); @@ -111,8 +118,26 @@ public class FileAdapter extends RecyclerView.Adapter implements if (clickedFile.isDirectory()) { - mFileList = generateFileList(clickedFile); - notifyDataSetChanged(); + final ArrayList fileList = generateFileList(clickedFile); + + if (fileList.isEmpty()) + { + Toast.makeText(view.getContext(), R.string.add_directory_empty_folder, Toast.LENGTH_SHORT).show(); + } else + { + // Delay the loading of the new directory to give a little bit of time for UI feedback + // to happen. Hacky, but good enough for now; this is necessary because we're modifying + // the RecyclerView's contents, rather than constructing a new one. + view.getHandler().postDelayed(new Runnable() + { + @Override + public void run() + { + mFileList = fileList; + notifyDataSetChanged(); + } + }, 200); + } } else { // Pass the activity the path of the parent directory of the clicked file. @@ -120,6 +145,12 @@ public class FileAdapter extends RecyclerView.Adapter implements } } + /** + * For a given directory, return a list of Files it contains. + * + * @param directory + * @return + */ private ArrayList generateFileList(File directory) { File[] children = directory.listFiles(); @@ -145,6 +176,12 @@ public class FileAdapter extends RecyclerView.Adapter implements return mPath; } + /** + * Mostly just allows the activity's menu option to kick us up a level in the directory + * structure. + * + * @param path + */ public void setPath(String path) { mPath = path; @@ -154,8 +191,11 @@ public class FileAdapter extends RecyclerView.Adapter implements notifyDataSetChanged(); } - public static interface FileClickListener + /** + * Callback for when the user wants to add the visible directory to the library. + */ + public interface FileClickListener { - public void finishSuccessfully(); + void finishSuccessfully(); } } 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 bf7bf435b7..883107a410 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 @@ -1,5 +1,7 @@ package org.dolphinemu.dolphinemu.adapters; +import android.app.Activity; +import android.content.Intent; import android.graphics.Rect; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -9,12 +11,16 @@ import android.view.ViewGroup; import com.squareup.picasso.Picasso; import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.dialogs.GameDetailsDialog; +import org.dolphinemu.dolphinemu.emulation.EmulationActivity; import org.dolphinemu.dolphinemu.model.Game; import org.dolphinemu.dolphinemu.viewholders.GameViewHolder; import java.util.ArrayList; -public class GameAdapter extends RecyclerView.Adapter +public class GameAdapter extends RecyclerView.Adapter implements + View.OnClickListener, + View.OnLongClickListener { private ArrayList mGameList; @@ -42,6 +48,9 @@ public class GameAdapter extends RecyclerView.Adapter View gameCard = LayoutInflater.from(parent.getContext()) .inflate(R.layout.card_game, parent, false); + gameCard.setOnClickListener(this); + gameCard.setOnLongClickListener(this); + // Use that view to create a ViewHolder. GameViewHolder holder = new GameViewHolder(gameCard); return holder; @@ -74,7 +83,6 @@ public class GameAdapter extends RecyclerView.Adapter { holder.textDescription.setText(game.getDescription()); } - holder.buttonDetails.setTag(game.getGameId()); holder.path = game.getPath(); holder.screenshotPath = game.getScreenPath(); @@ -92,6 +100,45 @@ public class GameAdapter extends RecyclerView.Adapter return mGameList.size(); } + /** + * Launches the game that was clicked on. + * + * @param view The card representing the game the user wants to play. + */ + @Override + public void onClick(View view) + { + GameViewHolder holder = (GameViewHolder) view.getTag(); + + // Start the emulation activity and send the path of the clicked ISO to it. + Intent intent = new Intent(view.getContext(), EmulationActivity.class); + + intent.putExtra("SelectedGame", holder.path); + + view.getContext().startActivity(intent); + } + + /** + * Launches the details activity for this Game, using an ID stored in the + * details button's Tag. + * + * @param view The Card button that was long-clicked. + */ + @Override + public boolean onLongClick(View view) + { + GameViewHolder holder = (GameViewHolder) view.getTag(); + + // Get the ID of the game we want to look at. + // TODO This should be all we need to pass in, eventually. + // String gameId = (String) holder.gameId; + + Activity activity = (Activity) view.getContext(); + GameDetailsDialog.newInstance(holder.game).show(activity.getFragmentManager(), "game_details"); + + return true; + } + public static class SpacesItemDecoration extends RecyclerView.ItemDecoration { private int space; @@ -108,7 +155,6 @@ public class GameAdapter extends RecyclerView.Adapter outRect.right = space; outRect.bottom = space; outRect.top = space; - } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/viewholders/GameViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/viewholders/GameViewHolder.java index 47acf588de..18e271e0f5 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/viewholders/GameViewHolder.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/viewholders/GameViewHolder.java @@ -19,7 +19,6 @@ public class GameViewHolder extends RecyclerView.ViewHolder public ImageView imageScreenshot; public TextView textGameTitle; public TextView textDescription; - public ImageButton buttonDetails; // Used to handle onClick(). Set this in onBindViewHolder(). public String path; @@ -30,54 +29,10 @@ public class GameViewHolder extends RecyclerView.ViewHolder { super(itemView); - itemView.setOnClickListener(mCardClickListener); + itemView.setTag(this); imageScreenshot = (ImageView) itemView.findViewById(R.id.image_game_screen); textGameTitle = (TextView) itemView.findViewById(R.id.text_game_title); textDescription = (TextView) itemView.findViewById(R.id.text_game_description); - buttonDetails = (ImageButton) itemView.findViewById(R.id.button_details); - - buttonDetails.setOnClickListener(mDetailsButtonListener); } - - private View.OnClickListener mCardClickListener = new View.OnClickListener() - { - /** - * Launches the game that was clicked on. - * - * @param view The card representing the game the user wants to play. - */ - @Override - public void onClick(View view) - { - // Start the emulation activity and send the path of the clicked ROM to it. - Intent intent = new Intent(view.getContext(), EmulationActivity.class); - - intent.putExtra("SelectedGame", path); - - view.getContext().startActivity(intent); - } - }; - - private View.OnClickListener mDetailsButtonListener = new View.OnClickListener() - { - - /** - * Launches the details activity for this Game, using an ID stored in the - * details button's Tag. - * - * @param view The Details button that was clicked on. - */ - @Override - public void onClick(View view) - { - // Get the ID of the game we want to look at. - // TODO This should be all we need to pass in, eventually. - // String gameId = (String) view.getTag(); - - Activity activity = (Activity) view.getContext(); - GameDetailsDialog.newInstance(game).show(activity.getFragmentManager(), "game_details"); - } - }; - } -- cgit v1.2.3 From ca4bec35399185dc57e250b54d5308abbc4f464e Mon Sep 17 00:00:00 2001 From: Eder Bastos Date: Sun, 10 May 2015 10:46:46 -0400 Subject: Don't show "Error" when a blank string is returned from a native method. --- .../activities/AddDirectoryActivity.java | 8 ++++++++ .../dolphinemu/activities/GameGridActivity.java | 23 ++++++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) (limited to 'Source/Android/app/src/main/java') 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 3a282f6433..04e6ffb9f6 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 @@ -15,6 +15,10 @@ import org.dolphinemu.dolphinemu.BuildConfig; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.adapters.FileAdapter; +/** + * 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 static final String KEY_CURRENT_PATH = BuildConfig.APPLICATION_ID + ".path"; @@ -74,6 +78,7 @@ public class AddDirectoryActivity extends Activity implements FileAdapter.FileCl return super.onOptionsItemSelected(item); } + @Override protected void onSaveInstanceState(Bundle outState) { @@ -83,6 +88,9 @@ public class AddDirectoryActivity extends Activity implements FileAdapter.FileCl outState.putString(KEY_CURRENT_PATH, mAdapter.getPath()); } + /** + * Tell the GameGridActivity that launched this Activity that the user picked a folder. + */ @Override public void finishSuccessfully() { 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 14633d1277..e5a8572e5b 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 @@ -3,16 +3,11 @@ package org.dolphinemu.dolphinemu.activities; import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; -import android.database.Cursor; -import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.preference.PreferenceManager; -import android.provider.DocumentsContract; -import android.provider.OpenableColumns; 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.View; @@ -32,6 +27,10 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; +/** + * 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 { private static final int REQUEST_ADD_DIRECTORY = 1; @@ -83,21 +82,33 @@ public final class GameGridActivity extends Activity } } + /** + * Callback from AddDirectoryActivity. Applies any changes necessary to the GameGridActivity. + * + * @param requestCode + * @param resultCode + * @param result + */ @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) { String path = result.getStringExtra(AddDirectoryActivity.KEY_CURRENT_PATH); + // Store this path as a preference. + // TODO Use SQLite instead. SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); SharedPreferences.Editor editor = prefs.edit(); editor.putString(AddDirectoryActivity.KEY_CURRENT_PATH, path); - // Using commit in order to block so the next method has the correct data to load. + // Using commit, not apply, in order to block so the next method has the correct data to load. editor.commit(); mAdapter.setGameList(getGameList()); -- cgit v1.2.3 From abaf41baa7ead3f4106a4493dc737cd9340bc448 Mon Sep 17 00:00:00 2001 From: Eder Bastos Date: Sun, 10 May 2015 11:07:16 -0400 Subject: Add a subtitle to AddDirectoryActivity containing the currently displayed folder's path. --- .../activities/AddDirectoryActivity.java | 16 +++++++--- .../dolphinemu/activities/GameGridActivity.java | 9 ++++-- .../dolphinemu/adapters/FileAdapter.java | 35 ++++++++++++++-------- 3 files changed, 40 insertions(+), 20 deletions(-) (limited to 'Source/Android/app/src/main/java') 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 04e6ffb9f6..1c536d8f91 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 @@ -24,6 +24,7 @@ public class AddDirectoryActivity extends Activity implements FileAdapter.FileCl public static final String KEY_CURRENT_PATH = BuildConfig.APPLICATION_ID + ".path"; private FileAdapter mAdapter; + private Toolbar mToolbar; @Override protected void onCreate(Bundle savedInstanceState) @@ -32,8 +33,8 @@ public class AddDirectoryActivity extends Activity implements FileAdapter.FileCl setContentView(R.layout.activity_add_directory); - Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_folder_list); - setActionBar(toolbar); + mToolbar = (Toolbar) findViewById(R.id.toolbar_folder_list); + setActionBar(mToolbar); RecyclerView recyclerView = (RecyclerView) findViewById(R.id.list_files); @@ -46,7 +47,8 @@ public class AddDirectoryActivity extends Activity implements FileAdapter.FileCl if (savedInstanceState == null) { path = Environment.getExternalStorageDirectory().getPath(); - } else + } + else { // Get the path we were looking at before we rotated. path = savedInstanceState.getString(KEY_CURRENT_PATH); @@ -71,7 +73,7 @@ public class AddDirectoryActivity extends Activity implements FileAdapter.FileCl switch (item.getItemId()) { case R.id.menu_up_one_level: - mAdapter.setPath(mAdapter.getPath() + "/.."); + mAdapter.upOneLevel(); break; } @@ -101,4 +103,10 @@ public class AddDirectoryActivity extends Activity implements FileAdapter.FileCl finish(); } + + @Override + public void updateSubtitle(String path) + { + mToolbar.setSubtitle(path); + } } 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 e5a8572e5b..bd922ecbed 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 @@ -69,6 +69,8 @@ public final class GameGridActivity extends Activity 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); } }); @@ -85,9 +87,9 @@ public final class GameGridActivity extends Activity /** * Callback from AddDirectoryActivity. Applies any changes necessary to the GameGridActivity. * - * @param requestCode - * @param resultCode - * @param result + * @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) @@ -99,6 +101,7 @@ public final class GameGridActivity extends Activity // other activities might use this callback in the future (don't forget to change Javadoc!) if (requestCode == REQUEST_ADD_DIRECTORY) { + // Get the path the user selected in AddDirectoryActivity. String path = result.getStringExtra(AddDirectoryActivity.KEY_CURRENT_PATH); // Store this path as a preference. diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java index 2414883279..9ae238d36c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java @@ -26,12 +26,14 @@ public class FileAdapter extends RecyclerView.Adapter implements * Initializes the dataset to be displayed, and associates the Adapter with the * Activity as an event listener. * - * @param gameList + * @param path A String containing the path to the directory to be shown by this Adapter. + * @param listener An Activity that can respond to callbacks from this Adapter. */ public FileAdapter(String path, FileClickListener listener) { mFileList = generateFileList(new File(path)); mListener = listener; + mListener.updateSubtitle(path); } /** @@ -107,12 +109,12 @@ public class FileAdapter extends RecyclerView.Adapter implements * When a file is clicked, determine if it is a directory; if it is, show that new directory's * contents. If it is not, end the activity successfully. * - * @param view + * @param view The View representing the file the user clicked on. */ @Override public void onClick(final View view) { - String path = (String) view.getTag(); + final String path = (String) view.getTag(); File clickedFile = new File(path); @@ -135,6 +137,7 @@ public class FileAdapter extends RecyclerView.Adapter implements { mFileList = fileList; notifyDataSetChanged(); + mListener.updateSubtitle(path); } }, 200); } @@ -148,7 +151,7 @@ public class FileAdapter extends RecyclerView.Adapter implements /** * For a given directory, return a list of Files it contains. * - * @param directory + * @param directory A File representing the directory that should have its contents displayed. * @return */ private ArrayList generateFileList(File directory) @@ -176,26 +179,32 @@ public class FileAdapter extends RecyclerView.Adapter implements return mPath; } - /** - * Mostly just allows the activity's menu option to kick us up a level in the directory - * structure. - * - * @param path - */ public void setPath(String path) { - mPath = path; - File parentDirectory = new File(path); + File directory = new File(path); + + mFileList = generateFileList(directory); + notifyDataSetChanged(); + mListener.updateSubtitle(path); + } + + public void upOneLevel() + { + File currentDirectory = new File(mPath); + File parentDirectory = currentDirectory.getParentFile(); mFileList = generateFileList(parentDirectory); notifyDataSetChanged(); + mListener.updateSubtitle(mPath); } /** - * Callback for when the user wants to add the visible directory to the library. + * Callback to the containing Activity. */ public interface FileClickListener { void finishSuccessfully(); + + void updateSubtitle(String path); } } -- cgit v1.2.3 From f3aec526b14faa34af0b99996998dabfb2637ac2 Mon Sep 17 00:00:00 2001 From: Eder Bastos Date: Sun, 10 May 2015 17:48:46 -0400 Subject: Add an IntelliJ settings file describing the Dolphin project code style. --- .../java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java | 8 +++++--- .../java/org/dolphinemu/dolphinemu/model/FileListItem.java | 12 ++++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'Source/Android/app/src/main/java') diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java index 9ae238d36c..7ce0047b08 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java @@ -26,7 +26,7 @@ public class FileAdapter extends RecyclerView.Adapter implements * Initializes the dataset to be displayed, and associates the Adapter with the * Activity as an event listener. * - * @param path A String containing the path to the directory to be shown by this Adapter. + * @param path A String containing the path to the directory to be shown by this Adapter. * @param listener An Activity that can respond to callbacks from this Adapter. */ public FileAdapter(String path, FileClickListener listener) @@ -125,7 +125,8 @@ public class FileAdapter extends RecyclerView.Adapter implements if (fileList.isEmpty()) { Toast.makeText(view.getContext(), R.string.add_directory_empty_folder, Toast.LENGTH_SHORT).show(); - } else + } + else { // Delay the loading of the new directory to give a little bit of time for UI feedback // to happen. Hacky, but good enough for now; this is necessary because we're modifying @@ -141,7 +142,8 @@ public class FileAdapter extends RecyclerView.Adapter implements } }, 200); } - } else + } + else { // Pass the activity the path of the parent directory of the clicked file. mListener.finishSuccessfully(); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/FileListItem.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/FileListItem.java index e15516dbaf..69b39438e8 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/FileListItem.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/FileListItem.java @@ -26,7 +26,8 @@ public class FileListItem implements Comparable if (file.isDirectory()) { mType = TYPE_FOLDER; - } else + } + else { String fileExtension = mPath.substring(mPath.lastIndexOf('.')); @@ -37,7 +38,8 @@ public class FileListItem implements Comparable if (allowedExtensions.contains(fileExtension)) { mType = NativeLibrary.IsWiiTitle(mPath) ? TYPE_WII : TYPE_GC; - } else + } + else { mType = TYPE_OTHER; } @@ -67,12 +69,14 @@ public class FileListItem implements Comparable if (theOther.getType() == getType()) { return getFilename().toLowerCase().compareTo(theOther.getFilename().toLowerCase()); - } else + } + else { if (getType() > theOther.getType()) { return 1; - } else + } + else { return -1; } -- cgit v1.2.3