Add File Browser screen to new UI.
@@ -15,7 +15,7 @@
|
||||
<activity
|
||||
android:name=".activities.GameGridActivity"
|
||||
android:label="Dolphin New UI"
|
||||
android:theme="@style/DolphinWii">
|
||||
android:theme="@style/DolphinGamecube">
|
||||
|
||||
<!-- This intentfilter marks this Activity as the one that gets launched from Home screen. -->
|
||||
<intent-filter>
|
||||
@@ -25,6 +25,12 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activities.AddDirectoryActivity"
|
||||
android:theme="@style/DolphinWii"
|
||||
android:label="@string/add_directory_title"/>
|
||||
|
||||
|
||||
<activity
|
||||
android:name="org.dolphinemu.dolphinemu.gamelist.GameListActivity"
|
||||
android:label="@string/app_name"
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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<String> exts = new HashSet<String>(Arrays.asList(".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".wad", ".wbfs"));
|
||||
|
||||
for (int a = 0; a < intDirectories; ++a)
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||
|
||||
String path = prefs.getString(AddDirectoryActivity.KEY_CURRENT_PATH, "/");
|
||||
|
||||
File currentDir = new File(path);
|
||||
File[] dirs = currentDir.listFiles();
|
||||
try
|
||||
{
|
||||
String BrowseDir = NativeLibrary.GetConfig("Dolphin.ini", "General", "ISOPath" + a, "");
|
||||
Log.v("DolphinEmu", "Directory " + a + ": " + BrowseDir);
|
||||
|
||||
File currentDir = new File(BrowseDir);
|
||||
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('.'))))
|
||||
{
|
||||
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);
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -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<FileViewHolder> implements View.OnClickListener
|
||||
{
|
||||
private ArrayList<FileListItem> 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<FileListItem> generateFileList(File directory)
|
||||
{
|
||||
File[] children = directory.listFiles();
|
||||
ArrayList<FileListItem> fileList = new ArrayList<FileListItem>(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();
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,6 @@ public class GameAdapter extends RecyclerView.Adapter<GameViewHolder>
|
||||
holder.path = game.getPath();
|
||||
holder.screenshotPath = game.getScreenPath();
|
||||
holder.game = game;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,4 +111,10 @@ public class GameAdapter extends RecyclerView.Adapter<GameViewHolder>
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void setGameList(ArrayList<Game> gameList)
|
||||
{
|
||||
mGameList = gameList;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<FileListItem>
|
||||
{
|
||||
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<String> allowedExtensions = new HashSet<String>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 223 B |
|
After Width: | Height: | Size: 224 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 174 B |
|
After Width: | Height: | Size: 206 B |
|
After Width: | Height: | Size: 825 B |
|
After Width: | Height: | Size: 608 B |
|
After Width: | Height: | Size: 198 B |
|
After Width: | Height: | Size: 273 B |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 222 B |