updating some dialog and documentfile related things
This commit is contained in:
parent
db42b53658
commit
464482bf1a
42 changed files with 278 additions and 188 deletions
|
@ -6,7 +6,7 @@ buildscript {
|
|||
propMinSdkVersion = 16
|
||||
propTargetSdkVersion = propCompileSdkVersion
|
||||
propVersionCode = 1
|
||||
propVersionName = '3.11.47'
|
||||
propVersionName = '3.11.48'
|
||||
kotlin_version = '1.2.21'
|
||||
support_libs = '27.0.2'
|
||||
}
|
||||
|
|
|
@ -183,8 +183,7 @@ open class BaseSimpleActivity : AppCompatActivity() {
|
|||
return
|
||||
}
|
||||
|
||||
val destinationFolder = File(destination)
|
||||
if (!destinationFolder.exists() && getSomeDocumentFile(destination) == null) {
|
||||
if (!doesFilePathExist(destination)) {
|
||||
toast(R.string.invalid_destination)
|
||||
return
|
||||
}
|
||||
|
@ -203,6 +202,7 @@ open class BaseSimpleActivity : AppCompatActivity() {
|
|||
val updatedFiles = ArrayList<FileDirItem>(fileDirItems.size * 2)
|
||||
updatedFiles.addAll(fileDirItems)
|
||||
try {
|
||||
val destinationFolder = File(destination)
|
||||
for (oldFileDirItem in fileDirItems) {
|
||||
val newFile = File(destinationFolder, oldFileDirItem.name)
|
||||
if (!newFile.exists() && File(oldFileDirItem.path).renameTo(newFile)) {
|
||||
|
@ -244,15 +244,15 @@ open class BaseSimpleActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
val file = files[index]
|
||||
val newFile = File(destinationFileDirItem.path, file.name)
|
||||
if (newFile.exists()) {
|
||||
FileConflictDialog(this, newFile) { resolution, applyForAll ->
|
||||
val newFileDirItem = FileDirItem("${destinationFileDirItem.path}/${file.name}", file.name, file.isDirectory)
|
||||
if (doesFilePathExist(newFileDirItem.path)) {
|
||||
FileConflictDialog(this, newFileDirItem) { resolution, applyForAll ->
|
||||
if (applyForAll) {
|
||||
conflictResolutions.clear()
|
||||
conflictResolutions[""] = resolution
|
||||
checkConflict(files, destinationFileDirItem, files.size, conflictResolutions, callback)
|
||||
} else {
|
||||
conflictResolutions[newFile.absolutePath] = resolution
|
||||
conflictResolutions[newFileDirItem.path] = resolution
|
||||
checkConflict(files, destinationFileDirItem, index + 1, conflictResolutions, callback)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -232,9 +232,9 @@ class CopyMoveTask(val activity: BaseSimpleActivity, val copyOnly: Boolean = fal
|
|||
while (bytes >= 0) {
|
||||
out!!.write(buffer, 0, bytes)
|
||||
copiedSize += bytes
|
||||
mCurrentProgress += bytes
|
||||
bytes = inputStream.read(buffer)
|
||||
}
|
||||
mCurrentProgress += copiedSize
|
||||
|
||||
if (source.size == copiedSize) {
|
||||
mTransferredFiles.add(source)
|
||||
|
|
|
@ -12,7 +12,7 @@ import java.io.File
|
|||
class CreateNewFolderDialog(val activity: BaseSimpleActivity, val path: String, val callback: (path: String) -> Unit) {
|
||||
init {
|
||||
val view = activity.layoutInflater.inflate(R.layout.dialog_create_new_folder, null)
|
||||
view.folder_path.text = activity.humanizePath(path).trimEnd('/') + "/"
|
||||
view.folder_path.text = "${activity.humanizePath(path)}/"
|
||||
|
||||
AlertDialog.Builder(activity)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
|
@ -45,9 +45,12 @@ class CreateNewFolderDialog(val activity: BaseSimpleActivity, val path: String,
|
|||
when {
|
||||
activity.needsStupidWritePermissions(path) -> activity.handleSAFDialog(path) {
|
||||
try {
|
||||
val documentFile = activity.getDocumentFile(path)
|
||||
documentFile?.createDirectory(path.getFilenameFromPath())
|
||||
sendSuccess(alertDialog, path)
|
||||
val documentFile = activity.getDocumentFile(path.getParentPath())
|
||||
if (documentFile?.createDirectory(path.getFilenameFromPath()) != null) {
|
||||
sendSuccess(alertDialog, path)
|
||||
} else {
|
||||
activity.toast(R.string.unknown_error_occurred)
|
||||
}
|
||||
} catch (e: SecurityException) {
|
||||
activity.showErrorToast(e)
|
||||
}
|
||||
|
|
|
@ -11,18 +11,18 @@ import com.simplemobiletools.commons.extensions.setupDialogStuff
|
|||
import com.simplemobiletools.commons.helpers.CONFLICT_MERGE
|
||||
import com.simplemobiletools.commons.helpers.CONFLICT_OVERWRITE
|
||||
import com.simplemobiletools.commons.helpers.CONFLICT_SKIP
|
||||
import com.simplemobiletools.commons.models.FileDirItem
|
||||
import kotlinx.android.synthetic.main.dialog_file_conflict.view.*
|
||||
import java.io.File
|
||||
|
||||
class FileConflictDialog(val activity: Activity, val file: File, val callback: (resolution: Int, applyForAll: Boolean) -> Unit) {
|
||||
class FileConflictDialog(val activity: Activity, val fileDirItem: FileDirItem, val callback: (resolution: Int, applyForAll: Boolean) -> Unit) {
|
||||
val view = activity.layoutInflater.inflate(R.layout.dialog_file_conflict, null)!!
|
||||
|
||||
init {
|
||||
view.apply {
|
||||
val stringBase = if (file.isDirectory) R.string.folder_already_exists else R.string.file_already_exists
|
||||
conflict_dialog_title.text = String.format(activity.getString(stringBase), file.name)
|
||||
val stringBase = if (fileDirItem.isDirectory) R.string.folder_already_exists else R.string.file_already_exists
|
||||
conflict_dialog_title.text = String.format(activity.getString(stringBase), fileDirItem.name)
|
||||
conflict_dialog_apply_to_all.isChecked = activity.baseConfig.lastConflictApplyToAll
|
||||
conflict_dialog_radio_merge.beVisibleIf(file.isDirectory)
|
||||
conflict_dialog_radio_merge.beVisibleIf(fileDirItem.isDirectory)
|
||||
|
||||
val resolutionButton = when (activity.baseConfig.lastConflictResolution) {
|
||||
CONFLICT_OVERWRITE -> conflict_dialog_radio_overwrite
|
||||
|
|
|
@ -94,7 +94,7 @@ class FilePickerDialog(val activity: BaseSimpleActivity,
|
|||
|
||||
private fun createNewFolder() {
|
||||
CreateNewFolderDialog(activity, currPath) {
|
||||
callback(it.trimEnd('/'))
|
||||
callback(it)
|
||||
mDialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,15 +6,16 @@ import android.media.ExifInterface
|
|||
import android.provider.MediaStore
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import com.simplemobiletools.commons.R
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.commons.helpers.sumByInt
|
||||
import com.simplemobiletools.commons.helpers.sumByLong
|
||||
import com.simplemobiletools.commons.models.FileDirItem
|
||||
import kotlinx.android.synthetic.main.dialog_properties.view.*
|
||||
import kotlinx.android.synthetic.main.property_item.view.*
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.util.*
|
||||
|
||||
|
@ -31,28 +32,33 @@ class PropertiesDialog() {
|
|||
* @param countHiddenItems toggle determining if we will count hidden files themselves and their sizes (reasonable only at directory properties)
|
||||
*/
|
||||
constructor(activity: Activity, path: String, countHiddenItems: Boolean = false) : this() {
|
||||
if (!activity.doesFilePathExist(path)) {
|
||||
activity.toast(String.format(activity.getString(R.string.source_file_doesnt_exist), path))
|
||||
return
|
||||
}
|
||||
|
||||
mInflater = LayoutInflater.from(activity)
|
||||
mResources = activity.resources
|
||||
val view = mInflater.inflate(R.layout.dialog_properties, null)
|
||||
mPropertyView = view.properties_holder
|
||||
|
||||
val file = File(path)
|
||||
addProperty(R.string.name, file.name)
|
||||
addProperty(R.string.path, file.parent)
|
||||
val fileDirItem = FileDirItem(path, path.getFilenameFromPath(), activity.getIsPathDirectory(path))
|
||||
addProperty(R.string.name, fileDirItem.name)
|
||||
addProperty(R.string.path, fileDirItem.getParentPath())
|
||||
addProperty(R.string.size, "…", R.id.properties_size)
|
||||
|
||||
Thread {
|
||||
val fileCount = file.getFileCount(countHiddenItems)
|
||||
val size = file.getProperSize(countHiddenItems).formatSize()
|
||||
val fileCount = fileDirItem.getProperFileCount(activity, countHiddenItems)
|
||||
val size = fileDirItem.getProperSize(activity, countHiddenItems).formatSize()
|
||||
activity.runOnUiThread {
|
||||
view.findViewById<TextView>(R.id.properties_size).property_value.text = size
|
||||
|
||||
if (file.isDirectory) {
|
||||
if (fileDirItem.isDirectory) {
|
||||
view.findViewById<TextView>(R.id.properties_file_count).property_value.text = fileCount.toString()
|
||||
}
|
||||
}
|
||||
|
||||
if (!file.isDirectory) {
|
||||
if (!fileDirItem.isDirectory) {
|
||||
val projection = arrayOf(MediaStore.Images.Media.DATE_MODIFIED)
|
||||
val uri = MediaStore.Files.getContentUri("external")
|
||||
val selection = "${MediaStore.MediaColumns.DATA} = ?"
|
||||
|
@ -60,37 +66,39 @@ class PropertiesDialog() {
|
|||
val cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor?.use {
|
||||
if (cursor.moveToFirst()) {
|
||||
val dateModified = cursor.getIntValue(MediaStore.Images.Media.DATE_MODIFIED)
|
||||
activity.runOnUiThread {
|
||||
view.findViewById<TextView>(R.id.properties_last_modified).property_value.text = (dateModified * 1000L).formatDate()
|
||||
}
|
||||
val dateModified = cursor.getLongValue(MediaStore.Images.Media.DATE_MODIFIED)
|
||||
updateLastModified(activity, view, dateModified)
|
||||
} else {
|
||||
updateLastModified(activity, view, fileDirItem.getLastModified(activity))
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
|
||||
when {
|
||||
file.isDirectory -> {
|
||||
addProperty(R.string.direct_children_count, getDirectChildrenCount(file, countHiddenItems))
|
||||
fileDirItem.isDirectory -> {
|
||||
addProperty(R.string.direct_children_count, fileDirItem.getDirectChildrenCount(activity, countHiddenItems).toString())
|
||||
addProperty(R.string.files_count, "…", R.id.properties_file_count)
|
||||
}
|
||||
file.isImageSlow() -> addProperty(R.string.resolution, file.getResolution().formatAsResolution())
|
||||
file.isAudioSlow() -> {
|
||||
file.getDuration().let { addProperty(R.string.duration, it) }
|
||||
file.getSongTitle()?.let { addProperty(R.string.song_title, it) }
|
||||
file.getArtist()?.let { addProperty(R.string.artist, it) }
|
||||
file.getAlbum()?.let { addProperty(R.string.album, it) }
|
||||
fileDirItem.path.isImageSlow() -> {
|
||||
fileDirItem.getResolution()?.let { addProperty(R.string.resolution, it.formatAsResolution()) }
|
||||
}
|
||||
file.isVideoSlow() -> {
|
||||
file.getDuration().let { addProperty(R.string.duration, it) }
|
||||
addProperty(R.string.resolution, file.getResolution().formatAsResolution())
|
||||
file.getArtist()?.let { addProperty(R.string.artist, it) }
|
||||
file.getAlbum()?.let { addProperty(R.string.album, it) }
|
||||
fileDirItem.path.isAudioSlow() -> {
|
||||
fileDirItem.getDuration()?.let { addProperty(R.string.duration, it) }
|
||||
fileDirItem.getSongTitle()?.let { addProperty(R.string.song_title, it) }
|
||||
fileDirItem.getArtist()?.let { addProperty(R.string.artist, it) }
|
||||
fileDirItem.getAlbum()?.let { addProperty(R.string.album, it) }
|
||||
}
|
||||
fileDirItem.path.isVideoSlow() -> {
|
||||
fileDirItem.getDuration()?.let { addProperty(R.string.duration, it) }
|
||||
fileDirItem.getResolution()?.let { addProperty(R.string.resolution, it.formatAsResolution()) }
|
||||
fileDirItem.getArtist()?.let { addProperty(R.string.artist, it) }
|
||||
fileDirItem.getAlbum()?.let { addProperty(R.string.album, it) }
|
||||
}
|
||||
}
|
||||
|
||||
if (file.isDirectory) {
|
||||
addProperty(R.string.last_modified, file.lastModified().formatDate())
|
||||
if (fileDirItem.isDirectory) {
|
||||
addProperty(R.string.last_modified, fileDirItem.getLastModified(activity).formatDate())
|
||||
} else {
|
||||
addProperty(R.string.last_modified, "…", R.id.properties_last_modified)
|
||||
try {
|
||||
|
@ -108,6 +116,12 @@ class PropertiesDialog() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateLastModified(activity: Activity, view: View, timestamp: Long) {
|
||||
activity.runOnUiThread {
|
||||
view.findViewById<TextView>(R.id.properties_last_modified).property_value.text = timestamp.formatDate()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A File Properties dialog constructor with an optional parameter, usable at multiple items selected
|
||||
*
|
||||
|
@ -121,22 +135,25 @@ class PropertiesDialog() {
|
|||
val view = mInflater.inflate(R.layout.dialog_properties, null)
|
||||
mPropertyView = view.properties_holder
|
||||
|
||||
val files = ArrayList<File>(paths.size)
|
||||
paths.forEach { files.add(File(it)) }
|
||||
val fileDirItems = ArrayList<FileDirItem>(paths.size)
|
||||
paths.forEach {
|
||||
val fileDirItem = FileDirItem(it, it.getFilenameFromPath(), activity.getIsPathDirectory(it))
|
||||
fileDirItems.add(fileDirItem)
|
||||
}
|
||||
|
||||
val isSameParent = isSameParent(files)
|
||||
val isSameParent = isSameParent(fileDirItems)
|
||||
|
||||
addProperty(R.string.items_selected, paths.size.toString())
|
||||
if (isSameParent) {
|
||||
addProperty(R.string.path, files[0].parent)
|
||||
addProperty(R.string.path, fileDirItems[0].getParentPath())
|
||||
}
|
||||
|
||||
addProperty(R.string.size, "…", R.id.properties_size)
|
||||
addProperty(R.string.files_count, "…", R.id.properties_file_count)
|
||||
|
||||
Thread {
|
||||
val fileCount = files.sumByInt { it.getFileCount(countHiddenItems) }
|
||||
val size = files.sumByLong { it.getProperSize(countHiddenItems) }.formatSize()
|
||||
val fileCount = fileDirItems.sumByInt { it.getProperFileCount(activity, countHiddenItems) }
|
||||
val size = fileDirItems.sumByLong { it.getProperSize(activity, countHiddenItems) }.formatSize()
|
||||
activity.runOnUiThread {
|
||||
view.findViewById<TextView>(R.id.properties_size).property_value.text = size
|
||||
view.findViewById<TextView>(R.id.properties_file_count).property_value.text = fileCount.toString()
|
||||
|
@ -168,10 +185,10 @@ class PropertiesDialog() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun isSameParent(files: List<File>): Boolean {
|
||||
var parent = files[0].parent
|
||||
for (file in files) {
|
||||
val curParent = file.parent
|
||||
private fun isSameParent(fileDirItems: List<FileDirItem>): Boolean {
|
||||
var parent = fileDirItems[0].getParentPath()
|
||||
for (file in fileDirItems) {
|
||||
val curParent = file.getParentPath()
|
||||
if (curParent != parent) {
|
||||
return false
|
||||
}
|
||||
|
@ -181,14 +198,6 @@ class PropertiesDialog() {
|
|||
return true
|
||||
}
|
||||
|
||||
private fun getDirectChildrenCount(file: File, countHiddenItems: Boolean): String {
|
||||
return if (file.listFiles() == null) {
|
||||
"0"
|
||||
} else {
|
||||
file.listFiles().filter { it != null && (!it.isHidden || (it.isHidden && countHiddenItems)) }.size.toString()
|
||||
}
|
||||
}
|
||||
|
||||
private fun addProperty(labelId: Int, value: String?, viewId: Int = 0) {
|
||||
if (value == null)
|
||||
return
|
||||
|
|
|
@ -6,18 +6,16 @@ import com.simplemobiletools.commons.R
|
|||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import kotlinx.android.synthetic.main.dialog_rename_item.view.*
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class RenameItemDialog(val activity: BaseSimpleActivity, val path: String, val callback: (newPath: String) -> Unit) {
|
||||
init {
|
||||
val file = File(path)
|
||||
val fullName = file.name
|
||||
val fullName = path.getFilenameFromPath()
|
||||
val dotAt = fullName.lastIndexOf(".")
|
||||
var name = fullName
|
||||
|
||||
val view = activity.layoutInflater.inflate(R.layout.dialog_rename_item, null).apply {
|
||||
if (dotAt > 0 && !file.isDirectory) {
|
||||
if (dotAt > 0 && !activity.getIsPathDirectory(path)) {
|
||||
name = fullName.substring(0, dotAt)
|
||||
val extension = fullName.substring(dotAt + 1)
|
||||
rename_item_extension.setText(extension)
|
||||
|
@ -27,7 +25,7 @@ class RenameItemDialog(val activity: BaseSimpleActivity, val path: String, val c
|
|||
}
|
||||
|
||||
rename_item_name.setText(name)
|
||||
rename_item_path.text = activity.humanizePath(file.parent ?: "") + "/"
|
||||
rename_item_path.text = activity.humanizePath(path.getParentPath())
|
||||
}
|
||||
|
||||
AlertDialog.Builder(activity)
|
||||
|
@ -50,22 +48,29 @@ class RenameItemDialog(val activity: BaseSimpleActivity, val path: String, val c
|
|||
return@setOnClickListener
|
||||
}
|
||||
|
||||
val updatedFiles = ArrayList<File>()
|
||||
updatedFiles.add(file)
|
||||
val updatedPaths = ArrayList<String>()
|
||||
updatedPaths.add(path)
|
||||
if (!newExtension.isEmpty()) {
|
||||
newName += ".$newExtension"
|
||||
}
|
||||
|
||||
val newFile = File(file.parent, newName)
|
||||
if (newFile.exists()) {
|
||||
if (!activity.doesFilePathExist(path)) {
|
||||
activity.toast(String.format(activity.getString(R.string.source_file_doesnt_exist), path))
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
val newPath = "${path.getParentPath()}/$newName"
|
||||
if (activity.doesFilePathExist(newPath)) {
|
||||
activity.toast(R.string.name_taken)
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
updatedFiles.add(newFile)
|
||||
activity.renameFile(path, "${file.parent}/$newName") {
|
||||
updatedPaths.add(newPath)
|
||||
activity.renameFile(path, newPath) {
|
||||
if (it) {
|
||||
sendSuccess(updatedFiles)
|
||||
activity.scanPaths(updatedPaths) {
|
||||
callback(newPath)
|
||||
}
|
||||
dismiss()
|
||||
} else {
|
||||
activity.toast(R.string.unknown_error_occurred)
|
||||
|
@ -75,30 +80,4 @@ class RenameItemDialog(val activity: BaseSimpleActivity, val path: String, val c
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendSuccess(updatedFiles: ArrayList<File>) {
|
||||
activity.apply {
|
||||
if (updatedFiles[1].isDirectory) {
|
||||
val files = updatedFiles[1].listFiles()
|
||||
if (files != null) {
|
||||
if (files.isEmpty()) {
|
||||
scanPath(updatedFiles[1].absolutePath) {
|
||||
callback(updatedFiles[1].absolutePath.trimEnd('/'))
|
||||
}
|
||||
} else {
|
||||
for (file in files) {
|
||||
scanPath(file.absolutePath) {
|
||||
callback(updatedFiles[1].absolutePath.trimEnd('/'))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
scanFiles(updatedFiles) {
|
||||
callback(updatedFiles[1].absolutePath.trimEnd('/'))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -452,7 +452,7 @@ fun BaseSimpleActivity.renameFile(oldPath: String, newPath: String, callback: ((
|
|||
}
|
||||
|
||||
try {
|
||||
val uri = DocumentsContract.renameDocument(applicationContext.contentResolver, document.uri, newPath)
|
||||
val uri = DocumentsContract.renameDocument(applicationContext.contentResolver, document.uri, newPath.getFilenameFromPath())
|
||||
if (document.uri != uri) {
|
||||
updateInMediaStore(oldPath, newPath)
|
||||
scanPaths(arrayListOf(oldPath, newPath)) {
|
||||
|
|
|
@ -98,7 +98,7 @@ fun Context.humanizePath(path: String): String {
|
|||
val basePath = path.getBasePath(this)
|
||||
return when (basePath) {
|
||||
"/" -> "${getHumanReadablePath(basePath)}$path"
|
||||
OTG_PATH -> path.replaceFirst(basePath, "${getHumanReadablePath(basePath)}/")
|
||||
OTG_PATH -> path.replaceFirst(basePath, getHumanReadablePath(basePath)).replaceFirst("otg://", OTG_PATH).trimEnd('/')
|
||||
else -> path.replaceFirst(basePath, getHumanReadablePath(basePath))
|
||||
}
|
||||
}
|
||||
|
@ -357,6 +357,14 @@ fun Context.trySAFFileDelete(fileDirItem: FileDirItem, allowDeleteFolder: Boolea
|
|||
|
||||
fun Context.doesFilePathExist(path: String) = if (isPathOnOTG(path)) getFastDocumentFile(path)?.exists() ?: false else File(path).exists()
|
||||
|
||||
fun Context.getIsPathDirectory(path: String): Boolean {
|
||||
return if (isPathOnOTG(path)) {
|
||||
getFastDocumentFile(path)?.isDirectory ?: false
|
||||
} else {
|
||||
File(path).isDirectory
|
||||
}
|
||||
}
|
||||
|
||||
// avoid these being set as SD card paths
|
||||
private val physicalPaths = arrayListOf(
|
||||
"/storage/sdcard1", // Motorola Xoom
|
||||
|
|
|
@ -27,3 +27,29 @@ private fun getDirectorySize(dir: DocumentFile, countHiddenItems: Boolean): Long
|
|||
}
|
||||
return size
|
||||
}
|
||||
|
||||
fun DocumentFile.getFileCount(countHiddenItems: Boolean): Int {
|
||||
return if (isDirectory) {
|
||||
getDirectoryFileCount(this, countHiddenItems)
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDirectoryFileCount(dir: DocumentFile, countHiddenItems: Boolean): Int {
|
||||
var count = 0
|
||||
if (dir.exists()) {
|
||||
val files = dir.listFiles()
|
||||
if (files != null) {
|
||||
for (i in files.indices) {
|
||||
val file = files[i]
|
||||
if (file.isDirectory) {
|
||||
count += getDirectoryFileCount(file, countHiddenItems)
|
||||
} else if (!file.name.startsWith(".") || countHiddenItems) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
|
|
@ -2,9 +2,6 @@ package com.simplemobiletools.commons.extensions
|
|||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Point
|
||||
import android.media.MediaMetadataRetriever
|
||||
import com.simplemobiletools.commons.models.FileDirItem
|
||||
import java.io.File
|
||||
|
||||
|
@ -20,80 +17,6 @@ fun File.isAudioSlow() = absolutePath.isAudioFast() || getMimeType().startsWith(
|
|||
|
||||
fun File.getMimeType() = absolutePath.getMimeTypeFromPath()
|
||||
|
||||
fun File.getDuration() = getDurationSeconds().getFormattedDuration()
|
||||
|
||||
fun File.getDurationSeconds(): Int {
|
||||
return try {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
retriever.setDataSource(absolutePath)
|
||||
val time = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
|
||||
val timeInMs = java.lang.Long.parseLong(time)
|
||||
(timeInMs / 1000).toInt()
|
||||
} catch (e: Exception) {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fun File.getArtist(): String? {
|
||||
return try {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
retriever.setDataSource(absolutePath)
|
||||
retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST)
|
||||
} catch (ignored: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun File.getAlbum(): String? {
|
||||
return try {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
retriever.setDataSource(absolutePath)
|
||||
retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM)
|
||||
} catch (ignored: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun File.getSongTitle(): String? {
|
||||
return try {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
retriever.setDataSource(absolutePath)
|
||||
retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE)
|
||||
} catch (ignored: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun File.getResolution(): Point {
|
||||
return if (isImageFast() || isImageSlow()) {
|
||||
getImageResolution()
|
||||
} else if (isVideoFast() || isVideoSlow()) {
|
||||
getVideoResolution()
|
||||
} else {
|
||||
return Point(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
fun File.getVideoResolution(): Point {
|
||||
try {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
retriever.setDataSource(absolutePath)
|
||||
val width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH).toInt()
|
||||
val height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT).toInt()
|
||||
return Point(width, height)
|
||||
} catch (ignored: Exception) {
|
||||
|
||||
}
|
||||
return Point(0, 0)
|
||||
}
|
||||
|
||||
fun File.getImageResolution(): Point {
|
||||
val options = BitmapFactory.Options()
|
||||
options.inJustDecodeBounds = true
|
||||
BitmapFactory.decodeFile(absolutePath, options)
|
||||
return Point(options.outWidth, options.outHeight)
|
||||
}
|
||||
|
||||
fun File.getCompressionFormat() = when (extension.toLowerCase()) {
|
||||
"png" -> Bitmap.CompressFormat.PNG
|
||||
"webp" -> Bitmap.CompressFormat.WEBP
|
||||
|
@ -102,7 +25,7 @@ fun File.getCompressionFormat() = when (extension.toLowerCase()) {
|
|||
|
||||
fun File.getProperSize(countHiddenItems: Boolean): Long {
|
||||
return if (isDirectory) {
|
||||
getDirectorySize(File(path), countHiddenItems)
|
||||
getDirectorySize(this, countHiddenItems)
|
||||
} else {
|
||||
length()
|
||||
}
|
||||
|
@ -127,7 +50,7 @@ private fun getDirectorySize(dir: File, countHiddenItems: Boolean): Long {
|
|||
|
||||
fun File.getFileCount(countHiddenItems: Boolean): Int {
|
||||
return if (isDirectory) {
|
||||
getDirectoryFileCount(File(path), countHiddenItems)
|
||||
getDirectoryFileCount(this, countHiddenItems)
|
||||
} else {
|
||||
1
|
||||
}
|
||||
|
@ -151,4 +74,4 @@ private fun getDirectoryFileCount(dir: File, countHiddenItems: Boolean): Int {
|
|||
return count
|
||||
}
|
||||
|
||||
fun File.toFileDirItem(context: Context) = FileDirItem(absolutePath, name, absolutePath.getIsDirectory(context), 0, 0L)
|
||||
fun File.toFileDirItem(context: Context) = FileDirItem(absolutePath, name, context.getIsPathDirectory(absolutePath), 0, 0L)
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package com.simplemobiletools.commons.extensions
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Point
|
||||
import android.media.ExifInterface
|
||||
import android.media.MediaMetadataRetriever
|
||||
import com.simplemobiletools.commons.helpers.OTG_PATH
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
@ -126,11 +128,83 @@ fun String.getGenericMimeType(): String {
|
|||
|
||||
fun String.getParentPath() = substring(0, length - getFilenameFromPath().length)
|
||||
|
||||
fun String.getIsDirectory(context: Context): Boolean {
|
||||
return if (context.isPathOnOTG(this)) {
|
||||
context.getFastDocumentFile(this)?.isDirectory ?: false
|
||||
fun String.getDuration() = getFileDurationSeconds()?.getFormattedDuration()
|
||||
|
||||
fun String.getFileDurationSeconds(): Int? {
|
||||
return try {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
retriever.setDataSource(this)
|
||||
val time = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
|
||||
val timeInMs = java.lang.Long.parseLong(time)
|
||||
(timeInMs / 1000).toInt()
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun String.getFileArtist(): String? {
|
||||
return try {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
retriever.setDataSource(this)
|
||||
retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST)
|
||||
} catch (ignored: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun String.getFileAlbum(): String? {
|
||||
return try {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
retriever.setDataSource(this)
|
||||
retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM)
|
||||
} catch (ignored: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun String.getFileSongTitle(): String? {
|
||||
return try {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
retriever.setDataSource(this)
|
||||
retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE)
|
||||
} catch (ignored: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun String.getResolution(): Point? {
|
||||
return if (isImageFast() || isImageSlow()) {
|
||||
getImageResolution()
|
||||
} else if (isVideoFast() || isVideoSlow()) {
|
||||
getVideoResolution()
|
||||
} else {
|
||||
File(this).isDirectory
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun String.getVideoResolution(): Point? {
|
||||
try {
|
||||
val retriever = MediaMetadataRetriever()
|
||||
retriever.setDataSource(this)
|
||||
val width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH).toInt()
|
||||
val height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT).toInt()
|
||||
return Point(width, height)
|
||||
} catch (ignored: Exception) {
|
||||
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun String.getImageResolution(): Point? {
|
||||
val options = BitmapFactory.Options()
|
||||
options.inJustDecodeBounds = true
|
||||
BitmapFactory.decodeFile(this, options)
|
||||
val width = options.outWidth
|
||||
val height = options.outHeight
|
||||
return if (width > 0 && height > 0) {
|
||||
Point(options.outWidth, options.outHeight)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -63,5 +63,45 @@ data class FileDirItem(val path: String, val name: String = "", var isDirectory:
|
|||
}
|
||||
}
|
||||
|
||||
fun getProperFileCount(context: Context, countHidden: Boolean): Int {
|
||||
return if (context.isPathOnOTG(path)) {
|
||||
context.getDocumentFile(path)?.getFileCount(countHidden) ?: 0
|
||||
} else {
|
||||
File(path).getFileCount(countHidden)
|
||||
}
|
||||
}
|
||||
|
||||
fun getDirectChildrenCount(context: Context, countHiddenItems: Boolean): Int {
|
||||
return if (context.isPathOnOTG(path)) {
|
||||
context.getDocumentFile(path)?.listFiles()?.filter { if (countHiddenItems) true else !it.name.startsWith(".") }?.size ?: 0
|
||||
} else {
|
||||
File(path).listFiles().filter { if (countHiddenItems) true else it.isHidden }.size
|
||||
}
|
||||
}
|
||||
|
||||
fun getLastModified(context: Context): Long {
|
||||
return if (context.isPathOnOTG(path)) {
|
||||
context.getFastDocumentFile(path)?.lastModified() ?: 0L
|
||||
} else {
|
||||
File(path).lastModified()
|
||||
}
|
||||
}
|
||||
|
||||
fun getParentPath() = path.getParentPath()
|
||||
|
||||
fun getDuration() = path.getDuration()
|
||||
|
||||
fun getFileDurationSeconds() = path.getFileDurationSeconds()
|
||||
|
||||
fun getArtist() = path.getFileArtist()
|
||||
|
||||
fun getAlbum() = path.getFileAlbum()
|
||||
|
||||
fun getSongTitle() = path.getFileSongTitle()
|
||||
|
||||
fun getResolution() = path.getResolution()
|
||||
|
||||
fun getVideoResolution() = path.getVideoResolution()
|
||||
|
||||
fun getImageResolution() = path.getImageResolution()
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">El nom de l\'arxiu no pot ser buit</string>
|
||||
<string name="filename_invalid_characters">El nom de l\'arxiu conté caràcters no vàlids</string>
|
||||
<string name="extension_cannot_be_empty">La extensió no pot estar buida</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Copiar</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Název souboru nemůže být prázdný</string>
|
||||
<string name="filename_invalid_characters">Název souboru obsahuje neplatné znaky</string>
|
||||
<string name="extension_cannot_be_empty">Přípona nemůže být prázdná</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Kopírovat</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Filen skal have et navn</string>
|
||||
<string name="filename_invalid_characters">Filnavnet indeholder ugyldige tegn</string>
|
||||
<string name="extension_cannot_be_empty">Filtypen kan ikke stå tom</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Kopier</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Dateiname darf nicht leer sein</string>
|
||||
<string name="filename_invalid_characters">Dateiname enthält ungültige Zeichen</string>
|
||||
<string name="extension_cannot_be_empty">Dateiendung darf nicht leer sein</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Kopieren</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">El nombre de archivo no puede estar vacío</string>
|
||||
<string name="filename_invalid_characters">El nombre archivo contiene caracteres no válidos</string>
|
||||
<string name="extension_cannot_be_empty">La extensión no puede estar vacía</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Copiar</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Filename cannot be empty</string>
|
||||
<string name="filename_invalid_characters">Filename contains invalid characters</string>
|
||||
<string name="extension_cannot_be_empty">Extension cannot be empty</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Copy</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Le nom de fichier ne peut pas rester vide</string>
|
||||
<string name="filename_invalid_characters">Le nom de fichier contient des caractères invalides</string>
|
||||
<string name="extension_cannot_be_empty">L\'extension ne peut pas rester vide</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Copier</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Filename cannot be empty</string>
|
||||
<string name="filename_invalid_characters">Filename contains invalid characters</string>
|
||||
<string name="extension_cannot_be_empty">Extension cannot be empty</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Copy</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Naziv datoteke ne smije biti prazan</string>
|
||||
<string name="filename_invalid_characters">Naziv datoteke sadrži ne podržane znakove</string>
|
||||
<string name="extension_cannot_be_empty">Ekstenzija ne smije biti prazna</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Kopiraj</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Filename cannot be empty</string>
|
||||
<string name="filename_invalid_characters">Filename contains invalid characters</string>
|
||||
<string name="extension_cannot_be_empty">Extension cannot be empty</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Copy</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Nama File Tidak Boleh Kosong</string>
|
||||
<string name="filename_invalid_characters">Nama mengandung Karakter Tidak Di Dukung</string>
|
||||
<string name="extension_cannot_be_empty">Extension Tidak Boleh Kosong</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Salin</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Il nome del file non deve essere vuoto</string>
|
||||
<string name="filename_invalid_characters">Il nome contiene caratteri non validi</string>
|
||||
<string name="extension_cannot_be_empty">L\'estensione non può essere vuota</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Copia</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">ファイル名は空にできません</string>
|
||||
<string name="filename_invalid_characters">ファイル名に無効な文字が含まれています</string>
|
||||
<string name="extension_cannot_be_empty">拡張子は省略できません</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">コピー</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">파일명이 비어있으면 안됨</string>
|
||||
<string name="filename_invalid_characters">파일명에 사용할 수 없는 문자가 포함됨</string>
|
||||
<string name="extension_cannot_be_empty">확장자가 비어있으면 안됨</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">복사</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Failo pavadinimas negali bûti paliktas tusèias</string>
|
||||
<string name="filename_invalid_characters">Failo varde yra negalimø simboliø</string>
|
||||
<string name="extension_cannot_be_empty">Papildinys negali bûti paliktas tuðèias</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Kopijuoti</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Filename cannot be empty</string>
|
||||
<string name="filename_invalid_characters">Filename contains invalid characters</string>
|
||||
<string name="extension_cannot_be_empty">Extension cannot be empty</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Kopier</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Bestandsnaam mag niet leeg zijn</string>
|
||||
<string name="filename_invalid_characters">Bestandsnaam bevat ongeldige tekens</string>
|
||||
<string name="extension_cannot_be_empty">Extensie mag niet leeg zijn</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Kopiëren</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Filename cannot be empty</string>
|
||||
<string name="filename_invalid_characters">Filename contains invalid characters</string>
|
||||
<string name="extension_cannot_be_empty">Extension cannot be empty</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Kopier</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Nazwa pliku nie może być pusta</string>
|
||||
<string name="filename_invalid_characters">Nazwa pliku zawiera niedozwolone znaki</string>
|
||||
<string name="extension_cannot_be_empty">Rozszerzenie pliku nie może być puste</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Kopiuj</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">O nome do arquivo não pode ficar em branco</string>
|
||||
<string name="filename_invalid_characters">O nome do arquivo contém caracteres inválidos</string>
|
||||
<string name="extension_cannot_be_empty">A extensão não pode ficar em branco</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Copiar</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">O nome do ficheiro não pode estar vazio</string>
|
||||
<string name="filename_invalid_characters">O nome do ficheiro contém caracteres inválidos</string>
|
||||
<string name="extension_cannot_be_empty">A extensão não pode estar vazia</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Copiar</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Имя файла не может быть пустым</string>
|
||||
<string name="filename_invalid_characters">Имя файла содержит недопустимые символы</string>
|
||||
<string name="extension_cannot_be_empty">Расширение не может быть пустым</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Копировать</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Názov súboru nemôže byť prázdny</string>
|
||||
<string name="filename_invalid_characters">Názov súboru obsahuje neplatné znaky</string>
|
||||
<string name="extension_cannot_be_empty">Prípona nesmie byť prázdna</string>
|
||||
<string name="source_file_doesnt_exist">Zdrojový súbor %s neexistuje</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Kopírovať</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Du måste ange ett filnamn</string>
|
||||
<string name="filename_invalid_characters">Filnamnet innehåller ogiltiga tecken</string>
|
||||
<string name="extension_cannot_be_empty">Filändelsen får inte vara tom</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Kopiera</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Dosya adı boş olamaz</string>
|
||||
<string name="filename_invalid_characters">Dosya adı geçersiz karakterler içeriyor</string>
|
||||
<string name="extension_cannot_be_empty">Uzantı boş olamaz</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Kopyala</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">文件名不能为空</string>
|
||||
<string name="filename_invalid_characters">文件名包含非法字符</string>
|
||||
<string name="extension_cannot_be_empty">扩展名不能为空</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">复制</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">檔名不得空白</string>
|
||||
<string name="filename_invalid_characters">檔名包含無效字符</string>
|
||||
<string name="extension_cannot_be_empty">副檔名不得空白</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">複製</string>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="filename_cannot_be_empty">Filename cannot be empty</string>
|
||||
<string name="filename_invalid_characters">Filename contains invalid characters</string>
|
||||
<string name="extension_cannot_be_empty">Extension cannot be empty</string>
|
||||
<string name="source_file_doesnt_exist">Source file %s doesn\'t exist</string>
|
||||
|
||||
<!-- Copy / Move -->
|
||||
<string name="copy">Copy</string>
|
||||
|
|
Loading…
Reference in a new issue