ultrasonic-app-subsonic-and.../ultrasonic/src/main/kotlin/org/moire/ultrasonic/filepicker/FilePickerAdapter.kt

230 lines
8.2 KiB
Kotlin

package org.moire.ultrasonic.filepicker
import android.content.Context
import android.graphics.drawable.Drawable
import android.os.Environment
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.AppCompatEditText
import androidx.recyclerview.widget.RecyclerView
import java.io.File
import java.util.LinkedList
import org.moire.ultrasonic.R
import org.moire.ultrasonic.util.Util
import timber.log.Timber
/**
* Adapter for the RecyclerView which handles listing, navigating and picking files
* @author this implementation is loosely based on the work of Yogesh Sundaresan,
* original license: http://www.apache.org/licenses/LICENSE-2.0
*/
internal class FilePickerAdapter(view: FilePickerView) :
RecyclerView.Adapter<FilePickerAdapter.FileListHolder>() {
private var data: MutableList<FileListItem> = LinkedList()
var defaultDirectory: File = Environment.getExternalStorageDirectory()
var initialDirectory: File = Environment.getExternalStorageDirectory()
lateinit var selectedDirectoryChanged: (String, Boolean) -> Unit
var selectedDirectory: File = defaultDirectory
private set
private var context: Context? = null
private var listerView: FilePickerView? = view
private var isRealDirectory: Boolean = false
private var folderIcon: Drawable? = null
private var upIcon: Drawable? = null
private var sdIcon: Drawable? = null
init {
this.context = view.context
upIcon = Util.getDrawableFromAttribute(context, R.attr.filepicker_subdirectory_up)
folderIcon = Util.getDrawableFromAttribute(context, R.attr.filepicker_folder)
sdIcon = Util.getDrawableFromAttribute(context, R.attr.filepicker_sd_card)
}
fun start() {
fileLister(initialDirectory)
}
private fun fileLister(currentDirectory: File) {
var fileList = LinkedList<FileListItem>()
val storages: List<File>?
val storagePaths: List<String>?
storages = context!!.getExternalFilesDirs(null).filterNotNull()
storagePaths = storages.map { i -> i.absolutePath }
if (currentDirectory.absolutePath == "/" ||
currentDirectory.absolutePath == "/storage" ||
currentDirectory.absolutePath == "/storage/emulated" ||
currentDirectory.absolutePath == "/mnt"
) {
isRealDirectory = false
fileList = getKitKatStorageItems(storages)
} else {
isRealDirectory = true
val files = currentDirectory.listFiles()
files?.forEach { file ->
if (file.isDirectory) {
fileList.add(FileListItem(file, file.name, folderIcon!!))
}
}
}
data = LinkedList(fileList)
data.sortWith { f1, f2 ->
if (f1.file!!.isDirectory && f2.file!!.isDirectory)
f1.name.compareTo(f2.name, ignoreCase = true)
else if (f1.file!!.isDirectory && !f2.file!!.isDirectory)
-1
else if (!f1.file!!.isDirectory && f2.file!!.isDirectory)
1
else if (!f1.file!!.isDirectory && !f2.file!!.isDirectory)
f1.name.compareTo(f2.name, ignoreCase = true)
else
0
}
selectedDirectory = currentDirectory
selectedDirectoryChanged.invoke(
if (isRealDirectory) selectedDirectory.absolutePath
else context!!.getString(R.string.filepicker_available_drives),
isRealDirectory
)
// Add the "Up" navigation to the list
if (currentDirectory.absolutePath != "/" && isRealDirectory) {
// If we are on KitKat or later, only the default App folder is usable, so we can't
// navigate the SD card. Jump to the root if "Up" is selected.
if (storagePaths.indexOf(currentDirectory.absolutePath) > 0)
data.add(0, FileListItem(File("/"), "..", upIcon!!))
else
data.add(0, FileListItem(selectedDirectory.parentFile!!, "..", upIcon!!))
}
notifyDataSetChanged()
listerView!!.scrollToPosition(0)
}
private fun getKitKatStorageItems(storages: List<File>): LinkedList<FileListItem> {
val fileList = LinkedList<FileListItem>()
if (storages.isNotEmpty()) {
for ((index, file) in storages.withIndex()) {
var path = file.absolutePath
path = path.replace("/Android/data/([a-zA-Z_][.\\w]*)/files".toRegex(), "")
if (index == 0) {
fileList.add(
FileListItem(
File(path),
context!!.getString(R.string.filepicker_internal, path),
sdIcon!!
)
)
} else {
fileList.add(
FileListItem(
file,
context!!.getString(R.string.filepicker_default_app_folder, path),
sdIcon!!
)
)
}
}
}
return fileList
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FileListHolder {
return FileListHolder(
LayoutInflater.from(context).inflate(
R.layout.filepicker_item_file_lister, listerView, false
)
)
}
override fun onBindViewHolder(holder: FileListHolder, position: Int) {
val actualFile = data[position]
holder.name.text = actualFile.name
holder.icon.setImageDrawable(actualFile.icon)
}
override fun getItemCount(): Int {
return data.size
}
fun goToDefault() {
fileLister(defaultDirectory)
}
fun createNewFolder() {
val view = View.inflate(context, R.layout.filepicker_dialog_create_folder, null)
val editText = view.findViewById<AppCompatEditText>(R.id.edittext)
val builder = AlertDialog.Builder(context!!)
.setView(view)
.setTitle(context!!.getString(R.string.filepicker_enter_folder_name))
.setPositiveButton(context!!.getString(R.string.filepicker_create)) { _, _ -> }
val dialog = builder.create()
dialog.show()
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
val name = editText.text!!.toString()
if (TextUtils.isEmpty(name)) {
Util.toast(context!!, context!!.getString(R.string.filepicker_name_invalid))
} else {
val file = File(selectedDirectory, name)
if (file.exists()) {
Util.toast(context!!, context!!.getString(R.string.filepicker_already_exists))
} else {
dialog.dismiss()
if (file.mkdirs()) {
fileLister(file)
} else {
Util.toast(
context!!,
context!!.getString(R.string.filepicker_create_folder_failed)
)
}
}
}
}
}
internal inner class FileListItem(
fileParameter: File,
nameParameter: String,
iconParameter: Drawable
) {
var file: File? = fileParameter
var name: String = nameParameter
var icon: Drawable? = iconParameter
}
internal inner class FileListHolder(
itemView: View
) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
var name: TextView = itemView.findViewById(R.id.name)
var icon: ImageView = itemView.findViewById(R.id.icon)
init {
itemView.findViewById<View>(R.id.layout).setOnClickListener(this)
}
override fun onClick(v: View) {
val clickedFile = data[adapterPosition]
selectedDirectory = clickedFile.file!!
fileLister(clickedFile.file!!)
Timber.d(clickedFile.file!!.absolutePath)
}
}
}