Improve volume adding UI

This commit is contained in:
Matéo Duparc 2024-07-22 21:06:29 +02:00
parent 85e24921fa
commit c0dcaed8d2
Signed by untrusted user: hardcoresushi
GPG Key ID: AFE384344A45E13A
15 changed files with 270 additions and 183 deletions

View File

@ -79,10 +79,12 @@ class VolumeData(
if (other !is VolumeData) {
return false
}
return other.uuid == uuid
return other.uuid == uuid || (other.name == name && other.isHidden == isHidden)
}
override fun hashCode() = uuid.hashCode()
override fun hashCode(): Int {
return name.hashCode()+isHidden.hashCode()
}
companion object {
const val VOLUMES_DIRECTORY = "volumes"

View File

@ -1,6 +1,16 @@
package sushi.hardcore.droidfs.add_volume
import sushi.hardcore.droidfs.R
enum class Action {
OPEN,
ADD,
CREATE,
;
fun getStringResId() = when (this) {
OPEN -> R.string.open
ADD -> R.string.add_volume
CREATE -> R.string.create_volume
}
}

View File

@ -67,17 +67,17 @@ class AddVolumeActivity: BaseActivity() {
finish()
}
fun onVolumeSelected(volume: VolumeData, rememberVolume: Boolean) {
if (rememberVolume) {
setResult(RESULT_USER_BACK)
finish()
} else {
volumeOpener.openVolume(volume, false, object : VolumeOpener.VolumeOpenerCallbacks {
override fun onVolumeOpened(id: Int) {
startExplorer(id, volume.shortName)
}
})
}
fun onVolumeAdded() {
setResult(RESULT_USER_BACK)
finish()
}
fun openVolume(volume: VolumeData, isVolumeKnown: Boolean) {
volumeOpener.openVolume(volume, isVolumeKnown, object : VolumeOpener.VolumeOpenerCallbacks {
override fun onVolumeOpened(id: Int) {
startExplorer(id, volume.shortName)
}
})
}
fun createVolume(volumePath: String, isHidden: Boolean, rememberVolume: Boolean) {

View File

@ -2,6 +2,7 @@ package sushi.hardcore.droidfs.add_volume
import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
@ -15,10 +16,14 @@ import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModel
import androidx.preference.PreferenceManager
import sushi.hardcore.droidfs.Constants
import sushi.hardcore.droidfs.R
@ -35,6 +40,10 @@ import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
import java.io.File
class SelectPathFragment: Fragment() {
internal class InputViewModel: ViewModel() {
var showEditText = false
}
companion object {
private const val KEY_THEME_VALUE = "theme"
private const val KEY_PICK_MODE = "pick"
@ -74,6 +83,7 @@ class SelectPathFragment: Fragment() {
private var originalRememberVolume = true
private var currentVolumeData: VolumeData? = null
private var volumeAction: Action? = null
private val inputViewModel: InputViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
@ -93,17 +103,13 @@ class SelectPathFragment: Fragment() {
theme = Compat.getParcelable(arguments, KEY_THEME_VALUE)!!
pickMode = arguments.getBoolean(KEY_PICK_MODE)
}
if (pickMode) {
binding.buttonAction.text = getString(R.string.add_volume)
}
volumeDatabase = VolumeDatabase(requireContext())
filesDir = requireContext().filesDir.path
binding.containerHiddenVolume.setOnClickListener {
binding.switchHiddenVolume.performClick()
}
binding.switchHiddenVolume.setOnClickListener {
showRightSection()
refreshStatus(binding.editVolumeName.text)
updateUi()
}
binding.buttonPickDirectory.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
@ -137,22 +143,41 @@ class SelectPathFragment: Fragment() {
launchPickDirectory()
}
}
binding.buttonEnterPath.setOnClickListener {
inputViewModel.showEditText = true
updateUi()
binding.editVolumeName.requestFocus()
(app.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).showSoftInput(
binding.editVolumeName,
InputMethodManager.SHOW_IMPLICIT
)
}
binding.editVolumeName.addTextChangedListener(object: TextWatcher {
override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
refreshStatus(s)
updateUi(s)
}
})
binding.switchRemember.setOnCheckedChangeListener { _, _ -> refreshButtonText() }
binding.editVolumeName.setOnEditorActionListener { _, _, _ -> onPathSelected(); true }
binding.switchRemember.setOnCheckedChangeListener { _, _ -> updateUi() }
binding.editVolumeName.setOnEditorActionListener { _, _, _ ->
if (binding.editVolumeName.text.isEmpty()) {
Toast.makeText(
requireContext(),
if (binding.switchHiddenVolume.isChecked) R.string.empty_volume_name else R.string.empty_volume_path,
Toast.LENGTH_SHORT
).show()
} else {
onPathSelected()
}
true
}
binding.buttonAction.setOnClickListener { onPathSelected() }
}
override fun onViewStateRestored(savedInstanceState: Bundle?) {
super.onViewStateRestored(savedInstanceState)
(activity as AddVolumeActivity).onFragmentLoaded(true)
showRightSection()
}
private fun launchPickDirectory() {
@ -160,70 +185,83 @@ class SelectPathFragment: Fragment() {
PathUtils.safePickDirectory(pickDirectory, requireContext(), theme)
}
private fun showRightSection() {
if (binding.switchHiddenVolume.isChecked) {
binding.textLabel.text = requireContext().getString(R.string.volume_name_label)
binding.editVolumeName.hint = requireContext().getString(R.string.volume_name_hint)
binding.buttonPickDirectory.visibility = View.GONE
} else {
binding.textLabel.text = requireContext().getString(R.string.volume_path_label)
binding.editVolumeName.hint = requireContext().getString(R.string.volume_path_hint)
binding.buttonPickDirectory.visibility = View.VISIBLE
}
}
private fun refreshButtonText() {
binding.buttonAction.text = getString(
if (pickMode || volumeAction == Action.ADD) {
if (binding.switchRemember.isChecked || currentVolumeData != null) {
R.string.add_volume
} else {
R.string.open_volume
}
private fun updateUi(volumeName: CharSequence = binding.editVolumeName.text) {
var warning = -1
fun updateWarning() {
if (warning == -1) {
binding.textWarning.isVisible = false
} else {
R.string.create_volume
binding.textWarning.isVisible = true
binding.textWarning.text = getString(warning)
}
)
}
}
private fun refreshStatus(content: CharSequence) {
val hidden = binding.switchHiddenVolume.isChecked
binding.editVolumeName.isVisible = hidden || inputViewModel.showEditText
binding.buttonPickDirectory.isVisible = !hidden
binding.textOr.isVisible = !hidden && !inputViewModel.showEditText
binding.buttonEnterPath.isVisible = !hidden && !inputViewModel.showEditText
if (hidden) {
binding.textLabel.text = getString(R.string.volume_name_label)
binding.editVolumeName.hint = getString(R.string.volume_name_hint)
} else {
binding.textLabel.text = getString(R.string.volume_path_label)
binding.editVolumeName.hint = getString(R.string.volume_path_hint)
}
if (hidden && volumeName.contains(PathUtils.SEPARATOR)) {
warning = R.string.error_slash_in_name
}
// exit early if possible to avoid filesystem queries
if (volumeName.isEmpty() || warning != -1 || (!hidden && !inputViewModel.showEditText)) {
binding.buttonAction.isVisible = false
binding.switchRemember.isVisible = false
updateWarning()
return
}
val path = File(getCurrentVolumePath())
volumeAction = if (path.isDirectory) {
if (path.list()?.isEmpty() == true || content.isEmpty()) Action.CREATE else Action.ADD
if (path.list()?.isEmpty() == true) {
Action.CREATE
} else if (pickMode || !binding.switchRemember.isChecked) {
Action.OPEN
} else {
Action.ADD
}
} else {
Action.CREATE
}
currentVolumeData = if (volumeAction == Action.CREATE) {
null
} else {
volumeDatabase.getVolume(content.toString(), binding.switchHiddenVolume.isChecked)
}
binding.textWarning.visibility = if (volumeAction == Action.CREATE && pickMode) {
binding.textWarning.text = getString(R.string.choose_existing_volume)
binding.buttonAction.isEnabled = false
View.VISIBLE
} else {
refreshButtonText()
binding.buttonAction.isEnabled = true
if (currentVolumeData == null) {
View.GONE
val valid = !(volumeAction == Action.CREATE && pickMode)
binding.switchRemember.isVisible = valid
binding.buttonAction.isVisible = valid
if (valid) {
binding.buttonAction.text = getString(volumeAction!!.getStringResId())
currentVolumeData = if (volumeAction == Action.CREATE) {
null
} else {
binding.textWarning.text = getString(R.string.volume_alread_saved)
View.VISIBLE
volumeDatabase.getVolume(volumeName.toString(), hidden)
}
if (currentVolumeData != null) {
warning = R.string.volume_alread_saved
}
} else {
warning = R.string.choose_existing_volume
}
updateWarning()
}
private fun onDirectoryPicked(uri: Uri) {
val path = PathUtils.getFullPathFromTreeUri(uri, requireContext())
if (path != null)
binding.editVolumeName.setText(path)
else
if (path == null) {
CustomAlertDialogBuilder(requireContext(), theme)
.setTitle(R.string.error)
.setMessage(R.string.path_error)
.setPositiveButton(R.string.ok, null)
.show()
} else {
binding.editVolumeName.setText(path)
inputViewModel.showEditText = true
updateUi(path)
}
}
private fun getCurrentVolumePath(): String {
@ -243,13 +281,7 @@ class SelectPathFragment: Fragment() {
if (currentVolumeData == null) { // volume not known
val currentVolumeValue = binding.editVolumeName.text.toString()
val isHidden = binding.switchHiddenVolume.isChecked
if (currentVolumeValue.isEmpty()) {
Toast.makeText(
requireContext(),
if (isHidden) R.string.enter_volume_name else R.string.enter_volume_path,
Toast.LENGTH_SHORT
).show()
} else if (isHidden && currentVolumeValue.contains(PathUtils.SEPARATOR)) {
if (isHidden && currentVolumeValue.contains(PathUtils.SEPARATOR)) {
Toast.makeText(requireContext(), R.string.error_slash_in_name, Toast.LENGTH_SHORT).show()
} else if (isHidden && volumeAction == Action.CREATE) {
CustomAlertDialogBuilder(requireContext(), theme)
@ -263,71 +295,83 @@ class SelectPathFragment: Fragment() {
onNewVolumeSelected(currentVolumeValue, isHidden)
}
} else {
(activity as AddVolumeActivity).onVolumeSelected(currentVolumeData!!, true)
with (activity as AddVolumeActivity) {
if (volumeAction!! == Action.OPEN) {
openVolume(currentVolumeData!!, true)
} else {
onVolumeAdded()
}
}
}
}
private fun onNewVolumeSelected(currentVolumeValue: String, isHidden: Boolean) {
val volumePath = getCurrentVolumePath()
when (volumeAction!!) {
Action.CREATE -> {
val volumeFile = File(volumePath)
var goodDirectory = false
if (volumeFile.isFile) {
Toast.makeText(requireContext(), R.string.error_is_file, Toast.LENGTH_SHORT).show()
} else if (volumeFile.isDirectory) {
val dirContent = volumeFile.list()
if (dirContent != null) {
if (dirContent.isEmpty()) {
if (volumeFile.canWrite()) {
goodDirectory = true
} else {
errorDirectoryNotWritable(volumePath)
}
if (volumeAction!! == Action.CREATE) {
val volumeFile = File(volumePath)
var goodDirectory = false
if (volumeFile.isFile) {
Toast.makeText(requireContext(), R.string.error_is_file, Toast.LENGTH_SHORT).show()
} else if (volumeFile.isDirectory) {
val dirContent = volumeFile.list()
if (dirContent != null) {
if (dirContent.isEmpty()) {
if (volumeFile.canWrite()) {
goodDirectory = true
} else {
Toast.makeText(requireContext(), R.string.dir_not_empty, Toast.LENGTH_SHORT).show()
errorDirectoryNotWritable(volumePath)
}
} else {
Toast.makeText(requireContext(), R.string.listdir_null_error_msg, Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), R.string.dir_not_empty, Toast.LENGTH_SHORT)
.show()
}
} else {
if (File(PathUtils.getParentPath(volumePath)).canWrite()) {
goodDirectory = true
} else {
errorDirectoryNotWritable(volumePath)
}
Toast.makeText(
requireContext(),
R.string.listdir_null_error_msg,
Toast.LENGTH_SHORT
).show()
}
if (goodDirectory) {
(activity as AddVolumeActivity).createVolume(volumePath, isHidden, binding.switchRemember.isChecked)
} else {
if (File(PathUtils.getParentPath(volumePath)).canWrite()) {
goodDirectory = true
} else {
errorDirectoryNotWritable(volumePath)
}
}
Action.ADD -> {
val volumeType = EncryptedVolume.getVolumeType(volumePath)
if (volumeType < 0) {
CustomAlertDialogBuilder(requireContext(), theme)
.setTitle(R.string.error)
.setMessage(R.string.error_not_a_volume)
.setPositiveButton(R.string.ok, null)
.show()
} else if (!File(volumePath).canWrite()) {
val dialog = CustomAlertDialogBuilder(requireContext(), theme)
.setTitle(R.string.warning)
.setCancelable(false)
.setPositiveButton(R.string.ok) { _, _ -> addVolume(if (isHidden) currentVolumeValue else volumePath, isHidden, volumeType) }
if (PathUtils.isPathOnExternalStorage(volumePath, requireContext())) {
dialog.setView(
DialogSdcardErrorBinding.inflate(layoutInflater).apply {
path.text = PathUtils.getPackageDataFolder(requireContext())
footer.text = getString(R.string.sdcard_error_add_footer)
}.root
)
} else {
dialog.setMessage(R.string.add_cant_write_warning)
}
dialog.show()
if (goodDirectory) {
(activity as AddVolumeActivity).createVolume(
volumePath,
isHidden,
binding.switchRemember.isChecked
)
}
} else {
val volumeType = EncryptedVolume.getVolumeType(volumePath)
if (volumeType < 0) {
CustomAlertDialogBuilder(requireContext(), theme)
.setTitle(R.string.error)
.setMessage(R.string.error_not_a_volume)
.setPositiveButton(R.string.ok, null)
.show()
} else if (!File(volumePath).canWrite()) {
val dialog = CustomAlertDialogBuilder(requireContext(), theme)
.setTitle(R.string.warning)
.setCancelable(false)
.setPositiveButton(R.string.ok) { _, _ -> onExistingVolumeSelected(if (isHidden) currentVolumeValue else volumePath, isHidden, volumeType) }
if (PathUtils.isPathOnExternalStorage(volumePath, requireContext())) {
dialog.setView(
DialogSdcardErrorBinding.inflate(layoutInflater).apply {
path.text = PathUtils.getPackageDataFolder(requireContext())
footer.text = getString(R.string.sdcard_error_add_footer)
}.root
)
} else {
addVolume(if (isHidden) currentVolumeValue else volumePath, isHidden, volumeType)
dialog.setMessage(R.string.add_cant_write_warning)
}
dialog.show()
} else {
onExistingVolumeSelected(if (isHidden) currentVolumeValue else volumePath, isHidden, volumeType)
}
}
}
@ -349,11 +393,17 @@ class SelectPathFragment: Fragment() {
dialog.show()
}
private fun addVolume(volumeName: String, isHidden: Boolean, volumeType: Byte) {
private fun onExistingVolumeSelected(volumeName: String, isHidden: Boolean, volumeType: Byte) {
val volumeData = VolumeData(VolumeData.newUuid(), volumeName, isHidden, volumeType)
if (binding.switchRemember.isChecked) {
volumeDatabase.saveVolume(volumeData)
}
(activity as AddVolumeActivity).onVolumeSelected(volumeData, binding.switchRemember.isChecked)
with (activity as AddVolumeActivity) {
if (volumeAction!! == Action.OPEN) {
openVolume(volumeData, binding.switchRemember.isChecked)
} else {
onVolumeAdded()
}
}
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="?attr/buttonBackgroundColor"/>
<corners android:radius="50dp"/>
</shape>
</item>
</selector>

View File

@ -55,44 +55,24 @@
</RelativeLayout>
<LinearLayout
<TextView
android:id="@+id/text_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/volume_operation_horizontal_gap"
android:text="@string/volume_path_label"
android:layout_marginBottom="10dp"/>
<EditText
android:id="@+id/edit_volume_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginHorizontal="@dimen/volume_operation_horizontal_gap">
<TextView
android:id="@+id/text_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/volume_path_label"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/edit_volume_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:inputType="text"
android:maxLines="1"
android:importantForAutofill="no"
android:hint="@string/volume_path_hint"/>
<ImageButton
android:id="@+id/button_pick_directory"
android:layout_width="@dimen/image_button_size"
android:layout_height="@dimen/image_button_size"
android:scaleType="fitCenter"
android:background="#00000000"
android:src="@drawable/icon_folder"
android:contentDescription="@string/pick_directory" />
</LinearLayout>
</LinearLayout>
android:layout_marginHorizontal="@dimen/volume_operation_horizontal_gap"
android:hint="@string/volume_path_hint"
android:importantForAutofill="no"
android:inputType="textNoSuggestions"
android:maxLines="1"
android:visibility="gone" />
<TextView
android:id="@+id/text_warning"
@ -102,12 +82,40 @@
android:layout_marginHorizontal="@dimen/volume_operation_horizontal_gap"
android:visibility="gone"/>
<Button
android:id="@+id/button_pick_directory"
android:layout_width="wrap_content"
style="@style/RoundButton"
android:drawableStart="@drawable/icon_folder_search"
android:text="@string/pick_directory"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"/>
<TextView
android:id="@+id/text_or"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/or"
android:layout_marginBottom="10dp"/>
<Button
android:id="@+id/button_enter_path"
android:layout_width="wrap_content"
style="@style/RoundButton"
android:drawableStart="@drawable/icon_edit"
android:text="@string/enter_volume_path"
android:layout_gravity="center_horizontal"/>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/switch_remember"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/remember_volume"
android:checked="true"
android:visibility="gone"
android:layout_marginTop="20dp"
android:layout_gravity="center"/>
<androidx.appcompat.widget.AppCompatButton
@ -117,6 +125,7 @@
android:layout_gravity="center"
android:layout_marginHorizontal="@dimen/volume_operation_button_horizontal_margin"
android:layout_marginTop="@dimen/volume_operation_vertical_gap"
android:visibility="gone"
android:text="@string/create_volume" />
</LinearLayout>

View File

@ -32,8 +32,8 @@
<string name="storage_perm_denied_msg">إن DroidFS لا يمكنه العمل بدون صلاحبات التخزين.</string>
<string name="get_size_failed">لقد فشلت عملية استرداد حجم الملف.</string>
<string name="parent_folder">المجلد الأصلي</string>
<string name="enter_volume_path">رجاءاً أدخل مسار المجلد المشفر</string>
<string name="enter_volume_name">رجاءاً أدخل اسم المجلد المشفر</string>
<string name="empty_volume_path">رجاءاً أدخل مسار المجلد المشفر</string>
<string name="empty_volume_name">رجاءاً أدخل اسم المجلد المشفر</string>
<string name="external_open">فتح بتطبيق خارجي</string>
<string name="single_delete_confirm">هل أنت متأكد من حذف %s ?</string>
<string name="multiple_delete_confirm">هل أنت متأكد من حذف هذه %s العناصر ?</string>

View File

@ -33,8 +33,8 @@
<string name="storage_perm_denied_msg">DroidFS kann ohne Speicherberechtigung nicht funktionieren</string>
<string name="get_size_failed">Fehlgeschlagen beim Abrufen der Dateigröße.</string>
<string name="parent_folder">Übergeordneter Ordner</string>
<string name="enter_volume_path">Bitte geben Sie den Volume-Pfad ein</string>
<string name="enter_volume_name">Bitte geben Sie den Datenträgernamen ein</string>
<string name="empty_volume_path">Bitte geben Sie den Volume-Pfad ein</string>
<string name="empty_volume_name">Bitte geben Sie den Datenträgernamen ein</string>
<string name="external_open">Öffnen mit externer Anwendung</string>
<string name="single_delete_confirm">Sind Sie sicher, dass Sie %s löschen wollen?</string>
<string name="multiple_delete_confirm">Sind Sie sicher, dass Sie diese %s Elemente löschen wollen?</string>

View File

@ -33,8 +33,8 @@
<string name="storage_perm_denied_msg">DroidFS no puede funcionar sin permisos de almacenamiento.</string>
<string name="get_size_failed">No se ha podido recuperar el tamaño del archivo.</string>
<string name="parent_folder">Carpeta superior</string>
<string name="enter_volume_path">Por favor, introduce la ruta del volumen</string>
<string name="enter_volume_name">Por favor, introduce el nombre del volumen</string>
<string name="empty_volume_path">Por favor, introduce la ruta del volumen</string>
<string name="empty_volume_name">Por favor, introduce el nombre del volumen</string>
<string name="external_open">Abrir con una aplicación externa</string>
<string name="single_delete_confirm">¿Estás seguro de que quieres borrar %s ?</string>
<string name="multiple_delete_confirm">¿Estás seguro de que quiere borrar %s objetos?</string>

View File

@ -32,8 +32,8 @@
<string name="storage_perm_denied_msg">DroidFS não pode funcionar sem permissão ao armazenamento.</string>
<string name="get_size_failed">Falha na recuperação do tamanho do arquivo.</string>
<string name="parent_folder">Pasta principal</string>
<string name="enter_volume_path">Por favor, digite a localização do volume</string>
<string name="enter_volume_name">Por favor, digite o nome do volume</string>
<string name="empty_volume_path">Por favor, digite a localização do volume</string>
<string name="empty_volume_name">Por favor, digite o nome do volume</string>
<string name="external_open">Abrir com app externo</string>
<string name="single_delete_confirm">Você tem certeza que quer excluir %s?</string>
<string name="multiple_delete_confirm">Você realmente deseja excluir estos %s itens?</string>

View File

@ -31,8 +31,8 @@
<string name="storage_perm_denied_msg">DroidFS не может работать без разрешения на доступ к хранилищу.</string>
<string name="get_size_failed">Невозможно получить размер файла.</string>
<string name="parent_folder">Родительская папка</string>
<string name="enter_volume_path">Введите путь тома</string>
<string name="enter_volume_name">Введите название тома</string>
<string name="empty_volume_path">Введите путь тома</string>
<string name="empty_volume_name">Введите название тома</string>
<string name="external_open">Открыть внешним приложением</string>
<string name="single_delete_confirm">Удалить %s?</string>
<string name="multiple_delete_confirm">Удалить %s элементов?</string>

View File

@ -33,8 +33,8 @@
<string name="storage_perm_denied_msg">DroidFS, depolama izinleri olmadan çalışamaz.</string>
<string name="get_size_failed">Dosya boyutu alınamadı.</string>
<string name="parent_folder">Ana klasör</string>
<string name="enter_volume_path">Lütfen birim yolunu girin</string>
<string name="enter_volume_name">Lütfen birim adını girin</string>
<string name="empty_volume_path">Lütfen birim yolunu girin</string>
<string name="empty_volume_name">Lütfen birim adını girin</string>
<string name="external_open">Harici uygulamayla aç</string>
<string name="single_delete_confirm">Silmek istediğimizden emin misiniz: %s</string>
<string name="multiple_delete_confirm">Bunları silmek istediğinizden emin misiniz: %s</string>

View File

@ -34,8 +34,8 @@
<string name="storage_perm_denied_msg">没有存储权限时DroidFS无法工作</string>
<string name="get_size_failed">无法获取文件的大小</string>
<string name="parent_folder">上一级文件夹</string>
<string name="enter_volume_path">输入卷的路径</string>
<string name="enter_volume_name">输入卷的名称</string>
<string name="empty_volume_path">输入卷的路径</string>
<string name="empty_volume_name">输入卷的名称</string>
<string name="external_open">使用外部软件打开</string>
<string name="single_delete_confirm">确认删除%s?</string>
<string name="multiple_delete_confirm">确认删除多个文件:%s</string>

View File

@ -33,8 +33,8 @@
<string name="storage_perm_denied_msg">DroidFS can\'t work without storage permissions.</string>
<string name="get_size_failed">Failed to retrieve file size.</string>
<string name="parent_folder">Parent Folder</string>
<string name="enter_volume_path">Please enter the volume path</string>
<string name="enter_volume_name">Please enter the volume name</string>
<string name="empty_volume_path">Please enter the volume path</string>
<string name="empty_volume_name">Please enter the volume name</string>
<string name="external_open">Open with external app</string>
<string name="single_delete_confirm">Are you sure you want to delete %s ?</string>
<string name="multiple_delete_confirm">Are you sure you want to delete these %s items ?</string>
@ -174,7 +174,7 @@
<string name="seek_seconds_forward">+%d seconds</string>
<string name="seek_seconds_backward">-%d seconds</string>
<string name="add_volume">Add volume</string>
<string name="pick_directory">Pick directory</string>
<string name="pick_directory">Pick a directory</string>
<string name="volume_alread_saved">Volume already saved</string>
<string name="open_dialog_title">Opening %s:</string>
<string name="remove">Remove</string>
@ -289,4 +289,6 @@
<string name="usf_keep_open_summary">Maintain the app always running in the background to keep volumes open</string>
<string name="gocryptfs_details">Fast, but doesn\'t hide file sizes and directory structure</string>
<string name="cryfs_details">Slower, but protects metadata and prevents replacement attacks</string>
<string name="or">or</string>
<string name="enter_volume_path">Enter volume path</string>
</resources>

View File

@ -8,7 +8,7 @@
<item name="android:statusBarColor">@color/primary</item>
<item name="infoBarBackgroundColor">#181818</item>
<item name="buttonBackgroundColor">#5B5A5C</item>
<item name="buttonStyle">@style/DarkButton</item>
<item name="buttonStyle">@style/Button</item>
</style>
<style name="DarkRed" parent="BaseTheme">
@ -35,7 +35,6 @@
<item name="android:navigationBarColor">@color/black</item>
<item name="infoBarBackgroundColor">@color/black</item>
<item name="buttonBackgroundColor">#3B3A3C</item>
<item name="buttonStyle">@style/BlackButton</item>
</style>
<style name="BlackRed" parent="BlackGreen">
<item name="colorAccent">@color/red</item>
@ -56,11 +55,17 @@
<item name="colorAccent">@color/pink</item>
</style>
<style name="DarkButton" parent="Widget.AppCompat.Button">
<style name="Button" parent="Widget.AppCompat.Button">
<item name="android:background">@drawable/button_background</item>
</style>
<style name="BlackButton" parent="Widget.AppCompat.Button">
<item name="android:background">@drawable/button_background</item>
<style name="RoundButton" parent="Widget.AppCompat.Button">
<item name="android:background">@drawable/round_button_background</item>
<item name="textAllCaps">false</item>
<item name="android:layout_height">35sp</item>
<item name="android:paddingStart">15dp</item>
<item name="android:paddingEnd">15dp</item>
<item name="android:drawablePadding">5dp</item>
</style>
<style name="infoBarTextView">