package what.whatandroid.settings;
import android.app.Activity;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.*;
import what.whatandroid.R;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A dialog fragment for navigating to and selecting a folder
*/
public class FolderPickerDialog extends DialogFragment
implements AdapterView.OnItemClickListener, View.OnClickListener {
private static String DIRECTORY = "what.whatandroid.folderpickerdialog.DIRECTORY",
FALLBACK_DIR = "what.whatandroid.folderpickerdialog.FALLBACK_DIR:";
/**
* Adapter displaying the list of directories in the current directory
*/
private ArrayAdapter<String> adapter;
/**
* The current directory we're in
*/
private File currentDir;
/**
* Header view showing the current directory's title
*/
private TextView currentDirTitle;
/**
* Listener to inform of the user's folder selection
*/
private FolderPickerCallback pickerCallback;
/**
* Callbacks to be implemented by the activity opening the folder picker dialog to
* get back the full path of the selected folder. If the user cancels no function will be called
*/
public interface FolderPickerCallback {
/**
* Called when the user has selected the desired folder
*
* @param folder the absolute path to the selected folder
*/
public void pickFolder(String folder);
}
/**
* Create the folder picker dialog and specify the initial directory to display
*
* @param dir initial directory to display
* @param fallbackDir directory to fallback to if dir can't be opened
*/
public static FolderPickerDialog newInstance(String dir, String fallbackDir){
FolderPickerDialog d = new FolderPickerDialog();
Bundle args = new Bundle();
args.putString(DIRECTORY, dir);
args.putString(FALLBACK_DIR, fallbackDir);
d.setArguments(args);
return d;
}
public FolderPickerDialog(){
//Required empty ctor
}
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
try {
pickerCallback = (FolderPickerCallback)activity;
}
catch (ClassCastException e){
throw new ClassCastException(activity.toString() + " must implement FolderPickerCallback");
}
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState){
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.dialog_folder_picker, null);
currentDirTitle = (TextView)view.findViewById(R.id.current_folder);
ListView list = (ListView)view.findViewById(R.id.list);
ImageButton imgAddFolder = (ImageButton) view.findViewById(R.id.new_folder);
imgAddFolder.setImageResource(R.drawable.ic_add_24dp);
imgAddFolder.setOnClickListener(this);
if (savedInstanceState != null){
currentDir = new File(savedInstanceState.getString(DIRECTORY));
}
else {
currentDir = new File(getArguments().getString(DIRECTORY));
}
//Try to open the directory and load the list of subdirectories
List<String> dirs = readDirectory(currentDir);
//If we fail to open the directory read the fallback directory
if (dirs == null){
Toast.makeText(getActivity(), "Could not enter directory " + currentDir.getName(), Toast.LENGTH_SHORT).show();
currentDir = new File(getArguments().getString(FALLBACK_DIR));
dirs = readDirectory(currentDir);
}
currentDirTitle.setText(currentDir.getName());
adapter = new ArrayAdapter<String>(getActivity(), R.layout.list_folder, R.id.folder_name, dirs);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
builder.setView(view)
.setTitle("Select Folder")
.setPositiveButton("Select", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which){
pickerCallback.pickFolder(currentDir.getAbsolutePath());
}
})
.setNegativeButton("Cancel", null);
return builder.create();
}
@Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putString(DIRECTORY, currentDir.getAbsolutePath());
}
/**
* When a directory is clicked in the list try to open it
*/
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id){
enterDirectory(adapter.getItem(position));
}
/**
* Read and return a list of all subdirectories in the passed directory, returns null
* if reading failed. This list will also contain '..' as the first entry if the
* directory has a parent directory
* @param directory directory to read
* @return list of subdirectories or null if we couldn't read the directory
*/
public List<String> readDirectory(File directory){
String sd[] = directory.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String filename){
return new File(dir, filename).isDirectory();
}
});
if (sd == null){
return null;
}
ArrayList<String> subdirs = new ArrayList<String>(Arrays.asList(sd));
if (directory.getParent() != null){
subdirs.add(0, "..");
}
return subdirs;
}
/**
* Enter a new directory from the current one, or go up a directory
*
* @param dir '..' will specify to go up to the parent if possible, any other string
* indicates a subdirectory to enter
*/
public void enterDirectory(String dir){
File prev = currentDir;
if (dir.equalsIgnoreCase("..")){
currentDir = currentDir.getParentFile();
}
else {
currentDir = new File(currentDir, dir);
}
List<String> dirs = readDirectory(currentDir);
//If we can't enter the directory don't update the list and inform the user (we probably don't have adequate permissions)
if (dirs == null){
Toast.makeText(getActivity(), "Could not enter directory " + dir, Toast.LENGTH_SHORT).show();
currentDir = prev;
return;
}
if (!currentDir.getName().isEmpty()){
currentDirTitle.setText(currentDir.getName());
}
else {
currentDirTitle.setText("/");
}
adapter.clear();
adapter.addAll(dirs);
adapter.notifyDataSetChanged();
}
public void createDirectory(String name){
File newDir = new File(currentDir, name);
//If we can't create the directory it's likely a permissions issue so let the user know
if (!newDir.mkdir()){
Toast.makeText(getActivity(), "Could not create directory " + name, Toast.LENGTH_LONG).show();
}
else {
enterDirectory(name);
}
}
/**
* When the new directory button is clicked we put up a text dialog to get the desired
* directory name from the user
*/
@Override
public void onClick(View v){
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final EditText input = new EditText(getActivity());
input.setSingleLine(true);
builder.setTitle("Enter New Directory Name:")
.setView(input)
.setPositiveButton("Create", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which){
if (input.getText().length() > 0){
createDirectory(input.getText().toString());
}
else {
Toast.makeText(getActivity(), "No directory name entered", Toast.LENGTH_SHORT).show();
}
}
})
.setNegativeButton("Cancel", null);
builder.show();
}
}