Directory Picker 구현해보기
16 May 2019 | Android팝업 형태의 다이얼로그(Dialog)로 실행하는 Directory Picker 입니다.
dialog_directory_picker.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimaryDark">
<TextView
android:textStyle="bold"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="12dp"
android:text="@string/directory_picker_title"
android:textColor="@color/colorDialogTitle"
android:textSize="24sp"/>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorCurrentPathBackground">
<TextView
android:id="@+id/current_path"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:layout_marginLeft="12dp"
android:text="current directory path"
android:textColor="@color/colorCurrentPathText"
android:textSize="16dp"/>
</FrameLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="16dp"
android:minHeight="320dp"/>
</LinearLayout>
DirectoryListAdapter.kt
import android.content.Context
import android.os.Environment
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.snowdeer.ftpserver.R
import kotlinx.android.synthetic.main.item_directory.view.*
import java.io.File
interface OnDirectoryListEventListener {
fun onDirectoryChanged(path: String)
}
data class DirectoryItem(val name: String, val path: String)
class DirectoryListAdapter(private val ctx: Context) : RecyclerView.Adapter<ViewHolder>() {
private val list = ArrayList<DirectoryItem>()
private val root = Environment.getExternalStorageDirectory().absolutePath
var currentPath: String = ""
var onDirectoryListEventListener: OnDirectoryListEventListener? = null
fun refresh(path: String) {
list.clear()
val file = File(path)
currentPath = file.path
onDirectoryListEventListener?.onDirectoryChanged(path)
addParentDirectory(file)
if (!file.exists()) {
notifyDataSetChanged()
return
}
val files = file.listFiles()
files?.let {
for (f in it) {
if (f.isHidden) {
continue
}
if (f.isDirectory) {
list.add(DirectoryItem(f.name, f.absolutePath))
}
}
}
notifyDataSetChanged()
}
private fun addParentDirectory(file: File) {
val path = file.path
if ((path == "/") || (path == root)) {
return
}
list.add(DirectoryItem("..", file.parentFile.path))
}
override fun onCreateViewHolder(parent: ViewGroup, position: Int): ViewHolder {
val view: View = LayoutInflater.from(ctx).inflate(R.layout.item_directory, parent, false)
return ViewHolder(view)
}
fun getItem(position: Int): DirectoryItem {
return list[position]
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(holder.adapterPosition)
holder.name.text = item.name
holder.layout_item.setOnClickListener {
refresh(item.path)
}
}
}
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val layout_item = view.layout_item!!
val name = view.name!!
}
DirectoryPickerDialog.kt
import android.app.Dialog
import android.os.Bundle
import android.support.v4.app.DialogFragment
import android.support.v4.app.FragmentActivity
import android.support.v7.app.AlertDialog
import android.support.v7.widget.LinearLayoutManager
import android.view.LayoutInflater
import android.widget.Toast
import com.snowdeer.ftpserver.R
import com.snowdeer.ftpserver.SnowPreference
import kotlinx.android.synthetic.main.dialog_directory_picker.view.*
import kotlinx.android.synthetic.main.item_directory.view.*
import java.io.File
import java.util.*
interface OnDirectoryPickerEventListener {
fun onDirectorySelected(path: String)
}
class DirectoryPickerDialog : DialogFragment() {
private lateinit var adapter: DirectoryListAdapter
var onDirectoryPickerEventListener: OnDirectoryPickerEventListener? = null
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(Objects.requireNonNull<FragmentActivity>(activity))
val inflater = activity!!.layoutInflater
val view = inflater.inflate(R.layout.dialog_directory_picker, null)
adapter = DirectoryListAdapter(activity!!)
adapter.onDirectoryListEventListener = object : OnDirectoryListEventListener {
override fun onDirectoryChanged(path: String) {
view.current_path.text = path
}
}
view.recycler_view.layoutManager = LinearLayoutManager(activity)
view.recycler_view.adapter = adapter
adapter.refresh(SnowPreference.getDirectory(activity!!))
builder.setView(view)
.setPositiveButton(getString(R.string.directory_picker_ok), null)
.setNeutralButton(getString(R.string.directory_picker_new_directory), null)
val dialog = builder.create()
dialog.setOnShowListener {
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
onDirectoryPickerEventListener?.onDirectorySelected(adapter.currentPath)
dialog.dismiss()
}
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener {
showNewDirectoryDialog(adapter.currentPath)
}
}
return dialog
}
private fun showNewDirectoryDialog(path: String) {
val view = LayoutInflater.from(activity).inflate(R.layout.dialog_new_directory, null)
AlertDialog.Builder(activity!!)
.setTitle(getString(R.string.directory_picker_new_directory))
.setView(view)
.setPositiveButton("Ok") { _, _ ->
val newPath = path + "/" + view.name.text.toString()
if (createDirectory(newPath)) {
adapter.refresh(path)
} else {
Toast.makeText(activity!!, getString(R.string.new_directory_failed), Toast.LENGTH_SHORT).show()
}
}
.show()
}
private fun createDirectory(path: String): Boolean {
val file = File(path)
if (file.exists()) {
return false
}
return file.mkdir()
}
}