forked from hardcoresushi/DroidFS
Thumbnails
This commit is contained in:
parent
e3df7be3b5
commit
fd5ddc02b1
@ -91,7 +91,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
|
||||
usf_keep_open = sharedPrefs.getBoolean("usf_keep_open", false)
|
||||
binding = ActivityCameraBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
gocryptfsVolume = GocryptfsVolume(intent.getIntExtra("sessionID", -1))
|
||||
gocryptfsVolume = GocryptfsVolume(applicationContext, intent.getIntExtra("sessionID", -1))
|
||||
outputDirectory = intent.getStringExtra("path")!!
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
|
@ -38,14 +38,5 @@ class ConstValues {
|
||||
fun isText(path: String): Boolean {
|
||||
return isExtensionType("text", path)
|
||||
}
|
||||
fun getAssociatedDrawable(path: String): Int {
|
||||
return when {
|
||||
isAudio(path) -> R.drawable.icon_file_audio
|
||||
isImage(path) -> R.drawable.icon_file_image
|
||||
isVideo(path) -> R.drawable.icon_file_video
|
||||
isText(path) -> R.drawable.icon_file_text
|
||||
else -> R.drawable.icon_file_unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -167,7 +167,7 @@ class CreateActivity : VolumeActionActivity() {
|
||||
super.onPause()
|
||||
//Closing volume if leaving activity while showing dialog
|
||||
if (sessionID != -1 && !isStartingExplorer) {
|
||||
GocryptfsVolume(sessionID).close()
|
||||
GocryptfsVolume(applicationContext, sessionID).close()
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import java.io.FileOutputStream
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
class GocryptfsVolume(var sessionID: Int) {
|
||||
class GocryptfsVolume(val applicationContext: Context, var sessionID: Int) {
|
||||
private external fun native_close(sessionID: Int)
|
||||
private external fun native_is_closed(sessionID: Int): Boolean
|
||||
private external fun native_list_dir(sessionID: Int, dir_path: String): MutableList<ExplorerElement>
|
||||
@ -47,79 +47,79 @@ class GocryptfsVolume(var sessionID: Int) {
|
||||
}
|
||||
|
||||
fun close() {
|
||||
synchronized(this){
|
||||
synchronized(applicationContext) {
|
||||
native_close(sessionID)
|
||||
}
|
||||
}
|
||||
|
||||
fun isClosed(): Boolean {
|
||||
synchronized(this){
|
||||
synchronized(applicationContext) {
|
||||
return native_is_closed(sessionID)
|
||||
}
|
||||
}
|
||||
|
||||
fun listDir(dir_path: String): MutableList<ExplorerElement> {
|
||||
synchronized(this){
|
||||
synchronized(applicationContext) {
|
||||
return native_list_dir(sessionID, dir_path)
|
||||
}
|
||||
}
|
||||
|
||||
fun mkdir(dir_path: String): Boolean {
|
||||
synchronized(this){
|
||||
synchronized(applicationContext) {
|
||||
return native_mkdir(sessionID, dir_path, ConstValues.DIRECTORY_MODE)
|
||||
}
|
||||
}
|
||||
|
||||
fun rmdir(dir_path: String): Boolean {
|
||||
synchronized(this){
|
||||
synchronized(applicationContext) {
|
||||
return native_rmdir(sessionID, dir_path)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeFile(file_path: String): Boolean {
|
||||
synchronized(this){
|
||||
synchronized(applicationContext) {
|
||||
return native_remove_file(sessionID, file_path)
|
||||
}
|
||||
}
|
||||
|
||||
fun pathExists(file_path: String): Boolean {
|
||||
synchronized(this){
|
||||
synchronized(applicationContext) {
|
||||
return native_path_exists(sessionID, file_path)
|
||||
}
|
||||
}
|
||||
|
||||
fun getSize(file_path: String): Long {
|
||||
synchronized(this){
|
||||
synchronized(applicationContext) {
|
||||
return native_get_size(sessionID, file_path)
|
||||
}
|
||||
}
|
||||
|
||||
fun closeFile(handleID: Int) {
|
||||
synchronized(this){
|
||||
synchronized(applicationContext) {
|
||||
native_close_file(sessionID, handleID)
|
||||
}
|
||||
}
|
||||
|
||||
fun openReadMode(file_path: String): Int {
|
||||
synchronized(this){
|
||||
synchronized(applicationContext) {
|
||||
return native_open_read_mode(sessionID, file_path)
|
||||
}
|
||||
}
|
||||
|
||||
fun openWriteMode(file_path: String): Int {
|
||||
synchronized(this){
|
||||
synchronized(applicationContext) {
|
||||
return native_open_write_mode(sessionID, file_path, ConstValues.FILE_MODE)
|
||||
}
|
||||
}
|
||||
|
||||
fun readFile(handleID: Int, offset: Long, buff: ByteArray): Int {
|
||||
synchronized(this){
|
||||
synchronized(applicationContext) {
|
||||
return native_read_file(sessionID, handleID, offset, buff)
|
||||
}
|
||||
}
|
||||
|
||||
fun writeFile(handleID: Int, offset: Long, buff: ByteArray, buff_size: Int): Int {
|
||||
synchronized(this){
|
||||
synchronized(applicationContext) {
|
||||
return native_write_file(sessionID, handleID, offset, buff, buff_size)
|
||||
}
|
||||
}
|
||||
@ -237,4 +237,40 @@ class GocryptfsVolume(var sessionID: Int) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun loadWholeFile(fullPath: String, maxSize: Long? = null): Pair<ByteArray?, Int> {
|
||||
val fileSize = getSize(fullPath)
|
||||
return if (fileSize >= 0) {
|
||||
maxSize?.let {
|
||||
if (fileSize > it) {
|
||||
return Pair(null, 0)
|
||||
}
|
||||
}
|
||||
try {
|
||||
val fileBuff = ByteArray(fileSize.toInt())
|
||||
val handleID = openReadMode(fullPath)
|
||||
if (handleID == -1) {
|
||||
Pair(null, 3)
|
||||
} else {
|
||||
var offset: Long = 0
|
||||
val ioBuffer = ByteArray(DefaultBS)
|
||||
var length: Int
|
||||
while (readFile(handleID, offset, ioBuffer).also { length = it } > 0) {
|
||||
System.arraycopy(ioBuffer, 0, fileBuff, offset.toInt(), length)
|
||||
offset += length.toLong()
|
||||
}
|
||||
closeFile(handleID)
|
||||
if (offset == fileBuff.size.toLong()) {
|
||||
Pair(fileBuff, 0)
|
||||
} else {
|
||||
Pair(null, 4)
|
||||
}
|
||||
}
|
||||
} catch (e: OutOfMemoryError) {
|
||||
Pair(null, 2)
|
||||
}
|
||||
} else {
|
||||
Pair(null, 1)
|
||||
}
|
||||
}
|
||||
}
|
@ -170,7 +170,7 @@ class OpenActivity : VolumeActionActivity() {
|
||||
if (success){
|
||||
startExplorer()
|
||||
} else {
|
||||
GocryptfsVolume(sessionID).close()
|
||||
GocryptfsVolume(applicationContext, sessionID).close()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -257,7 +257,7 @@ class OpenActivity : VolumeActionActivity() {
|
||||
if (intent.action == "pick" && !isFinishingIntentionally){
|
||||
val sessionID = intent.getIntExtra("sessionID", -1)
|
||||
if (sessionID != -1){
|
||||
GocryptfsVolume(sessionID).close()
|
||||
GocryptfsVolume(applicationContext, sessionID).close()
|
||||
RestrictedFileProvider.wipeAll(this)
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,18 @@
|
||||
package sushi.hardcore.droidfs.adapters
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import sushi.hardcore.droidfs.ConstValues.Companion.getAssociatedDrawable
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.target.DrawableImageViewTarget
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import sushi.hardcore.droidfs.ConstValues
|
||||
import sushi.hardcore.droidfs.GocryptfsVolume
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.explorers.ExplorerElement
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
@ -16,17 +20,17 @@ import java.text.DateFormat
|
||||
import java.util.*
|
||||
|
||||
class ExplorerElementAdapter(
|
||||
context: Context,
|
||||
private val onExplorerElementClick: (Int) -> Unit,
|
||||
private val onExplorerElementLongClick: (Int) -> Unit
|
||||
val activity: AppCompatActivity,
|
||||
val gocryptfsVolume: GocryptfsVolume?,
|
||||
val onExplorerElementClick: (Int) -> Unit,
|
||||
val onExplorerElementLongClick: (Int) -> Unit
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
private val dateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.getDefault())
|
||||
val dateFormat: DateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.getDefault())
|
||||
var explorerElements = listOf<ExplorerElement>()
|
||||
set(value) {
|
||||
field = value
|
||||
unSelectAll()
|
||||
}
|
||||
private val inflater: LayoutInflater = LayoutInflater.from(context)
|
||||
val selectedItems: MutableList<Int> = ArrayList()
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
@ -72,11 +76,7 @@ class ExplorerElementAdapter(
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
open class ExplorerElementViewHolder(
|
||||
itemView: View,
|
||||
private val onClick: (Int) -> Boolean,
|
||||
private val onLongClick: (Int) -> Boolean,
|
||||
) : RecyclerView.ViewHolder(itemView) {
|
||||
open class ExplorerElementViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
private val textElementName by lazy {
|
||||
itemView.findViewById<TextView>(R.id.text_element_name)
|
||||
}
|
||||
@ -99,57 +99,87 @@ class ExplorerElementAdapter(
|
||||
|
||||
open fun bind(explorerElement: ExplorerElement, position: Int) {
|
||||
textElementName.text = explorerElement.name
|
||||
(bindingAdapter as ExplorerElementAdapter?)?.let { adapter ->
|
||||
selectableContainer.setOnClickListener {
|
||||
setBackground(onClick(position))
|
||||
setBackground(adapter.onItemClick(position))
|
||||
}
|
||||
selectableContainer.setOnLongClickListener {
|
||||
setBackground(onLongClick(position))
|
||||
setBackground(adapter.onItemLongClick(position))
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class RegularElementViewHolder(
|
||||
itemView: View,
|
||||
private val dateFormat: DateFormat,
|
||||
onClick: (Int) -> Boolean,
|
||||
onLongClick: (Int) -> Boolean,
|
||||
) : ExplorerElementViewHolder(itemView, onClick, onLongClick) {
|
||||
open class RegularElementViewHolder(itemView: View) : ExplorerElementViewHolder(itemView) {
|
||||
open fun bind(explorerElement: ExplorerElement, position: Int, isSelected: Boolean) {
|
||||
super.bind(explorerElement, position)
|
||||
textElementSize.text = PathUtils.formatSize(explorerElement.size)
|
||||
textElementMtime.text = dateFormat.format(explorerElement.mTime)
|
||||
(bindingAdapter as ExplorerElementAdapter?)?.let {
|
||||
textElementMtime.text = it.dateFormat.format(explorerElement.mTime)
|
||||
}
|
||||
setBackground(isSelected)
|
||||
}
|
||||
}
|
||||
|
||||
class FileViewHolder(
|
||||
itemView: View,
|
||||
dateFormat: DateFormat,
|
||||
onClick: (Int) -> Boolean,
|
||||
onLongClick: (Int) -> Boolean,
|
||||
) : RegularElementViewHolder(itemView, dateFormat, onClick, onLongClick) {
|
||||
class FileViewHolder(itemView: View) : RegularElementViewHolder(itemView) {
|
||||
var displayThumbnail = true
|
||||
var target: DrawableImageViewTarget? = null
|
||||
|
||||
private fun loadThumbnail(fullPath: String) {
|
||||
(bindingAdapter as ExplorerElementAdapter?)?.let { adapter ->
|
||||
adapter.gocryptfsVolume?.let { volume ->
|
||||
displayThumbnail = true
|
||||
Thread {
|
||||
volume.loadWholeFile(fullPath, 50_000_000).first?.let {
|
||||
if (displayThumbnail) {
|
||||
adapter.activity.runOnUiThread {
|
||||
if (displayThumbnail) {
|
||||
target = Glide.with(adapter.activity).load(it).into(object : DrawableImageViewTarget(icon) {
|
||||
override fun onResourceReady(
|
||||
resource: Drawable,
|
||||
transition: Transition<in Drawable>?
|
||||
) {
|
||||
super.onResourceReady(resource, transition)
|
||||
target = null
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun bind(explorerElement: ExplorerElement, position: Int, isSelected: Boolean) {
|
||||
super.bind(explorerElement, position, isSelected)
|
||||
icon.setImageResource(getAssociatedDrawable(explorerElement.name))
|
||||
icon.setImageResource(
|
||||
when {
|
||||
ConstValues.isImage(explorerElement.name) -> {
|
||||
loadThumbnail(explorerElement.fullPath)
|
||||
R.drawable.icon_file_image
|
||||
}
|
||||
ConstValues.isVideo(explorerElement.name) -> {
|
||||
loadThumbnail(explorerElement.fullPath)
|
||||
R.drawable.icon_file_video
|
||||
}
|
||||
ConstValues.isText(explorerElement.name) -> R.drawable.icon_file_text
|
||||
ConstValues.isAudio(explorerElement.name) -> R.drawable.icon_file_audio
|
||||
else -> R.drawable.icon_file_unknown
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
class DirectoryViewHolder(
|
||||
itemView: View,
|
||||
dateFormat: DateFormat,
|
||||
onClick: (Int) -> Boolean,
|
||||
onLongClick: (Int) -> Boolean,
|
||||
) : RegularElementViewHolder(itemView, dateFormat, onClick, onLongClick) {
|
||||
|
||||
class DirectoryViewHolder(itemView: View) : RegularElementViewHolder(itemView) {
|
||||
override fun bind(explorerElement: ExplorerElement, position: Int, isSelected: Boolean) {
|
||||
super.bind(explorerElement, position, isSelected)
|
||||
icon.setImageResource(R.drawable.icon_folder)
|
||||
}
|
||||
}
|
||||
class ParentFolderViewHolder(
|
||||
itemView: View,
|
||||
onClick: (Int) -> Boolean,
|
||||
onLongClick: (Int) -> Boolean,
|
||||
): ExplorerElementViewHolder(itemView, onClick, onLongClick) {
|
||||
|
||||
class ParentFolderViewHolder(itemView: View): ExplorerElementViewHolder(itemView) {
|
||||
override fun bind(explorerElement: ExplorerElement, position: Int) {
|
||||
super.bind(explorerElement, position)
|
||||
textElementSize.text = ""
|
||||
@ -158,12 +188,22 @@ class ExplorerElementAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
|
||||
if (holder is FileViewHolder) {
|
||||
//cancel pending thumbnail display
|
||||
holder.displayThumbnail = false
|
||||
holder.target?.let {
|
||||
Glide.with(activity).clear(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val view = inflater.inflate(R.layout.adapter_explorer_element, parent, false)
|
||||
val view = activity.layoutInflater.inflate(R.layout.adapter_explorer_element, parent, false)
|
||||
return when (viewType) {
|
||||
ExplorerElement.REGULAR_FILE_TYPE -> FileViewHolder(view, dateFormat, ::onItemClick, ::onItemLongClick)
|
||||
ExplorerElement.DIRECTORY_TYPE -> DirectoryViewHolder(view, dateFormat, ::onItemClick, ::onItemLongClick)
|
||||
ExplorerElement.PARENT_FOLDER_TYPE -> ParentFolderViewHolder(view, ::onItemClick, ::onItemLongClick)
|
||||
ExplorerElement.REGULAR_FILE_TYPE -> FileViewHolder(view)
|
||||
ExplorerElement.DIRECTORY_TYPE -> DirectoryViewHolder(view)
|
||||
ExplorerElement.PARENT_FOLDER_TYPE -> ParentFolderViewHolder(view)
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
usf_keep_open = sharedPrefs.getBoolean("usf_keep_open", false)
|
||||
volumeName = intent.getStringExtra("volume_name") ?: ""
|
||||
val sessionID = intent.getIntExtra("sessionID", -1)
|
||||
gocryptfsVolume = GocryptfsVolume(sessionID)
|
||||
gocryptfsVolume = GocryptfsVolume(applicationContext, sessionID)
|
||||
sortOrderEntries = resources.getStringArray(R.array.sort_orders_entries)
|
||||
sortOrderValues = resources.getStringArray(R.array.sort_orders_values)
|
||||
foldersFirst = sharedPrefs.getBoolean("folders_first", true)
|
||||
@ -95,7 +95,16 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
setSupportActionBar(toolbar)
|
||||
title = ""
|
||||
titleText.text = getString(R.string.volume, volumeName)
|
||||
explorerAdapter = ExplorerElementAdapter(this, ::onExplorerItemClick, ::onExplorerItemLongClick)
|
||||
explorerAdapter = ExplorerElementAdapter(
|
||||
this,
|
||||
if (sharedPrefs.getBoolean("thumbnails", true)) {
|
||||
gocryptfsVolume
|
||||
} else {
|
||||
null
|
||||
},
|
||||
::onExplorerItemClick,
|
||||
::onExplorerItemLongClick
|
||||
)
|
||||
explorerViewModel= ViewModelProvider(this).get(ExplorerViewModel::class.java)
|
||||
currentDirectoryPath = explorerViewModel.currentDirectoryPath
|
||||
setCurrentPath(currentDirectoryPath)
|
||||
|
@ -36,7 +36,7 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
result.data?.let { resultIntent ->
|
||||
val remoteSessionID = resultIntent.getIntExtra("sessionID", -1)
|
||||
val remoteGocryptfsVolume = GocryptfsVolume(remoteSessionID)
|
||||
val remoteGocryptfsVolume = GocryptfsVolume(applicationContext, remoteSessionID)
|
||||
val path = resultIntent.getStringExtra("path")
|
||||
val operationFiles = ArrayList<OperationFile>()
|
||||
if (path == null){ //multiples elements
|
||||
|
@ -86,8 +86,7 @@ class ExplorerActivityPick : BaseExplorerActivity() {
|
||||
if (!isFinishingIntentionally && !usf_keep_open){
|
||||
val sessionID = intent.getIntExtra("originalSessionID", -1)
|
||||
if (sessionID != -1){
|
||||
val v = GocryptfsVolume(sessionID)
|
||||
v.close()
|
||||
GocryptfsVolume(applicationContext, sessionID).close()
|
||||
}
|
||||
super.closeVolumeOnDestroy()
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ abstract class FileViewerActivity: BaseActivity() {
|
||||
filePath = intent.getStringExtra("path")!!
|
||||
originalParentPath = PathUtils.getParentPath(filePath)
|
||||
val sessionID = intent.getIntExtra("sessionID", -1)
|
||||
gocryptfsVolume = GocryptfsVolume(sessionID)
|
||||
gocryptfsVolume = GocryptfsVolume(applicationContext, sessionID)
|
||||
usf_keep_open = sharedPrefs.getBoolean("usf_keep_open", false)
|
||||
foldersFirst = sharedPrefs.getBoolean("folders_first", true)
|
||||
windowInsetsController = WindowInsetsControllerCompat(window, window.decorView)
|
||||
@ -56,51 +56,20 @@ abstract class FileViewerActivity: BaseActivity() {
|
||||
}
|
||||
|
||||
protected fun loadWholeFile(path: String): ByteArray? {
|
||||
val fileSize = gocryptfsVolume.getSize(path)
|
||||
if (fileSize >= 0){
|
||||
try {
|
||||
val fileBuff = ByteArray(fileSize.toInt())
|
||||
var success = false
|
||||
val handleID = gocryptfsVolume.openReadMode(path)
|
||||
if (handleID != -1) {
|
||||
var offset: Long = 0
|
||||
val ioBuffer = ByteArray(GocryptfsVolume.DefaultBS)
|
||||
var length: Int
|
||||
while (gocryptfsVolume.readFile(handleID, offset, ioBuffer).also { length = it } > 0){
|
||||
System.arraycopy(ioBuffer, 0, fileBuff, offset.toInt(), length)
|
||||
offset += length.toLong()
|
||||
}
|
||||
gocryptfsVolume.closeFile(handleID)
|
||||
success = offset == fileBuff.size.toLong()
|
||||
}
|
||||
if (success){
|
||||
return fileBuff
|
||||
} else {
|
||||
CustomAlertDialogBuilder(this, themeValue)
|
||||
val result = gocryptfsVolume.loadWholeFile(path)
|
||||
if (result.second != 0) {
|
||||
val dialog = CustomAlertDialogBuilder(this, themeValue)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.read_file_failed)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.ok) { _, _ -> goBackToExplorer() }
|
||||
.show()
|
||||
when (result.second) {
|
||||
1 -> dialog.setMessage(R.string.get_size_failed)
|
||||
2 -> dialog.setMessage(R.string.outofmemoryerror_msg)
|
||||
else -> dialog.setMessage(R.string.read_file_failed)
|
||||
}
|
||||
} catch (e: OutOfMemoryError){
|
||||
CustomAlertDialogBuilder(this, themeValue)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.outofmemoryerror_msg)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.ok) { _, _ -> goBackToExplorer() }
|
||||
.show()
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
} else {
|
||||
CustomAlertDialogBuilder(this, themeValue)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.get_size_failed)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.ok) { _, _ -> goBackToExplorer() }
|
||||
.show()
|
||||
}
|
||||
return null
|
||||
return result.first
|
||||
}
|
||||
|
||||
protected fun createPlaylist() {
|
||||
|
5
app/src/main/res/drawable/icon_image.xml
Normal file
5
app/src/main/res/drawable/icon_image.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?attr/colorAccent" android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z"/>
|
||||
</vector>
|
@ -204,4 +204,6 @@
|
||||
<string name="encryption_cipher_label">Encryption cipher:</string>
|
||||
<string name="theme">Theme</string>
|
||||
<string name="theme_summary">Customize app theme</string>
|
||||
<string name="thumbnails">Thumbnails</string>
|
||||
<string name="thumbnails_summary">Show images and videos thumbnails</string>
|
||||
</resources>
|
||||
|
@ -38,6 +38,13 @@
|
||||
android:title="@string/folders_first"
|
||||
android:summary="@string/folders_first_summary"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:icon="@drawable/icon_image"
|
||||
android:key="thumbnails"
|
||||
android:title="@string/thumbnails"
|
||||
android:summary="@string/thumbnails_summary"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
app:icon="@drawable/icon_folder_search"
|
||||
|
Loading…
Reference in New Issue
Block a user