diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3397d71f2..c99bcbd1e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -98,24 +98,21 @@
-
-
+
-
-
+
- -->
-
+
@@ -294,6 +291,26 @@
android:autoRemoveFromRecents="true"
android:theme="@style/Theme.MaterialFiles.Translucent" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+ * All Rights Reserved.
+ */
+
+package me.zhanghai.android.files.filelist
+
+import android.app.Dialog
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatDialogFragment
+import androidx.fragment.app.Fragment
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import kotlinx.parcelize.Parcelize
+import me.zhanghai.android.files.R
+import me.zhanghai.android.files.file.FileItem
+import me.zhanghai.android.files.util.ParcelableArgs
+import me.zhanghai.android.files.util.args
+import me.zhanghai.android.files.util.putArgs
+import me.zhanghai.android.files.util.show
+
+class ConfirmReplaceFileDialogFragment : AppCompatDialogFragment() {
+ private val args by args()
+
+ private val listener: Listener
+ get() = requireParentFragment() as Listener
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ val file = args.file
+ return MaterialAlertDialogBuilder(requireContext(), theme)
+ .setMessage(getString(R.string.file_replace_message_format, file.name))
+ .setPositiveButton(android.R.string.ok) { _, _ -> listener.replaceFile(file) }
+ .setNegativeButton(android.R.string.cancel, null)
+ .create()
+ }
+
+ companion object {
+ fun show(file: FileItem, fragment: Fragment) {
+ ConfirmReplaceFileDialogFragment().putArgs(Args(file)).show(fragment)
+ }
+ }
+
+ @Parcelize
+ class Args(val file: FileItem) : ParcelableArgs
+
+ interface Listener {
+ fun replaceFile(file: FileItem)
+ }
+}
diff --git a/app/src/main/java/me/zhanghai/android/files/filelist/FileListActivity.kt b/app/src/main/java/me/zhanghai/android/files/filelist/FileListActivity.kt
index cb14fcdbb..982342861 100644
--- a/app/src/main/java/me/zhanghai/android/files/filelist/FileListActivity.kt
+++ b/app/src/main/java/me/zhanghai/android/files/filelist/FileListActivity.kt
@@ -50,22 +50,41 @@ class FileListActivity : AppActivity() {
.apply { extraPath = path }
}
- class PickDirectoryContract : ActivityResultContract() {
- override fun createIntent(context: Context, input: Path?): Intent =
+ class OpenFileContract : ActivityResultContract, Path?>() {
+ override fun createIntent(context: Context, input: List): Intent =
FileListActivity::class.createIntent()
- .setAction(Intent.ACTION_OPEN_DOCUMENT_TREE)
- .apply { input?.let { extraPath = it } }
+ .setAction(Intent.ACTION_OPEN_DOCUMENT)
+ .setType(MimeType.ANY.value)
+ .addCategory(Intent.CATEGORY_OPENABLE)
+ .putExtra(Intent.EXTRA_MIME_TYPES, input.map { it.value }.toTypedArray())
override fun parseResult(resultCode: Int, intent: Intent?): Path? =
if (resultCode == RESULT_OK) intent?.extraPath else null
}
- class PickFileContract : ActivityResultContract, Path?>() {
- override fun createIntent(context: Context, input: List): Intent =
+ class CreateFileContract : ActivityResultContract, Path?>() {
+ override fun createIntent(
+ context: Context,
+ input: Triple
+ ): Intent =
FileListActivity::class.createIntent()
- .setAction(Intent.ACTION_OPEN_DOCUMENT)
- .setType(MimeType.ANY.value)
- .putExtra(Intent.EXTRA_MIME_TYPES, input.map { it.value }.toTypedArray())
+ .setAction(Intent.ACTION_CREATE_DOCUMENT)
+ .setType(input.first.value)
+ .addCategory(Intent.CATEGORY_OPENABLE)
+ .apply {
+ input.second?.let { putExtra(Intent.EXTRA_TITLE, it) }
+ input.third?.let { extraPath = it }
+ }
+
+ override fun parseResult(resultCode: Int, intent: Intent?): Path? =
+ if (resultCode == RESULT_OK) intent?.extraPath else null
+ }
+
+ class OpenDirectoryContract : ActivityResultContract() {
+ override fun createIntent(context: Context, input: Path?): Intent =
+ FileListActivity::class.createIntent()
+ .setAction(Intent.ACTION_OPEN_DOCUMENT_TREE)
+ .apply { input?.let { extraPath = it } }
override fun parseResult(resultCode: Int, intent: Intent?): Path? =
if (resultCode == RESULT_OK) intent?.extraPath else null
diff --git a/app/src/main/java/me/zhanghai/android/files/filelist/FileListAdapter.kt b/app/src/main/java/me/zhanghai/android/files/filelist/FileListAdapter.kt
index 8ab0360b6..0d300aed3 100644
--- a/app/src/main/java/me/zhanghai/android/files/filelist/FileListAdapter.kt
+++ b/app/src/main/java/me/zhanghai/android/files/filelist/FileListAdapter.kt
@@ -134,10 +134,11 @@ class FileListAdapter(
private fun isFileSelectable(file: FileItem): Boolean {
val pickOptions = pickOptions ?: return true
- return if (pickOptions.pickDirectory) {
- file.attributes.isDirectory
- } else {
- !file.attributes.isDirectory && pickOptions.mimeTypes.any { it.match(file.mimeType) }
+ return when (pickOptions.mode) {
+ PickOptions.Mode.OPEN_FILE, PickOptions.Mode.CREATE_FILE ->
+ !file.attributes.isDirectory &&
+ pickOptions.mimeTypes.any { it.match(file.mimeType) }
+ PickOptions.Mode.OPEN_DIRECTORY -> file.attributes.isDirectory
}
}
diff --git a/app/src/main/java/me/zhanghai/android/files/filelist/FileListFragment.kt b/app/src/main/java/me/zhanghai/android/files/filelist/FileListFragment.kt
index 24825720a..6050c495d 100644
--- a/app/src/main/java/me/zhanghai/android/files/filelist/FileListFragment.kt
+++ b/app/src/main/java/me/zhanghai/android/files/filelist/FileListFragment.kt
@@ -25,6 +25,7 @@ import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
+import android.widget.EditText
import android.widget.ProgressBar
import android.widget.TextView
import androidx.activity.OnBackPressedCallback
@@ -38,6 +39,7 @@ import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import androidx.core.view.GravityCompat
+import androidx.core.view.isVisible
import androidx.core.view.updatePaddingRelative
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
@@ -64,6 +66,7 @@ import me.zhanghai.android.files.databinding.FileListFragmentSpeedDialIncludeBin
import me.zhanghai.android.files.file.FileItem
import me.zhanghai.android.files.file.MimeType
import me.zhanghai.android.files.file.asMimeTypeOrNull
+import me.zhanghai.android.files.file.extension
import me.zhanghai.android.files.file.fileProviderUri
import me.zhanghai.android.files.file.isApk
import me.zhanghai.android.files.file.isImage
@@ -100,6 +103,8 @@ import me.zhanghai.android.files.util.Stateful
import me.zhanghai.android.files.util.Success
import me.zhanghai.android.files.util.addOnBackPressedCallback
import me.zhanghai.android.files.util.args
+import me.zhanghai.android.files.util.asFileName
+import me.zhanghai.android.files.util.asFileNameOrNull
import me.zhanghai.android.files.util.checkSelfPermission
import me.zhanghai.android.files.util.copyText
import me.zhanghai.android.files.util.create
@@ -116,6 +121,7 @@ import me.zhanghai.android.files.util.getQuantityString
import me.zhanghai.android.files.util.hasSw600Dp
import me.zhanghai.android.files.util.isOrientationLandscape
import me.zhanghai.android.files.util.putArgs
+import me.zhanghai.android.files.util.setOnEditorConfirmActionListener
import me.zhanghai.android.files.util.showToast
import me.zhanghai.android.files.util.startActivitySafe
import me.zhanghai.android.files.util.supportsExternalStorageManager
@@ -127,11 +133,11 @@ import me.zhanghai.android.files.viewer.image.ImageViewerActivity
import kotlin.math.roundToInt
class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.Listener,
- OpenApkDialogFragment.Listener, ConfirmDeleteFilesDialogFragment.Listener,
- CreateArchiveDialogFragment.Listener, RenameFileDialogFragment.Listener,
- CreateFileDialogFragment.Listener, CreateDirectoryDialogFragment.Listener,
- NavigateToPathDialogFragment.Listener, NavigationFragment.Listener,
- ShowRequestAllFilesAccessRationaleDialogFragment.Listener,
+ ConfirmReplaceFileDialogFragment.Listener, OpenApkDialogFragment.Listener,
+ ConfirmDeleteFilesDialogFragment.Listener, CreateArchiveDialogFragment.Listener,
+ RenameFileDialogFragment.Listener, CreateFileDialogFragment.Listener,
+ CreateDirectoryDialogFragment.Listener, NavigateToPathDialogFragment.Listener,
+ NavigationFragment.Listener, ShowRequestAllFilesAccessRationaleDialogFragment.Listener,
ShowRequestNotificationPermissionRationaleDialogFragment.Listener,
ShowRequestNotificationPermissionInSettingsRationaleDialogFragment.Listener,
ShowRequestStoragePermissionRationaleDialogFragment.Listener,
@@ -280,23 +286,40 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
when (val action = intent.action ?: Intent.ACTION_VIEW) {
Intent.ACTION_GET_CONTENT, Intent.ACTION_OPEN_DOCUMENT,
Intent.ACTION_CREATE_DOCUMENT -> {
- val readOnly = action == Intent.ACTION_GET_CONTENT
+ val mode = if (action == Intent.ACTION_CREATE_DOCUMENT) {
+ PickOptions.Mode.CREATE_FILE
+ } else {
+ PickOptions.Mode.OPEN_FILE
+ }
val mimeType = intent.type?.asMimeTypeOrNull() ?: MimeType.ANY
- val extraMimeTypes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES)
- ?.mapNotNull { it.asMimeTypeOrNull() }?.takeIfNotEmpty()
+ val fileName = if (mode == PickOptions.Mode.CREATE_FILE) {
+ intent.getStringExtra(Intent.EXTRA_TITLE)?.asFileNameOrNull()?.value
+ ?: mimeType.extension?.let { "file.$it" } ?: "file"
+ } else {
+ null
+ }
+ val readOnly = action == Intent.ACTION_GET_CONTENT
+ val extraMimeTypes = if (mode == PickOptions.Mode.OPEN_FILE) {
+ intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES)
+ ?.mapNotNull { it.asMimeTypeOrNull() }?.takeIfNotEmpty()
+ } else {
+ null
+ }
val mimeTypes = extraMimeTypes ?: listOf(mimeType)
val localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false)
- val allowMultiple = intent.getBooleanExtra(Intent.EXTRA_ALLOW_MULTIPLE, false)
- // TODO: Actually support ACTION_CREATE_DOCUMENT.
- pickOptions = PickOptions(readOnly, false, mimeTypes, localOnly, allowMultiple)
+ val allowMultiple = mode != PickOptions.Mode.CREATE_FILE &&
+ intent.getBooleanExtra(Intent.EXTRA_ALLOW_MULTIPLE, false)
+ pickOptions =
+ PickOptions(mode, fileName, readOnly, mimeTypes, localOnly, allowMultiple)
}
Intent.ACTION_OPEN_DOCUMENT_TREE -> {
val localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false)
- pickOptions = PickOptions(false, true, emptyList(), localOnly, false)
+ pickOptions = PickOptions(
+ PickOptions.Mode.OPEN_DIRECTORY, null, false, emptyList(), localOnly, false
+ )
}
ACTION_VIEW_DOWNLOADS ->
path = Paths.get(
- @Suppress("DEPRECATION")
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS
).path
@@ -768,13 +791,14 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
val title = if (pickOptions == null) {
getString(R.string.file_list_title)
} else {
- val titleRes = if (pickOptions.pickDirectory) {
- R.plurals.file_list_title_pick_directory
- } else {
- R.plurals.file_list_title_pick_file
- }
val count = if (pickOptions.allowMultiple) Int.MAX_VALUE else 1
- getQuantityString(titleRes, count)
+ when (pickOptions.mode) {
+ PickOptions.Mode.OPEN_FILE ->
+ getQuantityString(R.plurals.file_list_title_open_file, count)
+ PickOptions.Mode.CREATE_FILE -> getString(R.string.file_list_title_create_file)
+ PickOptions.Mode.OPEN_DIRECTORY ->
+ getQuantityString(R.plurals.file_list_title_open_directory, count)
+ }
}
requireActivity().title = title
updateSelectAllMenuItem()
@@ -813,7 +837,7 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
flags = flags or (Intent.FLAG_GRANT_WRITE_URI_PERMISSION
or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
}
- if (pickOptions.pickDirectory) {
+ if (pickOptions.mode == PickOptions.Mode.OPEN_DIRECTORY) {
flags = flags or Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
}
addFlags(flags)
@@ -871,27 +895,27 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
AppBarLayoutExpandHackListener(binding.recyclerView)
)
overlayActionMode.start(object : ToolbarActionMode.Callback {
- override fun onToolbarActionModeStarted(toolbarActionMode: ToolbarActionMode) {}
-
- override fun onToolbarActionModeItemClicked(
+ override fun onToolbarActionModeMenuItemClicked(
toolbarActionMode: ToolbarActionMode,
item: MenuItem
- ): Boolean = onOverlayActionModeItemClicked(toolbarActionMode, item)
+ ): Boolean = onOverlayActionModeMenuItemClicked(item)
override fun onToolbarActionModeFinished(toolbarActionMode: ToolbarActionMode) {
- onOverlayActionModeFinished(toolbarActionMode)
+ onOverlayActionModeFinished()
}
})
}
}
- private fun onOverlayActionModeItemClicked(
- toolbarActionMode: ToolbarActionMode,
- item: MenuItem
- ): Boolean =
+ private fun onOverlayActionModeMenuItemClicked(item: MenuItem): Boolean =
when (item.itemId) {
R.id.action_pick -> {
- pickFiles(viewModel.selectedFiles)
+ when (viewModel.pickOptions!!.mode) {
+ PickOptions.Mode.OPEN_FILE,
+ PickOptions.Mode.OPEN_DIRECTORY -> pickFiles(viewModel.selectedFiles)
+ PickOptions.Mode.CREATE_FILE ->
+ confirmReplaceFile(viewModel.selectedFiles.single())
+ }
true
}
R.id.action_cut -> {
@@ -921,10 +945,25 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
else -> false
}
- private fun onOverlayActionModeFinished(toolbarActionMode: ToolbarActionMode) {
+ private fun onOverlayActionModeFinished() {
viewModel.clearSelectedFiles()
}
+ private fun confirmReplaceFile(file: FileItem, setFileName: Boolean = true) {
+ if (setFileName) {
+ val fileName = file.name
+ binding.bottomCreateFileNameEdit.setText(fileName)
+ binding.bottomCreateFileNameEdit.setSelection(
+ 0, fileName.asFileName().baseName.length
+ )
+ }
+ ConfirmReplaceFileDialogFragment.show(file, this)
+ }
+
+ override fun replaceFile(file: FileItem) {
+ pickFiles(fileItemSetOf(file))
+ }
+
private fun cutFiles(files: FileItemSet) {
viewModel.addToPasteState(false, files)
viewModel.selectFiles(files, false)
@@ -978,18 +1017,48 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
private fun updateBottomToolbar() {
val pickOptions = viewModel.pickOptions
if (pickOptions != null) {
- if (!pickOptions.pickDirectory) {
- if (bottomActionMode.isActive) {
- bottomActionMode.finish()
+ bottomActionMode.setMenuResource(R.menu.file_list_pick_bottom)
+ val menu = bottomActionMode.menu
+ when (pickOptions.mode) {
+ PickOptions.Mode.CREATE_FILE -> {
+ bottomActionMode.setNavigationIcon(
+ R.drawable.check_icon_control_normal_24dp, R.string.save
+ )
+ bottomActionMode.title = null
+ binding.bottomCreateFileNameEdit.isVisible = true
+ binding.bottomCreateFileNameEdit.setOnEditorConfirmActionListener {
+ onBottomActionModeNavigationIconClicked()
+ }
+ if (!viewModel.isCreateFileNameEditInitialized) {
+ val fileName = pickOptions.fileName!!
+ binding.bottomCreateFileNameEdit.setText(fileName)
+ binding.bottomCreateFileNameEdit.setSelection(
+ 0, fileName.asFileName().baseName.length
+ )
+ binding.bottomCreateFileNameEdit.requestFocus()
+ viewModel.isCreateFileNameEditInitialized = true
+ }
+ menu.findItem(R.id.action_reset).isVisible = true
+ }
+ PickOptions.Mode.OPEN_DIRECTORY -> {
+ bottomActionMode.setNavigationIcon(
+ R.drawable.check_icon_control_normal_24dp, R.string.select
+ )
+ val path = viewModel.currentPath
+ val navigationRoot = NavigationRootMapLiveData.valueCompat[path]
+ val name = navigationRoot?.getName(requireContext()) ?: path.name
+ bottomActionMode.title =
+ getString(R.string.file_list_open_current_directory_format, name)
+ binding.bottomCreateFileNameEdit.isVisible = false
+ menu.findItem(R.id.action_reset).isVisible = false
+ }
+ else -> {
+ if (bottomActionMode.isActive) {
+ bottomActionMode.finish()
+ }
+ return
}
- return
}
- bottomActionMode.setNavigationIcon(R.drawable.check_icon_control_normal_24dp)
- val path = viewModel.currentPath
- val navigationRoot = NavigationRootMapLiveData.valueCompat[path]
- val name = navigationRoot?.getName(requireContext()) ?: path.name
- bottomActionMode.title =
- getString(R.string.file_list_select_current_directory_format, name)
} else {
val pasteState = viewModel.pasteState
val files = pasteState.files
@@ -999,7 +1068,9 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
}
return
}
- bottomActionMode.setNavigationIcon(R.drawable.close_icon_control_normal_24dp)
+ bottomActionMode.setNavigationIcon(
+ R.drawable.close_icon_control_normal_24dp, R.string.close
+ )
val areAllFilesArchivePaths = files.all { it.path.isArchivePath }
bottomActionMode.title = getString(
if (pasteState.copy) {
@@ -1012,6 +1083,7 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
R.string.file_list_paste_move_title_format
}, files.size
)
+ binding.bottomCreateFileNameEdit.isVisible = false
bottomActionMode.setMenuResource(R.menu.file_list_paste)
val isCurrentPathReadOnly = viewModel.currentPath.fileSystem.isReadOnly
bottomActionMode.menu.findItem(R.id.action_paste)
@@ -1022,25 +1094,62 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
}
if (!bottomActionMode.isActive) {
bottomActionMode.start(object : ToolbarActionMode.Callback {
- override fun onToolbarActionModeStarted(toolbarActionMode: ToolbarActionMode) {}
+ override fun onToolbarNavigationIconClicked(toolbarActionMode: ToolbarActionMode) {
+ onBottomActionModeNavigationIconClicked()
+ }
- override fun onToolbarActionModeItemClicked(
+ override fun onToolbarActionModeMenuItemClicked(
toolbarActionMode: ToolbarActionMode,
item: MenuItem
- ): Boolean = onBottomActionModeItemClicked(toolbarActionMode, item)
+ ): Boolean = onBottomActionModeMenuItemClicked(item)
override fun onToolbarActionModeFinished(toolbarActionMode: ToolbarActionMode) {
- onBottomActionModeFinished(toolbarActionMode)
+ onBottomActionModeFinished()
}
})
}
}
- private fun onBottomActionModeItemClicked(
- toolbarActionMode: ToolbarActionMode,
- item: MenuItem
- ): Boolean =
+ private fun onBottomActionModeNavigationIconClicked() {
+ val pickOptions = viewModel.pickOptions
+ if (pickOptions != null) {
+ when (pickOptions.mode) {
+ PickOptions.Mode.CREATE_FILE -> {
+ val fileName = binding.bottomCreateFileNameEdit.text.toString()
+ if (fileName.isEmpty()) {
+ showToast(R.string.file_list_create_file_name_error_empty)
+ return
+ }
+ if (fileName.asFileNameOrNull() == null) {
+ showToast(R.string.file_list_create_file_name_error_invalid)
+ return
+ }
+ val file = getFileWithName(fileName)
+ if (file != null) {
+ confirmReplaceFile(file, false)
+ } else {
+ val path = viewModel.currentPath.resolve(fileName)
+ pickPaths(linkedSetOf(path))
+ }
+ }
+ PickOptions.Mode.OPEN_DIRECTORY -> pickPaths(linkedSetOf(viewModel.currentPath))
+ else -> bottomActionMode.finish()
+ }
+ } else {
+ bottomActionMode.finish()
+ }
+ }
+
+ private fun onBottomActionModeMenuItemClicked(item: MenuItem): Boolean =
when (item.itemId) {
+ R.id.action_reset -> {
+ val fileName = viewModel.pickOptions!!.fileName!!
+ binding.bottomCreateFileNameEdit.setText(fileName)
+ binding.bottomCreateFileNameEdit.setSelection(
+ 0, fileName.asFileName().baseName.length
+ )
+ true
+ }
R.id.action_paste -> {
pasteFiles(currentPath)
true
@@ -1048,13 +1157,9 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
else -> false
}
- private fun onBottomActionModeFinished(toolbarActionMode: ToolbarActionMode) {
+ private fun onBottomActionModeFinished() {
val pickOptions = viewModel.pickOptions
- if (pickOptions != null) {
- if (pickOptions.pickDirectory) {
- pickPaths(linkedSetOf(viewModel.currentPath))
- }
- } else {
+ if (pickOptions == null) {
viewModel.clearPasteState()
}
}
@@ -1097,8 +1202,12 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
if (pickOptions != null) {
if (file.attributes.isDirectory) {
navigateTo(file.path)
- } else if (!pickOptions.pickDirectory) {
- pickFiles(fileItemSetOf(file))
+ } else {
+ when (pickOptions.mode) {
+ PickOptions.Mode.OPEN_FILE -> pickFiles(fileItemSetOf(file))
+ PickOptions.Mode.CREATE_FILE -> confirmReplaceFile(file)
+ PickOptions.Mode.OPEN_DIRECTORY -> {}
+ }
}
return
}
@@ -1219,9 +1328,14 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
RenameFileDialogFragment.show(file, this)
}
- override fun hasFileWithName(name: String): Boolean {
+ override fun hasFileWithName(name: String): Boolean = getFileWithName(name) != null
+
+ private fun getFileWithName(name: String): FileItem? {
val fileListData = viewModel.fileListStateful
- return fileListData is Success && fileListData.value.any { it.name == name }
+ if (fileListData !is Success) {
+ return null
+ }
+ return fileListData.value.find { it.name == name }
}
override fun renameFile(file: FileItem, newName: String) {
@@ -1558,6 +1672,7 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
val recyclerView: RecyclerView,
val bottomBarLayout: ViewGroup,
val bottomToolbar: Toolbar,
+ val bottomCreateFileNameEdit: EditText,
val speedDialView: SpeedDialView
) {
companion object {
@@ -1581,7 +1696,7 @@ class FileListFragment : Fragment(), BreadcrumbLayout.Listener, FileListAdapter.
contentBinding.progress, contentBinding.errorText, contentBinding.emptyView,
contentBinding.swipeRefreshLayout, contentBinding.recyclerView,
bottomBarBinding.bottomBarLayout, bottomBarBinding.bottomToolbar,
- speedDialBinding.speedDialView
+ bottomBarBinding.bottomCreateFileNameEdit, speedDialBinding.speedDialView
)
}
}
diff --git a/app/src/main/java/me/zhanghai/android/files/filelist/FileListViewModel.kt b/app/src/main/java/me/zhanghai/android/files/filelist/FileListViewModel.kt
index b31eccbc1..bafa4c659 100644
--- a/app/src/main/java/me/zhanghai/android/files/filelist/FileListViewModel.kt
+++ b/app/src/main/java/me/zhanghai/android/files/filelist/FileListViewModel.kt
@@ -139,6 +139,8 @@ class FileListViewModel : ViewModel() {
_pickOptionsLiveData.value = value
}
+ var isCreateFileNameEditInitialized: Boolean = false
+
private val _selectedFilesLiveData = MutableLiveData(fileItemSetOf())
val selectedFilesLiveData: LiveData
get() = _selectedFilesLiveData
diff --git a/app/src/main/java/me/zhanghai/android/files/filelist/PickOptions.kt b/app/src/main/java/me/zhanghai/android/files/filelist/PickOptions.kt
index ab4f72f9a..1082d6fe1 100644
--- a/app/src/main/java/me/zhanghai/android/files/filelist/PickOptions.kt
+++ b/app/src/main/java/me/zhanghai/android/files/filelist/PickOptions.kt
@@ -8,9 +8,16 @@ package me.zhanghai.android.files.filelist
import me.zhanghai.android.files.file.MimeType
class PickOptions(
+ val mode: Mode,
+ val fileName: String?,
val readOnly: Boolean,
- val pickDirectory: Boolean,
val mimeTypes: List,
val localOnly: Boolean,
val allowMultiple: Boolean
-)
+) {
+ enum class Mode {
+ OPEN_FILE,
+ CREATE_FILE,
+ OPEN_DIRECTORY
+ }
+}
diff --git a/app/src/main/java/me/zhanghai/android/files/navigation/EditBookmarkDirectoryDialogFragment.kt b/app/src/main/java/me/zhanghai/android/files/navigation/EditBookmarkDirectoryDialogFragment.kt
index d14929423..e91a93958 100644
--- a/app/src/main/java/me/zhanghai/android/files/navigation/EditBookmarkDirectoryDialogFragment.kt
+++ b/app/src/main/java/me/zhanghai/android/files/navigation/EditBookmarkDirectoryDialogFragment.kt
@@ -30,9 +30,8 @@ import me.zhanghai.android.files.util.putState
import me.zhanghai.android.files.util.setTextWithSelection
class EditBookmarkDirectoryDialogFragment : AppCompatDialogFragment() {
- private val pickPathLauncher = registerForActivityResult(
- FileListActivity.PickDirectoryContract(), this::onPickPathResult
- )
+ private val openPathLauncher =
+ registerForActivityResult(FileListActivity.OpenDirectoryContract(), ::onOpenPathResult)
private val args by args()
@@ -75,10 +74,10 @@ class EditBookmarkDirectoryDialogFragment : AppCompatDialogFragment() {
}
private fun onEditPath() {
- pickPathLauncher.launchSafe(path, this)
+ openPathLauncher.launchSafe(path, this)
}
- private fun onPickPathResult(result: Path?) {
+ private fun onOpenPathResult(result: Path?) {
result ?: return
path = result
updatePathText()
diff --git a/app/src/main/java/me/zhanghai/android/files/settings/BookmarkDirectoryListFragment.kt b/app/src/main/java/me/zhanghai/android/files/settings/BookmarkDirectoryListFragment.kt
index b91f88df5..6852680f8 100644
--- a/app/src/main/java/me/zhanghai/android/files/settings/BookmarkDirectoryListFragment.kt
+++ b/app/src/main/java/me/zhanghai/android/files/settings/BookmarkDirectoryListFragment.kt
@@ -32,9 +32,8 @@ import me.zhanghai.android.files.util.putArgs
import me.zhanghai.android.files.util.startActivitySafe
class BookmarkDirectoryListFragment : Fragment(), BookmarkDirectoryListAdapter.Listener {
- private val pickPathLauncher = registerForActivityResult(
- FileListActivity.PickDirectoryContract(), this::onPickPathResult
- )
+ private val openPathLauncher =
+ registerForActivityResult(FileListActivity.OpenDirectoryContract(), ::onOpenPathResult)
private lateinit var binding: BookmarkDirectoryListFragmentBinding
@@ -98,10 +97,10 @@ class BookmarkDirectoryListFragment : Fragment(), BookmarkDirectoryListAdapter.L
}
private fun onAddBookmarkDirectory() {
- pickPathLauncher.launchSafe(null, this)
+ openPathLauncher.launchSafe(null, this)
}
- private fun onPickPathResult(result: Path?) {
+ private fun onOpenPathResult(result: Path?) {
result ?: return
BookmarkDirectories.add(BookmarkDirectory(null, result))
}
diff --git a/app/src/main/java/me/zhanghai/android/files/settings/PathPreference.kt b/app/src/main/java/me/zhanghai/android/files/settings/PathPreference.kt
index b4d310fb4..50d841a0f 100644
--- a/app/src/main/java/me/zhanghai/android/files/settings/PathPreference.kt
+++ b/app/src/main/java/me/zhanghai/android/files/settings/PathPreference.kt
@@ -24,7 +24,7 @@ import me.zhanghai.android.files.util.startActivityForResultSafe
import me.zhanghai.android.files.util.valueCompat
abstract class PathPreference : Preference, PreferenceActivityResultListener {
- private val pickDirectoryContract = FileListActivity.PickDirectoryContract()
+ private val openPathContract = FileListActivity.OpenDirectoryContract()
var path: Path = persistedPath
set(value) {
@@ -76,13 +76,13 @@ abstract class PathPreference : Preference, PreferenceActivityResultListener {
override fun onPreferenceClick(fragment: PreferenceFragmentCompat, preference: Preference) {
fragment.startActivityForResultSafe(
- pickDirectoryContract.createIntent(fragment.requireContext(), path), requestCode
+ openPathContract.createIntent(fragment.requireContext(), path), requestCode
)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == this.requestCode) {
- val result = pickDirectoryContract.parseResult(resultCode, data)
+ val result = openPathContract.parseResult(resultCode, data)
if (result != null) {
path = result
}
diff --git a/app/src/main/java/me/zhanghai/android/files/storage/EditSftpServerFragment.kt b/app/src/main/java/me/zhanghai/android/files/storage/EditSftpServerFragment.kt
index 122fefec4..3626fc48e 100644
--- a/app/src/main/java/me/zhanghai/android/files/storage/EditSftpServerFragment.kt
+++ b/app/src/main/java/me/zhanghai/android/files/storage/EditSftpServerFragment.kt
@@ -43,8 +43,8 @@ import me.zhanghai.android.files.util.viewModels
import java.net.URI
class EditSftpServerFragment : Fragment() {
- private val pickPrivateKeyFileLauncher = registerForActivityResult(
- FileListActivity.PickFileContract(), this::onPickPrivateKeyFileResult
+ private val openPrivateKeyFileLauncher = registerForActivityResult(
+ FileListActivity.OpenFileContract(), this::onOpenPrivateKeyFileResult
)
private val args by args()
@@ -204,10 +204,10 @@ class EditSftpServerFragment : Fragment() {
if (!viewModel.readPrivateKeyFileState.value.isReady) {
return
}
- pickPrivateKeyFileLauncher.launchSafe(listOf(MimeType.ANY), this)
+ openPrivateKeyFileLauncher.launchSafe(listOf(MimeType.ANY), this)
}
- private fun onPickPrivateKeyFileResult(result: Path?) {
+ private fun onOpenPrivateKeyFileResult(result: Path?) {
result ?: return
viewModel.readPrivateKeyFile(result)
}
diff --git a/app/src/main/java/me/zhanghai/android/files/ui/ToolbarActionMode.kt b/app/src/main/java/me/zhanghai/android/files/ui/ToolbarActionMode.kt
index db94b2daa..b80709577 100644
--- a/app/src/main/java/me/zhanghai/android/files/ui/ToolbarActionMode.kt
+++ b/app/src/main/java/me/zhanghai/android/files/ui/ToolbarActionMode.kt
@@ -24,9 +24,9 @@ abstract class ToolbarActionMode(
private var callback: Callback? = null
init {
- toolbar.setNavigationOnClickListener { finish() }
+ toolbar.setNavigationOnClickListener { callback?.onToolbarNavigationIconClicked(this) }
toolbar.setOnMenuItemClickListener {
- callback?.onToolbarActionModeItemClicked(this, it) ?: false
+ callback?.onToolbarActionModeMenuItemClicked(this, it) ?: false
}
}
@@ -42,8 +42,15 @@ abstract class ToolbarActionMode(
toolbar.navigationIcon = value
}
- fun setNavigationIcon(@DrawableRes iconRes: Int) {
+ var navigationContentDescription: CharSequence?
+ get() = toolbar.navigationContentDescription
+ set(value) {
+ toolbar.navigationContentDescription = value
+ }
+
+ fun setNavigationIcon(@DrawableRes iconRes: Int, @StringRes contentDescriptionRes: Int) {
toolbar.setNavigationIcon(iconRes)
+ toolbar.setNavigationContentDescription(contentDescriptionRes)
}
var title: CharSequence?
@@ -104,9 +111,13 @@ abstract class ToolbarActionMode(
protected abstract fun hide(bar: ViewGroup, animate: Boolean)
interface Callback {
- fun onToolbarActionModeStarted(toolbarActionMode: ToolbarActionMode)
+ fun onToolbarActionModeStarted(toolbarActionMode: ToolbarActionMode) {}
+
+ fun onToolbarNavigationIconClicked(toolbarActionMode: ToolbarActionMode) {
+ toolbarActionMode.finish()
+ }
- fun onToolbarActionModeItemClicked(
+ fun onToolbarActionModeMenuItemClicked(
toolbarActionMode: ToolbarActionMode,
item: MenuItem
): Boolean
diff --git a/app/src/main/java/me/zhanghai/android/files/util/FragmentExtensions.kt b/app/src/main/java/me/zhanghai/android/files/util/FragmentExtensions.kt
index 2ad3cfd9a..2b50e40fd 100644
--- a/app/src/main/java/me/zhanghai/android/files/util/FragmentExtensions.kt
+++ b/app/src/main/java/me/zhanghai/android/files/util/FragmentExtensions.kt
@@ -163,11 +163,13 @@ val Fragment.mediumAnimTime
val Fragment.longAnimTime
get() = requireContext().longAnimTime
-fun Fragment.showToast(textRes: Int, duration: Int = Toast.LENGTH_SHORT) =
+fun Fragment.showToast(textRes: Int, duration: Int = Toast.LENGTH_SHORT) {
requireContext().showToast(textRes, duration)
+}
-fun Fragment.showToast(text: CharSequence, duration: Int = Toast.LENGTH_SHORT) =
+fun Fragment.showToast(text: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
requireContext().showToast(text, duration)
+}
fun Fragment.startActivitySafe(intent: Intent, options: Bundle? = null) {
try {
diff --git a/app/src/main/java/me/zhanghai/android/files/util/IntentPathExtensions.kt b/app/src/main/java/me/zhanghai/android/files/util/IntentPathExtensions.kt
index 60a567205..62074bfca 100644
--- a/app/src/main/java/me/zhanghai/android/files/util/IntentPathExtensions.kt
+++ b/app/src/main/java/me/zhanghai/android/files/util/IntentPathExtensions.kt
@@ -37,6 +37,17 @@ var Intent.extraPath: Path?
putExtra(EXTRA_PATH_URI, value?.toUri()?.toString())
}
+val Intent.saveAsPath: Path?
+ get() {
+ val uri =
+ when (action) {
+ Intent.ACTION_VIEW -> data
+ Intent.ACTION_SEND -> getParcelableExtraSafe(Intent.EXTRA_STREAM) as? Uri
+ else -> null
+ }
+ return uri?.toPathOrNull()
+ }
+
private fun Uri.toPathOrNull(): Path? =
when (scheme) {
ContentResolver.SCHEME_FILE, null -> path?.takeIfNotEmpty()?.let { Paths.get(it) }
diff --git a/app/src/main/java/me/zhanghai/android/files/viewer/saveas/SaveAsActivity.kt b/app/src/main/java/me/zhanghai/android/files/viewer/saveas/SaveAsActivity.kt
new file mode 100644
index 000000000..a550f34c4
--- /dev/null
+++ b/app/src/main/java/me/zhanghai/android/files/viewer/saveas/SaveAsActivity.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2024 Hai Zhang
+ * All Rights Reserved.
+ */
+
+package me.zhanghai.android.files.viewer.saveas
+
+import android.os.Bundle
+import android.os.Environment
+import java8.nio.file.Path
+import java8.nio.file.Paths
+import me.zhanghai.android.files.R
+import me.zhanghai.android.files.app.AppActivity
+import me.zhanghai.android.files.file.MimeType
+import me.zhanghai.android.files.file.asMimeTypeOrNull
+import me.zhanghai.android.files.filejob.FileJobService
+import me.zhanghai.android.files.filelist.FileListActivity
+import me.zhanghai.android.files.util.saveAsPath
+import me.zhanghai.android.files.util.showToast
+
+class SaveAsActivity : AppActivity() {
+ private val createFileLauncher =
+ registerForActivityResult(FileListActivity.CreateFileContract(), ::onCreateFileResult)
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val intent = intent
+ val mimeType = intent.type?.asMimeTypeOrNull() ?: MimeType.ANY
+ val path = intent.saveAsPath
+ if (path == null) {
+ showToast(R.string.save_as_error)
+ finish()
+ return
+ }
+ val title = path.fileName.toString()
+ val initialPath =
+ Paths.get(
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).path
+ )
+ createFileLauncher.launch(Triple(mimeType, title, initialPath))
+ }
+
+ private fun onCreateFileResult(result: Path?) {
+ if (result == null) {
+ finish()
+ return
+ }
+ FileJobService.save(intent.saveAsPath!!, result, this)
+ finish()
+ }
+}
diff --git a/app/src/main/res/layout-sw600dp-land/file_list_fragment_include.xml b/app/src/main/res/layout-sw600dp-land/file_list_fragment_include.xml
index d63ce4d11..c24dabea8 100644
--- a/app/src/main/res/layout-sw600dp-land/file_list_fragment_include.xml
+++ b/app/src/main/res/layout-sw600dp-land/file_list_fragment_include.xml
@@ -38,7 +38,7 @@
-
+
diff --git a/app/src/main/res/layout/file_list_fragment_bottom_bar_include.xml b/app/src/main/res/layout/file_list_fragment_bottom_bar_include.xml
index 44f531e33..512cefb80 100644
--- a/app/src/main/res/layout/file_list_fragment_bottom_bar_include.xml
+++ b/app/src/main/res/layout/file_list_fragment_bottom_bar_include.xml
@@ -26,6 +26,17 @@
android:paddingStart="@dimen/file_list_toolbar_padding_start"
android:paddingEnd="@dimen/file_list_toolbar_padding_end_no_overflow"
app:navigationIcon="@drawable/close_icon_control_normal_24dp"
- app:popupTheme="?actionBarPopupTheme" />
+ app:popupTheme="?actionBarPopupTheme">
+
+
+
diff --git a/app/src/main/res/layout/file_list_fragment_include.xml b/app/src/main/res/layout/file_list_fragment_include.xml
index a4837e422..a873bffd2 100644
--- a/app/src/main/res/layout/file_list_fragment_include.xml
+++ b/app/src/main/res/layout/file_list_fragment_include.xml
@@ -35,7 +35,7 @@
-
+
diff --git a/app/src/main/res/menu/file_list_pick_bottom.xml b/app/src/main/res/menu/file_list_pick_bottom.xml
new file mode 100644
index 000000000..a69615f70
--- /dev/null
+++ b/app/src/main/res/menu/file_list_pick_bottom.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index ac2eaad82..37f3d40b3 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -349,7 +349,7 @@
مجلد جديد
ملفات
-
+
- تحديد الملف
- تحديد الملف
- تحديد الملفان
@@ -357,7 +357,7 @@
- تحديد الملفات
- تحديد الملفات
-
+
- تحديد المجلد
- تحديد المجلد
- تحديد المجلدان
@@ -404,7 +404,7 @@
إنشاء اختصار
افتح في نافذة جديدة
%1$,d
- تحديد ”%1$s“
+ تحديد ”%1$s“
نقل %1$,d
نسخ %1$,d
استخراج %1$,d
diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml
index b62997cc2..d2539b3aa 100644
--- a/app/src/main/res/values-bg/strings.xml
+++ b/app/src/main/res/values-bg/strings.xml
@@ -262,11 +262,11 @@
Нова папка
Файлове
-
+
- Избиране на файл
- Избиране на файлове
-
+
- Избиране на папка
- Избиране на папки
@@ -301,7 +301,7 @@
Създаване на пряк път
Отваряне в нов прозорез
%1$,d
- Избиране на „%1$s”
+ Избиране на „%1$s”
Преместване на %1$,d
Копиране на %1$,d
Извличане на %1$,d
diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml
index af79b836d..0304ecd11 100644
--- a/app/src/main/res/values-ca/strings.xml
+++ b/app/src/main/res/values-ca/strings.xml
@@ -262,11 +262,11 @@
Carpeta nova
Fitxers
-
+
- Seleccioneu un fitxer
- Seleccioneu els fitxers
-
+
- Seleccioneu una carpeta
- Seleccioneu les carpetes
@@ -301,7 +301,7 @@
Crea una drecera
Obre en una finestra nova
%1$,d
- Selecciona «%1$s»
+ Selecciona «%1$s»
S\'està movent %1$,d
S\'està copiant %1$,d
S\'està extraient %1$,d
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index c586be458..4a172df2a 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -309,13 +309,13 @@
Nová složka
Soubory
-
+
- Vyberte soubor
- Vyberte soubory
- Vyberte soubory
- Vyberte soubory
-
+
- Vyberte složku
- Vyberte složky
- Vyberte složky
@@ -355,7 +355,7 @@
Přidat záložku
Vytvořit zástupce
Otevřít v novém okně
- Vyberte \"%1$s\"
+ Vyberte \"%1$s\"
Přesouvání %1$,d
Kopírování %1$,d
Rozbalování %1$,d
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 5111eea69..d60dbd02e 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -262,11 +262,11 @@
Neuer Ordner
Dateien
-
+
- Wähle eine Datei aus
- Wähle Dateien aus
-
+
- Wähle einen Ordner aus
- Wähle Ordner aus
@@ -301,7 +301,7 @@
Verknüpfung erstellen
In neuem Fenster öffnen
%1$,d
- “%1$s” auswählen
+ “%1$s” auswählen
Verschiebe %1$,d
Kopiere %1$,d
Extrahiere %1$,d
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index 5b60262ed..71da4e161 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -253,11 +253,11 @@
Νέος φάκελος
Αρχεία
-
+
- Επιλογή αρχείου
- Επιλογή αρχείων
-
+
- Επιλογή φακέλου
- Επιλογή φακέλων
@@ -291,7 +291,7 @@
Προσθήκη σελιδοδείκτη
Δημιουργία συντόμευσης
Άνοιγμα σε νέο παράθυρο
- Επιλογή “%1$s”
+ Επιλογή “%1$s”
Μετακίνηση %1$,d
Αντιγραφή %1$,d
Εξαγωγή %1$,d
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 8927634c5..2b45b4377 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -286,12 +286,12 @@
Nueva carpeta
Archivos
-
+
- Seleccionar un archivo
- Seleccionar archivos
- Seleccionar archivos
-
+
- Seleccionar una carpeta
- Seleccionar carpetas
- Seleccionar carpetas
@@ -329,7 +329,7 @@
Crear atajo
Abrir en una nueva ventana
%1$,d
- Seleccionar \"%1$s\"
+ Seleccionar \"%1$s\"
Moviendo %1$,d
Copiando %1$,d
Extrayendo %1$,d
diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml
index e364f9f10..91521a631 100644
--- a/app/src/main/res/values-eu/strings.xml
+++ b/app/src/main/res/values-eu/strings.xml
@@ -233,11 +233,11 @@
Karpeta berria
Fitxategiak
-
+
- Hautatu fitxategia
- Hautatu fitxategiak
-
+
- Hautatu karpeta
- Hautatu karpetak
@@ -264,7 +264,7 @@
Gehitu laster-marka
Sortu laster-marka
Ireki leiho berrian
- Hautatu “%1$s”
+ Hautatu “%1$s”
%1$,d lekuz aldatzen
%1$,d kopiatzen
%1$,d erauzten
diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml
index d52942a66..6fe3514a9 100644
--- a/app/src/main/res/values-fa/strings.xml
+++ b/app/src/main/res/values-fa/strings.xml
@@ -254,11 +254,11 @@
شاخهٔ جدید
پروندهها
-
+
- گزینش یک پرونده
- گزینش پروندهها
-
+
- گزینش یک شاخه
- گزینش شاخهها
@@ -288,7 +288,7 @@
افزودن نشانک
ایجاد میانبر
گشودن در پنجرهٔ جدید
- گزینش «%1$s»
+ گزینش «%1$s»
در حال جابهجایی %1$,d
در حال رونوشت %1$,d
در حال استخراج %1$,d
diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml
index 47dd1ffe5..719186a83 100644
--- a/app/src/main/res/values-fi/strings.xml
+++ b/app/src/main/res/values-fi/strings.xml
@@ -241,11 +241,11 @@
Uusi kansio
Tiedostot
-
+
- Valitse tiedosto
- Valitse tiedostot
-
+
- Valitse kansio
- Valitse kansiot
@@ -280,7 +280,7 @@
Luo pikakuvake
Avaa uudessa ikkunassa
%1$,d
- Valitse “%1$s”
+ Valitse “%1$s”
Siirretään %1$,d
Kopioidaan %1$,d
Puretaan %1$,d
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index b7e0b4ef0..779b2eb98 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -288,12 +288,12 @@
Nouveau dossier
Fichiers
-
+
- Sélectionner un fichier
- Sélectionner les fichiers
- Sélectionner les fichiers
-
+
- Sélectionner un dossier
- Sélectionner les dossiers
- Sélectionner les dossiers
@@ -331,7 +331,7 @@
Créer un raccourci
Ouvrir dans une nouvelle fenêtre
%1$,d
- Selectionner “%1$s”
+ Selectionner “%1$s”
Déplacer %1$,d
Copier %1$,d
Extraire %1$,d
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index 2b2708a84..29201a1bf 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -253,11 +253,11 @@
Új mappa
Fájlok
-
+
- Fájl kiválasztása
- Fájlok kiválasztása
-
+
- Mappa kiválasztása
- Mappák kiválasztása
@@ -292,7 +292,7 @@
Parancsikon létrehozása
Megnyitás új ablakban
%1$,d
- „%1$s” kiválasztása
+ „%1$s” kiválasztása
%1$,d áthelyezése
%1$,d másolása
%1$,d fájl kibontása
diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml
index 9f4e53a08..44cd7470b 100644
--- a/app/src/main/res/values-in/strings.xml
+++ b/app/src/main/res/values-in/strings.xml
@@ -238,10 +238,10 @@
Folder baru
File
-
+
- Pilih berkas
-
+
- Pilih folder
@@ -273,7 +273,7 @@
Buat pintasan
Buka di jendela baru
%1$,d
- Pilih “%1$s”
+ Pilih “%1$s”
Memindahkan %1$,d
Menyalin %1$,d
Mengekstrak %1$,d
diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml
index 5825e5f9d..3f8717bd2 100644
--- a/app/src/main/res/values-is/strings.xml
+++ b/app/src/main/res/values-is/strings.xml
@@ -264,11 +264,11 @@
Ný mappa
Skrár
-
+
- Veldu skrá
- Veldu skrár
-
+
- Veldu möppu
- Veldu möppur
@@ -303,7 +303,7 @@
Útbúa flýtileið
Opna í nýjum glugga
%1$,d
- Velja “%1$s”
+ Velja “%1$s”
Færi %1$,d
Afrita %1$,d
Afþjappa %1$,d
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index e966cf5e6..29b70d274 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -286,12 +286,12 @@
Nuova cartella
File
-
+
- Seleziona un file
- Seleziona più file
- Seleziona più file
-
+
- Seleziona una cartella
- Seleziona cartelle
- Seleziona cartelle
@@ -329,7 +329,7 @@
Crea segnalibro
Apri in una nuova finestra
%1$,d
- Seleziona “%1$s”
+ Seleziona “%1$s”
Spostamento di %1$,d
Copia di %1$,d
Estrazione di %1$,d
diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml
index 2907b4980..8ec0d8d24 100644
--- a/app/src/main/res/values-iw/strings.xml
+++ b/app/src/main/res/values-iw/strings.xml
@@ -309,13 +309,13 @@
תיקיה חדשה
קבצים
-
+
- בחירת קובץ
- בחירת קבצים
- בחירת קבצים
- בחירת קבצים
-
+
- בחירת תיקייה
- בחירת תיקיות
- בחירת תיקיות
@@ -356,7 +356,7 @@
יצירת קיצור דרך
פתיחה בחלון חדש
%1$,d
- בחירת “%1$s”
+ בחירת “%1$s”
מעביר את %1$,d
מעתיק את %1$,d
מחלץ את %1$,d
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 009773876..2c8e9f206 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -238,10 +238,10 @@
新しいフォルダ
ファイル
-
+
- ファイルを選択
-
+
- フォルダを選択
@@ -273,7 +273,7 @@
ショートカットを作成
新しいウィンドウで開く
%1$,d
- 「%1$s」を選択
+ 「%1$s」を選択
%1$,d を移動中
%1$,d をコピー中
%1$,d を展開中
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index c970b98d4..856fd3d6f 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -238,10 +238,10 @@
새 폴더
파일
-
+
- 파일 선택
-
+
- 폴더 선택
@@ -273,7 +273,7 @@
바로가기 만들기
새 창에서 열기
%1$,d
- “%1$s” 선택
+ “%1$s” 선택
%1$,d개 항목 이동
%1$,d개 항목 복사
%1$,d개 항목 압축 해제
diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml
index 7853f45e0..422101127 100644
--- a/app/src/main/res/values-lt/strings.xml
+++ b/app/src/main/res/values-lt/strings.xml
@@ -303,13 +303,13 @@
Naujas aplankas
Failai
-
+
- Pasirinkti failą
- Pasirinkti failus
- Pasirinkti failus
- Pasirinkti failus
-
+
- Pasirinkti aplanką
- Pasirinkti aplankus
- Pasirinkti aplankus
@@ -350,7 +350,7 @@
Sukurti spartųjį kelią
Atidaryti naujame lange
%1$,d
- Pasirinkti \"%1$s\"
+ Pasirinkti \"%1$s\"
Perkeliama %1$,d
Kopijuojama %1$,d
Išskleidžiama %1$,d
diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml
index ac887cabd..8a63534e5 100644
--- a/app/src/main/res/values-nb/strings.xml
+++ b/app/src/main/res/values-nb/strings.xml
@@ -262,11 +262,11 @@
Ny mappe
Filer
-
+
- Velg en fil
- Velg filer
-
+
- Velg en mappe
- Velg mapper
@@ -301,7 +301,7 @@
Opprett snarvei
Åpne i et nytt vindu
%1$,d
- Velg «%1$s»
+ Velg «%1$s»
Flytter %1$,d
Kopierer %1$,d
Pakker ut %1$,d
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 5472e408d..c407552da 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -262,11 +262,11 @@
Nieuwe map
Bestanden
-
+
- Bestand selecteren
- Bestanden selecteren
-
+
- Map selecteren
- Mappen selecteren
@@ -301,7 +301,7 @@
Snelkoppeling maken
Openen in nieuw venster
%1$,d
- ‘%1$s’ selecteren
+ ‘%1$s’ selecteren
Bezig met verplaatsen van %1$,d
Bezig met kopiëren van %1$,d
Bezig met uitpakken van %1$,d
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 6858a5e7c..72f3def3f 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -310,13 +310,13 @@
Nowy katalog
Pliki
-
+
- Wybierz plik
- Wybierz pliki
- Wybierz pliki
- Wybierz pliki
-
+
- Wybierz katalog
- Wybierz katalogi
- Wybierz katalogi
@@ -357,7 +357,7 @@
Utwórz skrót
Otwórz w nowym oknie
%1$,d
- Wybierz „%1$s”
+ Wybierz „%1$s”
Przenoszenie %1$,d
Kopiowanie %1$,d
Rozpakowywanie %1$,d
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index bd7bb0ece..0baa9a706 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -286,12 +286,12 @@
Nova pasta
Arquivos
-
+
- Selecione um arquivo
- Selecionar arquivos
- Selecionar arquivos
-
+
- Selecione uma pasta
- Selecionar pastas
- Selecionar pastas
@@ -329,7 +329,7 @@
Criar atalho
Abrir em uma nova janela
%1$,d
- Selecionar “%1$s”
+ Selecionar “%1$s”
Movendo %1$,d
Copiando %1$,d
Extraindo %1$,d
diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml
index c48d20b8f..3eeb17b83 100644
--- a/app/src/main/res/values-pt-rPT/strings.xml
+++ b/app/src/main/res/values-pt-rPT/strings.xml
@@ -288,12 +288,12 @@
Nova pasta
Ficheiros
-
+
- Selecionar ficheiro
- Selecionar ficheiros
- Selecionar ficheiros
-
+
- Selecionar pasta
- Selecionar pastas
- Selecionar pastas
@@ -331,7 +331,7 @@
Criar atalho
Abrir em nova janela
%1$,d
- “%1$s” selecionado
+ “%1$s” selecionado
A mover %1$,d
A copiar %1$,d
A extrair %1$,d
diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml
index 6210c9757..b32939594 100644
--- a/app/src/main/res/values-ro/strings.xml
+++ b/app/src/main/res/values-ro/strings.xml
@@ -286,12 +286,12 @@
Dosar nou
Fișiere
-
+
- Selectează fișierul
- Selectează fișierele
- Selectează fișierele
-
+
- Selectează dosarul
- Selectează dosarele
- Selectează dosarele
@@ -329,7 +329,7 @@
Creează scurtătură
Deschide într-o fereastră nouă
%1$,d
- Selectat “%1$s”
+ Selectat “%1$s”
Se mută %1$,d
Se copiază %1$,d
Se extrag %1$,d
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 6643ca4b6..e94969492 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -312,13 +312,13 @@
Новая папка
Файлы
-
+
- Выбрать файл
- Выбрать файлы
- Выбрать файлы
- Выбрать файлы
-
+
- Выбрать папку
- Выбрать папки
- Выбрать папки
@@ -359,7 +359,7 @@
Создать ярлык
Открыть в новом окне
%1$,d
- Выбрать “%1$s”
+ Выбрать “%1$s”
Перемещение %1$,d
Копирование %1$,d
Извлечение %1$,d
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 16eec2d1f..18398b6f0 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -239,11 +239,11 @@
Yeni klasör
Dosyalar
-
+
- Bir dosya seç
- Dosyaları seç
-
+
- Bir klasör seç
- Klasörleri seç
@@ -270,7 +270,7 @@
Yer işareti ekle
Kısayol oluştur
Yeni pencerede aç
- “%1$s”`i seç
+ “%1$s”`i seç
%1$,d taşınıyor
%1$,d kopyalanıyor
%1$,d çıkartılıyor
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 3d49c4135..e41e7c7c3 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -312,13 +312,13 @@
Нова тека
Файли
-
+
- Вибрати файл
- Вибрати файли
- Вибрати файли
- Вибрати файли
-
+
- Вибарти теку
- Вибрати теки
- Вибрати теки
@@ -359,7 +359,7 @@
Створити скорочення
Відкрити в новому вікні
%1$,d
- Вибрати “%1$s”
+ Вибрати “%1$s”
Переміщення %1$,d
Копіювання %1$,d
Видобування %1$,d
diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml
index 17d02a4af..78af23044 100644
--- a/app/src/main/res/values-vi/strings.xml
+++ b/app/src/main/res/values-vi/strings.xml
@@ -228,10 +228,10 @@
Thư mục mới
Tệp
-
+
- Chọn tệp
-
+
- Chọn thư mục
@@ -258,7 +258,7 @@
Thêm đánh dấu
Tạo lối tắt
Mở trong cửa sổ mới
- Chọn “%1$s”
+ Chọn “%1$s”
Đang di chuyển %1$,d
Đang sao chép %1$,d
Đang giải nén %1$,d
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index d1a604a26..2721c003f 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -215,6 +215,7 @@
文件名不能为空
无效文件名
已存在同名的文件
+ 替换“%1$s”?
删除“%1$s”?
删除文件夹“%1$s”和它的内容?
@@ -236,10 +237,11 @@
新建文件夹
文件
-
+
- 选择文件
-
+ 保存文件
+
- 选择文件夹
@@ -271,7 +273,8 @@
创建快捷方式
在新窗口中打开
%1$,d
- 选择“%1$s”
+ 文件名
+ 选择“%1$s”
移动 %1$,d
复制 %1$,d
提取 %1$,d
@@ -541,6 +544,9 @@
归档文件查看器
图片查看器
%1$,d/%2$,d
+ 另存为
+ 保存时发生错误
+ 已将“%1$s”保存到“%2$s”
文本编辑器
%1$s
*%1$s
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 10ccbca41..2313926ca 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -215,6 +215,7 @@
檔案名稱不能為空
無效的檔案名稱
已存在同名的檔案
+ 取代「%1$s」?
刪除「%1$s」?
刪除資料夾「%1$s」和它的內容?
@@ -236,10 +237,11 @@
新資料夾
檔案
-
+
- 選取檔案
-
+ 儲存檔案
+
- 選取資料夾
@@ -271,7 +273,8 @@
建立捷徑
在新視窗中開啟
%1$,d
- 選取「%1$s」
+ 檔案名稱
+ 選取「%1$s」
移動 %1$,d
複製 %1$,d
解開 %1$,d
@@ -541,6 +544,9 @@
封存檔檢視器
圖片檢視器
%1$,d/%2$,d
+ 另存為
+ 儲存時發生錯誤
+ 已將「%1$s」儲存到「%2$s」
文字編輯器
%1$s
*%1$s
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6ac6e9353..b0c9d31df 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -241,6 +241,7 @@
File name cannot be empty
Invalid file name
A file with this name already exists
+ Replace “%1$s”?
Delete “%1$s”?
Delete folder “%1$s” and its contents?
@@ -265,11 +266,12 @@
New folder
Files
-
+
- Select a file
- Select files
-
+ Save file
+
- Select a folder
- Select folders
@@ -308,7 +310,10 @@
%1$,d
@string/file_item_action_extract
@string/file_item_action_archive
- Select “%1$s”
+ File name
+ @string/file_name_error_empty
+ @string/file_name_error_invalid
+ Select “%1$s”
Moving %1$,d
Copying %1$,d
Extracting %1$,d
@@ -681,6 +686,9 @@
Image viewer
%1$,d/%2$,d
@string/file_delete_message_file_format
+ Save as
+ Error while saving file
+ “%1$s” has been saved to “%2$s”
Text editor
%1$s
*%1$s