= ArrayList(users.size)
+ for (user in users) {
+ adapterUserList.add(UserListItem(user))
+ }
+ return adapterUserList
+ }
+
+ override fun onOptionItemClicked(user: User, view: View) {
+ // By default, access account if option is clicked
+ onAccountClicked(user)
+ }
+
+ override fun onAccountClicked(user: User) {
+ val parentActivity = activity as AccountChooserInterface?
+ parentActivity?.onAccountChosen(user)
+ dismiss()
+ }
+}
diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java
deleted file mode 100644
index ca73f2862f5e..000000000000
--- a/app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * ownCloud Android client application
- *
- * @author masensio
- * @author Andy Scherzinger
- * Copyright (C) 2015 ownCloud GmbH.
- * Copyright (C) 2018 Andy Scherzinger
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package com.owncloud.android.ui.dialog;
-
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-import com.nextcloud.client.di.Injectable;
-import com.owncloud.android.R;
-import com.owncloud.android.databinding.PasswordDialogBinding;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.lib.resources.shares.OCShare;
-import com.owncloud.android.ui.activity.FileActivity;
-import com.owncloud.android.utils.DisplayUtils;
-import com.owncloud.android.utils.KeyboardUtils;
-import com.owncloud.android.utils.theme.ViewThemeUtils;
-
-import javax.inject.Inject;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.DialogFragment;
-
-/**
- * Dialog to input the password for sharing a file/folder.
- *
- * Triggers the share when the password is introduced.
- */
-public class SharePasswordDialogFragment extends DialogFragment implements DialogInterface.OnClickListener, Injectable {
-
- private static final String ARG_FILE = "FILE";
- private static final String ARG_SHARE = "SHARE";
- private static final String ARG_CREATE_SHARE = "CREATE_SHARE";
- private static final String ARG_ASK_FOR_PASSWORD = "ASK_FOR_PASSWORD";
- public static final String PASSWORD_FRAGMENT = "PASSWORD_FRAGMENT";
-
- @Inject ViewThemeUtils viewThemeUtils;
- @Inject KeyboardUtils keyboardUtils;
-
- private PasswordDialogBinding binding;
- private OCFile file;
- private OCShare share;
- private boolean createShare;
- private boolean askForPassword;
-
- @Override
- public void onStart() {
- super.onStart();
-
- AlertDialog alertDialog = (AlertDialog) getDialog();
- if (alertDialog != null) {
- viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE),
- alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE));
- viewThemeUtils.platform.colorTextButtons(getResources().getColor(R.color.highlight_textColor_Warning),
- alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL));
-
- alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
- String password = binding.sharePassword.getText().toString();
-
- if (!askForPassword && TextUtils.isEmpty(password)) {
- DisplayUtils.showSnackMessage(binding.getRoot(), R.string.share_link_empty_password);
- return;
- }
-
- if (share == null) {
- setPassword(createShare, file, password);
- } else {
- setPassword(share, password);
- }
-
- alertDialog.dismiss();
- });
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- keyboardUtils.showKeyboardForEditText(requireDialog().getWindow(), binding.sharePassword);
- }
-
- /**
- * Public factory method to create new SharePasswordDialogFragment instances.
- *
- * @param file OCFile bound to the public share that which password will be set or updated
- * @param createShare When 'true', the request for password will be followed by the creation of a new public link;
- * when 'false', a public share is assumed to exist, and the password is bound to it.
- * @return Dialog ready to show.
- */
- public static SharePasswordDialogFragment newInstance(OCFile file, boolean createShare, boolean askForPassword) {
- SharePasswordDialogFragment frag = new SharePasswordDialogFragment();
- Bundle args = new Bundle();
- args.putParcelable(ARG_FILE, file);
- args.putBoolean(ARG_CREATE_SHARE, createShare);
- args.putBoolean(ARG_ASK_FOR_PASSWORD, askForPassword);
- frag.setArguments(args);
- return frag;
- }
-
- /**
- * Public factory method to create new SharePasswordDialogFragment instances.
- *
- * @param share OCFile bound to the public share that which password will be set or updated
- * @return Dialog ready to show.
- */
- public static SharePasswordDialogFragment newInstance(OCShare share, boolean askForPassword) {
- SharePasswordDialogFragment frag = new SharePasswordDialogFragment();
- Bundle args = new Bundle();
- args.putParcelable(ARG_SHARE, share);
- args.putBoolean(ARG_ASK_FOR_PASSWORD, askForPassword);
- frag.setArguments(args);
- return frag;
- }
-
- /**
- * Public factory method to create new SharePasswordDialogFragment instances.
- *
- * @param share OCFile bound to the public share that which password will be set or updated
- * @return Dialog ready to show.
- */
- public static SharePasswordDialogFragment newInstance(OCShare share) {
- SharePasswordDialogFragment frag = new SharePasswordDialogFragment();
- Bundle args = new Bundle();
- args.putParcelable(ARG_SHARE, share);
- frag.setArguments(args);
- return frag;
- }
-
- @NonNull
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- file = getArguments().getParcelable(ARG_FILE);
- share = getArguments().getParcelable(ARG_SHARE);
- createShare = getArguments().getBoolean(ARG_CREATE_SHARE, false);
- askForPassword = getArguments().getBoolean(ARG_ASK_FOR_PASSWORD, false);
-
- // Inflate the layout for the dialog
- LayoutInflater inflater = requireActivity().getLayoutInflater();
- binding = PasswordDialogBinding.inflate(inflater, null, false);
- View view = binding.getRoot();
-
- // Setup layout
- binding.sharePassword.setText("");
- viewThemeUtils.material.colorTextInputLayout(binding.sharePasswordContainer);
-
- int negativeButtonCaption;
- int title;
- if (askForPassword) {
- title = R.string.share_link_optional_password_title;
- negativeButtonCaption = R.string.common_skip;
- } else {
- title = R.string.share_link_password_title;
- negativeButtonCaption = R.string.common_cancel;
- }
-
- // Build the dialog
- MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(view.getContext());
-
- builder.setView(view)
- .setPositiveButton(R.string.common_ok, null)
- .setNegativeButton(negativeButtonCaption, this)
- .setNeutralButton(R.string.common_delete, this)
- .setTitle(title);
-
- viewThemeUtils.dialog.colorMaterialAlertDialogBackground(view.getContext(), builder);
-
- return builder.create();
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (which == AlertDialog.BUTTON_NEUTRAL) {
- if (share == null) {
- setPassword(createShare, file, null);
- } else {
- setPassword(share, null);
- }
- } else if (which == AlertDialog.BUTTON_NEGATIVE && askForPassword) {
- if (share == null) {
- setPassword(createShare, file, null);
- } else {
- setPassword(share, null);
- }
- }
- }
-
- private void setPassword(boolean createShare, OCFile file, String password) {
- if (createShare) {
- ((FileActivity) getActivity()).getFileOperationsHelper().shareFileViaPublicShare(file, password);
- } else {
- ((FileActivity) getActivity()).getFileOperationsHelper().setPasswordToShare(share, password);
- }
- }
-
- private void setPassword(OCShare share, String password) {
- ((FileActivity) getActivity()).getFileOperationsHelper().setPasswordToShare(share, password);
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- binding = null;
- }
-}
diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.kt
new file mode 100644
index 000000000000..6f7cdd08705b
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.kt
@@ -0,0 +1,250 @@
+/*
+ * ownCloud Android client application
+ *
+ * @author masensio
+ * @author Andy Scherzinger
+ * Copyright (C) 2015 ownCloud GmbH.
+ * Copyright (C) 2018 Andy Scherzinger
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.owncloud.android.ui.dialog
+
+import android.app.Dialog
+import android.content.DialogInterface
+import android.os.Build
+import android.os.Bundle
+import android.text.TextUtils
+import androidx.appcompat.app.AlertDialog
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.DialogFragment
+import com.google.android.material.button.MaterialButton
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.nextcloud.client.di.Injectable
+import com.owncloud.android.R
+import com.owncloud.android.databinding.PasswordDialogBinding
+import com.owncloud.android.datamodel.OCFile
+import com.owncloud.android.lib.resources.shares.OCShare
+import com.owncloud.android.ui.activity.FileActivity
+import com.owncloud.android.utils.DisplayUtils
+import com.owncloud.android.utils.KeyboardUtils
+import com.owncloud.android.utils.theme.ViewThemeUtils
+import javax.inject.Inject
+
+/**
+ * Dialog to input the password for sharing a file/folder.
+ *
+ *
+ * Triggers the share when the password is introduced.
+ */
+class SharePasswordDialogFragment : DialogFragment(), Injectable {
+ @JvmField
+ @Inject
+ var viewThemeUtils: ViewThemeUtils? = null
+
+ @JvmField
+ @Inject
+ var keyboardUtils: KeyboardUtils? = null
+
+ private var binding: PasswordDialogBinding? = null
+ private var file: OCFile? = null
+ private var share: OCShare? = null
+ private var createShare = false
+ private var askForPassword = false
+
+ override fun onStart() {
+ super.onStart()
+
+ val alertDialog = dialog as AlertDialog?
+
+ if (alertDialog != null) {
+ val positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as MaterialButton?
+ if (positiveButton != null) {
+ viewThemeUtils?.material?.colorMaterialButtonPrimaryTonal(positiveButton)
+ positiveButton.setOnClickListener {
+ val sharePassword = binding?.sharePassword?.text
+
+ if (sharePassword != null) {
+ val password = sharePassword.toString()
+ if (!askForPassword && TextUtils.isEmpty(password)) {
+ DisplayUtils.showSnackMessage(binding?.root, R.string.share_link_empty_password)
+ return@setOnClickListener
+ }
+ if (share == null) {
+ setPassword(createShare, file, password)
+ } else {
+ setPassword(share!!, password)
+ }
+ }
+
+ alertDialog.dismiss()
+ }
+ }
+
+ val negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as MaterialButton?
+ if (negativeButton != null) {
+ viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(negativeButton)
+ }
+
+ val neutralButton = alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL) as MaterialButton?
+ if (neutralButton != null) {
+ val warningColorId = ContextCompat.getColor(requireContext(), R.color.highlight_textColor_Warning)
+ viewThemeUtils?.platform?.colorTextButtons(warningColorId, neutralButton)
+ }
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ keyboardUtils?.showKeyboardForEditText(requireDialog().window, binding!!.sharePassword)
+ }
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ file = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ requireArguments().getParcelable(ARG_FILE, OCFile::class.java)
+ } else {
+ @Suppress("DEPRECATION")
+ requireArguments().getParcelable(ARG_FILE)
+ }
+
+ share = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ requireArguments().getParcelable(ARG_SHARE, OCShare::class.java)
+ } else {
+ @Suppress("DEPRECATION")
+ requireArguments().getParcelable(ARG_SHARE)
+ }
+
+ createShare = requireArguments().getBoolean(ARG_CREATE_SHARE, false)
+ askForPassword = requireArguments().getBoolean(ARG_ASK_FOR_PASSWORD, false)
+
+ // Inflate the layout for the dialog
+ val inflater = requireActivity().layoutInflater
+ binding = PasswordDialogBinding.inflate(inflater, null, false)
+
+ // Setup layout
+ binding?.sharePassword?.setText("")
+ viewThemeUtils?.material?.colorTextInputLayout(binding!!.sharePasswordContainer)
+
+ val neutralButtonTextId: Int
+ val title: Int
+ if (askForPassword) {
+ title = R.string.share_link_optional_password_title
+ neutralButtonTextId = R.string.common_skip
+ } else {
+ title = R.string.share_link_password_title
+ neutralButtonTextId = R.string.common_cancel
+ }
+
+ // Build the dialog
+ val builder = MaterialAlertDialogBuilder(requireContext())
+ builder.setView(binding!!.root)
+ .setPositiveButton(R.string.common_ok, null)
+ .setNegativeButton(R.string.common_delete) { _: DialogInterface?, _: Int -> callSetPassword() }
+ .setNeutralButton(neutralButtonTextId) { _: DialogInterface?, _: Int ->
+ if (askForPassword) {
+ callSetPassword()
+ }
+ }
+ .setTitle(title)
+
+ viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder)
+
+ return builder.create()
+ }
+
+ private fun callSetPassword() {
+ if (share == null) {
+ setPassword(createShare, file, null)
+ } else {
+ setPassword(share!!, null)
+ }
+ }
+
+ private fun setPassword(createShare: Boolean, file: OCFile?, password: String?) {
+ val fileOperationsHelper = (requireActivity() as FileActivity).fileOperationsHelper ?: return
+ if (createShare) {
+ fileOperationsHelper.shareFileViaPublicShare(file, password)
+ } else {
+ fileOperationsHelper.setPasswordToShare(share, password)
+ }
+ }
+
+ private fun setPassword(share: OCShare, password: String?) {
+ val fileOperationsHelper = (requireActivity() as FileActivity).fileOperationsHelper ?: return
+ fileOperationsHelper.setPasswordToShare(share, password)
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ binding = null
+ }
+
+ companion object {
+ private const val ARG_FILE = "FILE"
+ private const val ARG_SHARE = "SHARE"
+ private const val ARG_CREATE_SHARE = "CREATE_SHARE"
+ private const val ARG_ASK_FOR_PASSWORD = "ASK_FOR_PASSWORD"
+ const val PASSWORD_FRAGMENT = "PASSWORD_FRAGMENT"
+
+ /**
+ * Public factory method to create new SharePasswordDialogFragment instances.
+ *
+ * @param file OCFile bound to the public share that which
+ * password will be set or updated
+ * @param createShare When 'true', the request for password will be
+ * followed by the creation of a new public link
+ * when 'false', a public share is assumed to exist, and the password is bound to it.
+ * @return Dialog ready to show.
+ */
+ @JvmStatic
+ fun newInstance(file: OCFile?, createShare: Boolean, askForPassword: Boolean): SharePasswordDialogFragment {
+ val frag = SharePasswordDialogFragment()
+ val args = Bundle()
+ args.putParcelable(ARG_FILE, file)
+ args.putBoolean(ARG_CREATE_SHARE, createShare)
+ args.putBoolean(ARG_ASK_FOR_PASSWORD, askForPassword)
+ frag.arguments = args
+ return frag
+ }
+
+ /**
+ * Public factory method to create new SharePasswordDialogFragment instances.
+ *
+ * @param share OCFile bound to the public share that which password will be set or updated
+ * @return Dialog ready to show.
+ */
+ @JvmStatic
+ fun newInstance(share: OCShare?, askForPassword: Boolean): SharePasswordDialogFragment {
+ val frag = SharePasswordDialogFragment()
+ val args = Bundle()
+ args.putParcelable(ARG_SHARE, share)
+ args.putBoolean(ARG_ASK_FOR_PASSWORD, askForPassword)
+ frag.arguments = args
+ return frag
+ }
+
+ /**
+ * Public factory method to create new SharePasswordDialogFragment instances.
+ *
+ * @param share OCFile bound to the public share that which password will be set or updated
+ * @return Dialog ready to show.
+ */
+ fun newInstance(share: OCShare?): SharePasswordDialogFragment {
+ val frag = SharePasswordDialogFragment()
+ val args = Bundle()
+ args.putParcelable(ARG_SHARE, share)
+ frag.arguments = args
+ return frag
+ }
+ }
+}
diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.java
deleted file mode 100644
index 764ca5c5e480..000000000000
--- a/app/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Nextcloud Android client application
- *
- * @author Andy Scherzinger
- * Copyright (C) 2017 Andy Scherzinger
- * Copyright (C) 2017 Nextcloud
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this program. If not, see .
- */
-
-package com.owncloud.android.ui.dialog;
-
-import android.app.Dialog;
-import android.graphics.Typeface;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.TextView;
-
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-import com.nextcloud.client.di.Injectable;
-import com.owncloud.android.R;
-import com.owncloud.android.databinding.SortingOrderFragmentBinding;
-import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.utils.FileSortOrder;
-import com.owncloud.android.utils.theme.ViewThemeUtils;
-
-import javax.inject.Inject;
-
-import androidx.annotation.NonNull;
-import androidx.fragment.app.DialogFragment;
-
-/**
- * Dialog to show and choose the sorting order for the file listing.
- */
-public class SortingOrderDialogFragment extends DialogFragment implements Injectable {
-
- private final static String TAG = SortingOrderDialogFragment.class.getSimpleName();
-
- public static final String SORTING_ORDER_FRAGMENT = "SORTING_ORDER_FRAGMENT";
- private static final String KEY_SORT_ORDER = "SORT_ORDER";
-
- private SortingOrderFragmentBinding binding;
- private View[] mTaggedViews;
- private String mCurrentSortOrderName;
-
-
- @Inject ViewThemeUtils viewThemeUtils;
-
- public static SortingOrderDialogFragment newInstance(FileSortOrder sortOrder) {
- SortingOrderDialogFragment dialogFragment = new SortingOrderDialogFragment();
-
- Bundle args = new Bundle();
- args.putString(KEY_SORT_ORDER, sortOrder.name);
- dialogFragment.setArguments(args);
-
- dialogFragment.setStyle(STYLE_NORMAL, R.style.Theme_ownCloud_Dialog);
-
- return dialogFragment;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // keep the state of the fragment on configuration changes
- setRetainInstance(true);
-
- binding = null;
- mCurrentSortOrderName = getArguments().getString(KEY_SORT_ORDER, FileSortOrder.sort_a_to_z.name);
- }
-
- /**
- * find all relevant UI elements and set their values.
- *
- * @param binding the parent binding
- */
- private void setupDialogElements(SortingOrderFragmentBinding binding) {
- viewThemeUtils.platform.colorTextButtons(binding.cancel);
-
- mTaggedViews = new View[12];
- mTaggedViews[0] = binding.sortByNameAscending;
- mTaggedViews[0].setTag(FileSortOrder.sort_a_to_z);
- mTaggedViews[1] = binding.sortByNameAZText;
- mTaggedViews[1].setTag(FileSortOrder.sort_a_to_z);
- mTaggedViews[2] = binding.sortByNameDescending;
- mTaggedViews[2].setTag(FileSortOrder.sort_z_to_a);
- mTaggedViews[3] = binding.sortByNameZAText;
- mTaggedViews[3].setTag(FileSortOrder.sort_z_to_a);
- mTaggedViews[4] = binding.sortByModificationDateAscending;
- mTaggedViews[4].setTag(FileSortOrder.sort_old_to_new);
- mTaggedViews[5] = binding.sortByModificationDateOldestFirstText;
- mTaggedViews[5].setTag(FileSortOrder.sort_old_to_new);
- mTaggedViews[6] = binding.sortByModificationDateDescending;
- mTaggedViews[6].setTag(FileSortOrder.sort_new_to_old);
- mTaggedViews[7] = binding.sortByModificationDateNewestFirstText;
- mTaggedViews[7].setTag(FileSortOrder.sort_new_to_old);
- mTaggedViews[8] = binding.sortBySizeAscending;
- mTaggedViews[8].setTag(FileSortOrder.sort_small_to_big);
- mTaggedViews[9] = binding.sortBySizeSmallestFirstText;
- mTaggedViews[9].setTag(FileSortOrder.sort_small_to_big);
- mTaggedViews[10] = binding.sortBySizeDescending;
- mTaggedViews[10].setTag(FileSortOrder.sort_big_to_small);
- mTaggedViews[11] = binding.sortBySizeBiggestFirstText;
- mTaggedViews[11].setTag(FileSortOrder.sort_big_to_small);
-
- setupActiveOrderSelection();
- }
-
- /**
- * tints the icon reflecting the actual sorting choice in the apps primary color.
- */
- private void setupActiveOrderSelection() {
- for (View view : mTaggedViews) {
- if (!((FileSortOrder) view.getTag()).name.equals(mCurrentSortOrderName)) {
- continue;
- }
- if (view instanceof ImageButton) {
- viewThemeUtils.platform.themeImageButton((ImageButton) view);
- ((ImageButton) view).setSelected(true);
- }
- if (view instanceof TextView) {
- viewThemeUtils.platform.colorPrimaryTextViewElement((TextView) view);
- ((TextView) view).setTypeface(Typeface.DEFAULT_BOLD);
- }
- }
- }
-
- /**
- * setup all listeners.
- */
- private void setupListeners() {
- binding.cancel.setOnClickListener(view -> dismiss());
-
- OnSortOrderClickListener sortOrderClickListener = new OnSortOrderClickListener();
-
- for (View view : mTaggedViews) {
- view.setOnClickListener(sortOrderClickListener);
- }
- }
-
- @Override
- @NonNull
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- binding = SortingOrderFragmentBinding.inflate(requireActivity().getLayoutInflater(), null, false);
-
- setupDialogElements(binding);
- setupListeners();
-
- MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(binding.getRoot().getContext());
- builder.setView(binding.getRoot());
-
- viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.getRoot().getContext(), builder);
-
- return builder.create();
- }
-
- @Override
- public void onDestroyView() {
- Log_OC.d(TAG, "destroy SortingOrderDialogFragment view");
- if (getDialog() != null && getRetainInstance()) {
- getDialog().setDismissMessage(null);
- }
- super.onDestroyView();
- }
-
- private class OnSortOrderClickListener implements View.OnClickListener {
- @Override
- public void onClick(View v) {
- dismissAllowingStateLoss();
- ((SortingOrderDialogFragment.OnSortingOrderListener) getActivity())
- .onSortingOrderChosen((FileSortOrder) v.getTag());
- }
- }
-
- public interface OnSortingOrderListener {
- void onSortingOrderChosen(FileSortOrder selection);
- }
-}
diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.kt
new file mode 100644
index 000000000000..3c1a84871e10
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.kt
@@ -0,0 +1,134 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Andy Scherzinger
+ * Copyright (C) 2017 Andy Scherzinger
+ * Copyright (C) 2017 Nextcloud
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this program. If not, see .
+ */
+package com.owncloud.android.ui.dialog
+
+import android.app.Dialog
+import android.os.Bundle
+import android.view.View
+import androidx.fragment.app.DialogFragment
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.nextcloud.client.di.Injectable
+import com.owncloud.android.R
+import com.owncloud.android.databinding.SortingOrderFragmentBinding
+import com.owncloud.android.lib.common.utils.Log_OC
+import com.owncloud.android.utils.FileSortOrder
+import com.owncloud.android.utils.theme.ViewThemeUtils
+import javax.inject.Inject
+
+/**
+ * Dialog to show and choose the sorting order for the file listing.
+ */
+class SortingOrderDialogFragment : DialogFragment(), Injectable {
+
+ private var binding: SortingOrderFragmentBinding? = null
+
+ private var currentSortOrderName: String? = null
+
+ @JvmField
+ @Inject
+ var viewThemeUtils: ViewThemeUtils? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ // keep the state of the fragment on configuration changes
+ retainInstance = true
+
+ binding = null
+ currentSortOrderName = requireArguments().getString(KEY_SORT_ORDER, FileSortOrder.sort_a_to_z.name)
+ }
+
+ /**
+ * find all relevant UI elements and set their values.
+ *
+ * @param binding the parent binding
+ */
+ private fun setupDialogElements(binding: SortingOrderFragmentBinding) {
+ val bindings = listOf(
+ binding.sortByNameAscending to FileSortOrder.sort_a_to_z,
+ binding.sortByNameDescending to FileSortOrder.sort_z_to_a,
+ binding.sortByModificationDateAscending to FileSortOrder.sort_old_to_new,
+ binding.sortByModificationDateDescending to FileSortOrder.sort_new_to_old,
+ binding.sortBySizeAscending to FileSortOrder.sort_small_to_big,
+ binding.sortBySizeDescending to FileSortOrder.sort_big_to_small
+ )
+
+ bindings.forEach { (view, sortOrder) ->
+ view.tag = sortOrder
+ view.let {
+ it.setOnClickListener(OnSortOrderClickListener())
+ viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(it)
+ }
+ }
+
+ viewThemeUtils?.material?.colorMaterialButtonPrimaryTonal(binding.cancel)
+ binding.cancel.setOnClickListener { dismiss() }
+ }
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ binding = SortingOrderFragmentBinding.inflate(requireActivity().layoutInflater, null, false)
+ setupDialogElements(binding!!)
+
+ val builder = MaterialAlertDialogBuilder(requireContext())
+ builder.setView(binding?.root)
+
+ viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder)
+
+ return builder.create()
+ }
+
+ override fun onDestroyView() {
+ Log_OC.d(TAG, "destroy SortingOrderDialogFragment view")
+
+ if (dialog != null && retainInstance) {
+ dialog?.setDismissMessage(null)
+ }
+
+ super.onDestroyView()
+ }
+
+ private inner class OnSortOrderClickListener : View.OnClickListener {
+ override fun onClick(v: View) {
+ dismissAllowingStateLoss()
+ (activity as OnSortingOrderListener?)?.onSortingOrderChosen(v.tag as FileSortOrder)
+ }
+ }
+
+ interface OnSortingOrderListener {
+ fun onSortingOrderChosen(selection: FileSortOrder?)
+ }
+
+ companion object {
+
+ private val TAG = SortingOrderDialogFragment::class.java.simpleName
+ const val SORTING_ORDER_FRAGMENT = "SORTING_ORDER_FRAGMENT"
+ private const val KEY_SORT_ORDER = "SORT_ORDER"
+
+ @JvmStatic
+ fun newInstance(sortOrder: FileSortOrder): SortingOrderDialogFragment {
+ val dialogFragment = SortingOrderDialogFragment()
+ val args = Bundle()
+ args.putString(KEY_SORT_ORDER, sortOrder.name)
+ dialogFragment.arguments = args
+ dialogFragment.setStyle(STYLE_NORMAL, R.style.Theme_ownCloud_Dialog)
+ return dialogFragment
+ }
+ }
+}
diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SyncFileNotEnoughSpaceDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/SyncFileNotEnoughSpaceDialogFragment.java
deleted file mode 100644
index a614a8a8a6f9..000000000000
--- a/app/src/main/java/com/owncloud/android/ui/dialog/SyncFileNotEnoughSpaceDialogFragment.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Nextcloud Android client application
- *
- * @author Kilian Périsset
- * Copyright (C) 2020 Infomaniak Network SA
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License (GPLv3),
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package com.owncloud.android.ui.dialog;
-
-import android.app.Dialog;
-import android.content.Intent;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.storage.StorageManager;
-
-import com.nextcloud.client.di.Injectable;
-import com.owncloud.android.R;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.ui.dialog.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
-import com.owncloud.android.ui.fragment.OCFileListFragment;
-import com.owncloud.android.utils.DisplayUtils;
-import com.owncloud.android.utils.theme.ViewThemeUtils;
-
-import javax.inject.Inject;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
-import androidx.appcompat.app.AlertDialog;
-
-/**
- * Dialog requiring confirmation when a file/folder is too "big" to be synchronized/downloaded on device.
- */
-public class SyncFileNotEnoughSpaceDialogFragment extends ConfirmationDialogFragment implements
- ConfirmationDialogFragmentListener, Injectable {
-
- private static final String ARG_PASSED_FILE = "fragment_parent_caller";
- private static final int REQUEST_CODE_STORAGE = 20;
-
- private OCFile targetFile;
-
- @Inject ViewThemeUtils viewThemeUtils;
-
- public static SyncFileNotEnoughSpaceDialogFragment newInstance(OCFile file, long availableDeviceSpace) {
- Bundle args = new Bundle();
- SyncFileNotEnoughSpaceDialogFragment frag = new SyncFileNotEnoughSpaceDialogFragment();
- String properFileSize = DisplayUtils.bytesToHumanReadable(file.getFileLength());
- String properDiskAvailableSpace = DisplayUtils.bytesToHumanReadable(availableDeviceSpace);
-
- // Defining title, message and resources
- args.putInt(ARG_TITLE_ID, R.string.sync_not_enough_space_dialog_title);
- args.putInt(ARG_MESSAGE_RESOURCE_ID, R.string.sync_not_enough_space_dialog_placeholder);
- args.putStringArray(ARG_MESSAGE_ARGUMENTS,
- new String[]{
- file.getFileName(),
- properFileSize,
- properDiskAvailableSpace});
- args.putParcelable(ARG_PASSED_FILE, file);
-
- // Defining buttons
- if (file.isFolder()) {
- args.putInt(ARG_POSITIVE_BTN_RES, R.string.sync_not_enough_space_dialog_action_choose);
- }
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N_MR1) {
- args.putInt(ARG_NEGATIVE_BTN_RES, R.string.sync_not_enough_space_dialog_action_free_space);
- }
- args.putInt(ARG_NEUTRAL_BTN_RES, R.string.common_cancel);
-
- frag.setArguments(args);
- return frag;
- }
-
- @Override
- public void onStart() {
- super.onStart();
-
- AlertDialog alertDialog = (AlertDialog) getDialog();
-
- if (alertDialog != null) {
- viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE),
- alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL),
- alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE));
- }
- }
-
- @NonNull
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- Bundle arguments = getArguments();
-
- if (arguments == null) {
- throw new IllegalArgumentException("Arguments may not be null");
- }
-
- targetFile = arguments.getParcelable(ARG_PASSED_FILE);
- setOnConfirmationListener(this);
-
- return super.onCreateDialog(savedInstanceState);
- }
-
- /**
- * (Only if file is a folder), will access the destination folder to allow user to choose what to synchronize
- */
- @Override
- public void onConfirmation(String callerTag) {
- OCFileListFragment frag = (OCFileListFragment) getTargetFragment();
- if (frag != null && targetFile != null) {
- frag.onItemClicked(targetFile);
- }
- }
-
- /**
- * Will abort/cancel the process (is neutral to "hack" android button position ._.)
- */
- @Override
- public void onNeutral(String callerTag) {
- // Nothing
- }
-
- /**
- * Will access to storage manager in order to empty useless files
- */
- @RequiresApi(api = Build.VERSION_CODES.N_MR1)
- @Override
- public void onCancel(String callerTag) {
- Intent storageIntent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);
- startActivityForResult(storageIntent, REQUEST_CODE_STORAGE);
- }
-}
diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SyncFileNotEnoughSpaceDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/SyncFileNotEnoughSpaceDialogFragment.kt
new file mode 100644
index 000000000000..ed1f7c4d251c
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/ui/dialog/SyncFileNotEnoughSpaceDialogFragment.kt
@@ -0,0 +1,119 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Kilian Périsset
+ * Copyright (C) 2020 Infomaniak Network SA
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License (GPLv3),
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.owncloud.android.ui.dialog
+
+import android.app.Dialog
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import android.os.storage.StorageManager
+import androidx.annotation.RequiresApi
+import com.owncloud.android.R
+import com.owncloud.android.datamodel.OCFile
+import com.owncloud.android.ui.dialog.ConfirmationDialogFragment.ConfirmationDialogFragmentListener
+import com.owncloud.android.ui.fragment.OCFileListFragment
+import com.owncloud.android.utils.DisplayUtils
+
+/**
+ * Dialog requiring confirmation when a file/folder is too "big" to be synchronized/downloaded on device.
+ */
+class SyncFileNotEnoughSpaceDialogFragment :
+ ConfirmationDialogFragment(),
+ ConfirmationDialogFragmentListener {
+
+ private var targetFile: OCFile? = null
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ targetFile = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ requireArguments().getParcelable(ARG_PASSED_FILE, OCFile::class.java)
+ } else {
+ @Suppress("DEPRECATION")
+ requireArguments().getParcelable(ARG_PASSED_FILE)
+ }
+
+ setOnConfirmationListener(this)
+
+ return super.onCreateDialog(savedInstanceState)
+ }
+
+ /**
+ * (Only if file is a folder), will access the destination folder to allow user to choose what to synchronize
+ */
+ override fun onConfirmation(callerTag: String?) {
+ val frag = targetFragment as OCFileListFragment?
+
+ if (frag != null && targetFile != null) {
+ frag.onItemClicked(targetFile)
+ }
+ }
+
+ /**
+ * Will abort/cancel the process (is neutral to "hack" android button position ._.)
+ */
+ override fun onNeutral(callerTag: String?) {
+ // Nothing
+ }
+
+ /**
+ * Will access to storage manager in order to empty useless files
+ */
+ @RequiresApi(api = Build.VERSION_CODES.N_MR1)
+ override fun onCancel(callerTag: String?) {
+ val storageIntent = Intent(StorageManager.ACTION_MANAGE_STORAGE)
+ startActivityForResult(storageIntent, REQUEST_CODE_STORAGE)
+ }
+
+ companion object {
+ private const val ARG_PASSED_FILE = "fragment_parent_caller"
+ private const val REQUEST_CODE_STORAGE = 20
+
+ @JvmStatic
+ fun newInstance(file: OCFile, availableDeviceSpace: Long): SyncFileNotEnoughSpaceDialogFragment {
+ val args = Bundle()
+ val frag = SyncFileNotEnoughSpaceDialogFragment()
+ val properFileSize = DisplayUtils.bytesToHumanReadable(file.fileLength)
+ val properDiskAvailableSpace = DisplayUtils.bytesToHumanReadable(availableDeviceSpace)
+
+ // Defining title, message and resources
+ args.putInt(ARG_TITLE_ID, R.string.sync_not_enough_space_dialog_title)
+ args.putInt(ARG_MESSAGE_RESOURCE_ID, R.string.sync_not_enough_space_dialog_placeholder)
+ args.putStringArray(
+ ARG_MESSAGE_ARGUMENTS,
+ arrayOf(
+ file.fileName,
+ properFileSize,
+ properDiskAvailableSpace
+ )
+ )
+ args.putParcelable(ARG_PASSED_FILE, file)
+
+ // Defining buttons
+ if (file.isFolder) {
+ args.putInt(ARG_POSITIVE_BTN_RES, R.string.sync_not_enough_space_dialog_action_choose)
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
+ args.putInt(ARG_NEGATIVE_BTN_RES, R.string.sync_not_enough_space_dialog_action_free_space)
+ }
+ args.putInt(ARG_NEUTRAL_BTN_RES, R.string.common_cancel)
+
+ frag.arguments = args
+ return frag
+ }
+ }
+}
diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.java
deleted file mode 100644
index 48a13f8f3281..000000000000
--- a/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.java
+++ /dev/null
@@ -1,655 +0,0 @@
-/*
- * Nextcloud Android client application
- *
- * @author Andy Scherzinger
- * Copyright (C) 2016 Andy Scherzinger
- * Copyright (C) 2016 Nextcloud
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this program. If not, see .
- */
-package com.owncloud.android.ui.dialog;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.graphics.Typeface;
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.text.style.StyleSpan;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.AdapterView;
-import android.widget.LinearLayout;
-import android.widget.Spinner;
-import android.widget.TextView;
-
-import com.google.android.material.button.MaterialButton;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-import com.nextcloud.client.di.Injectable;
-import com.nextcloud.client.preferences.SubFolderRule;
-import com.owncloud.android.R;
-import com.owncloud.android.databinding.SyncedFoldersSettingsLayoutBinding;
-import com.owncloud.android.datamodel.MediaFolderType;
-import com.owncloud.android.datamodel.SyncedFolder;
-import com.owncloud.android.datamodel.SyncedFolderDisplayItem;
-import com.owncloud.android.files.services.NameCollisionPolicy;
-import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.ui.activity.FolderPickerActivity;
-import com.owncloud.android.ui.activity.UploadFilesActivity;
-import com.owncloud.android.ui.dialog.parcel.SyncedFolderParcelable;
-import com.owncloud.android.utils.DisplayUtils;
-import com.owncloud.android.utils.FileStorageUtils;
-import com.owncloud.android.utils.theme.ViewThemeUtils;
-
-import java.io.File;
-
-import javax.inject.Inject;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.widget.AppCompatCheckBox;
-import androidx.appcompat.widget.SwitchCompat;
-import androidx.fragment.app.DialogFragment;
-
-import static com.owncloud.android.datamodel.SyncedFolderDisplayItem.UNPERSISTED_ID;
-import static com.owncloud.android.ui.activity.UploadFilesActivity.REQUEST_CODE_KEY;
-
-/**
- * Dialog to show the preferences/configuration of a synced folder allowing the user to change the different
- * parameters.
- */
-public class SyncedFolderPreferencesDialogFragment extends DialogFragment implements Injectable {
-
- public static final String SYNCED_FOLDER_PARCELABLE = "SyncedFolderParcelable";
- public static final int REQUEST_CODE__SELECT_REMOTE_FOLDER = 0;
- public static final int REQUEST_CODE__SELECT_LOCAL_FOLDER = 1;
-
- private final static String TAG = SyncedFolderPreferencesDialogFragment.class.getSimpleName();
- private static final String BEHAVIOUR_DIALOG_STATE = "BEHAVIOUR_DIALOG_STATE";
- private static final String NAME_COLLISION_POLICY_DIALOG_STATE = "NAME_COLLISION_POLICY_DIALOG_STATE";
- private final static float alphaEnabled = 1.0f;
- private final static float alphaDisabled = 0.7f;
-
- @Inject ViewThemeUtils viewThemeUtils;
-
- private CharSequence[] mUploadBehaviorItemStrings;
- private CharSequence[] mNameCollisionPolicyItemStrings;
- private SwitchCompat mEnabledSwitch;
- private AppCompatCheckBox mUploadOnWifiCheckbox;
- private AppCompatCheckBox mUploadOnChargingCheckbox;
- private AppCompatCheckBox mUploadExistingCheckbox;
- private AppCompatCheckBox mUploadUseSubfoldersCheckbox;
- private Spinner mUploadSubfolderRuleSpinner;
- private TextView mUploadBehaviorSummary;
- private TextView mNameCollisionPolicySummary;
- private TextView mLocalFolderPath;
- private TextView mLocalFolderSummary;
- private TextView mRemoteFolderSummary;
- private LinearLayout mUploadSubfolderRulesContainer;
-
- private SyncedFolderParcelable mSyncedFolder;
- private MaterialButton mCancel;
- private MaterialButton mSave;
- private boolean behaviourDialogShown;
- private boolean nameCollisionPolicyDialogShown;
- private AlertDialog behaviourDialog;
- private SyncedFoldersSettingsLayoutBinding binding;
-
- public static SyncedFolderPreferencesDialogFragment newInstance(SyncedFolderDisplayItem syncedFolder, int section) {
- if (syncedFolder == null) {
- throw new IllegalArgumentException("SyncedFolder is mandatory but NULL!");
- }
-
- Bundle args = new Bundle();
- args.putParcelable(SYNCED_FOLDER_PARCELABLE, new SyncedFolderParcelable(syncedFolder, section));
-
- SyncedFolderPreferencesDialogFragment dialogFragment = new SyncedFolderPreferencesDialogFragment();
- dialogFragment.setArguments(args);
- dialogFragment.setStyle(STYLE_NORMAL, R.style.Theme_ownCloud_Dialog);
-
- return dialogFragment;
- }
-
- @Override
- public void onAttach(@NonNull Activity activity) {
- super.onAttach(activity);
- if (!(activity instanceof OnSyncedFolderPreferenceListener)) {
- throw new IllegalArgumentException("The host activity must implement "
- + OnSyncedFolderPreferenceListener.class.getCanonicalName());
- }
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // keep the state of the fragment on configuration changes
- setRetainInstance(true);
-
- binding = null;
-
- mSyncedFolder = getArguments().getParcelable(SYNCED_FOLDER_PARCELABLE);
- mUploadBehaviorItemStrings = getResources().getTextArray(R.array.pref_behaviour_entries);
- mNameCollisionPolicyItemStrings = getResources().getTextArray(R.array.pref_name_collision_policy_entries);
- }
-
- /**
- * find all relevant UI elements and set their values.
- *
- * @param binding the parent binding
- */
- private void setupDialogElements(SyncedFoldersSettingsLayoutBinding binding) {
- if (mSyncedFolder.getType().getId() > MediaFolderType.CUSTOM.getId()) {
- // hide local folder chooser and delete for non-custom folders
- binding.localFolderContainer.setVisibility(View.GONE);
- binding.delete.setVisibility(View.GONE);
- } else if (mSyncedFolder.getId() <= UNPERSISTED_ID) {
- // Hide delete/enabled for unpersisted custom folders
- binding.delete.setVisibility(View.GONE);
- binding.syncEnabled.setVisibility(View.GONE);
-
- // auto set custom folder to enabled
- mSyncedFolder.setEnabled(true);
-
- // switch text to create headline
- binding.syncedFoldersSettingsTitle.setText(R.string.autoupload_create_new_custom_folder);
-
- // disable save button
- binding.save.setEnabled(false);
- } else {
- binding.localFolderContainer.setVisibility(View.GONE);
- }
-
- // find/saves UI elements
- mEnabledSwitch = binding.syncEnabled;
- viewThemeUtils.androidx.colorSwitchCompat(mEnabledSwitch);
-
- mLocalFolderPath = binding.syncedFoldersSettingsLocalFolderPath;
-
- mLocalFolderSummary = binding.localFolderSummary;
- mRemoteFolderSummary = binding.remoteFolderSummary;
-
- mUploadOnWifiCheckbox = binding.settingInstantUploadOnWifiCheckbox;
-
- mUploadOnChargingCheckbox = binding.settingInstantUploadOnChargingCheckbox;
-
- mUploadExistingCheckbox = binding.settingInstantUploadExistingCheckbox;
-
- mUploadUseSubfoldersCheckbox = binding.settingInstantUploadPathUseSubfoldersCheckbox;
-
- mUploadSubfolderRuleSpinner = binding.settingInstantUploadSubfolderRuleSpinner;
- mUploadSubfolderRulesContainer = binding.settingInstantUploadSubfolderRuleContainer;
-
-
-
- viewThemeUtils.platform.themeCheckbox(mUploadOnWifiCheckbox,
- mUploadOnChargingCheckbox,
- mUploadExistingCheckbox,
- mUploadUseSubfoldersCheckbox);
-
- mUploadBehaviorSummary = binding.settingInstantBehaviourSummary;
-
- mNameCollisionPolicySummary = binding.settingInstantNameCollisionPolicySummary;
-
- mCancel = binding.cancel;
- mSave = binding.save;
-
- viewThemeUtils.platform.colorTextButtons(mCancel, mSave);
-
- // Set values
- setEnabled(mSyncedFolder.isEnabled());
-
- if (!TextUtils.isEmpty(mSyncedFolder.getLocalPath())) {
- mLocalFolderPath.setText(
- DisplayUtils.createTextWithSpan(
- String.format(
- getString(R.string.synced_folders_preferences_folder_path),
- mSyncedFolder.getLocalPath()),
- mSyncedFolder.getFolderName(),
- new StyleSpan(Typeface.BOLD)));
- mLocalFolderSummary.setText(FileStorageUtils.pathToUserFriendlyDisplay(
- mSyncedFolder.getLocalPath(),
- getActivity(),
- getResources()));
- } else {
- mLocalFolderSummary.setText(R.string.choose_local_folder);
- }
-
- if (!TextUtils.isEmpty(mSyncedFolder.getLocalPath())) {
- mRemoteFolderSummary.setText(mSyncedFolder.getRemotePath());
- } else {
- mRemoteFolderSummary.setText(R.string.choose_remote_folder);
- }
-
- mUploadOnWifiCheckbox.setChecked(mSyncedFolder.isWifiOnly());
- mUploadOnChargingCheckbox.setChecked(mSyncedFolder.isChargingOnly());
-
- mUploadExistingCheckbox.setChecked(mSyncedFolder.isExisting());
- mUploadUseSubfoldersCheckbox.setChecked(mSyncedFolder.isSubfolderByDate());
-
- mUploadSubfolderRuleSpinner.setSelection(mSyncedFolder.getSubFolderRule().ordinal());
- if (mUploadUseSubfoldersCheckbox.isChecked()) {
- mUploadSubfolderRulesContainer.setVisibility(View.VISIBLE);
- } else {
- mUploadSubfolderRulesContainer.setVisibility(View.GONE);
- }
-
- mUploadBehaviorSummary.setText(mUploadBehaviorItemStrings[mSyncedFolder.getUploadActionInteger()]);
-
- final int nameCollisionPolicyIndex =
- getSelectionIndexForNameCollisionPolicy(mSyncedFolder.getNameCollisionPolicy());
- mNameCollisionPolicySummary.setText(mNameCollisionPolicyItemStrings[nameCollisionPolicyIndex]);
- }
-
- /**
- * set correct icon/flag.
- *
- * @param enabled if enabled or disabled
- */
- private void setEnabled(boolean enabled) {
- mSyncedFolder.setEnabled(enabled);
- mEnabledSwitch.setChecked(enabled);
-
- setupViews(binding, enabled);
- }
-
- /**
- * set (new) remote path on activity result of the folder picker activity. The result gets originally propagated to
- * the underlying activity since the picker is an activity and the result can't get passed to the dialog fragment
- * directly.
- *
- * @param path the remote path to be set
- */
- public void setRemoteFolderSummary(String path) {
- mSyncedFolder.setRemotePath(path);
- mRemoteFolderSummary.setText(path);
- checkAndUpdateSaveButtonState();
- }
-
- /**
- * set (new) local path on activity result of the folder picker activity. The result gets originally propagated to
- * the underlying activity since the picker is an activity and the result can't get passed to the dialog fragment
- * directly.
- *
- * @param path the local path to be set
- */
- public void setLocalFolderSummary(String path) {
- mSyncedFolder.setLocalPath(path);
- mLocalFolderSummary.setText(FileStorageUtils.pathToUserFriendlyDisplay(path, getActivity(), getResources()));
- mLocalFolderPath.setText(
- DisplayUtils.createTextWithSpan(
- String.format(
- getString(R.string.synced_folders_preferences_folder_path),
- mSyncedFolder.getLocalPath()),
- new File(mSyncedFolder.getLocalPath()).getName(),
- new StyleSpan(Typeface.BOLD)));
- checkAndUpdateSaveButtonState();
- }
-
- private void checkAndUpdateSaveButtonState() {
- if (mSyncedFolder.getLocalPath() != null && mSyncedFolder.getRemotePath() != null) {
- binding.save.setEnabled(true);
- } else {
- binding.save.setEnabled(false);
- }
-
- checkWritableFolder();
- }
-
- private void checkWritableFolder() {
- if (!mSyncedFolder.isEnabled()) {
- binding.settingInstantBehaviourContainer.setEnabled(false);
- binding.settingInstantBehaviourContainer.setAlpha(alphaDisabled);
- return;
- }
-
- if (mSyncedFolder.getLocalPath() != null && new File(mSyncedFolder.getLocalPath()).canWrite()) {
- binding.settingInstantBehaviourContainer.setEnabled(true);
- binding.settingInstantBehaviourContainer.setAlpha(alphaEnabled);
- mUploadBehaviorSummary.setText(mUploadBehaviorItemStrings[mSyncedFolder.getUploadActionInteger()]);
- } else {
- binding.settingInstantBehaviourContainer.setEnabled(false);
- binding.settingInstantBehaviourContainer.setAlpha(alphaDisabled);
-
- mSyncedFolder.setUploadAction(
- getResources().getTextArray(R.array.pref_behaviour_entryValues)[0].toString());
-
- mUploadBehaviorSummary.setText(R.string.auto_upload_file_behaviour_kept_in_folder);
- }
- }
-
- private void setupViews(SyncedFoldersSettingsLayoutBinding binding, boolean enable) {
- float alpha;
- if (enable) {
- alpha = alphaEnabled;
- } else {
- alpha = alphaDisabled;
- }
- binding.settingInstantUploadOnWifiContainer.setEnabled(enable);
- binding.settingInstantUploadOnWifiContainer.setAlpha(alpha);
-
- binding.settingInstantUploadOnChargingContainer.setEnabled(enable);
- binding.settingInstantUploadOnChargingContainer.setAlpha(alpha);
-
- binding.settingInstantUploadExistingContainer.setEnabled(enable);
- binding.settingInstantUploadExistingContainer.setAlpha(alpha);
-
- binding.settingInstantUploadPathUseSubfoldersContainer.setEnabled(enable);
- binding.settingInstantUploadPathUseSubfoldersContainer.setAlpha(alpha);
-
- binding.remoteFolderContainer.setEnabled(enable);
- binding.remoteFolderContainer.setAlpha(alpha);
-
- binding.localFolderContainer.setEnabled(enable);
- binding.localFolderContainer.setAlpha(alpha);
-
- binding.settingInstantNameCollisionPolicyContainer.setEnabled(enable);
- binding.settingInstantNameCollisionPolicyContainer.setAlpha(alpha);
-
- mUploadOnWifiCheckbox.setEnabled(enable);
- mUploadOnChargingCheckbox.setEnabled(enable);
- mUploadExistingCheckbox.setEnabled(enable);
- mUploadUseSubfoldersCheckbox.setEnabled(enable);
-
- checkWritableFolder();
- }
-
- /**
- * setup all listeners.
- *
- * @param binding the parent binding
- */
- private void setupListeners(SyncedFoldersSettingsLayoutBinding binding) {
- mSave.setOnClickListener(new OnSyncedFolderSaveClickListener());
- mCancel.setOnClickListener(new OnSyncedFolderCancelClickListener());
- binding.delete.setOnClickListener(new OnSyncedFolderDeleteClickListener());
-
- binding.settingInstantUploadOnWifiContainer.setOnClickListener(
- new OnClickListener() {
- @Override
- public void onClick(View v) {
- mSyncedFolder.setWifiOnly(!mSyncedFolder.isWifiOnly());
- mUploadOnWifiCheckbox.toggle();
- }
- });
-
- binding.settingInstantUploadOnChargingContainer.setOnClickListener(
- new OnClickListener() {
- @Override
- public void onClick(View v) {
- mSyncedFolder.setChargingOnly(!mSyncedFolder.isChargingOnly());
- mUploadOnChargingCheckbox.toggle();
- }
- });
-
- binding.settingInstantUploadExistingContainer.setOnClickListener(
- new OnClickListener() {
- @Override
- public void onClick(View v) {
- mSyncedFolder.setExisting(!mSyncedFolder.isExisting());
- mUploadExistingCheckbox.toggle();
- }
- });
-
- binding.settingInstantUploadPathUseSubfoldersContainer.setOnClickListener(
- new OnClickListener() {
- @Override
- public void onClick(View v) {
- mSyncedFolder.setSubfolderByDate(!mSyncedFolder.isSubfolderByDate());
- mUploadUseSubfoldersCheckbox.toggle();
- // Only allow setting subfolder rule if subfolder is allowed
- if (mUploadUseSubfoldersCheckbox.isChecked()) {
- mUploadSubfolderRulesContainer.setVisibility(View.VISIBLE);
- } else {
- mUploadSubfolderRulesContainer.setVisibility(View.GONE);
- }
- }
- });
-
- binding.settingInstantUploadSubfolderRuleSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView> adapterView, View view, int i, long l) {
- mSyncedFolder.setSubFolderRule(SubFolderRule.values()[i]);
- }
-
- @Override
- public void onNothingSelected(AdapterView> adapterView) {
- mSyncedFolder.setSubFolderRule(SubFolderRule.YEAR_MONTH);
- }
- });
-
- binding.remoteFolderContainer.setOnClickListener(v -> {
- Intent action = new Intent(getActivity(), FolderPickerActivity.class);
- getActivity().startActivityForResult(action, REQUEST_CODE__SELECT_REMOTE_FOLDER);
- });
-
- binding.localFolderContainer.setOnClickListener(v -> {
- Intent action = new Intent(getActivity(), UploadFilesActivity.class);
- action.putExtra(UploadFilesActivity.KEY_LOCAL_FOLDER_PICKER_MODE, true);
- action.putExtra(REQUEST_CODE_KEY, REQUEST_CODE__SELECT_LOCAL_FOLDER);
- getActivity().startActivityForResult(action, REQUEST_CODE__SELECT_LOCAL_FOLDER);
- });
-
- binding.syncEnabled.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- setEnabled(!mSyncedFolder.isEnabled());
- }
- });
-
- binding.settingInstantBehaviourContainer.setOnClickListener(
- new OnClickListener() {
- @Override
- public void onClick(View v) {
- showBehaviourDialog();
- }
- });
-
- binding.settingInstantNameCollisionPolicyContainer.setOnClickListener(
- new OnClickListener() {
- @Override
- public void onClick(View v) {
- showNameCollisionPolicyDialog();
- }
- });
- }
-
- private void showBehaviourDialog() {
- MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity());
- builder.setTitle(R.string.prefs_instant_behaviour_dialogTitle)
- .setSingleChoiceItems(getResources().getTextArray(R.array.pref_behaviour_entries),
- mSyncedFolder.getUploadActionInteger(),
- new
- DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- mSyncedFolder.setUploadAction(
- getResources().getTextArray(
- R.array.pref_behaviour_entryValues)[which].toString());
- mUploadBehaviorSummary.setText(SyncedFolderPreferencesDialogFragment
- .this.mUploadBehaviorItemStrings[which]);
- behaviourDialogShown = false;
- dialog.dismiss();
- }
- })
- .setOnCancelListener(new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialog) {
- behaviourDialogShown = false;
- }
- });
- behaviourDialogShown = true;
-
- viewThemeUtils.dialog.colorMaterialAlertDialogBackground(getActivity(), builder);
-
- behaviourDialog = builder.create();
- behaviourDialog.show();
- }
-
- private void showNameCollisionPolicyDialog() {
- MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity());
-
- builder.setTitle(R.string.pref_instant_name_collision_policy_dialogTitle)
- .setSingleChoiceItems(getResources().getTextArray(R.array.pref_name_collision_policy_entries),
- getSelectionIndexForNameCollisionPolicy(mSyncedFolder.getNameCollisionPolicy()),
- new OnNameCollisionDialogClickListener())
- .setOnCancelListener(dialog -> nameCollisionPolicyDialogShown = false);
-
- nameCollisionPolicyDialogShown = true;
-
- viewThemeUtils.dialog.colorMaterialAlertDialogBackground(getActivity(), builder);
-
- behaviourDialog = builder.create();
- behaviourDialog.show();
- }
-
- @Override
- @NonNull
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- Log_OC.d(TAG, "onCreateView, savedInstanceState is " + savedInstanceState);
-
- binding = SyncedFoldersSettingsLayoutBinding.inflate(requireActivity().getLayoutInflater(), null, false);
-
- setupDialogElements(binding);
- setupListeners(binding);
-
- MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(binding.getRoot().getContext());
- builder.setView(binding.getRoot());
-
- viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.getRoot().getContext(), builder);
-
- return builder.create();
- }
-
- @Override
- public void onDestroyView() {
- Log_OC.d(TAG, "destroy SyncedFolderPreferencesDialogFragment view");
- if (getDialog() != null && getRetainInstance()) {
- getDialog().setDismissMessage(null);
- }
-
- if (behaviourDialog != null && behaviourDialog.isShowing()) {
- behaviourDialog.dismiss();
- }
-
- super.onDestroyView();
- }
-
- @Override
- public void onSaveInstanceState(@NonNull Bundle outState) {
- outState.putBoolean(BEHAVIOUR_DIALOG_STATE, behaviourDialogShown);
- outState.putBoolean(NAME_COLLISION_POLICY_DIALOG_STATE, nameCollisionPolicyDialogShown);
-
- super.onSaveInstanceState(outState);
- }
-
- @Override
- public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
- behaviourDialogShown = savedInstanceState != null &&
- savedInstanceState.getBoolean(BEHAVIOUR_DIALOG_STATE, false);
- nameCollisionPolicyDialogShown = savedInstanceState != null &&
- savedInstanceState.getBoolean(NAME_COLLISION_POLICY_DIALOG_STATE, false);
-
- if (behaviourDialogShown) {
- showBehaviourDialog();
- }
- if (nameCollisionPolicyDialogShown) {
- showNameCollisionPolicyDialog();
- }
-
- super.onViewStateRestored(savedInstanceState);
- }
-
- public interface OnSyncedFolderPreferenceListener {
- void onSaveSyncedFolderPreference(SyncedFolderParcelable syncedFolder);
-
- void onCancelSyncedFolderPreference();
-
- void onDeleteSyncedFolderPreference(SyncedFolderParcelable syncedFolder);
- }
-
- private class OnSyncedFolderSaveClickListener implements OnClickListener {
- @Override
- public void onClick(View v) {
- dismiss();
- ((OnSyncedFolderPreferenceListener) getActivity()).onSaveSyncedFolderPreference(mSyncedFolder);
- }
- }
-
- private class OnSyncedFolderCancelClickListener implements OnClickListener {
- @Override
- public void onClick(View v) {
- dismiss();
- ((OnSyncedFolderPreferenceListener) getActivity()).onCancelSyncedFolderPreference();
- }
- }
-
- private class OnSyncedFolderDeleteClickListener implements OnClickListener {
- @Override
- public void onClick(View v) {
- dismiss();
- ((OnSyncedFolderPreferenceListener) getActivity()).onDeleteSyncedFolderPreference(mSyncedFolder);
- }
- }
-
- private class OnNameCollisionDialogClickListener implements DialogInterface.OnClickListener {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- mSyncedFolder.setNameCollisionPolicy(getNameCollisionPolicyForSelectionIndex(which));
-
- mNameCollisionPolicySummary.setText(
- SyncedFolderPreferencesDialogFragment.this.mNameCollisionPolicyItemStrings[which]);
- nameCollisionPolicyDialogShown = false;
- dialog.dismiss();
- }
- }
-
- /**
- * Get index for name collision selection dialog.
- *
- * @return 0 if ASK_USER, 1 if OVERWRITE, 2 if RENAME, 3 if SKIP, Otherwise: 0
- */
- static private Integer getSelectionIndexForNameCollisionPolicy(NameCollisionPolicy nameCollisionPolicy) {
- switch (nameCollisionPolicy) {
- case OVERWRITE:
- return 1;
- case RENAME:
- return 2;
- case CANCEL:
- return 3;
- case ASK_USER:
- default:
- return 0;
- }
- }
-
- /**
- * Get index for name collision selection dialog. Inverse of getSelectionIndexForNameCollisionPolicy.
- *
- * @return ASK_USER if 0, OVERWRITE if 1, RENAME if 2, SKIP if 3. Otherwise: ASK_USER
- */
- static private NameCollisionPolicy getNameCollisionPolicyForSelectionIndex(int index) {
- switch (index) {
- case 1:
- return NameCollisionPolicy.OVERWRITE;
- case 2:
- return NameCollisionPolicy.RENAME;
- case 3:
- return NameCollisionPolicy.CANCEL;
- case 0:
- default:
- return NameCollisionPolicy.ASK_USER;
- }
- }
-}
diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.kt
new file mode 100644
index 000000000000..01672938757d
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.kt
@@ -0,0 +1,566 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Andy Scherzinger
+ * Copyright (C) 2016 Andy Scherzinger
+ * Copyright (C) 2016 Nextcloud
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this program. If not, see .
+ */
+package com.owncloud.android.ui.dialog
+
+import android.app.Activity
+import android.app.Dialog
+import android.content.DialogInterface
+import android.content.Intent
+import android.graphics.Typeface
+import android.os.Build
+import android.os.Bundle
+import android.text.TextUtils
+import android.text.style.StyleSpan
+import android.view.View
+import android.widget.AdapterView
+import androidx.appcompat.app.AlertDialog
+import androidx.fragment.app.DialogFragment
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.nextcloud.client.di.Injectable
+import com.nextcloud.client.preferences.SubFolderRule
+import com.owncloud.android.R
+import com.owncloud.android.databinding.SyncedFoldersSettingsLayoutBinding
+import com.owncloud.android.datamodel.MediaFolderType
+import com.owncloud.android.datamodel.SyncedFolder
+import com.owncloud.android.datamodel.SyncedFolderDisplayItem
+import com.owncloud.android.files.services.NameCollisionPolicy
+import com.owncloud.android.lib.common.utils.Log_OC
+import com.owncloud.android.ui.activity.FolderPickerActivity
+import com.owncloud.android.ui.activity.UploadFilesActivity
+import com.owncloud.android.ui.dialog.parcel.SyncedFolderParcelable
+import com.owncloud.android.utils.DisplayUtils
+import com.owncloud.android.utils.FileStorageUtils
+import com.owncloud.android.utils.theme.ViewThemeUtils
+import java.io.File
+import javax.inject.Inject
+
+/**
+ * Dialog to show the preferences/configuration of a synced folder allowing the user to change the different
+ * parameters.
+ */
+class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable {
+
+ @JvmField
+ @Inject
+ var viewThemeUtils: ViewThemeUtils? = null
+
+ private lateinit var uploadBehaviorItemStrings: Array
+ private lateinit var nameCollisionPolicyItemStrings: Array
+
+ private var syncedFolder: SyncedFolderParcelable? = null
+ private var behaviourDialogShown = false
+ private var nameCollisionPolicyDialogShown = false
+ private var behaviourDialog: AlertDialog? = null
+ private var binding: SyncedFoldersSettingsLayoutBinding? = null
+ private var isNeutralButtonActive = true
+
+ @Deprecated("Deprecated in Java")
+ override fun onAttach(activity: Activity) {
+ super.onAttach(activity)
+ require(activity is OnSyncedFolderPreferenceListener) {
+ (
+ "The host activity must implement " +
+ OnSyncedFolderPreferenceListener::class.java.canonicalName
+ )
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ // keep the state of the fragment on configuration changes
+ retainInstance = true
+ binding = null
+
+ val arguments = arguments
+ if (arguments != null) {
+ syncedFolder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ arguments.getParcelable(SYNCED_FOLDER_PARCELABLE, SyncedFolderParcelable::class.java)
+ } else {
+ @Suppress("DEPRECATION")
+ arguments.getParcelable(SYNCED_FOLDER_PARCELABLE)
+ }
+ }
+
+ uploadBehaviorItemStrings = resources.getTextArray(R.array.pref_behaviour_entries)
+ nameCollisionPolicyItemStrings = resources.getTextArray(R.array.pref_name_collision_policy_entries)
+ }
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ Log_OC.d(TAG, "onCreateView, savedInstanceState is $savedInstanceState")
+ binding = SyncedFoldersSettingsLayoutBinding.inflate(requireActivity().layoutInflater, null, false)
+
+ setupDialogElements(binding!!)
+ setupListeners(binding!!)
+
+ val builder = MaterialAlertDialogBuilder(requireContext())
+ builder.setView(binding!!.getRoot())
+
+ viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder)
+
+ return builder.create()
+ }
+
+ /**
+ * find all relevant UI elements and set their values.
+ *
+ * @param binding the parent binding
+ */
+ private fun setupDialogElements(binding: SyncedFoldersSettingsLayoutBinding) {
+ setupLayout(binding)
+ applyUserColor(binding)
+ setButtonOrder(binding)
+ setValuesViaSyncedFolder(binding)
+ }
+
+ private fun setupLayout(binding: SyncedFoldersSettingsLayoutBinding) {
+ if (syncedFolder!!.type.id > MediaFolderType.CUSTOM.id) {
+ // hide local folder chooser and delete for non-custom folders
+ binding.localFolderContainer.visibility = View.GONE
+ isNeutralButtonActive = false
+ } else if (syncedFolder!!.id <= SyncedFolder.UNPERSISTED_ID) {
+ isNeutralButtonActive = false
+
+ // Hide delete/enabled for unpersisted custom folders
+ binding.syncEnabled.visibility = View.GONE
+
+ // auto set custom folder to enabled
+ syncedFolder?.isEnabled = true
+
+ // switch text to create headline
+ binding.syncedFoldersSettingsTitle.setText(R.string.autoupload_create_new_custom_folder)
+
+ // disable save button
+ binding.btnPositive.isEnabled = false
+ } else {
+ binding.localFolderContainer.visibility = View.GONE
+ }
+ }
+
+ private fun applyUserColor(binding: SyncedFoldersSettingsLayoutBinding) {
+ viewThemeUtils?.androidx?.colorSwitchCompat(binding.syncEnabled)
+
+ viewThemeUtils?.platform?.themeCheckbox(
+ binding.settingInstantUploadOnWifiCheckbox,
+ binding.settingInstantUploadOnChargingCheckbox,
+ binding.settingInstantUploadExistingCheckbox,
+ binding.settingInstantUploadPathUseSubfoldersCheckbox
+ )
+
+ viewThemeUtils?.material?.colorMaterialButtonPrimaryTonal(binding.btnPositive)
+ viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(binding.btnNegative)
+ viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(binding.btnNeutral)
+ }
+
+ private fun setButtonOrder(binding: SyncedFoldersSettingsLayoutBinding) {
+ // btnNeutral btnNegative btnPositive
+ if (isNeutralButtonActive) {
+ // Cancel Delete Save
+ binding.btnNeutral.setText(R.string.common_cancel)
+ binding.btnNegative.setText(R.string.common_delete)
+ } else {
+ // Cancel Save
+ binding.btnNeutral.visibility = View.GONE
+ binding.btnNegative.setText(R.string.common_cancel)
+ }
+ }
+
+ private fun setValuesViaSyncedFolder(binding: SyncedFoldersSettingsLayoutBinding) {
+ syncedFolder?.let {
+ setEnabled(it.isEnabled)
+
+ if (!TextUtils.isEmpty(it.localPath)) {
+ binding.syncedFoldersSettingsLocalFolderPath.text = DisplayUtils.createTextWithSpan(
+ String.format(
+ getString(R.string.synced_folders_preferences_folder_path),
+ it.localPath
+ ),
+ it.folderName,
+ StyleSpan(Typeface.BOLD)
+ )
+ binding.localFolderSummary.text = FileStorageUtils.pathToUserFriendlyDisplay(
+ it.localPath,
+ activity,
+ resources
+ )
+ } else {
+ binding.localFolderSummary.setText(R.string.choose_local_folder)
+ }
+
+ if (!TextUtils.isEmpty(it.localPath)) {
+ binding.remoteFolderSummary.text = it.remotePath
+ } else {
+ binding.remoteFolderSummary.setText(R.string.choose_remote_folder)
+ }
+
+ binding.settingInstantUploadOnWifiCheckbox.isChecked = it.isWifiOnly
+ binding.settingInstantUploadOnChargingCheckbox.isChecked = it.isChargingOnly
+ binding.settingInstantUploadExistingCheckbox.isChecked = it.isExisting
+ binding.settingInstantUploadPathUseSubfoldersCheckbox.isChecked = it.isSubfolderByDate
+
+ binding.settingInstantUploadSubfolderRuleSpinner.setSelection(it.subFolderRule.ordinal)
+
+ binding.settingInstantUploadSubfolderRuleContainer.visibility =
+ if (binding.settingInstantUploadPathUseSubfoldersCheckbox.isChecked) View.VISIBLE else View.GONE
+
+ binding.settingInstantBehaviourSummary.text = uploadBehaviorItemStrings[it.uploadActionInteger]
+ val nameCollisionPolicyIndex = getSelectionIndexForNameCollisionPolicy(
+ it.nameCollisionPolicy
+ )
+ binding.settingInstantNameCollisionPolicySummary.text =
+ nameCollisionPolicyItemStrings[nameCollisionPolicyIndex]
+ }
+ }
+
+ /**
+ * set correct icon/flag.
+ *
+ * @param enabled if enabled or disabled
+ */
+ private fun setEnabled(enabled: Boolean) {
+ syncedFolder?.isEnabled = enabled
+ binding?.syncEnabled?.isChecked = enabled
+ setupViews(binding, enabled)
+ }
+
+ /**
+ * set (new) remote path on activity result of the folder picker activity. The result gets originally propagated to
+ * the underlying activity since the picker is an activity and the result can't get passed to the dialog fragment
+ * directly.
+ *
+ * @param path the remote path to be set
+ */
+ fun setRemoteFolderSummary(path: String?) {
+ syncedFolder?.remotePath = path
+ binding?.remoteFolderSummary?.text = path
+ checkAndUpdateSaveButtonState()
+ }
+
+ /**
+ * set (new) local path on activity result of the folder picker activity. The result gets originally propagated to
+ * the underlying activity since the picker is an activity and the result can't get passed to the dialog fragment
+ * directly.
+ *
+ * @param path the local path to be set
+ */
+ fun setLocalFolderSummary(path: String?) {
+ syncedFolder?.localPath = path
+ binding?.localFolderSummary?.text = FileStorageUtils.pathToUserFriendlyDisplay(path, activity, resources)
+ binding?.syncedFoldersSettingsLocalFolderPath?.text = DisplayUtils.createTextWithSpan(
+ String.format(
+ getString(R.string.synced_folders_preferences_folder_path),
+ syncedFolder!!.localPath
+ ),
+ File(syncedFolder!!.localPath).name,
+ StyleSpan(Typeface.BOLD)
+ )
+ checkAndUpdateSaveButtonState()
+ }
+
+ private fun checkAndUpdateSaveButtonState() {
+ binding?.btnPositive?.isEnabled = syncedFolder!!.localPath != null && syncedFolder!!.remotePath != null
+ checkWritableFolder()
+ }
+
+ private fun checkWritableFolder() {
+ if (!syncedFolder!!.isEnabled) {
+ binding?.settingInstantBehaviourContainer?.isEnabled = false
+ binding?.settingInstantBehaviourContainer?.alpha = alphaDisabled
+ return
+ }
+ if (syncedFolder!!.localPath != null && File(syncedFolder!!.localPath).canWrite()) {
+ binding?.settingInstantBehaviourContainer?.isEnabled = true
+ binding?.settingInstantBehaviourContainer?.alpha = alphaEnabled
+ binding?.settingInstantBehaviourSummary?.text =
+ uploadBehaviorItemStrings[syncedFolder!!.uploadActionInteger]
+ } else {
+ binding?.settingInstantBehaviourContainer?.isEnabled = false
+ binding?.settingInstantBehaviourContainer?.alpha = alphaDisabled
+ syncedFolder?.setUploadAction(
+ resources.getTextArray(R.array.pref_behaviour_entryValues)[0].toString()
+ )
+ binding?.settingInstantBehaviourSummary?.setText(R.string.auto_upload_file_behaviour_kept_in_folder)
+ }
+ }
+
+ private fun setupViews(optionalBinding: SyncedFoldersSettingsLayoutBinding?, enable: Boolean) {
+ val alpha: Float = if (enable) {
+ alphaEnabled
+ } else {
+ alphaDisabled
+ }
+
+ optionalBinding?.let { binding ->
+ binding.settingInstantUploadOnWifiContainer.isEnabled = enable
+ binding.settingInstantUploadOnWifiContainer.alpha = alpha
+ binding.settingInstantUploadOnChargingContainer.isEnabled = enable
+ binding.settingInstantUploadOnChargingContainer.alpha = alpha
+ binding.settingInstantUploadExistingContainer.isEnabled = enable
+ binding.settingInstantUploadExistingContainer.alpha = alpha
+ binding.settingInstantUploadPathUseSubfoldersContainer.isEnabled = enable
+ binding.settingInstantUploadPathUseSubfoldersContainer.alpha = alpha
+ binding.remoteFolderContainer.isEnabled = enable
+ binding.remoteFolderContainer.alpha = alpha
+ binding.localFolderContainer.isEnabled = enable
+ binding.localFolderContainer.alpha = alpha
+ binding.settingInstantNameCollisionPolicyContainer.isEnabled = enable
+ binding.settingInstantNameCollisionPolicyContainer.alpha = alpha
+ binding.settingInstantUploadOnWifiCheckbox.isEnabled = enable
+ binding.settingInstantUploadOnChargingCheckbox.isEnabled = enable
+ binding.settingInstantUploadExistingCheckbox.isEnabled = enable
+ binding.settingInstantUploadPathUseSubfoldersCheckbox.isEnabled = enable
+ }
+
+ checkWritableFolder()
+ }
+
+ /**
+ * setup all listeners.
+ *
+ * @param binding the parent binding
+ */
+ private fun setupListeners(binding: SyncedFoldersSettingsLayoutBinding) {
+ binding.btnPositive.setOnClickListener(OnSyncedFolderSaveClickListener())
+ if (isNeutralButtonActive) {
+ binding.btnNeutral.setOnClickListener(OnSyncedFolderCancelClickListener())
+ binding.btnNegative.setOnClickListener(OnSyncedFolderDeleteClickListener())
+ } else {
+ binding.btnNegative.setOnClickListener(OnSyncedFolderCancelClickListener())
+ }
+
+ syncedFolder?.let { syncedFolder ->
+ binding.settingInstantUploadOnWifiContainer.setOnClickListener {
+ syncedFolder.isWifiOnly = !syncedFolder.isWifiOnly
+ binding.settingInstantUploadOnWifiCheckbox.toggle()
+ }
+ binding.settingInstantUploadOnChargingContainer.setOnClickListener {
+ syncedFolder.isChargingOnly = !syncedFolder.isChargingOnly
+ binding.settingInstantUploadOnChargingCheckbox.toggle()
+ }
+ binding.settingInstantUploadExistingContainer.setOnClickListener {
+ syncedFolder.isExisting = !syncedFolder.isExisting
+ binding.settingInstantUploadExistingCheckbox.toggle()
+ }
+ binding.settingInstantUploadPathUseSubfoldersContainer.setOnClickListener {
+ syncedFolder.isSubfolderByDate = !syncedFolder.isSubfolderByDate
+ binding.settingInstantUploadPathUseSubfoldersCheckbox.toggle()
+
+ // Only allow setting subfolder rule if subfolder is allowed
+ if (binding.settingInstantUploadPathUseSubfoldersCheckbox.isChecked) {
+ binding.settingInstantUploadSubfolderRuleContainer.visibility = View.VISIBLE
+ } else {
+ binding.settingInstantUploadSubfolderRuleContainer.visibility = View.GONE
+ }
+ }
+ binding.settingInstantUploadSubfolderRuleSpinner.onItemSelectedListener =
+ object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(adapterView: AdapterView<*>?, view: View, i: Int, l: Long) {
+ syncedFolder.subFolderRule = SubFolderRule.values()[i]
+ }
+
+ override fun onNothingSelected(adapterView: AdapterView<*>?) {
+ syncedFolder.subFolderRule = SubFolderRule.YEAR_MONTH
+ }
+ }
+
+ binding.syncEnabled.setOnClickListener { setEnabled(!syncedFolder.isEnabled) }
+ }
+
+ binding.remoteFolderContainer.setOnClickListener {
+ val action = Intent(activity, FolderPickerActivity::class.java)
+ requireActivity().startActivityForResult(action, REQUEST_CODE__SELECT_REMOTE_FOLDER)
+ }
+ binding.localFolderContainer.setOnClickListener {
+ val action = Intent(activity, UploadFilesActivity::class.java)
+ action.putExtra(UploadFilesActivity.KEY_LOCAL_FOLDER_PICKER_MODE, true)
+ action.putExtra(UploadFilesActivity.REQUEST_CODE_KEY, REQUEST_CODE__SELECT_LOCAL_FOLDER)
+ requireActivity().startActivityForResult(action, REQUEST_CODE__SELECT_LOCAL_FOLDER)
+ }
+
+ binding.settingInstantBehaviourContainer.setOnClickListener { showBehaviourDialog() }
+ binding.settingInstantNameCollisionPolicyContainer.setOnClickListener { showNameCollisionPolicyDialog() }
+ }
+
+ private fun showBehaviourDialog() {
+ val builder = MaterialAlertDialogBuilder(requireActivity())
+
+ syncedFolder?.let {
+ val behaviourEntries = resources.getTextArray(R.array.pref_behaviour_entries)
+ val behaviourEntryValues = resources.getTextArray(R.array.pref_behaviour_entryValues)
+ builder.setTitle(R.string.prefs_instant_behaviour_dialogTitle)
+ .setSingleChoiceItems(behaviourEntries, it.uploadActionInteger) { dialog: DialogInterface, which: Int ->
+ it.setUploadAction(behaviourEntryValues[which].toString())
+ binding?.settingInstantBehaviourSummary?.text = uploadBehaviorItemStrings[which]
+ behaviourDialogShown = false
+ dialog.dismiss()
+ }
+ .setOnCancelListener { behaviourDialogShown = false }
+ }
+
+ behaviourDialogShown = true
+ viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireActivity(), builder)
+
+ behaviourDialog = builder.create()
+ behaviourDialog?.show()
+ }
+
+ private fun showNameCollisionPolicyDialog() {
+ syncedFolder?.let {
+ val builder = MaterialAlertDialogBuilder(requireActivity())
+ builder.setTitle(R.string.pref_instant_name_collision_policy_dialogTitle)
+ .setSingleChoiceItems(
+ resources.getTextArray(R.array.pref_name_collision_policy_entries),
+ getSelectionIndexForNameCollisionPolicy(it.nameCollisionPolicy),
+ OnNameCollisionDialogClickListener()
+ )
+ .setOnCancelListener { nameCollisionPolicyDialogShown = false }
+
+ nameCollisionPolicyDialogShown = true
+
+ viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireActivity(), builder)
+ behaviourDialog = builder.create()
+ behaviourDialog?.show()
+ }
+ }
+
+ override fun onDestroyView() {
+ Log_OC.d(TAG, "destroy SyncedFolderPreferencesDialogFragment view")
+ if (dialog != null && retainInstance) {
+ dialog?.setDismissMessage(null)
+ }
+ if (behaviourDialog != null && behaviourDialog!!.isShowing) {
+ behaviourDialog?.dismiss()
+ }
+
+ super.onDestroyView()
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ outState.putBoolean(BEHAVIOUR_DIALOG_STATE, behaviourDialogShown)
+ outState.putBoolean(NAME_COLLISION_POLICY_DIALOG_STATE, nameCollisionPolicyDialogShown)
+ super.onSaveInstanceState(outState)
+ }
+
+ override fun onViewStateRestored(savedInstanceState: Bundle?) {
+ behaviourDialogShown = savedInstanceState != null &&
+ savedInstanceState.getBoolean(BEHAVIOUR_DIALOG_STATE, false)
+ nameCollisionPolicyDialogShown = savedInstanceState != null &&
+ savedInstanceState.getBoolean(NAME_COLLISION_POLICY_DIALOG_STATE, false)
+ if (behaviourDialogShown) {
+ showBehaviourDialog()
+ }
+ if (nameCollisionPolicyDialogShown) {
+ showNameCollisionPolicyDialog()
+ }
+
+ super.onViewStateRestored(savedInstanceState)
+ }
+
+ interface OnSyncedFolderPreferenceListener {
+ fun onSaveSyncedFolderPreference(syncedFolder: SyncedFolderParcelable?)
+ fun onCancelSyncedFolderPreference()
+ fun onDeleteSyncedFolderPreference(syncedFolder: SyncedFolderParcelable?)
+ }
+
+ private inner class OnSyncedFolderSaveClickListener : View.OnClickListener {
+ override fun onClick(v: View) {
+ dismiss()
+ (activity as OnSyncedFolderPreferenceListener?)?.onSaveSyncedFolderPreference(syncedFolder)
+ }
+ }
+
+ private inner class OnSyncedFolderCancelClickListener : View.OnClickListener {
+ override fun onClick(v: View) {
+ dismiss()
+ (activity as OnSyncedFolderPreferenceListener?)?.onCancelSyncedFolderPreference()
+ }
+ }
+
+ private inner class OnSyncedFolderDeleteClickListener : View.OnClickListener {
+ override fun onClick(v: View) {
+ dismiss()
+ (activity as OnSyncedFolderPreferenceListener?)?.onDeleteSyncedFolderPreference(syncedFolder)
+ }
+ }
+
+ private inner class OnNameCollisionDialogClickListener : DialogInterface.OnClickListener {
+ override fun onClick(dialog: DialogInterface, which: Int) {
+ syncedFolder!!.nameCollisionPolicy =
+ getNameCollisionPolicyForSelectionIndex(which)
+ binding?.settingInstantNameCollisionPolicySummary?.text =
+ nameCollisionPolicyItemStrings[which]
+ nameCollisionPolicyDialogShown = false
+ dialog.dismiss()
+ }
+ }
+
+ companion object {
+ const val SYNCED_FOLDER_PARCELABLE = "SyncedFolderParcelable"
+ const val REQUEST_CODE__SELECT_REMOTE_FOLDER = 0
+ const val REQUEST_CODE__SELECT_LOCAL_FOLDER = 1
+ private val TAG = SyncedFolderPreferencesDialogFragment::class.java.simpleName
+ private const val BEHAVIOUR_DIALOG_STATE = "BEHAVIOUR_DIALOG_STATE"
+ private const val NAME_COLLISION_POLICY_DIALOG_STATE = "NAME_COLLISION_POLICY_DIALOG_STATE"
+ private const val alphaEnabled = 1.0f
+ private const val alphaDisabled = 0.7f
+
+ @JvmStatic
+ fun newInstance(syncedFolder: SyncedFolderDisplayItem?, section: Int): SyncedFolderPreferencesDialogFragment {
+ requireNotNull(syncedFolder) { "SyncedFolder is mandatory but NULL!" }
+ val args = Bundle()
+ args.putParcelable(SYNCED_FOLDER_PARCELABLE, SyncedFolderParcelable(syncedFolder, section))
+ val dialogFragment = SyncedFolderPreferencesDialogFragment()
+ dialogFragment.arguments = args
+ dialogFragment.setStyle(STYLE_NORMAL, R.style.Theme_ownCloud_Dialog)
+ return dialogFragment
+ }
+
+ /**
+ * Get index for name collision selection dialog.
+ *
+ * @return 0 if ASK_USER, 1 if OVERWRITE, 2 if RENAME, 3 if SKIP, Otherwise: 0
+ */
+ @Suppress("MagicNumber")
+ private fun getSelectionIndexForNameCollisionPolicy(nameCollisionPolicy: NameCollisionPolicy): Int {
+ return when (nameCollisionPolicy) {
+ NameCollisionPolicy.OVERWRITE -> 1
+ NameCollisionPolicy.RENAME -> 2
+ NameCollisionPolicy.CANCEL -> 3
+ NameCollisionPolicy.ASK_USER -> 0
+ }
+ }
+
+ /**
+ * Get index for name collision selection dialog. Inverse of getSelectionIndexForNameCollisionPolicy.
+ *
+ * @return ASK_USER if 0, OVERWRITE if 1, RENAME if 2, SKIP if 3. Otherwise: ASK_USER
+ */
+ @Suppress("MagicNumber")
+ private fun getNameCollisionPolicyForSelectionIndex(index: Int): NameCollisionPolicy {
+ return when (index) {
+ 1 -> NameCollisionPolicy.OVERWRITE
+ 2 -> NameCollisionPolicy.RENAME
+ 3 -> NameCollisionPolicy.CANCEL
+ 0 -> NameCollisionPolicy.ASK_USER
+ else -> NameCollisionPolicy.ASK_USER
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java
index 76b5393ecf4c..97f777d4c492 100644
--- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java
+++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java
@@ -278,8 +278,7 @@ private void onOverflowIconClicked() {
R.id.action_favorite,
R.id.action_unset_favorite,
R.id.action_see_details,
- R.id.action_move,
- R.id.action_copy,
+ R.id.action_move_or_copy,
R.id.action_stream_media,
R.id.action_send_share_file,
R.id.action_pin_to_homescreen
@@ -694,7 +693,7 @@ public void listenForTransferProgress() {
if (progressListener != null) {
if (containerActivity.getFileDownloaderBinder() != null) {
containerActivity.getFileDownloaderBinder().
- addDatatransferProgressListener(progressListener, getFile());
+ addDataTransferProgressListener(progressListener, getFile());
}
if (containerActivity.getFileUploaderBinder() != null) {
containerActivity.getFileUploaderBinder().
@@ -709,7 +708,7 @@ private void leaveTransferProgress() {
if (progressListener != null) {
if (containerActivity.getFileDownloaderBinder() != null) {
containerActivity.getFileDownloaderBinder().
- removeDatatransferProgressListener(progressListener, getFile());
+ removeDataTransferProgressListener(progressListener, getFile());
}
if (containerActivity.getFileUploaderBinder() != null) {
containerActivity.getFileUploaderBinder().
diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java
index e7745f3ba368..26f2ac3ecdce 100644
--- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java
+++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java
@@ -1235,11 +1235,8 @@ public boolean onFileActionChosen(@IdRes final int itemId, Set checkedFi
} else if (itemId == R.id.action_unset_favorite) {
mContainerActivity.getFileOperationsHelper().toggleFavoriteFiles(checkedFiles, false);
return true;
- } else if (itemId == R.id.action_move) {
- pickFolderForMoveOrCopy(FolderPickerActivity.MOVE, checkedFiles);
- return true;
- } else if (itemId == R.id.action_copy) {
- pickFolderForMoveOrCopy(FolderPickerActivity.COPY, checkedFiles);
+ } else if (itemId == R.id.action_move_or_copy) {
+ pickFolderForMoveOrCopy(checkedFiles);
return true;
} else if (itemId == R.id.action_select_all_action_menu) {
selectAllFiles(true);
@@ -1257,18 +1254,9 @@ public boolean onFileActionChosen(@IdRes final int itemId, Set checkedFi
return false;
}
- private void pickFolderForMoveOrCopy(final String extraAction, final Set checkedFiles) {
- int requestCode;
- switch (extraAction) {
- case FolderPickerActivity.MOVE:
- requestCode = FileDisplayActivity.REQUEST_CODE__MOVE_FILES;
- break;
- case FolderPickerActivity.COPY:
- requestCode = FileDisplayActivity.REQUEST_CODE__COPY_FILES;
- break;
- default:
- throw new IllegalArgumentException("Unknown extra action: " + extraAction);
- }
+ private void pickFolderForMoveOrCopy(final Set checkedFiles) {
+ int requestCode = FileDisplayActivity.REQUEST_CODE__MOVE_OR_COPY_FILES;
+ String extraAction = FolderPickerActivity.MOVE_OR_COPY;
final Intent action = new Intent(getActivity(), FolderPickerActivity.class);
final ArrayList paths = new ArrayList<>(checkedFiles.size());
diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt
index 9af639d82e63..d14e37204f08 100644
--- a/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt
+++ b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt
@@ -30,7 +30,6 @@ import android.view.ViewGroup
import android.widget.ImageView
import androidx.annotation.VisibleForTesting
import androidx.appcompat.widget.SearchView
-import androidx.core.view.MenuItemCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
@@ -89,7 +88,7 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- vm = ViewModelProvider(this, vmFactory).get(UnifiedSearchViewModel::class.java)
+ vm = ViewModelProvider(this, vmFactory)[UnifiedSearchViewModel::class.java]
setUpViewModel()
val query = savedInstanceState?.getString(ARG_QUERY) ?: arguments?.getString(ARG_QUERY)
@@ -125,7 +124,7 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface
binding.emptyList.emptyListViewText.text =
requireContext().getString(R.string.file_list_empty_unified_search_no_results)
binding.emptyList.emptyListIcon.setImageDrawable(
- viewThemeUtils.platform.tintPrimaryDrawable(requireContext(), R.drawable.ic_search_grey)
+ viewThemeUtils.platform.tintDrawable(requireContext(), R.drawable.ic_search_grey)
)
}
}
@@ -151,10 +150,12 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface
}
}
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ @Suppress("DEPRECATION")
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = ListFragmentBinding.inflate(inflater, container, false)
binding.listRoot.updatePadding(top = resources.getDimension(R.dimen.standard_half_padding).toInt())
setUpBinding()
+
setHasOptionsMenu(true)
return binding.root
}
@@ -223,8 +224,14 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface
@Deprecated("Deprecated in Java")
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
val item = menu.findItem(R.id.action_search)
- searchView = MenuItemCompat.getActionView(item) as SearchView
+ searchView = item.actionView as SearchView?
+
+ // Required to align with TextView width.
+ // Because this fragment is opened with TextView onClick on the previous screen
+ searchView?.maxWidth = Integer.MAX_VALUE
+
viewThemeUtils.androidx.themeToolbarSearchView(searchView!!)
+
searchView?.setQuery(vm.query.value, false)
searchView?.setOnQueryTextListener(this)
searchView?.isIconified = false
diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java
index 2a382c2a78f7..68f3720a28c6 100755
--- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java
+++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java
@@ -1007,27 +1007,7 @@ public void cancelTransference(OCFile file) {
}
}
- /**
- * Start operations to move one or several files
- *
- * @param filePaths Remote paths of files to move
- * @param targetFolder Folder where the files while be moved into
- */
- public void moveFiles(final List filePaths, final OCFile targetFolder) {
- copyOrMoveFiles(OperationsService.ACTION_MOVE_FILE, filePaths, targetFolder);
- }
-
- /**
- * Start operations to copy one or several files
- *
- * @param filePaths Remote paths of files to move
- * @param targetFolder Folder where the files while be copied into
- */
- public void copyFiles(final List filePaths, final OCFile targetFolder) {
- copyOrMoveFiles(OperationsService.ACTION_COPY_FILE, filePaths, targetFolder);
- }
-
- private void copyOrMoveFiles(final String action, final List filePaths, final OCFile targetFolder) {
+ public void moveOrCopyFiles(String action, final List filePaths, final OCFile targetFolder) {
for (String path : filePaths) {
Intent service = new Intent(fileActivity, OperationsService.class);
service.setAction(action);
@@ -1039,7 +1019,6 @@ private void copyOrMoveFiles(final String action, final List filePaths,
fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment));
}
-
public void exportFiles(Collection files,
Context context,
View view,
diff --git a/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java
index ffca7c685a83..62a098e37d6e 100644
--- a/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java
+++ b/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java
@@ -261,7 +261,7 @@ private void setButtonsForRemote() {
public void listenForTransferProgress() {
if (mProgressListener != null && !mListening && containerActivity.getFileDownloaderBinder() != null) {
- containerActivity.getFileDownloaderBinder().addDatatransferProgressListener(mProgressListener, getFile());
+ containerActivity.getFileDownloaderBinder().addDataTransferProgressListener(mProgressListener, getFile());
mListening = true;
setButtonsForTransferring();
}
@@ -271,7 +271,7 @@ public void listenForTransferProgress() {
public void leaveTransferProgress() {
if (mProgressListener != null && containerActivity.getFileDownloaderBinder() != null) {
containerActivity.getFileDownloaderBinder()
- .removeDatatransferProgressListener(mProgressListener, getFile());
+ .removeDataTransferProgressListener(mProgressListener, getFile());
mListening = false;
}
}
diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java
index 09e03ab9b62f..b0ec4ee1b400 100644
--- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java
+++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java
@@ -375,8 +375,7 @@ private void showFileActions(OCFile file) {
Arrays.asList(
R.id.action_rename_file,
R.id.action_sync_file,
- R.id.action_move,
- R.id.action_copy,
+ R.id.action_move_or_copy,
R.id.action_favorite,
R.id.action_unset_favorite,
R.id.action_pin_to_homescreen
diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java
index 18ee93690fe2..20d82add5a4b 100644
--- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java
+++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java
@@ -424,8 +424,7 @@ private void showFileActions(OCFile file) {
Arrays.asList(
R.id.action_rename_file,
R.id.action_sync_file,
- R.id.action_move,
- R.id.action_copy,
+ R.id.action_move_or_copy,
R.id.action_favorite,
R.id.action_unset_favorite,
R.id.action_pin_to_homescreen
diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java
index e34031a51a71..16648c631c71 100644
--- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java
+++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java
@@ -300,8 +300,7 @@ private void showFileActions(OCFile file) {
Arrays.asList(
R.id.action_rename_file,
R.id.action_sync_file,
- R.id.action_move,
- R.id.action_copy,
+ R.id.action_move_or_copy,
R.id.action_favorite,
R.id.action_unset_favorite,
R.id.action_pin_to_homescreen
diff --git a/app/src/main/java/com/owncloud/android/utils/WebViewUtil.kt b/app/src/main/java/com/owncloud/android/utils/WebViewUtil.kt
new file mode 100644
index 000000000000..93dde6c9d3db
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/utils/WebViewUtil.kt
@@ -0,0 +1,110 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Alper Ozturk
+ * Copyright (C) 2023 Alper Ozturk
+ * Copyright (C) 2023 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.owncloud.android.utils
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.owncloud.android.R
+
+class WebViewUtil(private val context: Context) {
+
+ private val packageName = "com.google.android.webview"
+
+ fun checkWebViewVersion() {
+ if (!isWebViewVersionValid()) {
+ showUpdateDialog()
+ }
+ }
+
+ private fun isWebViewVersionValid(): Boolean {
+ val currentWebViewVersion = getCurrentWebViewMajorVersion() ?: return true
+ val minSupportedWebViewVersion: String = getMinimumSupportedMajorWebViewVersion()
+ return currentWebViewVersion.toInt() >= minSupportedWebViewVersion.toInt()
+ }
+
+ private fun showUpdateDialog() {
+ val builder = MaterialAlertDialogBuilder(context)
+ .setTitle(context.getString(R.string.webview_version_check_alert_dialog_title))
+ .setMessage(context.getString(R.string.webview_version_check_alert_dialog_message))
+ .setCancelable(false)
+ .setPositiveButton(
+ context.getString(R.string.webview_version_check_alert_dialog_positive_button_title)
+ ) { _, _ ->
+ redirectToAndroidSystemWebViewStorePage()
+ }
+
+ val dialog = builder.create()
+ dialog.show()
+ }
+
+ private fun redirectToAndroidSystemWebViewStorePage() {
+ val uri = Uri.parse("market://details?id=$packageName")
+ val intent = Intent(Intent.ACTION_VIEW, uri)
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+
+ try {
+ context.startActivity(intent)
+ } catch (e: android.content.ActivityNotFoundException) {
+ redirectToPlayStoreWebsiteForAndroidSystemWebView()
+ }
+ }
+
+ private fun redirectToPlayStoreWebsiteForAndroidSystemWebView() {
+ val playStoreWebUri = Uri.parse("https://play.google.com/store/apps/details?id=$packageName")
+ val webIntent = Intent(Intent.ACTION_VIEW, playStoreWebUri)
+ context.startActivity(webIntent)
+ }
+
+ private fun getCurrentWebViewMajorVersion(): String? {
+ val pm: PackageManager = context.packageManager
+
+ return try {
+ val pi = pm.getPackageInfo("com.google.android.webview", 0)
+ val fullVersion = pi.versionName
+
+ // Split the version string by "." and get the first part
+ val versionParts = fullVersion.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }
+ .toTypedArray()
+
+ if (versionParts.isNotEmpty()) {
+ versionParts[0]
+ } else {
+ null
+ }
+ } catch (e: PackageManager.NameNotFoundException) {
+ null
+ }
+ }
+
+ /**
+ * Ideally we should fetch from database, reading actual value
+ * from PlayStore not feasible due to frequently api changes made by
+ * Google
+ *
+ */
+ private fun getMinimumSupportedMajorWebViewVersion(): String {
+ return "118"
+ }
+}
diff --git a/app/src/main/res/drawable/ic_move.xml b/app/src/main/res/drawable/ic_move.xml
deleted file mode 100644
index bea61c0c3fe6..000000000000
--- a/app/src/main/res/drawable/ic_move.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
diff --git a/app/src/main/res/layout/files_folder_picker.xml b/app/src/main/res/layout/files_folder_picker.xml
index a9b85539fad4..c4d77b680856 100644
--- a/app/src/main/res/layout/files_folder_picker.xml
+++ b/app/src/main/res/layout/files_folder_picker.xml
@@ -46,27 +46,39 @@
+
+
+
+
diff --git a/app/src/main/res/layout/loading_dialog.xml b/app/src/main/res/layout/loading_dialog.xml
index 9625b7954e35..cdef05385fcd 100644
--- a/app/src/main/res/layout/loading_dialog.xml
+++ b/app/src/main/res/layout/loading_dialog.xml
@@ -16,7 +16,8 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see .
-->
-
- .
-->
-
+ android:layout_height="wrap_content">
-
-
-
+ android:orientation="vertical">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_height="wrap_content"
+ android:gravity="center|start"
+ android:layout_marginBottom="@dimen/standard_margin"
+ android:text="@string/sort_by"/>
-
+
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/app/src/main/res/layout/storage_path_item.xml b/app/src/main/res/layout/storage_path_item.xml
index dfcbf39ae9e7..5a7cfeba0b28 100644
--- a/app/src/main/res/layout/storage_path_item.xml
+++ b/app/src/main/res/layout/storage_path_item.xml
@@ -1,5 +1,4 @@
-
-
-
-
-
-
-
-
+ android:text="@string/menu_item_sort_by_name_z_a"
+ app:icon="@drawable/ic_user"
+ app:iconPadding="@dimen/standard_padding"
+ tools:text="DCIM" />
diff --git a/app/src/main/res/layout/synced_folders_settings_layout.xml b/app/src/main/res/layout/synced_folders_settings_layout.xml
index 153684a0e39e..14dc2f0d9687 100644
--- a/app/src/main/res/layout/synced_folders_settings_layout.xml
+++ b/app/src/main/res/layout/synced_folders_settings_layout.xml
@@ -61,9 +61,9 @@
android:layout_width="@dimen/synced_folders_control_width"
android:layout_height="match_parent"
android:gravity="center"
- android:padding="@dimen/standard_padding">
+ android:padding="@dimen/standard_half_padding">
-
-
+ android:text="@string/common_cancel"
+ android:layout_weight="1"/>
-
+
+
-
-
+ android:text="@string/common_delete"
+ android:layout_weight="1"/>
-
-
-
+
+
diff --git a/app/src/main/res/values-es-rCR/strings.xml b/app/src/main/res/values-es-rCR/strings.xml
index 6881255cf44f..9652d8bf0e11 100644
--- a/app/src/main/res/values-es-rCR/strings.xml
+++ b/app/src/main/res/values-es-rCR/strings.xml
@@ -240,6 +240,7 @@
Crear
No hay carpetas aquí
Seleccionar
+ Mover
No se te permite %s
para copiar este archivo
para crear este archivo
diff --git a/app/src/main/res/values-es-rDO/strings.xml b/app/src/main/res/values-es-rDO/strings.xml
index ca2e385c934e..e8ae500158c7 100644
--- a/app/src/main/res/values-es-rDO/strings.xml
+++ b/app/src/main/res/values-es-rDO/strings.xml
@@ -255,6 +255,7 @@
Crear
No hay carpetas aquí
Seleccionar
+ Mover
No se te permite %s
para copiar este archivo
para crear este archivo
diff --git a/app/src/main/res/values-es-rEC/strings.xml b/app/src/main/res/values-es-rEC/strings.xml
index 76819a2725fa..a78a292b441d 100644
--- a/app/src/main/res/values-es-rEC/strings.xml
+++ b/app/src/main/res/values-es-rEC/strings.xml
@@ -387,6 +387,8 @@
Crear
No hay carpetas aquí
Seleccionar
+ Selecciona la carpeta de destino.
+ Mover
No se te permite %s
para copiar este archivo
para crear este archivo
diff --git a/app/src/main/res/values-es-rGT/strings.xml b/app/src/main/res/values-es-rGT/strings.xml
index c335c3b518ca..2a4400a0c654 100644
--- a/app/src/main/res/values-es-rGT/strings.xml
+++ b/app/src/main/res/values-es-rGT/strings.xml
@@ -240,6 +240,7 @@
Crear
No hay carpetas aquí
Seleccionar
+ Mover
No se te permite %s
para copiar este archivo
para crear este archivo
diff --git a/app/src/main/res/values-es-rMX/strings.xml b/app/src/main/res/values-es-rMX/strings.xml
index f94a9d7fbb94..c9969fa3638c 100644
--- a/app/src/main/res/values-es-rMX/strings.xml
+++ b/app/src/main/res/values-es-rMX/strings.xml
@@ -329,6 +329,8 @@
Crear
No hay carpetas aquí
Seleccionar
+ Elegir carpeta destino
+ Mover
No se te permite %s
para copiar este archivo
para crear este archivo
diff --git a/app/src/main/res/values-es-rSV/strings.xml b/app/src/main/res/values-es-rSV/strings.xml
index 6881255cf44f..9652d8bf0e11 100644
--- a/app/src/main/res/values-es-rSV/strings.xml
+++ b/app/src/main/res/values-es-rSV/strings.xml
@@ -240,6 +240,7 @@
Crear
No hay carpetas aquí
Seleccionar
+ Mover
No se te permite %s
para copiar este archivo
para crear este archivo
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index ed1bb858abc6..449c6147c232 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -253,7 +253,7 @@
No es posible sin conexión a internet
Más
Notas
- Coloquio
+ Talk
Más apps de Nextcloud
Nextcloud Notas
Nextcloud Talk
diff --git a/app/src/main/res/values-et-rEE/strings.xml b/app/src/main/res/values-et-rEE/strings.xml
index 6dea94f883c5..845e7deb5e81 100644
--- a/app/src/main/res/values-et-rEE/strings.xml
+++ b/app/src/main/res/values-et-rEE/strings.xml
@@ -263,6 +263,8 @@
Loo
Siin ei ole kaustu
Vali
+ Vali sihtkaust
+ Liiguta
Sul ei ole %s õigusi
et kopeerida seda faili
selle faili loomiseks
@@ -436,6 +438,7 @@
Staatuse teade
Vaikeväärtus
Allalaadimised
+ Aasta
\"%1$s\" on sinuga jagatud
%1$s jagas sinuga \"%2$s\"
Leite konflikte
diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml
index bf0a2aa802ac..d88f97b2deb7 100644
--- a/app/src/main/res/values-eu/strings.xml
+++ b/app/src/main/res/values-eu/strings.xml
@@ -392,6 +392,8 @@
Sortu
Ez dago karpetarik hemen
Aukeratu
+ Aukeratu helburuko karpeta
+ Mugitu
Ez daukazu baimenik %s
fitxategi hau kopiatzeko
fitxategi hau sortzeko
diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml
index 6e739ade6904..bf89788c8ad4 100644
--- a/app/src/main/res/values-fa/strings.xml
+++ b/app/src/main/res/values-fa/strings.xml
@@ -392,6 +392,8 @@
ایجاد کردن
هیچ پوشه ای اینجا وجود ندارد
انتخاب کردن
+ پوشهٔ هدف را انتخاب کنید
+ انتقال
شما مجاز نیستید%s
کپی این فایل
برای ساختن این پرونده
diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml
index b7e81f464eef..0352263ba128 100644
--- a/app/src/main/res/values-fi-rFI/strings.xml
+++ b/app/src/main/res/values-fi-rFI/strings.xml
@@ -380,6 +380,8 @@
Luo
Ei kansioita täällä
Valitse
+ Valitse kohdekansio
+ Siirrä
Sinulla ei ole oikeutta %s
kopioida tämä tiedosto
luoda tätä tiedostoa
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index aff2b3fb4a29..066438b9f495 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -394,6 +394,9 @@ Attention, la suppression est irréversible.
Créer
Aucun dossier
Valider
+ Sélectionner le dossier cible
+ Copier
+ Déplacer
Vous n\'avez pas la permission %s
de copier ce fichier
de créer ce fichier
diff --git a/app/src/main/res/values-gd/strings.xml b/app/src/main/res/values-gd/strings.xml
index e12eebe7f3d6..e5feb7e13238 100644
--- a/app/src/main/res/values-gd/strings.xml
+++ b/app/src/main/res/values-gd/strings.xml
@@ -336,6 +336,8 @@
Cruthaich
Chan eil pasgan an-seo
Tagh
+ Dèan lethbhreac
+ Gluais
Chan fhad thu %s
lethbhreac dhen fhaidhle seo a dhèanamh
am faidhle seo a chruthachadh
diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml
index 15ddb5798876..83a632ebc77c 100644
--- a/app/src/main/res/values-gl/strings.xml
+++ b/app/src/main/res/values-gl/strings.xml
@@ -392,6 +392,9 @@
Crear
Aquí non hai cartafoles
Escoller
+ Escoller o cartafol de destino
+ Copiar
+ Mover
Non ten permiso %s
copiar este ficheiro
para crear este ficheiro
diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml
index 6be9e609e82a..36cb7c17eb4f 100644
--- a/app/src/main/res/values-hr/strings.xml
+++ b/app/src/main/res/values-hr/strings.xml
@@ -369,6 +369,9 @@
Stvori
Ovdje nema mapa
Odaberite
+ Odaberi ciljnu mapu
+ Kopirajte
+ Premjesti
Nemate dopuštenje %s
za kopiranje ove datoteke
za izradu ove datoteke
@@ -877,6 +880,7 @@
Pričekajte…
U tijeku je provjera spremljenih vjerodajnica
Kopiranje datoteke iz osobnog podatkovnog prostora
+ Ažuriraj
Što je nova slika
Preskoči
Novo u %1$s
diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml
index 7f89e32a81fd..2e77e1d75e17 100644
--- a/app/src/main/res/values-hu-rHU/strings.xml
+++ b/app/src/main/res/values-hu-rHU/strings.xml
@@ -392,6 +392,9 @@
Létrehozás
Itt nincsenek mappák
Válasszon
+ Válasszon célmappát
+ Másolás
+ Áthelyezés
Nem engedélyezett %s
a fájl másolása
fájl létrehozása
@@ -959,6 +962,7 @@ A Nextcloud itt érhető el: https://nextcloud.com
Egy pillanat…
Tárolt hitelesítő adatok ellenőrzése
Fájl másolása a privát tárolóról
+ Frissítés
Újdonságok kép
Kihagyás
Új itt: %1$s
diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml
index d10a78189142..ce04c1f25c75 100644
--- a/app/src/main/res/values-in/strings.xml
+++ b/app/src/main/res/values-in/strings.xml
@@ -329,6 +329,8 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini
Buat
Tidak ada folder
Pilih
+ Pilih folder target
+ Pindah
Anda tidak memiliki izin %s
untuk menyalin berkas ini
untuk membuat berkas ini
@@ -668,6 +670,7 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini
Tunggu sebentar…
Mengecek kredensial yang tersimpan
Menyalin berkas dari penyimpanan pribadi
+ Perbarui
Lewat
Apa yang baru di %1$s
Kirim surel
diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml
index 1d850a399041..00b618ac3c8d 100644
--- a/app/src/main/res/values-is/strings.xml
+++ b/app/src/main/res/values-is/strings.xml
@@ -340,6 +340,8 @@
Búa til
Engar möppur hér
Velja
+ Veldu úttaksmöppu
+ Færa
Þú hefur ekki heimild %s
til að afrita þessa skrá
til að búa til þessa skrá
@@ -793,6 +795,7 @@
Bíddu augnablik…
Athuga geymd auðkenni
Afrita skrá úr einkageymslu
+ Uppfæra
Mynd fyrir \'Hvað er nýtt\'
Sleppa
(Nýtt í %s)
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 97c0acb7d21b..853538454e40 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -392,6 +392,9 @@
Crea
Qui non c\'è alcuna cartella
Scegli
+ Scegli la cartella di destinazione
+ Copia
+ Sposta
Non ti è consentito %s
per copiare questo file
per creare questo file
@@ -941,6 +944,7 @@
Attendi…
Controllo delle credenziali memorizzate
Copia file dall\'archiviazione privata
+ Aggiorna
Immagine Cosa c\'è di nuovo
Salta
Prima volta su %1$s
diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml
index c52880031c86..7c8b9e26a98b 100644
--- a/app/src/main/res/values-iw/strings.xml
+++ b/app/src/main/res/values-iw/strings.xml
@@ -348,6 +348,9 @@
יצירה
אין כאן תיקיות
בחירה
+ נא לבחור תיקיית יעד
+ העתקה
+ העברה
אין לך הרשאה %s
להעתיק את הקובץ הזה
ליצור את הקובץ הזה
@@ -807,6 +810,7 @@
נא להמתין רגע…
בודק אישורים שמורים
מעתיק קובץ מאחסון פרטי
+ עדכון
תמונת מה חדש
דלג
חדש ב־%1$s
diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml
index 8712d6f4355c..3e40a180b51c 100644
--- a/app/src/main/res/values-ja-rJP/strings.xml
+++ b/app/src/main/res/values-ja-rJP/strings.xml
@@ -388,6 +388,9 @@
作成
フォルダーがありません
選択
+ ターゲットフォルダーを選択
+ コピー
+ 移動
%sが許可されていません。
このファイルをコピー
このファイルを作成する
@@ -922,6 +925,7 @@
少々お待ちください…
保存された資格情報をチェック
プライベートストレージからファイルをコピー中
+ 更新
新しいイメージとは
スキップ
%1$sの新機能
diff --git a/app/src/main/res/values-ka-rGE/strings.xml b/app/src/main/res/values-ka-rGE/strings.xml
index f849a3320722..f243aecc967e 100644
--- a/app/src/main/res/values-ka-rGE/strings.xml
+++ b/app/src/main/res/values-ka-rGE/strings.xml
@@ -219,6 +219,7 @@
შექმნა
აქ დირექტორიები არაა
არჩევა
+ გადატანა
თქვენ არ გაქვთ უფლება, %s
რომ დააკოპიროთ ეს ფაილი
შექმნათ ეს ფაილი
@@ -505,6 +506,7 @@
ჩამოტვირთვა
მოწმდება შენახული უფლებამოსილებანი
ფაილის კოპირება პირადი საცავიდან
+ განახლება
რა არის ახალი სურათი
გამოტოვება
ახალი %1$s-ში
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index 4fe95c0c284d..aa76b63429c6 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -389,6 +389,8 @@
생성
폴더가 없습니다
선택
+ 폴더 선택
+ 이동
%s 권한이 없음
이 파일을 복사할
파일을 생성할
@@ -941,6 +943,7 @@ Nextcloud를 여기서 확인하십시오: https://nextcloud.com
잠시 기다려 주십시오…
저장된 인증 정보 확인 중
개인 저장소에서 파일 복사
+ 업데이트
새로운 기능 사진
건너뛰기
%1$s의 새로운 것
diff --git a/app/src/main/res/values-lo/strings.xml b/app/src/main/res/values-lo/strings.xml
index cc130232f389..ce605d3f413e 100644
--- a/app/src/main/res/values-lo/strings.xml
+++ b/app/src/main/res/values-lo/strings.xml
@@ -342,6 +342,8 @@
ສ້າງ
ບໍ່ມີໂຟນເດີ
ເລືອກ
+ ສຳເນົາ
+ ຍ້າຍ
ບໍ່ໄດ້ຮັບອານຸຍາດ%s
ສໍາເນົາຟາຍນີ້
ສ້າງຟາຍນີ້
diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml
index 2d63918af878..87fdde43f23b 100644
--- a/app/src/main/res/values-lt-rLT/strings.xml
+++ b/app/src/main/res/values-lt-rLT/strings.xml
@@ -363,6 +363,9 @@
Sukurti
Čia aplankų nėra
Pasirinkti
+ Pasirinkite paskirties aplanką
+ Kopija
+ Perkelti
Neturite leidimo %s
kopijuoti failo
Sukurti failą
@@ -851,6 +854,7 @@
Palaukite…
Dekriptuojami prisijungimo duomenys
Kopijuojamas failas iš privačios saugyklos
+ Atnaujinti
Koks naujas vaizdas
Praleisti
Naujas %1$s
diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml
index 773cf0affdf4..aff3996614f8 100644
--- a/app/src/main/res/values-lv/strings.xml
+++ b/app/src/main/res/values-lv/strings.xml
@@ -253,6 +253,7 @@
Izveidot
Šeit nav mapju
Izvēlieties
+ Pārvietot
Jums nav atļaujas %s
lai kopētu šo datni
lai izveidotu šo datni
@@ -543,6 +544,7 @@
Uzgaidiet brītiņu…
Pārbauda saglabātos akredācijas datus
Kopē datni no privātās krātuves
+ Atjaunināt
Kas jauns attēls
Izlaist
Jaunums %1$s
diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml
index 07e5e22fca3e..f015c210a0ca 100644
--- a/app/src/main/res/values-mk/strings.xml
+++ b/app/src/main/res/values-mk/strings.xml
@@ -344,6 +344,8 @@
Креирај
Тука нема папки
Избери
+ Избери папка
+ Премести
Вие не сте овластени %s
за да ја копирате оваа датотека
да креирате датотека
@@ -793,6 +795,7 @@
Почекајте малку…
Проверка на зачуваните акредитиви
Копирам датотека од приватното складиште
+ Ажурирај
Слика од тоа што е ново
Прескокни
Ново во %1$s
diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml
index 14cc430980b7..e33b3fbc7606 100644
--- a/app/src/main/res/values-nb-rNO/strings.xml
+++ b/app/src/main/res/values-nb-rNO/strings.xml
@@ -392,6 +392,9 @@
Opprett
Ingen mapper her
Velg
+ Velg målmappe
+ Kopi
+ Flytt
Du har ikke tillatelse til %s
å kopiere denne filen
å opprette filen
@@ -929,6 +932,7 @@
Vent et øyeblikk…
Sjekker lagrede påloggingsdetaljer
Kopierer fil fra privat lager
+ Oppdater
Hva er nytt-bilde
Hopp over
Nytt i %1$s
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 6329f0587aca..7cfd4257ef78 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -372,6 +372,9 @@
Aanmaken
Hier zijn geen bestanden
Kiezen
+ Kies doelmap…
+ Kopiëren
+ Verplaatsen
Je mist autorisatie %s
om dit bestand te kopiëren
om dit bestand te creëren
@@ -886,6 +889,7 @@
Wacht even…
Opgeslagen inloggegevens nakijken
Bestand vanaf privéopslag kopiëren
+ Update
Wat is nieuw afbeelding
Overslaan
Nieuw in %1$s
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index ebb36dd77b4e..e6198a5a30bf 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -392,6 +392,9 @@
Utwórz
Brak katalogów
Wybierz
+ Wybierz katalog docelowy
+ Skopiuj
+ Przenieś
Nie masz uprawnień %s
do kopiowania tego pliku
do utworzenia tego pliku
@@ -941,6 +944,7 @@
Proszę czekać…
Sprawdzanie danych
Kopiowanie pliku z prywatnego magazynu
+ Aktualizuj
Jaki jest nowy obraz
Pomiń
Co nowego w %1$s
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index f349e72750dc..00a8328d9320 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -392,6 +392,9 @@
Criar
Sem pastas aqui
Escolher
+ Escolher pasta destino
+ Copiar
+ Mover
Você não tem permissão %s
para copiar este arquivo
para criar este arquivo
@@ -941,6 +944,7 @@
Aguarde um momento…
Verificando credenciais salvas
Copiando o arquivo da armazenagem privada
+ Atualizar
Imagem nova
Saltar
Novo em %1$s
diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml
index 1c45a1ddbc51..af909d1bc6c9 100644
--- a/app/src/main/res/values-pt-rPT/strings.xml
+++ b/app/src/main/res/values-pt-rPT/strings.xml
@@ -381,6 +381,9 @@
Criar
Sem pastas aqui
Escolher
+ Escolher pasta de destino
+ copiar
+ Mover
Não tem permissão %s
para copiar este ficheiro
para criar este ficheiro
@@ -921,6 +924,7 @@ Aproveite o novo e melhorado envio automático.
Aguarde um momento…
A verificar as credenciais guardadas
A copiar o ficheiro do armazenamento privado
+ Atualizar
Imagem de novidades
Passar à frente
Novo em %1$s
diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml
index fe2d34b6695e..ad4ea64a1137 100644
--- a/app/src/main/res/values-ro/strings.xml
+++ b/app/src/main/res/values-ro/strings.xml
@@ -386,6 +386,9 @@
Creați
Niciun dosar aici
Alege
+ Alege directorul destinație
+ Copiază
+ Mută
Nu ai permisiunea %s
să copiați acest fișier
pentru a crea fisierul
@@ -910,6 +913,7 @@
Așteaptă un moment…
Se verifică datele de autentificare stocate
Copiere fișier din stocare privată
+ Actualizare
Ce imagine este nouă
Sari peste
Nou în %1$s
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 940c6eeeef0b..de75e897a0c5 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -393,6 +393,9 @@
Создать
Здесь нет каталогов
Выбрать
+ Выбор папки назначения
+ Копировать
+ Переместить
У вас нет разрешений %s
для копирования этого файла
для создания файла
@@ -942,6 +945,7 @@
Подождите немного…
Проверка сохранённых реквизитов учётных данных
Копирование файла из частного хранилища
+ Изменение
Изображение «что нового»
Пропустить
Новое в %1$s
diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml
index e83542f790b5..481deb0d2c27 100644
--- a/app/src/main/res/values-sc/strings.xml
+++ b/app/src/main/res/values-sc/strings.xml
@@ -346,6 +346,9 @@
Crea
Peruna cartella inoghe
Sèbera
+ Sèbera cartella de destinatzione
+ Còpia
+ Tràmuda
Non tenes su permissu%s
de copiare custu documentu
de creare custu archìviu
@@ -819,6 +822,7 @@
Abeta pagu pagu...
Controllende is credentziales sarvadas
Copiende s\'archìviu dae s\'archiviatzione privada
+ Agiorna
Immàgine de ite ddoe est de nou
Brinca
Prima borta in %1$s
diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml
index 6949ae517a7c..377e6a28fa7a 100644
--- a/app/src/main/res/values-sk-rSK/strings.xml
+++ b/app/src/main/res/values-sk-rSK/strings.xml
@@ -376,6 +376,8 @@
Vytvoriť
Nie sú tu žiadne priečinky
Vybrať
+ Vyberte cieľový priečinok
+ Presunúť
Nemáte oprávnenie %s
kopírovať súbor
vytvoriť súbor
@@ -896,6 +898,7 @@
Počkajte chvíľu…
Overujem uložené prihlasovacie údaje
Kopírovanie súboru z privátneho úložiska
+ Aktualizovať
Obrázok čo je nové
Preskočiť
Nové v %1$s
diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml
index 54ffc676dd2d..abc7c38411ef 100644
--- a/app/src/main/res/values-sl/strings.xml
+++ b/app/src/main/res/values-sl/strings.xml
@@ -389,6 +389,9 @@
Ustvari
Ni map
Izbor
+ Izbor ciljne mape
+ Kopiraj
+ Premakni
Ni ustreznega dovoljenja %s
za kopiranje te datoteke
za ustvarjanje datoteke
@@ -925,6 +928,7 @@
Počakajte trenutek …
Poteka preverjanje shranjenih poveril
Kopiranje datoteke iz zasebne shrambe
+ Posodobi
Kaj je nova slika
Preskoči
Novo v %1$s
diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml
index c879badd5b8c..72ccedae22f2 100644
--- a/app/src/main/res/values-sq/strings.xml
+++ b/app/src/main/res/values-sq/strings.xml
@@ -312,6 +312,8 @@
Krijo
Këtu nuk ka dosje
Zgjidhni
+ Kopjoni
+ Zhvendos
Nuk keni leje %s
për kopjim të kësaj kartele
për krijim kartele
@@ -732,6 +734,7 @@
Prisni një moment…
Po kontrollohen kredenciale të depozituara
Po kopjohet skedar nga depo private
+ Përditëso
Imazhi me çfarë është e re
Kalo
I ri në %1$s
diff --git a/app/src/main/res/values-sr-rSP/strings.xml b/app/src/main/res/values-sr-rSP/strings.xml
index 9a30b0358719..e7d600837b31 100644
--- a/app/src/main/res/values-sr-rSP/strings.xml
+++ b/app/src/main/res/values-sr-rSP/strings.xml
@@ -286,6 +286,8 @@
Napravi
Bez fascikli
Odaberi
+ Kopiraj
+ Premesti
Nije vam dozvoljeno da %s
da kopirate ovaj fajl
da napravite fajl
diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml
index 4d3e9ca96442..e40a4b282f64 100644
--- a/app/src/main/res/values-sr/strings.xml
+++ b/app/src/main/res/values-sr/strings.xml
@@ -392,6 +392,9 @@
Направи
Нема фасцикли овде
Одабери
+ Одаберите одредишну фасциклу
+ Копирај
+ Помери
Није вам дозвољено %s
да копирате овај фајл
да направите фајл
@@ -941,6 +944,7 @@
Сачекајте мало…
Проверавам сачуване акредитиве
Копирам фајл из личног складишта
+ Ажурирај
Слика шта је ново
Прескочи
Ново у %1$s
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index 5b608555a95d..f8394b873cb4 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -392,6 +392,9 @@
Skapa
Inga mappar här
Välj
+ Välj målmapp
+ Kopiera
+ Flytta
Du har inte tillstånd %s
att kopiera denna fil
att skapa denna fil
@@ -941,6 +944,7 @@
Vänligen vänta…
Kontrollerar lagrade inloggningsuppgifter
Kopierar fil från privat lagring
+ Uppdatera
Vad är nytt-bild
Hoppa över
Ny i %1$s
diff --git a/app/src/main/res/values-th-rTH/strings.xml b/app/src/main/res/values-th-rTH/strings.xml
index 0f284c4bc34f..764ebe348367 100644
--- a/app/src/main/res/values-th-rTH/strings.xml
+++ b/app/src/main/res/values-th-rTH/strings.xml
@@ -334,6 +334,9 @@
สร้าง
ไม่มีโฟลเดอร์ที่นี่
เลือก
+ เลือกโฟลเดอร์เป้าหมาย
+ คัดลอก
+ ย้าย
คุณไม่ได้รับอนุญาต%s
ให้คัดลอกไฟล์นี้
ให้สร้างไฟล์นี้
@@ -630,6 +633,7 @@
ดาวน์โหลด
รอสักครู่…
กำลังคัดลอกไฟล์จากพื้นที่จัดเก็บส่วนตัว
+ อัปเดต
รูปภาพมีอะไรใหม่
ข้าม
มีอะไรใหม่ใน %1$s
diff --git a/app/src/main/res/values-tk/strings.xml b/app/src/main/res/values-tk/strings.xml
index 962bfb591000..d2eb9098cf29 100644
--- a/app/src/main/res/values-tk/strings.xml
+++ b/app/src/main/res/values-tk/strings.xml
@@ -330,6 +330,8 @@
Dörediň
Bu ýerde bukjalar ýok
Saýlaň
+ Göçüriň
+ Göçüriň
%sSize rugsat berilmeýär
bu faýly göçürmek
bu faýly döretmek
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 47e5571f75b4..123bfa207c7f 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -392,6 +392,9 @@
Ekle
Burada herhangi bir klasör yok
Seçin
+ Hedef klasörü seçin
+ Kopyala
+ Taşı
%s izniniz yok
bu dosyayı kopyalayın
bu dosyayı oluşturamazsınız
@@ -941,6 +944,7 @@
Lütfen bekleyin …
Kayıtlı kimlik bilgileri denetleniyor
Dosya kişisel depolamadan kopyalanıyor
+ Güncelle
Yenilikler görseli
Atla
%1$s yenilikleri
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index b5491249045a..9c66b218e5c0 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -314,7 +314,7 @@
Додати або завантажити
Не вдалося передати файл до менеджера звантажень
Не вдалося роздрукувати файл
- Не вдалося запустити редактор
+ Не вдалося відкрити редактор
Неможливо оновити інтерфейс
Додати зірочку
Із зірочкою
@@ -390,6 +390,9 @@
Створити
Тут відсутні каталоги
Вибрати
+ Виберіть каталог призначення
+ Копія
+ Перемістити
У вас відсутні повноваження %s
скопіювати цей файл
щоб створити цей файл
@@ -931,6 +934,7 @@
Зачекайте трохи…
Перевірка збережених даних авторизації
Копіювання файлу з приватного сховища
+ Оновлення
Зображення про нові функції
Пропустити
Нове у %1$s
diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml
index b78e6fd7ba7f..ba2e5d6ee42f 100644
--- a/app/src/main/res/values-vi/strings.xml
+++ b/app/src/main/res/values-vi/strings.xml
@@ -376,6 +376,8 @@
Tạo
Không có thư mục nào
Chọn
+ Chọn thư mục đích
+ Dịch chuyển
Bạn không được cho phép %s
sao chép tập tin này
tạo tập tin này
@@ -883,6 +885,7 @@
Đợi một chút…
Kiểm tra thông tin đăng nhập đã lưu trữ
Sao chép tệp từ bộ nhớ riêng
+ Cập nhật
Hình ảnh mới là gì
Bỏ qua
Mới trong %1$s
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index 83f3a23314ee..32f36352e970 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -392,6 +392,9 @@
创建
这里没有文件夹
选择
+ 选择目标文件夹
+ 复制
+ 移动
您没有 %s 的权限
复制这个文件
创建这个文件
@@ -944,6 +947,7 @@
请稍等…
正在检查保存的证书
正在从私有存储中复制文件
+ 更新
有什么新图片
跳过
新建%1$s
diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml
index 0fc553cb404d..c603bbdf982b 100644
--- a/app/src/main/res/values-zh-rHK/strings.xml
+++ b/app/src/main/res/values-zh-rHK/strings.xml
@@ -392,6 +392,9 @@
建立
這裡沒有資料夾
選擇
+ 選擇目標資料夾
+ 複製
+ 移動
您沒有%s的權限
複製這個檔案
建立此檔案
@@ -941,6 +944,7 @@
請稍候…
檢查儲存的身分驗證
從私有儲存空間複製檔案中
+ 更新
有什麼新圖像?
略過
新增到 %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 7a74434ec14e..944b5fda4342 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -392,6 +392,9 @@
建立
這裡沒有資料夾
選擇
+ 選擇目標資料夾
+ 複製
+ 移動
您沒有 %s 的權限
複製這個檔案
建立此檔案
@@ -941,6 +944,7 @@
稍候……
正在檢查儲存的憑證
從私有儲存空間複製檔案中
+ 更新
有什麼新圖片?
略過
新增到 %1$s
diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml
index 60e85c4e8b1c..113e681bbd2b 100644
--- a/app/src/main/res/values/ids.xml
+++ b/app/src/main/res/values/ids.xml
@@ -30,8 +30,7 @@
-
-
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 75112b21250e..d552f8c69bc1 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -162,6 +162,7 @@
Fetching server version…
Waiting to upload
%1$s (%2$d)
+ Downloading \u0020
Downloading…
%1$d%% Downloading %2$s
Downloaded
@@ -428,10 +429,12 @@
No app for sending logs found. Please install an email client.
%1$s Android app logs
- Move
- Copy
+ Move or Copy
Nothing in here. You can add a folder.
- Choose
+
+ Copy
+ Move
+ Choose target folder
Unable to move file. Please check whether it exists.
It is not possible to move a folder into one of its own underlying folders
@@ -439,7 +442,6 @@
An error occurred while trying to move this file or folder
to move this file
-
Unable to copy. Please check whether the file exists.
It is not possible to copy a folder into one of its own underlying folders
The file is already present in the destination folder
@@ -545,8 +547,6 @@
Get release candidate from F-Droid app
Get development release from F-Droid app
Download development release directly
- Move to…
- Copy to…
Choose remote folder…
Choose local folder…
%1$s/%2$s
@@ -656,12 +656,6 @@
shared via link
shared
More menu
- A - Z
- Newest first
- Biggest first
- Smallest first
- Z - A
- Oldest first
Type
Sync status button
Settings button
@@ -976,6 +970,10 @@
Close
Login with %1$s to %2$s
Login via direct link failed!
+ Update Android System WebView
+ Please update the Android System WebView app for a login
+ Update
+
The link to your %1$s web interface when you open it in the browser.
Delayed due to too many wrong attempts
Create
@@ -1035,8 +1033,6 @@
Show videos
Videos only
Set media folder
- Choose location
- Select
Lock file
Unlock file
Error changing file lock status