From 68b196de520d53cec51543db6fc219ee63af7565 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Thu, 12 Mar 2020 18:31:58 +0200 Subject: [PATCH] Storage select dialog --- .../kotatsu/ui/common/BaseActivity.kt | 5 ++ .../ui/common/dialog/StorageSelectDialog.kt | 75 +++++++++++++++++++ .../org/koitharu/kotatsu/utils/ext/FileExt.kt | 10 ++- app/src/main/res/layout/item_storage.xml | 35 +++++++++ app/src/main/res/values-ru/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + 6 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/org/koitharu/kotatsu/ui/common/dialog/StorageSelectDialog.kt create mode 100644 app/src/main/res/layout/item_storage.xml diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/common/BaseActivity.kt b/app/src/main/java/org/koitharu/kotatsu/ui/common/BaseActivity.kt index 482dd0bf3..c988c710b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/common/BaseActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/common/BaseActivity.kt @@ -11,6 +11,7 @@ import moxy.MvpAppCompatActivity import org.koin.core.KoinComponent import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.ui.common.dialog.StorageSelectDialog abstract class BaseActivity : MvpAppCompatActivity(), KoinComponent { @@ -68,6 +69,10 @@ abstract class BaseActivity : MvpAppCompatActivity(), KoinComponent { recreate() return true } + if (BuildConfig.DEBUG && keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { + StorageSelectDialog.Builder(this).create().show() + return true + } return super.onKeyDown(keyCode, event) } diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/common/dialog/StorageSelectDialog.kt b/app/src/main/java/org/koitharu/kotatsu/ui/common/dialog/StorageSelectDialog.kt new file mode 100644 index 000000000..57e881b5f --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/common/dialog/StorageSelectDialog.kt @@ -0,0 +1,75 @@ +package org.koitharu.kotatsu.ui.common.dialog + +import android.content.Context +import android.content.DialogInterface +import android.os.Environment +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter +import androidx.annotation.StringRes +import androidx.appcompat.app.AlertDialog +import kotlinx.android.synthetic.main.item_storage.view.* +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.utils.ext.findParent +import org.koitharu.kotatsu.utils.ext.inflate +import org.koitharu.kotatsu.utils.ext.longHashCode +import java.io.File + +class StorageSelectDialog private constructor(private val delegate: AlertDialog) : + DialogInterface by delegate { + + fun show() = delegate.show() + + class Builder(context: Context) { + + private val delegate = AlertDialog.Builder(context) + .setAdapter(VolumesAdapter(context)) { _, _ -> + + } + + fun setTitle(@StringRes titleResId: Int): Builder { + delegate.setTitle(titleResId) + return this + } + + fun setTitle(title: CharSequence): Builder { + delegate.setTitle(title) + return this + } + + fun create() = StorageSelectDialog(delegate.create()) + } + + private class VolumesAdapter(context: Context): BaseAdapter() { + + private val volumes = getAvailableVolumes(context) + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + val view = convertView ?: parent.inflate(R.layout.item_storage) + val item = volumes[position] + view.textView_title.text = item.second + view.textView_subtitle.text = item.first.path + return view + } + + override fun getItem(position: Int): Any = volumes[position] + + override fun getItemId(position: Int) = volumes[position].first.absolutePath.longHashCode() + + override fun getCount() = volumes.size + + } + + private companion object { + + @JvmStatic + fun getAvailableVolumes(context: Context): List> = context.getExternalFilesDirs(null).mapNotNull { + val root = it.findParent { x -> x.name == "Android" }?.parentFile ?: return@mapNotNull null + root to when { + Environment.isExternalStorageEmulated(root) -> context.getString(R.string.internal_storage) + Environment.isExternalStorageRemovable(root) -> context.getString(R.string.external_storage) + else -> root.name + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FileExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FileExt.kt index 444737bba..f6af711a7 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FileExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FileExt.kt @@ -18,4 +18,12 @@ fun File.computeSize(): Long = listFiles()?.sumByLong { x -> } else { x.length() } -} ?: 0L \ No newline at end of file +} ?: 0L + +inline fun File.findParent(predicate: (File) -> Boolean): File? { + var current = this + while(!predicate(current)) { + current = current.parentFile ?: return null + } + return current +} \ No newline at end of file diff --git a/app/src/main/res/layout/item_storage.xml b/app/src/main/res/layout/item_storage.xml new file mode 100644 index 000000000..8399bef2d --- /dev/null +++ b/app/src/main/res/layout/item_storage.xml @@ -0,0 +1,35 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index cca0155f7..21837c952 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -100,4 +100,6 @@ Очистить историю поиска История поиска очищена Только жесты + Internal storage + External storage \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fea03487f..0910746b7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -101,4 +101,6 @@ Clear search history Search history cleared Gestures only + Internal storage + External storage \ No newline at end of file