Merge remote-tracking branch 'origin/master' into dev

This commit is contained in:
Tobias Kaminsky 2024-08-19 02:31:49 +02:00
commit 05884978c4
15 changed files with 174 additions and 150 deletions

View file

@ -16,7 +16,7 @@ import org.gradle.internal.jvm.Jvm
buildscript {
dependencies {
classpath "com.android.tools.build:gradle:$androidPluginVersion"
classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.19'
classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.0.20'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.23.6"
classpath "commons-httpclient:commons-httpclient:3.1@jar" // remove after entire switch to lib v2

View file

@ -148,7 +148,7 @@ class FilesSyncWork(
private fun setSyncedFolder(syncedFolderID: Long): Boolean {
val syncedFolderTmp = syncedFolderProvider.getSyncedFolderByID(syncedFolderID)
if (syncedFolderTmp == null || !syncedFolderTmp.isEnabled || !syncedFolderTmp.isExisting) {
if (syncedFolderTmp == null || !syncedFolderTmp.isEnabled) {
return false
}
syncedFolder = syncedFolderTmp

View file

@ -462,6 +462,7 @@ public abstract class DrawerActivity extends ToolbarActivity
return true;
});
User account = accountManager.getUser();
filterDrawerMenu(navigationView.getMenu(), account);
}
@ -1052,6 +1053,10 @@ public abstract class DrawerActivity extends ToolbarActivity
updateQuotaLink();
}
public int getCheckedMenuItem() {
return mCheckedMenuItem;
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);

View file

@ -1168,7 +1168,12 @@ public class FileDisplayActivity extends FileActivity
setDrawerMenuItemChecked(R.id.nav_on_device);
setupToolbar();
} else {
setDrawerMenuItemChecked(R.id.nav_all_files);
int lastMenuItem = getCheckedMenuItem();
if (lastMenuItem == Menu.NONE) {
lastMenuItem = R.id.nav_all_files;
}
setDrawerMenuItemChecked(lastMenuItem);
setupHomeSearchToolbarWithSortAndListButtons();
}
}

View file

@ -19,6 +19,7 @@ import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import androidx.annotation.VisibleForTesting
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.google.android.material.snackbar.Snackbar
import com.nextcloud.android.common.ui.theme.utils.ColorRole
import com.nextcloud.client.di.Injectable
@ -28,7 +29,11 @@ import com.owncloud.android.authentication.PassCodeManager
import com.owncloud.android.databinding.PasscodelockBinding
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.ui.components.PassCodeEditText
import com.owncloud.android.ui.components.showKeyboard
import com.owncloud.android.utils.theme.ViewThemeUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import javax.inject.Inject
@Suppress("TooManyFunctions", "MagicNumber")
@ -51,17 +56,14 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
const val PREFERENCE_PASSCODE_D4 = "PrefPinCode4"
}
@JvmField
@Inject
var preferences: AppPreferences? = null
lateinit var preferences: AppPreferences
@JvmField
@Inject
var passCodeManager: PassCodeManager? = null
lateinit var passCodeManager: PassCodeManager
@JvmField
@Inject
var viewThemeUtils: ViewThemeUtils? = null
lateinit var viewThemeUtils: ViewThemeUtils
@get:VisibleForTesting
lateinit var binding: PasscodelockBinding
@ -85,8 +87,8 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
}
private fun applyTint() {
viewThemeUtils?.platform?.colorViewBackground(binding.cardViewContent, ColorRole.SURFACE_VARIANT)
viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(binding.cancel)
viewThemeUtils.platform.colorViewBackground(binding.cardViewContent, ColorRole.SURFACE_VARIANT)
viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(binding.cancel)
}
private fun setupPasscodeEditTexts() {
@ -96,10 +98,16 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
passCodeEditTexts[3] = binding.txt3
passCodeEditTexts.forEach {
it?.let { viewThemeUtils?.platform?.colorEditText(it) }
it?.let { editText ->
viewThemeUtils.platform.colorEditText(editText)
}
}
passCodeEditTexts[0]?.requestFocus()
binding.cardViewContent.setOnClickListener {
binding.txt0.showKeyboard()
}
}
private fun setSoftInputMode() {
@ -140,14 +148,17 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
}
private fun setCancelButtonEnabled(enabled: Boolean) {
binding.cancel.visibility = if (enabled) {
View.VISIBLE
} else {
View.INVISIBLE
}
binding.cancel.setOnClickListener {
if (enabled) {
finish()
binding.cancel.run {
visibility = if (enabled) {
View.VISIBLE
} else {
View.INVISIBLE
}
setOnClickListener {
if (enabled) {
finish()
}
}
}
}
@ -193,6 +204,7 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
} else if (!changed) {
changed = true
}
false
}
}
@ -207,24 +219,24 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
private fun processFullPassCode() {
if (ACTION_CHECK == intent.action) {
if (checkPassCode()) {
preferences?.resetPinWrongAttempts()
preferences.resetPinWrongAttempts()
// / pass code accepted in request, user is allowed to access the app
passCodeManager?.updateLockTimestamp()
hideSoftKeyboard()
passCodeManager.updateLockTimestamp()
hideKeyboard()
finish()
} else {
preferences?.increasePinWrongAttempts()
preferences.increasePinWrongAttempts()
showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, View.INVISIBLE)
}
} else if (ACTION_CHECK_WITH_RESULT == intent.action) {
if (checkPassCode()) {
passCodeManager?.updateLockTimestamp()
passCodeManager.updateLockTimestamp()
val resultIntent = Intent()
resultIntent.putExtra(KEY_CHECK_RESULT, true)
setResult(RESULT_OK, resultIntent)
hideSoftKeyboard()
hideKeyboard()
finish()
} else {
showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, View.INVISIBLE)
@ -246,7 +258,7 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
}
}
private fun hideSoftKeyboard() {
private fun hideKeyboard() {
currentFocus?.let {
val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(
@ -275,7 +287,7 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
}
private fun checkPassCode(): Boolean {
val savedPassCodeDigits = preferences?.passCode
val savedPassCodeDigits = preferences.passCode
return passCodeDigits.zip(savedPassCodeDigits.orEmpty()) { input, saved ->
input == saved
}.all { it }
@ -320,14 +332,14 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
passCodeDigits[0] + passCodeDigits[1] + passCodeDigits[2] + passCodeDigits[3]
)
setResult(RESULT_OK, resultIntent)
passCodeManager?.updateLockTimestamp()
passCodeManager.updateLockTimestamp()
finish()
}
private fun showDelay() {
val delay = preferences?.pinBruteForceDelay() ?: 0
val delayValue = preferences.pinBruteForceDelay()
if (delay <= 0) {
if (delayValue <= 0) {
return
}
@ -338,29 +350,28 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
binding.txt2.isEnabled = false
binding.txt3.isEnabled = false
Thread(object : Runnable {
override fun run() {
try {
Thread.sleep(delay * 1000L)
lifecycleScope.launch(Dispatchers.IO) {
delay(delayValue * 1000L)
runOnUiThread {
binding.explanation.visibility = View.INVISIBLE
binding.txt0.isEnabled = true
binding.txt1.isEnabled = true
binding.txt2.isEnabled = true
binding.txt3.isEnabled = true
}
} catch (e: InterruptedException) {
Log_OC.e(this, "Could not delay password input prompt")
}
launch(Dispatchers.Main) {
binding.explanation.visibility = View.INVISIBLE
binding.txt0.isEnabled = true
binding.txt1.isEnabled = true
binding.txt2.isEnabled = true
binding.txt3.isEnabled = true
binding.txt0.requestFocus()
binding.txt0.showKeyboard()
}
}).start()
}
}
public override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putBoolean(KEY_CONFIRMING_PASSCODE, confirmingPassCode)
outState.putStringArray(KEY_PASSCODE_DIGITS, passCodeDigits)
outState.run {
putBoolean(KEY_CONFIRMING_PASSCODE, confirmingPassCode)
putStringArray(KEY_PASSCODE_DIGITS, passCodeDigits)
}
}
private inner class PassCodeDigitTextWatcher(index: Int, lastOne: Boolean) : TextWatcher {
@ -408,12 +419,7 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
}
}
@Suppress("EmptyFunctionBlock")
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
@Suppress("EmptyFunctionBlock")
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) = Unit
}
}

View file

@ -13,6 +13,7 @@ import android.util.AttributeSet
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.View
import android.view.inputmethod.InputMethodManager
import androidx.appcompat.widget.AppCompatEditText
@SuppressLint("ClickableViewAccessibility")
@ -25,7 +26,10 @@ class PassCodeEditText(context: Context, attrs: AttributeSet?) : AppCompatEditTe
private fun disableFocusChangeViaTap() {
setSelectAllOnFocus(false)
setTextIsSelectable(false)
setOnTouchListener { _: View?, _: MotionEvent? -> true }
setOnTouchListener { _: View?, _: MotionEvent? ->
showKeyboard()
true
}
}
override fun onKeyPreIme(keyCode: Int, event: KeyEvent): Boolean {
@ -37,3 +41,8 @@ class PassCodeEditText(context: Context, attrs: AttributeSet?) : AppCompatEditTe
return super.dispatchKeyEvent(event)
}
}
fun PassCodeEditText.showKeyboard() {
val imm = this.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
}

View file

@ -1,13 +1,8 @@
/*
* Nextcloud Android client application
* Nextcloud - Android Client
*
* @author Tobias Kaminsky
* @author TSI-mc
* Copyright (C) 2017 Tobias Kaminsky
* Copyright (C) 2017 Nextcloud GmbH.
* Copyright (C) 2023 TSI-mc
*
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package com.owncloud.android.ui.dialog
@ -52,9 +47,8 @@ import javax.inject.Inject
*/
class SetupEncryptionDialogFragment : DialogFragment(), Injectable {
@JvmField
@Inject
var viewThemeUtils: ViewThemeUtils? = null
lateinit var viewThemeUtils: ViewThemeUtils
private var user: User? = null
private var arbitraryDataProvider: ArbitraryDataProvider? = null
@ -77,15 +71,14 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable {
val alertDialog = dialog as AlertDialog?
if (alertDialog != null) {
positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as MaterialButton?
negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as MaterialButton?
if (positiveButton != null) {
viewThemeUtils?.material?.colorMaterialButtonPrimaryTonal(positiveButton!!)
positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as? MaterialButton?
positiveButton?.let {
viewThemeUtils.material.colorMaterialButtonPrimaryTonal(it)
}
if (negativeButton != null) {
viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(negativeButton!!)
negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as? MaterialButton?
negativeButton?.let {
viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(it)
}
}
}
@ -111,30 +104,25 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable {
binding = SetupEncryptionDialogBinding.inflate(inflater, null, false)
// Setup layout
viewThemeUtils?.material?.colorTextInputLayout(binding.encryptionPasswordInputContainer)
viewThemeUtils.material.colorTextInputLayout(binding.encryptionPasswordInputContainer)
return createDialog(binding.root)
val builder = buildMaterialAlertDialog(binding.root)
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(requireContext(), builder)
return builder.create().apply {
setCanceledOnTouchOutside(false)
setOnShowListener { dialog1: DialogInterface ->
val button = (dialog1 as AlertDialog).getButton(AlertDialog.BUTTON_POSITIVE)
button.setOnClickListener { positiveButtonOnClick(this) }
}
}
}
private fun createDialog(v: View): Dialog {
val builder = MaterialAlertDialogBuilder(v.context)
builder
private fun buildMaterialAlertDialog(v: View): MaterialAlertDialogBuilder {
return MaterialAlertDialogBuilder(requireContext())
.setView(v)
.setPositiveButton(R.string.common_ok, null)
.setNegativeButton(R.string.common_cancel) { dialog: DialogInterface, _: Int -> dialog.cancel() }
.setTitle(R.string.end_to_end_encryption_title)
viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(v.context, builder)
val dialog: Dialog = builder.create()
dialog.setCanceledOnTouchOutside(false)
dialog.setOnShowListener { dialog1: DialogInterface ->
val button = (dialog1 as AlertDialog).getButton(AlertDialog.BUTTON_POSITIVE)
button.setOnClickListener { positiveButtonOnClick(dialog) }
}
return dialog
}
private fun positiveButtonOnClick(dialog: DialogInterface) {
@ -243,23 +231,26 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable {
private val resultIntent: Intent
get() {
val intentCreated = Intent()
intentCreated.putExtra(SUCCESS, true)
intentCreated.putExtra(ARG_POSITION, requireArguments().getInt(ARG_POSITION))
return intentCreated
return Intent().apply {
putExtra(SUCCESS, true)
putExtra(ARG_POSITION, requireArguments().getInt(ARG_POSITION))
}
}
private val resultBundle: Bundle
get() {
val bundle = Bundle()
bundle.putBoolean(SUCCESS, true)
bundle.putInt(ARG_POSITION, requireArguments().getInt(ARG_POSITION))
return bundle
return Bundle().apply {
putBoolean(SUCCESS, true)
putInt(ARG_POSITION, requireArguments().getInt(ARG_POSITION))
}
}
override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog)
val bundle = Bundle()
bundle.putBoolean(RESULT_KEY_CANCELLED, true)
val bundle = Bundle().apply {
putBoolean(RESULT_KEY_CANCELLED, true)
}
parentFragmentManager.setFragmentResult(RESULT_REQUEST_KEY, bundle)
}
@ -270,11 +261,7 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable {
@SuppressLint("StaticFieldLeak")
inner class DownloadKeysAsyncTask(context: Context) : AsyncTask<Void?, Void?, String?>() {
private val mWeakContext: WeakReference<Context>
init {
mWeakContext = WeakReference(context)
}
private val mWeakContext: WeakReference<Context> = WeakReference(context)
@Suppress("ReturnCount", "LongMethod")
@Deprecated("Deprecated in Java")
@ -289,26 +276,26 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable {
val publicKeyResult = publicKeyOperation.executeNextcloudClient(user, context)
if (publicKeyResult.isSuccess) {
Log_OC.d(TAG, "public key successful downloaded for " + user.accountName)
val publicKeyFromServer = publicKeyResult.resultData
if (arbitraryDataProvider != null) {
arbitraryDataProvider?.storeOrUpdateKeyValue(
user.accountName,
EncryptionUtils.PUBLIC_KEY,
publicKeyFromServer
)
} else {
return null
}
} else {
if (!publicKeyResult.isSuccess) {
return null
}
Log_OC.d(TAG, "public key successful downloaded for " + user.accountName)
if (arbitraryDataProvider == null) {
return null
}
val publicKeyFromServer = publicKeyResult.resultData
arbitraryDataProvider?.storeOrUpdateKeyValue(
user.accountName,
EncryptionUtils.PUBLIC_KEY,
publicKeyFromServer
)
val privateKeyResult = GetPrivateKeyRemoteOperation().executeNextcloudClient(user, context)
if (privateKeyResult.isSuccess) {
Log_OC.d(TAG, "private key successful downloaded for " + user!!.accountName)
Log_OC.d(TAG, "private key successful downloaded for " + user.accountName)
keyResult = KEY_EXISTING_USED
return privateKeyResult.resultData.getKey()
}
@ -333,6 +320,7 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable {
Log_OC.e(TAG, "Context lost after fetching private keys.")
return
}
if (privateKey == null) {
// first show info
try {
@ -355,11 +343,7 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable {
@SuppressLint("StaticFieldLeak")
inner class GenerateNewKeysAsyncTask(context: Context) : AsyncTask<Void?, Void?, String>() {
private val mWeakContext: WeakReference<Context>
init {
mWeakContext = WeakReference(context)
}
private val mWeakContext: WeakReference<Context> = WeakReference(context)
@Deprecated("Deprecated in Java")
override fun onPreExecute() {
@ -470,12 +454,16 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable {
private fun generateMnemonicString(withWhitespace: Boolean): String {
val stringBuilder = StringBuilder()
for (string in keyWords!!) {
stringBuilder.append(string)
if (withWhitespace) {
stringBuilder.append(' ')
keyWords?.let {
for (string in it) {
stringBuilder.append(string)
if (withWhitespace) {
stringBuilder.append(' ')
}
}
}
return stringBuilder.toString()
}
@ -487,13 +475,20 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable {
}
requireDialog().setTitle(R.string.end_to_end_encryption_passphrase_title)
binding.encryptionStatus.setText(R.string.end_to_end_encryption_keywords_description)
viewThemeUtils!!.material.colorTextInputLayout(binding.encryptionPasswordInputContainer)
viewThemeUtils.material.colorTextInputLayout(binding.encryptionPasswordInputContainer)
binding.encryptionPassphrase.text = generateMnemonicString(true)
binding.encryptionPassphrase.visibility = View.VISIBLE
positiveButton!!.setText(R.string.end_to_end_encryption_confirm_button)
positiveButton!!.visibility = View.VISIBLE
negativeButton!!.visibility = View.VISIBLE
viewThemeUtils!!.platform.colorTextButtons(positiveButton!!, negativeButton!!)
positiveButton?.setText(R.string.end_to_end_encryption_confirm_button)
positiveButton?.visibility = View.VISIBLE
negativeButton?.visibility = View.VISIBLE
positiveButton?.let { positiveButton ->
negativeButton?.let { negativeButton ->
viewThemeUtils.platform.colorTextButtons(positiveButton, negativeButton)
}
}
keyResult = KEY_GENERATE
}
@ -511,9 +506,8 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable {
positiveButton?.setText(R.string.end_to_end_encryption_dialog_close)
positiveButton?.visibility = View.VISIBLE
if (positiveButton != null) {
viewThemeUtils?.platform?.colorTextButtons(positiveButton!!)
positiveButton?.let {
viewThemeUtils.platform.colorTextButtons(it)
}
}
@ -545,12 +539,14 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable {
*/
@JvmStatic
fun newInstance(user: User?, position: Int): SetupEncryptionDialogFragment {
val fragment = SetupEncryptionDialogFragment()
val args = Bundle()
args.putParcelable(ARG_USER, user)
args.putInt(ARG_POSITION, position)
fragment.arguments = args
return fragment
val bundle = Bundle().apply {
putParcelable(ARG_USER, user)
putInt(ARG_POSITION, position)
}
return SetupEncryptionDialogFragment().apply {
arguments = bundle
}
}
}
}

View file

@ -660,7 +660,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
@Override
public void onHeaderClicked() {
if (!getAdapter().isMultiSelect() && mContainerActivity instanceof FileDisplayActivity) {
if (getAdapter() != null && !getAdapter().isMultiSelect() && mContainerActivity instanceof FileDisplayActivity) {
((FileDisplayActivity) mContainerActivity).startRichWorkspacePreview(getCurrentFile());
}
}
@ -1088,7 +1088,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
fileActivity.checkInternetConnection();
}
if (getCommonAdapter().isMultiSelect()) {
if (getCommonAdapter() != null && getCommonAdapter().isMultiSelect()) {
toggleItemToCheckedList(file);
} else {
if (file == null) {
@ -1096,9 +1096,8 @@ public class OCFileListFragment extends ExtendedListFragment implements
return;
}
int position = getCommonAdapter().getItemPosition(file);
if (file.isFolder()) {
if (getCommonAdapter() != null && file.isFolder()) {
int position = getCommonAdapter().getItemPosition(file);
folderOnItemClick(file, position);
} else if (mFileSelectable) {
Intent intent = new Intent();

View file

@ -368,7 +368,7 @@
<string name="file_list_empty_headline"> Keine Dateien vorhanden </string>
<string name="file_list_empty_headline_search">Keine Ergebnisse in diesem Ordner</string>
<string name="file_list_empty_headline_server_search">Keine Ergebnisse</string>
<string name="file_list_empty_local_search">Keine Datei und kein Ordner entsprechen Ihrer Suche</string>
<string name="file_list_empty_local_search">Keine Datei oder Ordner entsprechen Ihrer Suche</string>
<string name="file_list_empty_moving">Noch nichts vorhanden. Sie können einen Ordner hinzufügen.</string>
<string name="file_list_empty_on_device">Heruntergeladene Dateien und Ordner werden hier angezeigt werden.</string>
<string name="file_list_empty_recently_modified">Keine, innerhalb der letzten 7 Tage, geänderten Dateien gefunden</string>

View file

@ -368,6 +368,7 @@
<string name="file_list_empty_headline">Níl aon chomhaid anseo</string>
<string name="file_list_empty_headline_search">Níl aon torthaí san fhillteán seo</string>
<string name="file_list_empty_headline_server_search">Gan torthaí</string>
<string name="file_list_empty_local_search">Níl aon chomhad nó fillteán ag teacht le do chuardach</string>
<string name="file_list_empty_moving">Ní dhéanfaidh aon ní anseo. Is féidir leat fillteán a chur leis.</string>
<string name="file_list_empty_on_device">Taispeánfar comhaid agus fillteáin íosluchtaithe anseo.</string>
<string name="file_list_empty_recently_modified">Níor aimsíodh aon chomhad a athraíodh le 7 lá anuas</string>

View file

@ -368,6 +368,7 @@
<string name="file_list_empty_headline">Aquí non hai ficheiros</string>
<string name="file_list_empty_headline_search">Non hai resultados neste cartafol</string>
<string name="file_list_empty_headline_server_search">Sen resultados</string>
<string name="file_list_empty_local_search">Non hai ningún ficheiro ou cartafol que coincida coa busca</string>
<string name="file_list_empty_moving">Aquí non hai nada. Pode engadir un cartafol.</string>
<string name="file_list_empty_on_device">Aquí amosaranse os ficheiros e cartafoles descargados</string>
<string name="file_list_empty_recently_modified">Non se atoparon ficheiros modificados nos últimos 7 días.</string>

View file

@ -368,6 +368,7 @@
<string name="file_list_empty_headline">Ingen filer her</string>
<string name="file_list_empty_headline_search">Ingen resultater i denne mappen</string>
<string name="file_list_empty_headline_server_search">Ingen resultater</string>
<string name="file_list_empty_local_search">Ingen fil eller mappe som samsvarer med søket ditt</string>
<string name="file_list_empty_moving">Ingenting her. Du kan legge til en mappe!</string>
<string name="file_list_empty_on_device">Nedlastede filer og mapper vil vises her.</string>
<string name="file_list_empty_recently_modified">Fant ingen filer endret de siste 7 dagene</string>

View file

@ -368,6 +368,7 @@
<string name="file_list_empty_headline">Burada herhangi bir dosya yok</string>
<string name="file_list_empty_headline_search">Bu klasörde herhangi bir sonuç yok</string>
<string name="file_list_empty_headline_server_search">Herhangi bir sonuç bulunamadı</string>
<string name="file_list_empty_local_search">Aramanıza uygun bir dosya ya da klasör bulunamadı</string>
<string name="file_list_empty_moving">Burada bir şey yok. Bir klasör ekleyebilirsiniz!</string>
<string name="file_list_empty_on_device">İndirilmiş dosya ve klasörler burada görüntülenir.</string>
<string name="file_list_empty_recently_modified">Son 7 gün içinde düzenlenmiş bir dosya bulunamadı</string>

Binary file not shown.

View file

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME