Merge pull request #6282 from mahdihijazi/replace_file_browser
[Android] Replace current file browser
This commit is contained in:
commit
a1467f0e5a
|
@ -96,6 +96,8 @@ dependencies {
|
|||
|
||||
// Allows FRP-style asynchronous operations in Android.
|
||||
api 'io.reactivex:rxandroid:1.2.1'
|
||||
|
||||
compile 'com.nononsenseapps:filepicker:4.1.0'
|
||||
}
|
||||
|
||||
def getVersion() {
|
||||
|
|
|
@ -50,11 +50,6 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activities.AddDirectoryActivity"
|
||||
android:theme="@style/DolphinGamecube"
|
||||
android:label="@string/add_directory_title"/>
|
||||
|
||||
<activity
|
||||
android:name=".ui.settings.SettingsActivity"
|
||||
android:theme="@style/DolphinSettingsGamecube"
|
||||
|
@ -64,6 +59,15 @@
|
|||
android:name=".activities.EmulationActivity"
|
||||
android:theme="@style/DolphinEmulationGamecube"/>
|
||||
|
||||
<activity
|
||||
android:name=".activities.CustomFilePickerActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/FilePickerTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.GET_CONTENT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service android:name=".services.DirectoryInitializationService"/>
|
||||
|
||||
|
@ -74,6 +78,16 @@
|
|||
android:exported="false">
|
||||
</provider>
|
||||
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:authorities="${applicationId}.filesprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/nnf_provider_paths" />
|
||||
</provider>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -1,141 +0,0 @@
|
|||
package org.dolphinemu.dolphinemu.activities;
|
||||
|
||||
import android.content.AsyncQueryHandler;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
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)
|
||||
* contains the user's games.
|
||||
*/
|
||||
public class AddDirectoryActivity extends AppCompatActivity implements FileAdapter.FileClickListener
|
||||
{
|
||||
private static final String KEY_CURRENT_PATH = "path";
|
||||
|
||||
private FileAdapter mAdapter;
|
||||
private Toolbar mToolbar;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_add_directory);
|
||||
|
||||
mToolbar = (Toolbar) findViewById(R.id.toolbar_folder_list);
|
||||
setSupportActionBar(mToolbar);
|
||||
|
||||
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.upOneLevel();
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a directory to the library, and if successful, end the activity.
|
||||
*/
|
||||
@Override
|
||||
public void addDirectory()
|
||||
{
|
||||
// Set up a callback for when the addition is complete
|
||||
// TODO This has a nasty warning on it; find a cleaner way to do this Insert asynchronously
|
||||
AsyncQueryHandler handler = new AsyncQueryHandler(getContentResolver())
|
||||
{
|
||||
@Override
|
||||
protected void onInsertComplete(int token, Object cookie, Uri uri)
|
||||
{
|
||||
Intent resultData = new Intent();
|
||||
|
||||
resultData.putExtra(KEY_CURRENT_PATH, mAdapter.getPath());
|
||||
setResult(RESULT_OK, resultData);
|
||||
|
||||
finish();
|
||||
}
|
||||
};
|
||||
|
||||
ContentValues file = new ContentValues();
|
||||
file.put(GameDatabase.KEY_FOLDER_PATH, mAdapter.getPath());
|
||||
|
||||
handler.startInsert(0, // We don't need to identify this call to the handler
|
||||
null, // We don't need to pass additional data to the handler
|
||||
GameProvider.URI_FOLDER, // Tell the GameProvider we are adding a folder
|
||||
file); // Tell the GameProvider what folder we are adding
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSubtitle(String path)
|
||||
{
|
||||
mToolbar.setSubtitle(path);
|
||||
}
|
||||
|
||||
public static void launch(FragmentActivity activity)
|
||||
{
|
||||
Intent fileChooser = new Intent(activity, AddDirectoryActivity.class);
|
||||
activity.startActivityForResult(fileChooser, MainPresenter.REQUEST_ADD_DIRECTORY);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package org.dolphinemu.dolphinemu.activities;
|
||||
|
||||
import android.os.Environment;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.nononsenseapps.filepicker.AbstractFilePickerFragment;
|
||||
import com.nononsenseapps.filepicker.FilePickerActivity;
|
||||
|
||||
import org.dolphinemu.dolphinemu.fragments.CustomFilePickerFragment;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class CustomFilePickerActivity extends FilePickerActivity
|
||||
|
||||
{
|
||||
@Override
|
||||
protected AbstractFilePickerFragment<File> getFragment(
|
||||
@Nullable final String startPath, final int mode, final boolean allowMultiple,
|
||||
final boolean allowCreateDir, final boolean allowExistingFile,
|
||||
final boolean singleClick)
|
||||
{
|
||||
AbstractFilePickerFragment<File> fragment = new CustomFilePickerFragment();
|
||||
// startPath is allowed to be null. In that case, default folder should be SD-card and not "/"
|
||||
fragment.setArgs(startPath != null ? startPath : Environment.getExternalStorageDirectory().getPath(),
|
||||
mode, allowMultiple, allowCreateDir, allowExistingFile, singleClick);
|
||||
return fragment;
|
||||
}
|
||||
}
|
|
@ -1,217 +0,0 @@
|
|||
package org.dolphinemu.dolphinemu.adapters;
|
||||
|
||||
import android.os.Environment;
|
||||
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;
|
||||
import org.dolphinemu.dolphinemu.viewholders.FileViewHolder;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
public final 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 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 The View representing the file the user clicked on.
|
||||
*/
|
||||
@Override
|
||||
public void onClick(final View view)
|
||||
{
|
||||
final String path = (String) view.getTag();
|
||||
|
||||
File clickedFile = new File(path);
|
||||
|
||||
if (clickedFile.isDirectory())
|
||||
{
|
||||
final ArrayList<FileListItem> 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(() ->
|
||||
{
|
||||
mFileList = fileList;
|
||||
notifyDataSetChanged();
|
||||
mListener.updateSubtitle(path);
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pass the activity the path of the parent directory of the clicked file.
|
||||
mListener.addDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given directory, return a list of Files it contains.
|
||||
*
|
||||
* @param directory A File representing the directory that should have its contents displayed.
|
||||
* @return The list of files contained in the directory.
|
||||
*/
|
||||
private ArrayList<FileListItem> generateFileList(File directory)
|
||||
{
|
||||
File[] children = directory.listFiles();
|
||||
mPath = directory.getAbsolutePath();
|
||||
ArrayList<FileListItem> fileList = new ArrayList<FileListItem>(0);
|
||||
|
||||
if (children != null)
|
||||
{
|
||||
|
||||
fileList = new ArrayList<FileListItem>(children.length);
|
||||
|
||||
for (File child : children)
|
||||
{
|
||||
if (!child.isHidden())
|
||||
{
|
||||
FileListItem item = new FileListItem(child);
|
||||
fileList.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(fileList);
|
||||
}
|
||||
return fileList;
|
||||
}
|
||||
|
||||
public String getPath()
|
||||
{
|
||||
return mPath;
|
||||
}
|
||||
|
||||
public void setPath(String path)
|
||||
{
|
||||
File directory = new File(path);
|
||||
|
||||
mFileList = generateFileList(directory);
|
||||
notifyDataSetChanged();
|
||||
mListener.updateSubtitle(path);
|
||||
}
|
||||
|
||||
public void upOneLevel()
|
||||
{
|
||||
if (!mPath.equals("/"))
|
||||
{
|
||||
File currentDirectory = new File(mPath);
|
||||
File parentDirectory = currentDirectory.getParentFile();
|
||||
|
||||
mFileList = generateFileList(parentDirectory);
|
||||
notifyDataSetChanged();
|
||||
mListener.updateSubtitle(mPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to the containing Activity.
|
||||
*/
|
||||
public interface FileClickListener
|
||||
{
|
||||
void addDirectory();
|
||||
|
||||
void updateSubtitle(String path);
|
||||
}
|
||||
}
|
|
@ -18,9 +18,9 @@ import org.dolphinemu.dolphinemu.utils.PicassoUtils;
|
|||
import org.dolphinemu.dolphinemu.viewholders.GameViewHolder;
|
||||
|
||||
/**
|
||||
* This adapter, unlike {@link FileAdapter} which is backed by an ArrayList, gets its
|
||||
* information from a database Cursor. This fact, paired with the usage of ContentProviders
|
||||
* and Loaders, allows for efficient display of a limited view into a (possibly) large dataset.
|
||||
* This adapter gets its information from a database Cursor. This fact, paired with the usage of
|
||||
* ContentProviders and Loaders, allows for efficient display of a limited view into a (possibly)
|
||||
* large dataset.
|
||||
*/
|
||||
public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> implements
|
||||
View.OnClickListener,
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package org.dolphinemu.dolphinemu.fragments;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.FileProvider;
|
||||
|
||||
import com.nononsenseapps.filepicker.FilePickerFragment;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class CustomFilePickerFragment extends FilePickerFragment
|
||||
{
|
||||
@NonNull
|
||||
@Override
|
||||
public Uri toUri(@NonNull final File file)
|
||||
{
|
||||
return FileProvider
|
||||
.getUriForFile(getContext(),
|
||||
getContext().getApplicationContext().getPackageName() + ".filesprovider",
|
||||
file);
|
||||
}
|
||||
}
|
|
@ -17,13 +17,14 @@ import android.view.View;
|
|||
import android.widget.Toast;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity;
|
||||
import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter;
|
||||
import org.dolphinemu.dolphinemu.model.GameProvider;
|
||||
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
|
||||
import org.dolphinemu.dolphinemu.ui.platform.Platform;
|
||||
import org.dolphinemu.dolphinemu.ui.platform.PlatformGamesView;
|
||||
import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity;
|
||||
import org.dolphinemu.dolphinemu.utils.AddDirectoryHelper;
|
||||
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper;
|
||||
import org.dolphinemu.dolphinemu.utils.PermissionsHandler;
|
||||
import org.dolphinemu.dolphinemu.utils.StartupHandler;
|
||||
|
||||
|
@ -71,6 +72,13 @@ public final class MainActivity extends AppCompatActivity implements MainView
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
mPresenter.addDirIfNeeded(new AddDirectoryHelper(this));
|
||||
}
|
||||
|
||||
// TODO: Replace with a ButterKnife injection.
|
||||
private void findViews()
|
||||
{
|
||||
|
@ -127,7 +135,7 @@ public final class MainActivity extends AppCompatActivity implements MainView
|
|||
@Override
|
||||
public void launchFileListActivity()
|
||||
{
|
||||
AddDirectoryActivity.launch(this);
|
||||
FileBrowserHelper.openDirectoryPicker(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -137,8 +145,6 @@ public final class MainActivity extends AppCompatActivity implements MainView
|
|||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@ -146,7 +152,20 @@ public final class MainActivity extends AppCompatActivity implements MainView
|
|||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent result)
|
||||
{
|
||||
mPresenter.handleActivityResult(requestCode, resultCode);
|
||||
switch (requestCode)
|
||||
{
|
||||
case MainPresenter.REQUEST_ADD_DIRECTORY:
|
||||
// If the user picked a file, as opposed to just backing out.
|
||||
if (resultCode == MainActivity.RESULT_OK)
|
||||
{
|
||||
mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result));
|
||||
}
|
||||
break;
|
||||
|
||||
case MainPresenter.REQUEST_EMULATE_GAME:
|
||||
mPresenter.refreshFragmentScreenshot(resultCode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -198,7 +217,7 @@ public final class MainActivity extends AppCompatActivity implements MainView
|
|||
@Nullable
|
||||
private PlatformGamesView getPlatformGamesView(Platform platform)
|
||||
{
|
||||
String fragmentTag = "android:switcher:" + mViewPager.getId() + ":" + platform;
|
||||
String fragmentTag = "android:switcher:" + mViewPager.getId() + ":" + platform.toInt();
|
||||
|
||||
return (PlatformGamesView) getSupportFragmentManager().findFragmentByTag(fragmentTag);
|
||||
}
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
package org.dolphinemu.dolphinemu.ui.main;
|
||||
|
||||
|
||||
import android.database.Cursor;
|
||||
|
||||
import org.dolphinemu.dolphinemu.BuildConfig;
|
||||
import org.dolphinemu.dolphinemu.DolphinApplication;
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.model.GameDatabase;
|
||||
import org.dolphinemu.dolphinemu.ui.platform.Platform;
|
||||
import org.dolphinemu.dolphinemu.utils.AddDirectoryHelper;
|
||||
import org.dolphinemu.dolphinemu.utils.SettingsFile;
|
||||
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.functions.Action1;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
public final class MainPresenter
|
||||
|
@ -20,6 +18,7 @@ public final class MainPresenter
|
|||
public static final int REQUEST_EMULATE_GAME = 2;
|
||||
|
||||
private final MainView mView;
|
||||
private String mDirToAdd;
|
||||
|
||||
public MainPresenter(MainView view)
|
||||
{
|
||||
|
@ -71,24 +70,27 @@ public final class MainPresenter
|
|||
return false;
|
||||
}
|
||||
|
||||
public void handleActivityResult(int requestCode, int resultCode)
|
||||
public void addDirIfNeeded(AddDirectoryHelper helper)
|
||||
{
|
||||
switch (requestCode)
|
||||
if (mDirToAdd != null)
|
||||
{
|
||||
case REQUEST_ADD_DIRECTORY:
|
||||
// If the user picked a file, as opposed to just backing out.
|
||||
if (resultCode == MainActivity.RESULT_OK)
|
||||
{
|
||||
mView.refresh();
|
||||
}
|
||||
break;
|
||||
helper.addDirectory(mDirToAdd, mView::refresh);
|
||||
|
||||
case REQUEST_EMULATE_GAME:
|
||||
mView.refreshFragmentScreenshot(resultCode);
|
||||
break;
|
||||
mDirToAdd = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void onDirectorySelected(String dir)
|
||||
{
|
||||
mDirToAdd = dir;
|
||||
}
|
||||
|
||||
public void refreshFragmentScreenshot(int resultCode)
|
||||
{
|
||||
mView.refreshFragmentScreenshot(resultCode);
|
||||
}
|
||||
|
||||
|
||||
public void loadGames(final Platform platform)
|
||||
{
|
||||
GameDatabase databaseHelper = DolphinApplication.databaseHelper;
|
||||
|
|
|
@ -12,17 +12,12 @@ import android.support.v17.leanback.widget.CursorObjectAdapter;
|
|||
import android.support.v17.leanback.widget.HeaderItem;
|
||||
import android.support.v17.leanback.widget.ListRow;
|
||||
import android.support.v17.leanback.widget.ListRowPresenter;
|
||||
import android.support.v17.leanback.widget.OnItemViewClickedListener;
|
||||
import android.support.v17.leanback.widget.Presenter;
|
||||
import android.support.v17.leanback.widget.Row;
|
||||
import android.support.v17.leanback.widget.RowPresenter;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity;
|
||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
||||
import org.dolphinemu.dolphinemu.adapters.GameRowPresenter;
|
||||
import org.dolphinemu.dolphinemu.adapters.SettingsRowPresenter;
|
||||
|
@ -31,6 +26,8 @@ import org.dolphinemu.dolphinemu.model.TvSettingsItem;
|
|||
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
|
||||
import org.dolphinemu.dolphinemu.ui.platform.Platform;
|
||||
import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity;
|
||||
import org.dolphinemu.dolphinemu.utils.AddDirectoryHelper;
|
||||
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper;
|
||||
import org.dolphinemu.dolphinemu.utils.PermissionsHandler;
|
||||
import org.dolphinemu.dolphinemu.utils.StartupHandler;
|
||||
import org.dolphinemu.dolphinemu.viewholders.TvGameViewHolder;
|
||||
|
@ -58,6 +55,13 @@ public final class TvMainActivity extends FragmentActivity implements MainView
|
|||
StartupHandler.HandleInit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
mPresenter.addDirIfNeeded(new AddDirectoryHelper(this));
|
||||
}
|
||||
|
||||
void setupUI() {
|
||||
final FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
mBrowseFragment = new BrowseSupportFragment();
|
||||
|
@ -125,7 +129,7 @@ public final class TvMainActivity extends FragmentActivity implements MainView
|
|||
@Override
|
||||
public void launchFileListActivity()
|
||||
{
|
||||
AddDirectoryActivity.launch(this);
|
||||
FileBrowserHelper.openDirectoryPicker(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -150,7 +154,20 @@ public final class TvMainActivity extends FragmentActivity implements MainView
|
|||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent result)
|
||||
{
|
||||
mPresenter.handleActivityResult(requestCode, resultCode);
|
||||
switch (requestCode)
|
||||
{
|
||||
case MainPresenter.REQUEST_ADD_DIRECTORY:
|
||||
// If the user picked a file, as opposed to just backing out.
|
||||
if (resultCode == MainActivity.RESULT_OK)
|
||||
{
|
||||
mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result));
|
||||
}
|
||||
break;
|
||||
|
||||
case MainPresenter.REQUEST_EMULATE_GAME:
|
||||
mPresenter.refreshFragmentScreenshot(resultCode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package org.dolphinemu.dolphinemu.utils;
|
||||
|
||||
import android.content.AsyncQueryHandler;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.dolphinemu.dolphinemu.model.GameDatabase;
|
||||
import org.dolphinemu.dolphinemu.model.GameProvider;
|
||||
|
||||
public class AddDirectoryHelper
|
||||
{
|
||||
private Context mContext;
|
||||
|
||||
public interface AddDirectoryListener
|
||||
{
|
||||
void onDirectoryAdded();
|
||||
}
|
||||
|
||||
public AddDirectoryHelper(Context context)
|
||||
{
|
||||
this.mContext = context;
|
||||
}
|
||||
|
||||
public void addDirectory(String dir, AddDirectoryListener addDirectoryListener)
|
||||
{
|
||||
AsyncQueryHandler handler = new AsyncQueryHandler(mContext.getContentResolver())
|
||||
{
|
||||
@Override
|
||||
protected void onInsertComplete(int token, Object cookie, Uri uri)
|
||||
{
|
||||
addDirectoryListener.onDirectoryAdded();
|
||||
}
|
||||
};
|
||||
|
||||
ContentValues file = new ContentValues();
|
||||
file.put(GameDatabase.KEY_FOLDER_PATH, dir);
|
||||
|
||||
handler.startInsert(0, // We don't need to identify this call to the handler
|
||||
null, // We don't need to pass additional data to the handler
|
||||
GameProvider.URI_FOLDER, // Tell the GameProvider we are adding a folder
|
||||
file);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package org.dolphinemu.dolphinemu.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
|
||||
import com.nononsenseapps.filepicker.FilePickerActivity;
|
||||
import com.nononsenseapps.filepicker.Utils;
|
||||
|
||||
import org.dolphinemu.dolphinemu.activities.CustomFilePickerActivity;
|
||||
import org.dolphinemu.dolphinemu.ui.main.MainPresenter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public final class FileBrowserHelper
|
||||
{
|
||||
public static void openDirectoryPicker(FragmentActivity activity) {
|
||||
Intent i = new Intent(activity, CustomFilePickerActivity.class);
|
||||
|
||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false);
|
||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, false);
|
||||
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR);
|
||||
i.putExtra(FilePickerActivity.EXTRA_START_PATH, Environment.getExternalStorageDirectory().getPath());
|
||||
|
||||
activity.startActivityForResult(i, MainPresenter.REQUEST_ADD_DIRECTORY);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getSelectedDirectory(Intent result) {
|
||||
// Use the provided utility method to parse the result
|
||||
List<Uri> files = Utils.getSelectedFilesFromResult(result);
|
||||
if(!files.isEmpty()) {
|
||||
File file = Utils.getFileForUri(files.get(0));
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -145,4 +145,27 @@
|
|||
<item name="android:textColor">@color/button_text_color</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
<!-- You can also inherit from NNF_BaseTheme.Light -->
|
||||
<style name="FilePickerTheme" parent="NNF_BaseTheme.Light">
|
||||
<item name="colorPrimary">@color/dolphin_blue</item>
|
||||
<item name="colorPrimaryDark">@color/dolphin_blue_dark</item>
|
||||
<item name="colorAccent">@color/dolphin_accent_gamecube</item>
|
||||
|
||||
<!--<!– Setting a divider is entirely optional –>-->
|
||||
<item name="nnf_list_item_divider">?android:attr/listDivider</item>
|
||||
|
||||
<!-- Need to set this also to style create folder dialog -->
|
||||
<item name="alertDialogTheme">@style/FilePickerAlertDialogTheme</item>
|
||||
|
||||
<!-- If you want to set a specific toolbar theme, do it here -->
|
||||
|
||||
<item name="nnf_toolbarTheme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
|
||||
</style>
|
||||
|
||||
<style name="FilePickerAlertDialogTheme" parent="Theme.AppCompat.Dialog.Alert">
|
||||
<item name="colorPrimary">@color/dolphin_blue</item>
|
||||
<item name="colorPrimaryDark">@color/dolphin_blue_dark</item>
|
||||
<item name="colorAccent">@color/dolphin_accent_gamecube</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue