diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt index 463ea2c40a..acb9df079f 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt @@ -14,7 +14,6 @@ import android.app.Dialog import android.content.DialogInterface import android.os.Bundle import android.text.Editable -import android.text.TextUtils import android.text.TextWatcher import android.view.View import android.widget.TextView @@ -25,11 +24,11 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.common.collect.Sets import com.nextcloud.client.di.Injectable import com.nextcloud.utils.extensions.getParcelableArgument +import com.nextcloud.utils.fileNameValidator.FileNameValidator import com.owncloud.android.R import com.owncloud.android.databinding.EditBoxDialogBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.lib.resources.files.FileUtils import com.owncloud.android.ui.activity.ComponentsGetter import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.KeyboardUtils @@ -43,17 +42,16 @@ import javax.inject.Inject * Triggers the folder creation when name is confirmed. */ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickListener, Injectable { - @JvmField - @Inject - var fileDataStorageManager: FileDataStorageManager? = null - @JvmField @Inject - var viewThemeUtils: ViewThemeUtils? = null + lateinit var fileDataStorageManager: FileDataStorageManager - @JvmField @Inject - var keyboardUtils: KeyboardUtils? = null + lateinit var viewThemeUtils: ViewThemeUtils + + @Inject + lateinit var keyboardUtils: KeyboardUtils + private var mParentFolder: OCFile? = null private var positiveButton: MaterialButton? = null @@ -71,105 +69,98 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE) as MaterialButton val negativeButton = dialog.getButton(AlertDialog.BUTTON_NEGATIVE) as MaterialButton - viewThemeUtils?.material?.colorMaterialButtonPrimaryTonal(positiveButton!!) - viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(negativeButton) + viewThemeUtils.material.colorMaterialButtonPrimaryTonal(positiveButton!!) + viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(negativeButton) } } override fun onResume() { super.onResume() bindButton() - keyboardUtils!!.showKeyboardForEditText(requireDialog().window, binding.userInput) + keyboardUtils.showKeyboardForEditText(requireDialog().window, binding.userInput) } @Suppress("EmptyFunctionBlock") override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { mParentFolder = arguments?.getParcelableArgument(ARG_PARENT_FOLDER, OCFile::class.java) - // Inflate the layout for the dialog val inflater = requireActivity().layoutInflater binding = EditBoxDialogBinding.inflate(inflater, null, false) val view: View = binding.root - // Setup layout binding.userInput.setText(R.string.empty) - viewThemeUtils?.material?.colorTextInputLayout(binding.userInputContainer) + viewThemeUtils.material.colorTextInputLayout(binding.userInputContainer) val parentFolder = requireArguments().getParcelableArgument(ARG_PARENT_FOLDER, OCFile::class.java) - val folderContent = fileDataStorageManager!!.getFolderContent(parentFolder, false) + val folderContent = fileDataStorageManager.getFolderContent(parentFolder, false) val fileNames: MutableSet = Sets.newHashSetWithExpectedSize(folderContent.size) for (file in folderContent) { fileNames.add(file.fileName) } - // Add TextChangedListener to handle showing/hiding the input warning message binding.userInput.addTextChangedListener(object : TextWatcher { override fun afterTextChanged(s: Editable) {} override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} - - /** - * When user enters a hidden file name, the 'hidden file' message is shown. Otherwise, - * the message is ensured to be hidden. - */ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { - var newFileName = "" - if (binding.userInput.text != null) { - newFileName = binding.userInput.text.toString().trim { it <= ' ' } - } - if (!TextUtils.isEmpty(newFileName) && newFileName[0] == '.') { - binding.userInputContainer.error = getText(R.string.hidden_file_name_warning) - } else if (TextUtils.isEmpty(newFileName)) { - binding.userInputContainer.error = getString(R.string.filename_empty) - if (positiveButton == null) { - bindButton() - } - positiveButton!!.isEnabled = false - } else if (!FileUtils.isValidName(newFileName)) { - binding.userInputContainer.error = getString(R.string.filename_forbidden_charaters_from_server) - positiveButton!!.isEnabled = false - } else if (fileNames.contains(newFileName)) { - binding.userInputContainer.error = getText(R.string.file_already_exists) - positiveButton!!.isEnabled = false - } else if (binding.userInputContainer.error != null) { - binding.userInputContainer.error = null - // Called to remove extra padding - binding.userInputContainer.isErrorEnabled = false - positiveButton!!.isEnabled = true - } + checkFileNameAfterEachType(fileNames) } }) - // Build the dialog val builder = buildMaterialAlertDialog(view) - viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(binding.userInputContainer.context, builder) + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.userInputContainer.context, builder) return builder.create() } + private fun checkFileNameAfterEachType(fileNames: MutableSet) { + val newFileName = binding.userInput.text?.toString()?.trim() ?: "" + val errorMessageId: Int? = FileNameValidator.isValid(newFileName)?.messageId + + val error = when { + newFileName.isEmpty() -> null + newFileName[0] == '.' -> R.string.hidden_file_name_warning + errorMessageId != null -> errorMessageId + fileNames.contains(newFileName) -> R.string.file_already_exists + else -> null + } + + if (error != null) { + binding.userInputContainer.error = getString(error) + positiveButton?.isEnabled = false + if (positiveButton == null) { + bindButton() + } + } else { + binding.userInputContainer.error = null + binding.userInputContainer.isErrorEnabled = false + positiveButton?.isEnabled = true + } + } + private fun buildMaterialAlertDialog(view: View): MaterialAlertDialogBuilder { - val builder = MaterialAlertDialogBuilder(requireActivity()) - builder + return MaterialAlertDialogBuilder(requireActivity()) .setView(view) .setPositiveButton(R.string.folder_confirm_create, this) .setNegativeButton(R.string.common_cancel, this) .setTitle(R.string.uploader_info_dirname) - return builder } override fun onClick(dialog: DialogInterface, which: Int) { if (which == AlertDialog.BUTTON_POSITIVE) { val newFolderName = (getDialog()!!.findViewById(R.id.user_input) as TextView) .text.toString().trim { it <= ' ' } - if (TextUtils.isEmpty(newFolderName)) { - DisplayUtils.showSnackMessage(requireActivity(), R.string.filename_empty) + + val errorMessageId: Int? = FileNameValidator.isValid(newFolderName)?.messageId + + if (errorMessageId != null) { + DisplayUtils.showSnackMessage(requireActivity(), errorMessageId) return } - if (!FileUtils.isValidName(newFolderName)) { - DisplayUtils.showSnackMessage(requireActivity(), R.string.filename_forbidden_charaters_from_server) - return + + val path = mParentFolder?.decryptedRemotePath + newFolderName + OCFile.PATH_SEPARATOR + if (requireActivity() is ComponentsGetter) { + (requireActivity() as ComponentsGetter).fileOperationsHelper.createFolder(path) } - val path = mParentFolder!!.decryptedRemotePath + newFolderName + OCFile.PATH_SEPARATOR - (requireActivity() as ComponentsGetter).fileOperationsHelper.createFolder(path) } } @@ -185,11 +176,13 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList */ @JvmStatic fun newInstance(parentFolder: OCFile?): CreateFolderDialogFragment { - val frag = CreateFolderDialogFragment() - val args = Bundle() - args.putParcelable(ARG_PARENT_FOLDER, parentFolder) - frag.arguments = args - return frag + val bundle = Bundle().apply { + putParcelable(ARG_PARENT_FOLDER, parentFolder) + } + + return CreateFolderDialogFragment().apply { + arguments = bundle + } } } }