Storage select dialog
This commit is contained in:
@@ -11,6 +11,7 @@ import moxy.MvpAppCompatActivity
|
|||||||
import org.koin.core.KoinComponent
|
import org.koin.core.KoinComponent
|
||||||
import org.koitharu.kotatsu.BuildConfig
|
import org.koitharu.kotatsu.BuildConfig
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.ui.common.dialog.StorageSelectDialog
|
||||||
|
|
||||||
abstract class BaseActivity : MvpAppCompatActivity(), KoinComponent {
|
abstract class BaseActivity : MvpAppCompatActivity(), KoinComponent {
|
||||||
|
|
||||||
@@ -68,6 +69,10 @@ abstract class BaseActivity : MvpAppCompatActivity(), KoinComponent {
|
|||||||
recreate()
|
recreate()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if (BuildConfig.DEBUG && keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
|
||||||
|
StorageSelectDialog.Builder(this).create().show()
|
||||||
|
return true
|
||||||
|
}
|
||||||
return super.onKeyDown(keyCode, event)
|
return super.onKeyDown(keyCode, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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<Pair<File,String>> = 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,4 +18,12 @@ fun File.computeSize(): Long = listFiles()?.sumByLong { x ->
|
|||||||
} else {
|
} else {
|
||||||
x.length()
|
x.length()
|
||||||
}
|
}
|
||||||
} ?: 0L
|
} ?: 0L
|
||||||
|
|
||||||
|
inline fun File.findParent(predicate: (File) -> Boolean): File? {
|
||||||
|
var current = this
|
||||||
|
while(!predicate(current)) {
|
||||||
|
current = current.parentFile ?: return null
|
||||||
|
}
|
||||||
|
return current
|
||||||
|
}
|
||||||
35
app/src/main/res/layout/item_storage.xml
Normal file
35
app/src/main/res/layout/item_storage.xml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:minHeight="?listPreferredItemHeightLarge"
|
||||||
|
android:paddingStart="?listPreferredItemPaddingStart"
|
||||||
|
android:paddingEnd="?listPreferredItemPaddingEnd"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
tools:text="@tools:sample/lorem[3]"
|
||||||
|
android:textColor="?android:textColorPrimary"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView_subtitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="6dp"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
tools:text="@tools:sample/lorem[3]"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -100,4 +100,6 @@
|
|||||||
<string name="clear_search_history">Очистить историю поиска</string>
|
<string name="clear_search_history">Очистить историю поиска</string>
|
||||||
<string name="search_history_cleared">История поиска очищена</string>
|
<string name="search_history_cleared">История поиска очищена</string>
|
||||||
<string name="gestures_only">Только жесты</string>
|
<string name="gestures_only">Только жесты</string>
|
||||||
|
<string name="internal_storage">Internal storage</string>
|
||||||
|
<string name="external_storage">External storage</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -101,4 +101,6 @@
|
|||||||
<string name="clear_search_history">Clear search history</string>
|
<string name="clear_search_history">Clear search history</string>
|
||||||
<string name="search_history_cleared">Search history cleared</string>
|
<string name="search_history_cleared">Search history cleared</string>
|
||||||
<string name="gestures_only">Gestures only</string>
|
<string name="gestures_only">Gestures only</string>
|
||||||
|
<string name="internal_storage">Internal storage</string>
|
||||||
|
<string name="external_storage">External storage</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user