diff --git a/.drone.yml b/.drone.yml index 3fb8dcefca0a..ed29ca7b2090 100644 --- a/.drone.yml +++ b/.drone.yml @@ -32,7 +32,7 @@ services: image: ghcr.io/nextcloud/continuous-integration-shallow-server:latest # also change in updateScreenshots.sh environment: EVAL: true - SERVER_VERSION: 'stable25' + SERVER_VERSION: 'stable27' commands: - BRANCH="$SERVER_VERSION" /usr/local/bin/initnc.sh - echo 127.0.0.1 server >> /etc/hosts @@ -171,4 +171,6 @@ name: GIT_TOKEN data: XIoa9IYq+xQ+N5iln8dlpWv0jV6ROr7HuE24ioUr4uQ8m8SjyH0yognWYLYLqnbTKrFWlFZiEMQTH/sZiWjRFvV1iL0= --- kind: signature -hmac: aec1cabcb7b4f98f1be1d5b7a052a629ce3193e19a3692dd52ada48b6e72a1c9 +hmac: b78dcc477ff74ccbd7877df011090783847f8b5215a994be6597408bd735b524 + +... diff --git a/app/src/main/java/com/nextcloud/client/onboarding/WhatsNewActivity.java b/app/src/main/java/com/nextcloud/client/onboarding/WhatsNewActivity.java deleted file mode 100644 index dd43cb5f2fb6..000000000000 --- a/app/src/main/java/com/nextcloud/client/onboarding/WhatsNewActivity.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Bartosz Przybylski - * @author Chris Narkiewicz - * Copyright (C) 2015 Bartosz Przybylski - * Copyright (C) 2015 ownCloud Inc. - * Copyright (C) 2016 Nextcloud. - * Copyright (C) 2019 Chris Narkiewicz - * - * 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.nextcloud.client.onboarding; - -import android.os.Bundle; -import android.view.View; -import android.widget.Button; -import android.widget.ImageButton; -import android.widget.TextView; - -import com.google.android.material.button.MaterialButton; -import com.nextcloud.android.common.ui.theme.utils.ColorRole; -import com.nextcloud.client.appinfo.AppInfo; -import com.nextcloud.client.di.Injectable; -import com.nextcloud.client.preferences.AppPreferences; -import com.owncloud.android.BuildConfig; -import com.owncloud.android.R; -import com.owncloud.android.databinding.WhatsNewActivityBinding; -import com.owncloud.android.ui.adapter.FeaturesViewAdapter; -import com.owncloud.android.ui.adapter.FeaturesWebViewAdapter; -import com.owncloud.android.ui.whatsnew.ProgressIndicator; -import com.owncloud.android.utils.theme.ViewThemeUtils; - -import javax.inject.Inject; - -import androidx.fragment.app.FragmentActivity; -import androidx.viewpager.widget.ViewPager; - -/** - * Activity displaying new features after an update. - */ -public class WhatsNewActivity extends FragmentActivity implements ViewPager.OnPageChangeListener, Injectable { - - @Inject AppPreferences preferences; - @Inject AppInfo appInfo; - @Inject OnboardingService onboarding; - @Inject ViewThemeUtils.Factory viewThemeUtilsFactory; - private ViewThemeUtils viewThemeUtils; - - private WhatsNewActivityBinding binding; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - binding = WhatsNewActivityBinding.inflate(getLayoutInflater()); - setContentView(binding.getRoot()); - - viewThemeUtils = viewThemeUtilsFactory.withPrimaryAsBackground(); - viewThemeUtils.platform.themeStatusBar(this, ColorRole.PRIMARY); - - - String[] urls = getResources().getStringArray(R.array.whatsnew_urls); - - boolean showWebView = urls.length > 0; - - if (showWebView) { - FeaturesWebViewAdapter featuresWebViewAdapter = new FeaturesWebViewAdapter(getSupportFragmentManager(), - urls); - binding.progressIndicator.setNumberOfSteps(featuresWebViewAdapter.getCount()); - binding.contentPanel.setAdapter(featuresWebViewAdapter); - } else { - FeaturesViewAdapter featuresViewAdapter = new FeaturesViewAdapter(getSupportFragmentManager(), - onboarding.getWhatsNew()); - binding.progressIndicator.setNumberOfSteps(featuresViewAdapter.getCount()); - binding.contentPanel.setAdapter(featuresViewAdapter); - } - - binding.contentPanel.addOnPageChangeListener(this); - - viewThemeUtils.platform.colorImageView(binding.forward, ColorRole.ON_PRIMARY); - - binding.forward.setOnClickListener(view -> { - if (binding.progressIndicator.hasNextStep()) { - binding.contentPanel.setCurrentItem(binding.contentPanel.getCurrentItem() + 1, true); - binding.progressIndicator.animateToStep(binding.contentPanel.getCurrentItem() + 1); - } else { - onFinish(); - finish(); - } - updateNextButtonIfNeeded(); - }); - - binding.forward.setBackground(null); - - viewThemeUtils.platform.colorTextView(binding.skip, ColorRole.ON_PRIMARY); - binding.skip.setOnClickListener(view -> { - onFinish(); - finish(); - }); - - viewThemeUtils.platform.colorTextView(binding.welcomeText, ColorRole.ON_PRIMARY); - - if (showWebView) { - binding.welcomeText.setText(R.string.app_name); - } else { - binding.welcomeText.setText(String.format(getString(R.string.whats_new_title), appInfo.getVersionName())); - } - - updateNextButtonIfNeeded(); - } - - @Override - public void onBackPressed() { - onFinish(); - super.onBackPressed(); - } - - private void updateNextButtonIfNeeded() { - if (!binding.progressIndicator.hasNextStep()) { - binding.forward.setImageResource(R.drawable.ic_ok); - binding.skip.setVisibility(View.INVISIBLE); - } else { - binding.forward.setImageResource(R.drawable.arrow_right); - binding.skip.setVisibility(View.VISIBLE); - } - } - - private void onFinish() { - preferences.setLastSeenVersionCode(BuildConfig.VERSION_CODE); - } - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - // unused but to be implemented due to abstract parent - } - - @Override - public void onPageSelected(int position) { - binding.progressIndicator.animateToStep(position + 1); - updateNextButtonIfNeeded(); - } - - @Override - public void onPageScrollStateChanged(int state) { - // unused but to be implemented due to abstract parent - } -} - diff --git a/app/src/main/java/com/nextcloud/client/onboarding/WhatsNewActivity.kt b/app/src/main/java/com/nextcloud/client/onboarding/WhatsNewActivity.kt new file mode 100644 index 000000000000..9a25653147dd --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/onboarding/WhatsNewActivity.kt @@ -0,0 +1,169 @@ +/* + * Nextcloud Android client application + * + * @author Bartosz Przybylski + * @author Chris Narkiewicz + * Copyright (C) 2015 Bartosz Przybylski + * Copyright (C) 2015 ownCloud Inc. + * Copyright (C) 2016 Nextcloud. + * Copyright (C) 2019 Chris Narkiewicz + * + * 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.nextcloud.client.onboarding + +import android.os.Bundle +import android.view.View +import androidx.activity.OnBackPressedCallback +import androidx.fragment.app.FragmentActivity +import androidx.viewpager.widget.ViewPager +import com.nextcloud.android.common.ui.theme.utils.ColorRole +import com.nextcloud.client.appinfo.AppInfo +import com.nextcloud.client.di.Injectable +import com.nextcloud.client.preferences.AppPreferences +import com.owncloud.android.BuildConfig +import com.owncloud.android.R +import com.owncloud.android.databinding.WhatsNewActivityBinding +import com.owncloud.android.ui.adapter.FeaturesViewAdapter +import com.owncloud.android.ui.adapter.FeaturesWebViewAdapter +import com.owncloud.android.utils.theme.ViewThemeUtils +import javax.inject.Inject + +/** + * Activity displaying new features after an update. + */ +class WhatsNewActivity : FragmentActivity(), ViewPager.OnPageChangeListener, Injectable { + + @JvmField + @Inject + var preferences: AppPreferences? = null + + @JvmField + @Inject + var appInfo: AppInfo? = null + + @JvmField + @Inject + var onboarding: OnboardingService? = null + + @JvmField + @Inject + var viewThemeUtilsFactory: ViewThemeUtils.Factory? = null + + private var viewThemeUtils: ViewThemeUtils? = null + + private lateinit var binding: WhatsNewActivityBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + binding = WhatsNewActivityBinding.inflate(layoutInflater) + setContentView(binding.root) + + viewThemeUtils = viewThemeUtilsFactory?.withPrimaryAsBackground() + viewThemeUtils?.platform?.themeStatusBar(this, ColorRole.PRIMARY) + + val urls = resources.getStringArray(R.array.whatsnew_urls) + val showWebView = urls.isNotEmpty() + + setupFeatureViewAdapter(showWebView, urls) + binding.contentPanel.addOnPageChangeListener(this) + setupForwardImageButton() + setupSkipImageButton() + setupWelcomeText(showWebView) + updateNextButtonIfNeeded() + handleOnBackPressed() + } + + @Suppress("SpreadOperator") + private fun setupFeatureViewAdapter(showWebView: Boolean, urls: Array) { + val adapter = if (showWebView) { + FeaturesWebViewAdapter(supportFragmentManager, *urls) + } else { + onboarding?.let { + FeaturesViewAdapter(supportFragmentManager, *it.whatsNew) + } + } + + adapter?.let { + binding.progressIndicator.setNumberOfSteps(it.count) + binding.contentPanel.adapter = it + } + } + + private fun setupForwardImageButton() { + viewThemeUtils?.platform?.colorImageView(binding.forward, ColorRole.ON_PRIMARY) + binding.forward.setOnClickListener { + if (binding.progressIndicator.hasNextStep()) { + binding.contentPanel.setCurrentItem(binding.contentPanel.currentItem + 1, true) + binding.progressIndicator.animateToStep(binding.contentPanel.currentItem + 1) + } else { + onFinish() + finish() + } + updateNextButtonIfNeeded() + } + binding.forward.background = null + } + + private fun setupSkipImageButton() { + viewThemeUtils?.platform?.colorTextView(binding.skip, ColorRole.ON_PRIMARY) + binding.skip.setOnClickListener { + onFinish() + finish() + } + } + + private fun setupWelcomeText(showWebView: Boolean) { + viewThemeUtils?.platform?.colorTextView(binding.welcomeText, ColorRole.ON_PRIMARY) + binding.welcomeText.text = if (showWebView) { + getString(R.string.app_name) + } else { + String.format(getString(R.string.whats_new_title), appInfo?.versionName) + } + } + + private fun handleOnBackPressed() { + onBackPressedDispatcher.addCallback( + this, + object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + onFinish() + onBackPressedDispatcher.onBackPressed() + } + } + ) + } + + private fun updateNextButtonIfNeeded() { + val hasNextStep = binding.progressIndicator.hasNextStep() + binding.forward.setImageResource(if (hasNextStep) R.drawable.arrow_right else R.drawable.ic_ok) + binding.skip.visibility = if (hasNextStep) View.VISIBLE else View.INVISIBLE + } + + private fun onFinish() { + preferences?.lastSeenVersionCode = BuildConfig.VERSION_CODE + } + + override fun onPageSelected(position: Int) { + binding.progressIndicator.animateToStep(position + 1) + updateNextButtonIfNeeded() + } + + @Suppress("EmptyFunctionBlock") + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {} + + @Suppress("EmptyFunctionBlock") + override fun onPageScrollStateChanged(state: Int) {} +} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java index 3fe049ef391e..279b8cd9a098 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java @@ -30,7 +30,6 @@ import android.text.TextWatcher; import android.view.KeyEvent; import android.view.View; -import android.view.View.OnClickListener; import android.view.Window; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; @@ -42,6 +41,7 @@ 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.utils.theme.ViewThemeUtils; import java.util.Arrays; @@ -74,7 +74,7 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { @Inject PassCodeManager passCodeManager; @Inject ViewThemeUtils viewThemeUtils; private PasscodelockBinding binding; - private final EditText[] passCodeEditTexts = new EditText[4]; + private final PassCodeEditText[] passCodeEditTexts = new PassCodeEditText[4]; private String[] passCodeDigits = {"", "", "", ""}; private boolean confirmingPassCode; private boolean changed = true; // to control that only one blocks jump @@ -91,7 +91,6 @@ protected void onCreate(Bundle savedInstanceState) { binding = PasscodelockBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); - viewThemeUtils.platform.colorTextButtons(binding.cancel); passCodeEditTexts[0] = binding.txt0; @@ -105,7 +104,6 @@ protected void onCreate(Bundle savedInstanceState) { passCodeEditTexts[0].requestFocus(); - Window window = getWindow(); if (window != null) { window.setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); @@ -125,7 +123,7 @@ protected void onCreate(Bundle savedInstanceState) { passCodeDigits = savedInstanceState.getStringArray(PassCodeActivity.KEY_PASSCODE_DIGITS); } if (confirmingPassCode) { - // the app was in the passcodeconfirmation + // the app was in the passcode confirmation requestPassCodeConfirmation(); } else { // pass code preference has just been activated in SettingsActivity; @@ -158,12 +156,7 @@ protected void onCreate(Bundle savedInstanceState) { protected void setCancelButtonEnabled(boolean enabled) { if (enabled) { binding.cancel.setVisibility(View.VISIBLE); - binding.cancel.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); + binding.cancel.setOnClickListener(v -> finish()); } else { binding.cancel.setVisibility(View.INVISIBLE); binding.cancel.setOnClickListener(null); @@ -179,20 +172,18 @@ public PasscodelockBinding getBinding() { * Binds the appropriate listeners to the input boxes receiving each digit of the pass code. */ protected void setTextListeners() { - passCodeEditTexts[0].addTextChangedListener(new PassCodeDigitTextWatcher(0, false)); - passCodeEditTexts[1].addTextChangedListener(new PassCodeDigitTextWatcher(1, false)); - passCodeEditTexts[2].addTextChangedListener(new PassCodeDigitTextWatcher(2, false)); - passCodeEditTexts[3].addTextChangedListener(new PassCodeDigitTextWatcher(3, true)); - - setOnKeyListener(1); - setOnKeyListener(2); - setOnKeyListener(3); + for (int i = 0; i < passCodeEditTexts.length; i++) { + final PassCodeEditText editText = passCodeEditTexts[i]; + boolean isLast = (i == 3); - passCodeEditTexts[1].setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(1)); - - passCodeEditTexts[2].setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(2)); + editText.addTextChangedListener(new PassCodeDigitTextWatcher(i, isLast)); + if (i > 0) { + setOnKeyListener(i); + } - passCodeEditTexts[3].setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(3)); + int finalIndex = i; + editText.setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(finalIndex)); + } } private void onPassCodeEditTextFocusChange(final int passCodeIndex) { @@ -265,9 +256,7 @@ private void processFullPassCode() { savePassCodeAndExit(); } else { - showErrorAndRestart( - R.string.pass_code_mismatch, R.string.pass_code_configure_your_pass_code, View.VISIBLE - ); + showErrorAndRestart(R.string.pass_code_mismatch, R.string.pass_code_configure_your_pass_code, View.VISIBLE); } } } @@ -279,13 +268,11 @@ private void hideSoftKeyboard() { (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow( focusedView.getWindowToken(), - 0 - ); + 0); } } - private void showErrorAndRestart(int errorMessage, int headerMessage, - int explanationVisibility) { + private void showErrorAndRestart(int errorMessage, int headerMessage, int explanationVisibility) { Arrays.fill(passCodeDigits, null); Snackbar.make(findViewById(android.R.id.content), getString(errorMessage), Snackbar.LENGTH_LONG).show(); binding.header.setText(headerMessage); // TODO check if really needed @@ -312,8 +299,6 @@ protected void requestPassCodeConfirmation() { * @return 'True' if entered pass code equals to the saved one. */ protected boolean checkPassCode() { - - String[] savedPassCodeDigits = preferences.getPassCode(); boolean result = true; @@ -331,11 +316,13 @@ protected boolean checkPassCode() { protected boolean confirmPassCode() { confirmingPassCode = false; - boolean result = true; - for (int i = 0; i < passCodeEditTexts.length && result; i++) { - result = passCodeEditTexts[i].getText().toString().equals(passCodeDigits[i]); + for (int i = 0; i < passCodeEditTexts.length; i++) { + Editable passCodeText = passCodeEditTexts[i].getText(); + if (passCodeText == null || !passCodeText.toString().equals(passCodeDigits[i])) { + return false; + } } - return result; + return true; } /** @@ -401,7 +388,7 @@ private void showDelay() { @Override public void run() { try { - Thread.sleep(delay * 1000); + Thread.sleep(delay * 1000L); runOnUiThread(() -> { binding.explanation.setVisibility(View.INVISIBLE); @@ -418,7 +405,6 @@ public void run() { } } - @Override public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); @@ -440,6 +426,7 @@ private class PassCodeDigitTextWatcher implements TextWatcher { PassCodeDigitTextWatcher(int index, boolean lastOne) { mIndex = index; mLastOne = lastOne; + if (mIndex < 0) { throw new IllegalArgumentException( "Invalid index in " + PassCodeDigitTextWatcher.class.getSimpleName() + @@ -463,12 +450,17 @@ private int next() { public void afterTextChanged(Editable s) { if (s.length() > 0) { if (!confirmingPassCode) { - passCodeDigits[mIndex] = passCodeEditTexts[mIndex].getText().toString(); + Editable passCodeText = passCodeEditTexts[mIndex].getText(); + + if (passCodeText != null) { + passCodeDigits[mIndex] = passCodeText.toString(); + } } - passCodeEditTexts[next()].requestFocus(); if (mLastOne) { processFullPassCode(); + } else { + passCodeEditTexts[next()].requestFocus(); } } else { @@ -477,13 +469,10 @@ public void afterTextChanged(Editable s) { } @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // nothing to do - } + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - // nothing to do - } + public void onTextChanged(CharSequence s, int start, int before, int count) {} } + } diff --git a/app/src/main/java/com/owncloud/android/ui/components/PassCodeEditText.kt b/app/src/main/java/com/owncloud/android/ui/components/PassCodeEditText.kt new file mode 100644 index 000000000000..6e1668429a53 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/components/PassCodeEditText.kt @@ -0,0 +1,52 @@ +/* + * 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.ui.components + +import android.annotation.SuppressLint +import android.content.Context +import android.util.AttributeSet +import android.view.KeyEvent +import android.view.MotionEvent +import android.view.View +import androidx.appcompat.widget.AppCompatEditText + +@SuppressLint("ClickableViewAccessibility") +class PassCodeEditText(context: Context, attrs: AttributeSet?) : AppCompatEditText(context, attrs) { + + init { + disableFocusChangeViaTap() + } + + private fun disableFocusChangeViaTap() { + setSelectAllOnFocus(false) + setTextIsSelectable(false) + setOnTouchListener { _: View?, _: MotionEvent? -> true } + } + + override fun onKeyPreIme(keyCode: Int, event: KeyEvent): Boolean { + val isBackButtonPressed = (event.keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) + if (isBackButtonPressed) { + // Override default behaviour and prevent dismissing the keyboard + return true + } + return super.dispatchKeyEvent(event) + } +} diff --git a/app/src/main/res/layout/passcodelock.xml b/app/src/main/res/layout/passcodelock.xml index 94374e44e8a9..81004efa37e3 100644 --- a/app/src/main/res/layout/passcodelock.xml +++ b/app/src/main/res/layout/passcodelock.xml @@ -69,41 +69,26 @@ android:layout_height="wrap_content" android:gravity="center_horizontal"> - + - - - - - - diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 02ce3fe7894c..5c024cac6f24 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -18,6 +18,7 @@ Kopiér Ny mappe Flyt + Flyt eller kopier Åbn med Søg Detaljer @@ -204,6 +205,7 @@ Checkede ikke for duplikater. Denne fordøgelsesalgorytme er ikke tilgængelig på din telefon. Login via direkte link mislykkedes! + Login med %1$s til %2$s Deaktiver Afvis Fjern notifikation @@ -251,8 +253,11 @@ E2E er endnu ikke konfigureret Ikke muligt uden internetforbindelse Mere + Noter Snak + Flere Nextcloud apps Nextcloud noter + Nextcloud Snak Angiv som krypteret Indstil kryptering Dekrypterer... @@ -320,6 +325,7 @@ Slet Fejl ved indlæsning af aktiviteter for fil Fejl ved indlæsning af detaljer + Downloader \u0020 Fil Behold Upload indhold eller synkronisér med dine enheder. @@ -421,6 +427,13 @@ Roter mod uret Roter med uret Kunne ikke redigere billede. + Fil detaljer + Billede optagelsestilstande + ƒ/%s + ISO %s + %s MP + %s mm + %s s i mappen %1$s Send også eksisterende filer Upload kun under opladning @@ -448,6 +461,7 @@ Låst af app\'en %1$s %1$s Android-app - logge Der er ingen app tilgængelig til at sende log filer. Venligst installér en email klient. + Logget på som %1$s Log ind Linket til dit %1$s web interface når du åbner den i browseren. Slet logs @@ -500,6 +514,7 @@ Ingen kalender eksisterer Ingen app tilgængelig til at håndtere mailadresser Ingen elementer + Ingen App tilgængelig til håndtering af Kort kun en konto tilladt Ingen App tilgængelig til håndtering af PDF Der er ingen tilgængelig app til at sende de valgte filer @@ -586,7 +601,9 @@ Aftryk Oprindelig fil vil blive... Oprindelig fil vil blive... + Gem i undermapper baseret på dato Benyt undermapper + Undermappe muligheder Tilføj end-to-end kryptering for denne klient Licens App adgangskode @@ -602,6 +619,8 @@ Enheds legitimationsoplysninger er sat op Foreslå til en ven Fjern kryptering lokalt Opsæt end-to-end kryptering + Vis app skifter + Nextcloud app anbefalinger i navigationspanelet Vis skjulte filer Hent kildetekst Lagringsmappe for data @@ -776,6 +795,8 @@ Enheds legitimationsoplysninger er sat op Intern streaming ikke mulig Hent venligst media i stedet, eller brug ekstern app. Streng tilstand: Ingen http forbindelser tilladt! + År/Måned/Dag + År/Måned År \"%1$s\" er blevet delt med dig %1$s delte \"%2$s\" med dig @@ -927,7 +948,9 @@ Enheds legitimationsoplysninger er sat op Vent et øjeblik... Undersøger lagrede certificeringer Kopierer fil fra privat lager. + Opdater Android System WebView appen for at logge på Opdatér + Opdater Android System WebView Hvad nyt billede Spring over Nyt i %1$s diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index fb7a61128072..d1794b910693 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -18,6 +18,7 @@ Copiar Nueva carpeta Mover + Mover o Copiar Abrir con Buscar Detalles diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index f3555a7f4fc8..0c0202b9fcaf 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -327,7 +327,7 @@ Attention, la suppression est irréversible. Supprimer Erreur lors de la récupération de l’activité du fichier Impossible de charger les détails - Téléchargement \u0020 + Téléchargement de \u0020 Fichier Conserver Déposez du contenu ou synchronisez vos appareils. diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 83a632ebc77c..5117e01527ce 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -18,6 +18,7 @@ Copiar Novo cartafol Mover + Mover ou copiar Abrir con Buscar Detalles @@ -324,6 +325,7 @@ Eliminar Produciuse un erro ao recuperar actividades para o ficheiro Produciuse un fallo ao cargar os detalles + Descargando \u0020 Ficheiro Conservar Envíe algún contido ou sincronice cos seus dispositivos. @@ -945,6 +947,9 @@ Agarde un chisco… Verificando as credenciais almacenadas Copiando o ficheiro dende o almacenamento privado + Actualice a aplicación WebView do sistema Android para acceder + Actualizar + Actualizar WebView do sistema Android Imaxe de Que hai de novo Omitir Novo en %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 3e40a180b51c..cea72ad5bab1 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -14,10 +14,11 @@ 送信/共有 グリッド表示 リスト表示 - 連絡先とカレンダーを復元する + 連絡先とカレンダーを復元 コピー 新しいフォルダー 移動 + 移動またはコピー 次で開く 検索 詳細 @@ -30,12 +31,12 @@ 送信 リンク送信… アクティビティ - 別のリンクを作成 + 別のリンクを追加 新規公開共有リンクを追加 新しいセキュアなファイルドロップを追加 %1$s に追加 高度な設定 - 再共有を許可 + 再共有を許可する ダッシュボードから一つのウィジェットを表示 %s の中を検索 関連付けられたアカウントが見つかりません! @@ -45,7 +46,7 @@ 入力されたユーザーはこのアカウントのユーザーと一致しません 認識できないサーバーのバージョンです 接続が確立しました - サーバーが正しいユーザーIDを返していない場合、管理者に連絡してください。 + サーバーが正しいユーザーIDを返していません。管理者に連絡してください。 サーバーアドレス https://… サーバーアドレスの書式が違います サーバーが見つかりません @@ -550,6 +551,7 @@ ファイルをダウンロードとアップロードする追加の権限が必要です。 画像を設定するアプリが見つかりませんでした ホームスクリーンにピン留めする + %1$sを開く 389 KB placeholder.txt 12:23:45 @@ -591,6 +593,7 @@ 元のファイルになります… 日付を基にしたサブフォルダーに保存 サブフォルダーを利用 + サブフォルダーのオプション このクライアントに End-to-End 暗号化を追加 ライセンス アプリパスコード @@ -603,6 +606,7 @@ アカウント管理 友達にすすめる end-to-end 暗号化を設定 + アップスイッチャーを表示 隠しファイルを表示 ソースコードを入手 データ保存フォルダー @@ -925,7 +929,9 @@ 少々お待ちください… 保存された資格情報をチェック プライベートストレージからファイルをコピー中 + ログインするにはAndroidシステムのWebViewを更新してください 更新 + AndroidシステムのWebViewをアップデート 新しいイメージとは スキップ %1$sの新機能 diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 7cfd4257ef78..aa2cf593479a 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -205,6 +205,7 @@ Weigeren Handel melding af Niet storen + PDF-bestand Klaar Niet opruimen Kan geen lokaal bestand aanmaken @@ -240,6 +241,7 @@ Meer Notities Talk + Meer Nextcloud Apps Nextcloud Notities Instellen als versleuteld Instellen versleuteling @@ -398,6 +400,7 @@ Host je eigen server Pictogram van dashboard widget Pictogram van widget vermelding + Bestandsdetails in map %1$s Upload ook bestaande bestanden Alleen uploaden bij opladen @@ -739,6 +742,8 @@ Intern streamen niet mogelijk Download media in plaats van gebruik externe app. Strict modus: geen HTTP-verbinding toegestaan! + Jaar/Maand/Dag + Jaar/Maand Jaar \"%1$s\" is met je gedeeld %1$s deelde \"%2$s\" met jou diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index 377e6a28fa7a..054339f319b3 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -335,7 +335,7 @@ %1$s potrebuje na nahrávanie súborov oprávnenie na správu súborov. Môžete si vybrať úplný prístup ku všetkým súborom alebo prístup iba na čítanie k fotografiám a videám. Kontrolujem umiestnenie… Čistenie… - Aktualizujem adresár dátového úložiska + Aktualizujem priečinok dátového úložiska Dátový priečinok uz existuje. Vyberte jednu z možností: Nextcloud priečinok už existuje Nedostatok priestoru @@ -349,7 +349,7 @@ Pripravujem migráciu… Obnovujem konfiguráciu účtu… Ukladám konfiguráciu účtov… - Ste si istý že chcete zmeniť adresár úložiska na %1$s?\n\nVšetky údaje musia byť znova stiahnuté. + Ste si istý že chcete zmeniť priečinok úložiska na %1$s?\n\nVšetky údaje musia byť znova stiahnuté. Zdrojový priečinok nie je čitateľný! Aktualizujem zoznam… Použi @@ -402,7 +402,7 @@ Ikona pre prázdny zoznam Ikona widgetu na hlavnom paneli Ikona položky ovládacieho panelu - v adresári %1$s + v priečinku %1$s Nahrať aj existujúce súbory Nahrať iba počas nabíjania /InstantUpload @@ -581,8 +581,8 @@ Nastaviť šifrovanie end-to-end Zobraziť skryté súbory Získajte zdrojový kód - Adresár dátového úložiska - Spravovať adresár pre automatické nahrávanie + Priečinok dátového úložiska + Spravovať priečinky pre automatické nahrávanie Lokálny priečinok Vzdialený priečinok Motív vzhľadu @@ -658,7 +658,7 @@ %1$s (skupina) Sprístupniť interný odkaz Interný odkaz na zdieľanie funguje iba pre používateľov s prístupom k tomuto súboru - Interný odkaz na zdieľanie funguje iba pre používateľov s prístupom k tomuto adresáru + Interný odkaz na zdieľanie funguje iba pre používateľov s prístupom k tomuto priečinku na %1$s Sprístupniť odkaz Musíte vložiť heslo @@ -763,7 +763,7 @@ Synchronizácia neúspešná Synchronizácia neúspešná, je potrebné sa znovu prihlásiť Obsah súboru je zosynchronizovaný - Synchronizáciu adresára %1$s sa nedarí dokončiť + Synchronizáciu priečinka %1$s sa nedarí dokončiť Od verzie 1.3.16 sú súbory nahrané z tohoto zariadenia kopírované do lokálneho priečinka %1$s, aby sa zabránilo strate dát pri synchronizácii jedného súboru s viacerými účtami.\n\nVšetky súbory nahraté predchádzajúcimi verziami aplikácie boli z tohoto dôvodu prekopírované do priečinka %2$s. Bohužiaľ sa objavila chyba zabraňujúca dokončeniu tejto operácie v priebehu synchronizácie účtu. Buď môžete súbor(y) ponechať ako sú a odobrať odkaz z priečinka %3$s, alebo presunúť súbor(y) do priečinka %1$s a zachovať odkaz na %4$s.\n\nNižšie je uvedený lokálny súbor(y) a vzdialený súbor(y) v %5$s, s ktorým je prepojený. Niektoré lokálne súbory boli zabudnuté Načítavam najnovšiu verziu súboru. @@ -906,8 +906,8 @@ Widgety sú dostupné iba na %1$s 25 alebo vyšší Nie je k dispozícií Odoslať email - Adresár pre úložisko dát neexistuje! - Môže to byť spôsobené obnovením zálohy na inom zariadení. Návrat na predvolené hodnoty. Skontrolujte adresár a upravte adresár pre ukladanie údajov. + Priečinok pre úložisko dát neexistuje! + Môže to byť spôsobené obnovením zálohy na inom zariadení. Návrat na predvolené hodnoty. Skontrolujte priečinok a upravte adresár pre ukladanie údajov. Nie je možné synchronizovať %1$d súbor (konflikty: %2$d) Nie je možné synchronizovať %1$d súbory (konflikty: %2$d) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 400b7bb7d326..c8383be19632 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -324,9 +324,11 @@