diff --git a/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java b/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java index f285b2abb6..e6d297e76c 100644 --- a/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java +++ b/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java @@ -17,6 +17,7 @@ import android.Manifest; import android.accounts.Account; import android.accounts.AccountManager; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -33,29 +34,42 @@ import android.os.IBinder; import android.preference.PreferenceManager; import android.text.TextUtils; import android.util.AndroidRuntimeException; +import android.util.DisplayMetrics; +import android.view.Gravity; import android.view.KeyEvent; import android.view.View; +import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.webkit.CookieManager; import android.webkit.CookieSyncManager; import android.webkit.WebResourceRequest; import android.webkit.WebResourceResponse; import android.webkit.WebView; +import android.widget.Button; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; import android.widget.Toast; import com.blikoon.qrcodescanner.QrCodeActivity; +import com.google.android.material.button.MaterialButton; import com.google.android.material.snackbar.Snackbar; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.nextcloud.android.common.ui.color.ColorUtil; import com.nextcloud.android.common.ui.theme.utils.ColorRole; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.device.DeviceInfo; import com.nextcloud.client.di.Injectable; +import com.nextcloud.client.network.ClientFactory; import com.nextcloud.client.onboarding.FirstRunActivity; import com.nextcloud.client.onboarding.OnboardingService; import com.nextcloud.client.preferences.AppPreferences; +import com.nextcloud.common.PlainClient; +import com.nextcloud.operations.PostMethod; import com.nextcloud.utils.extensions.BundleExtensionsKt; import com.owncloud.android.MainApp; import com.owncloud.android.R; @@ -100,6 +114,8 @@ import com.owncloud.android.utils.WebViewUtil; import com.owncloud.android.utils.theme.CapabilityUtils; import com.owncloud.android.utils.theme.ViewThemeUtils; +import org.json.JSONObject; + import java.io.InputStream; import java.net.URLDecoder; import java.util.HashMap; @@ -107,9 +123,13 @@ import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import javax.inject.Inject; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -125,6 +145,8 @@ import de.cotech.hw.fido.ui.FidoDialogOptions; import de.cotech.hw.fido2.WebViewWebauthnBridge; import de.cotech.hw.fido2.ui.WebauthnDialogOptions; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import okhttp3.FormBody; +import okhttp3.RequestBody; import static com.owncloud.android.utils.PermissionUtil.PERMISSIONS_CAMERA; @@ -162,7 +184,17 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity private static final String KEY_USERNAME = "USERNAME"; private static final String KEY_PASSWORD = "PASSWORD"; private static final String KEY_ASYNC_TASK_IN_PROGRESS = "AUTH_IN_PROGRESS"; - public static final String WEB_LOGIN = "/index.php/login/flow"; + + /** + * Login Flow v1 + */ + // public static final String WEB_LOGIN = "/index.php/login/flow"; + + /** + * Login Flow v2 + */ + public static final String WEB_LOGIN = "/index.php/login/v2"; + public static final String PROTOCOL_SUFFIX = "://"; public static final String LOGIN_URL_DATA_KEY_VALUE_SEPARATOR = ":"; public static final String HTTPS_PROTOCOL = "https://"; @@ -171,7 +203,6 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity public static final int NO_ICON = 0; public static final String EMPTY_STRING = ""; - private static final int REQUEST_CODE_QR_SCAN = 101; public static final int REQUEST_CODE_FIRST_RUN = 102; /// parameters from EXTRAs in starter Intent @@ -218,6 +249,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity @Inject PassCodeManager passCodeManager; @Inject ViewThemeUtils.Factory viewThemeUtilsFactory; @Inject ColorUtil colorUtil; + @Inject ClientFactory clientFactory; + + private String token; private boolean onlyAdd = false; @SuppressLint("ResourceAsColor") @ColorInt @@ -242,7 +276,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity viewThemeUtils = viewThemeUtilsFactory.withPrimaryAsBackground(); viewThemeUtils.platform.themeStatusBar(this, ColorRole.PRIMARY); - WebViewUtil webViewUtil = new WebViewUtil(this); + // WebViewUtil webViewUtil = new WebViewUtil(this); Uri data = getIntent().getData(); boolean directLogin = data != null && data.toString().startsWith(getString(R.string.login_data_own_scheme)); @@ -298,7 +332,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity if (webViewLoginMethod) { accountSetupWebviewBinding = AccountSetupWebviewBinding.inflate(getLayoutInflater()); setContentView(accountSetupWebviewBinding.getRoot()); - initWebViewLogin(webloginUrl, false); + anonymouslyPostLoginRequest(webloginUrl); + // initWebViewLogin(webloginUrl, false); } else { accountSetupBinding = AccountSetupBinding.inflate(getLayoutInflater()); setContentView(accountSetupBinding.getRoot()); @@ -314,7 +349,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity initServerPreFragment(savedInstanceState); - webViewUtil.checkWebViewVersion(); + // webViewUtil.checkWebViewVersion(); } private void deleteCookies() { @@ -326,11 +361,57 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity } } + private String baseUrl; + + /** + * This function facilitates the login process by anonymously posting a login request to a specified URL. + * After posting the request, it retrieves the login URL for completing the login flow. + * The login flow version used is v2. + * + * @param url The URL where the login request is to be anonymously posted. + * This URL should handle the login request and return the login URL. + * It's typically the entry point for the login process. + * Example: "https://example.com/index.php/login/v2" + */ + private void anonymouslyPostLoginRequest(String url) { + baseUrl = url; + + Thread thread = new Thread(() -> { + PostMethod post = new PostMethod(baseUrl, false, new FormBody.Builder().build()); + + PlainClient client = clientFactory.createPlainClient(); + post.execute(client); + String response = post.getResponseBodyAsString(); + JsonObject jsonObject = JsonParser.parseString(response).getAsJsonObject(); + String login = jsonObject.get("login").getAsString(); + if (login == null) { + login = getResources().getString(R.string.webview_login_url); + } + + String loginUrl = login; + runOnUiThread(() -> { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(loginUrl)); + loginFlowResultLauncher.launch(intent); + }); + + token = jsonObject.getAsJsonObject("poll").get("token").getAsString(); + }); + + thread.start(); + } + + private final ActivityResultLauncher loginFlowResultLauncher = registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), result -> poolLogin(clientFactory.createPlainClient())); + private static String getWebLoginUserAgent() { return Build.MANUFACTURER.substring(0, 1).toUpperCase(Locale.getDefault()) + Build.MANUFACTURER.substring(1).toLowerCase(Locale.getDefault()) + " " + Build.MODEL + " (Android)"; } + /** + * @Deprecated This function is deprecated. Please use the {@link #anonymouslyPostLoginRequest(String)} method instead, which utilizes the improved login flow v2. + */ + @Deprecated @SuppressFBWarnings("ANDROID_WEB_VIEW_JAVASCRIPT") @SuppressLint("SetJavaScriptEnabled") private void initWebViewLogin(String baseURL, boolean useGenericUserAgent) { @@ -680,7 +761,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity if (intent.getBooleanExtra(EXTRA_USE_PROVIDER_AS_WEBLOGIN, false)) { accountSetupWebviewBinding = AccountSetupWebviewBinding.inflate(getLayoutInflater()); setContentView(accountSetupWebviewBinding.getRoot()); - initWebViewLogin(getString(R.string.provider_registration_server), true); + anonymouslyPostLoginRequest(getString(R.string.provider_registration_server)); + // initWebViewLogin(getString(R.string.provider_registration_server), true); } } @@ -915,7 +997,16 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity accountSetupWebviewBinding = AccountSetupWebviewBinding.inflate(getLayoutInflater()); setContentView(accountSetupWebviewBinding.getRoot()); - initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, false); + + if (!isLoginProcessCompleted) { + if (!isRedirectedToTheDefaultBrowser) { + anonymouslyPostLoginRequest(mServerInfo.mBaseUrl + WEB_LOGIN); + isRedirectedToTheDefaultBrowser = true; + } else { + initLoginInfoView(); + } + // initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, false); + } } } else { updateServerStatusIconAndText(result); @@ -928,6 +1019,19 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity } } + // region LoginInfoView + private void initLoginInfoView() { + LinearLayout loginFlowLayout = accountSetupWebviewBinding.loginFlowV2.getRoot(); + MaterialButton cancelButton = accountSetupWebviewBinding.loginFlowV2.cancelButton; + loginFlowLayout.setVisibility(View.VISIBLE); + + cancelButton.setOnClickListener(v -> { + loginFlowExecutorService.shutdown(); + recreate(); + }); + } + // endregion + /** * Chooses the right icon and text to show to the user for the received operation result. * @@ -1169,7 +1273,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity } else { // authorization fail due to client side - probably wrong credentials if (accountSetupWebviewBinding != null) { - initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, false); + anonymouslyPostLoginRequest(mServerInfo.mBaseUrl + WEB_LOGIN); + // initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, false); DisplayUtils.showSnackMessage(this, accountSetupWebviewBinding.loginWebview, R.string.auth_access_failed, result.getLogMessage()); @@ -1340,9 +1445,37 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity private void startQRScanner() { Intent intent = new Intent(this, QrCodeActivity.class); - startActivityForResult(intent, REQUEST_CODE_QR_SCAN); + qrScanResultLauncher.launch(intent); } + private final ActivityResultLauncher qrScanResultLauncher = registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + result -> { + if (result.getResultCode() == Activity.RESULT_OK) { + Intent data = result.getData(); + + if (data == null) { + return; + } + + String resultData = data.getStringExtra("com.blikoon.qrcodescanner.got_qr_scan_relult"); + + if (resultData == null || !resultData.startsWith(getString(R.string.login_data_own_scheme))) { + mServerStatusIcon = R.drawable.ic_alert; + mServerStatusText = "QR Code could not be read!"; + showServerStatus(); + return; + } + + if (!getResources().getBoolean(R.bool.multiaccount_support) && + accountManager.getAccounts().length == 1) { + Toast.makeText(this, R.string.no_mutliple_accounts_allowed, Toast.LENGTH_LONG).show(); + } else { + parseAndLoginFromWebView(resultData); + } + } + }); + @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @@ -1362,7 +1495,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity * server. */ private void showServerStatus() { - if (accountSetupBinding == null) return; + if (accountSetupBinding == null) { + return; + } if (mServerStatusIcon == NO_ICON && EMPTY_STRING.equals(mServerStatusText)) { accountSetupBinding.serverStatusText.setVisibility(View.INVISIBLE); @@ -1486,32 +1621,69 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity } } - @Override - protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (requestCode == REQUEST_CODE_QR_SCAN) { - if (data == null) { - return; - } + private final ScheduledExecutorService loginFlowExecutorService = Executors.newSingleThreadScheduledExecutor(); + private boolean isLoginProcessCompleted = false; + private boolean isRedirectedToTheDefaultBrowser = false; - String result = data.getStringExtra("com.blikoon.qrcodescanner.got_qr_scan_relult"); - - if (result == null || !result.startsWith(getString(R.string.login_data_own_scheme))) { - mServerStatusIcon = R.drawable.ic_alert; - mServerStatusText = "QR Code could not be read!"; - showServerStatus(); - return; + private void poolLogin(PlainClient client) { + loginFlowExecutorService.scheduleAtFixedRate(() -> { + if (!isLoginProcessCompleted) { + performLoginFlowV2(client); } + }, 0, 30, TimeUnit.SECONDS); + } - if (!getResources().getBoolean(R.bool.multiaccount_support) && - accountManager.getAccounts().length == 1) { - Toast.makeText(this, R.string.no_mutliple_accounts_allowed, Toast.LENGTH_LONG).show(); - } else { - parseAndLoginFromWebView(result); - } + private void performLoginFlowV2(PlainClient client) { + String postRequestUrl = baseUrl + "/poll"; + + RequestBody requestBody = new FormBody.Builder() + .add("token", token) + .build(); + + PostMethod post = new PostMethod(postRequestUrl, false, requestBody); + int status = post.execute(client); + String response = post.getResponseBodyAsString(); + + Log_OC.d(TAG, "performLoginFlowV2 status: " + status); + Log_OC.d(TAG, "performLoginFlowV2 response: " + response); + + if (!response.isEmpty()) { + runOnUiThread(() -> completeLoginFlow(response, status)); } } + private void completeLoginFlow(String response, int status) { + try { + JSONObject jsonObject = new JSONObject(response); + + String server = jsonObject.getString("server"); + String loginName = jsonObject.getString("loginName"); + String appPassword = jsonObject.getString("appPassword"); + + LoginUrlInfo loginUrlInfo = new LoginUrlInfo(); + loginUrlInfo.serverAddress = server; + loginUrlInfo.username = loginName; + loginUrlInfo.password = appPassword; + + isLoginProcessCompleted = (status == 200 && !server.isEmpty() && !loginName.isEmpty() && !appPassword.isEmpty()); + + if (accountSetupBinding != null) { + accountSetupBinding.hostUrlInput.setText(""); + } + mServerInfo.mBaseUrl = AuthenticatorUrlUtils.INSTANCE.normalizeUrlSuffix(loginUrlInfo.serverAddress); + webViewUser = loginUrlInfo.username; + webViewPassword = loginUrlInfo.password; + } catch (Exception e) { + Log_OC.d(TAG, "Error caught at completeLoginFlow: " + e); + mServerStatusIcon = R.drawable.ic_alert; + mServerStatusText = getString(R.string.qr_could_not_be_read); + showServerStatus(); + } + + checkOcServer(); + loginFlowExecutorService.shutdown(); + } + /** * Called from SslValidatorDialog when a new server certificate was correctly saved. */ diff --git a/app/src/main/res/layout/account_setup_webview.xml b/app/src/main/res/layout/account_setup_webview.xml index e0b843650a..8be7ab1d1f 100644 --- a/app/src/main/res/layout/account_setup_webview.xml +++ b/app/src/main/res/layout/account_setup_webview.xml @@ -7,21 +7,31 @@ ~ SPDX-License-Identifier: AGPL-3.0-or-later --> + android:layout_width="match_parent" + android:layout_height="match_parent" + xmlns:tools="http://schemas.android.com/tools" + android:orientation="vertical"> + + + + + android:indeterminate="true" /> diff --git a/app/src/main/res/layout/login_flow_info_layout_v2.xml b/app/src/main/res/layout/login_flow_info_layout_v2.xml new file mode 100644 index 0000000000..1e96175246 --- /dev/null +++ b/app/src/main/res/layout/login_flow_info_layout_v2.xml @@ -0,0 +1,41 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 2fbc92625e..0032cd0c84 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -13,6 +13,7 @@ Kirim/Bagi Tampilan kotak Tampilan lis + Pulihkan kontak dan kalender Folder baru Pindah atau Salin Buka dengan @@ -32,10 +33,30 @@ Tambahkan ke %1$s Pengaturan Tambahan Izinkan pembagian ulang + Menampilkan satu gawit dari dasbor Cari dalam %s Semua + Tulis beberapa teks + Apakah Anda yakin ingin menghapus tugas ini? + Hapus Tugas + Gagal + Daftar Tugas sedang dimuat, mohon tunggu + Tidak ada tugas yang tersedia. Pilih jenis tugas untuk membuat tugas baru. + Tidak ada tugas yang tersedia untuk jenis tugas %s, Anda dapat membuat tugas baru dari pojok kanan bawah. + Sedang Berlangsung + Dijadwalkan Selesai + Terjadi kesalahan saat membuat tugas + Tugas berhasil dibuat + Terjadi kesalahan saat menghapus tugas + Tugas berhasil dihapus + Tidak dapat memperoleh daftar tugas, mohon periksa koneksi internet Anda. + Hapus Tugas + Tidak dapat memperoleh jenis tugas, mohon periksa koneksi internet Anda. + Asisten Tidak diketahui + Input + Output Akun terkait tidak ditemukan! Akses gagal: %1$s Akun ini belum ditambahkan ke perangkat ini @@ -74,9 +95,11 @@ Pasang folder kostum. Non-aktifkan pemeriksaan mode hemat daya Sembunyikan folder + Menyiapkan unggah otomatis Avatar Jauh Pengaturan Pencadangan + Pencadangan kontak dan kalender Tutup Nonaktifkan Optimisasi baterai perangkat Anda mungkin sedang aktif. @@ -87,11 +110,13 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Kalender Terjadi permasalahan memuat sertifikat. Perubahan versi dev + Periksa kembali nanti atau muat ulang. Kotak centang Pilih folder lokal… Pilih folder remot… Mohon pilih templat dan masukkan nama file. Pilih file mana yang ditahan! + Pilih gawit Gagal membersihkan notifikasi Kosongkan status pesan Kosongkan status pesan setelah @@ -127,6 +152,7 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Ini termasuk semua fitur yang akan datang. Bug/galat bisa terjadi, bila terjadi harap laporkan ke kami. forum Bantu yang lain di + Tinjau, ubah, dan tulis kode, lihat %1$suntuk detailnya. Berkontribusi Aktif aplikasi Terjemahkan @@ -146,6 +172,7 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Apakah anda yakin ingin menghapus %1$s beserta isinya? Apa anda yakin ingin menghapus item yang terpilih beserta isinya? Lokal saja + Dialog penyelesaian konflik tidak dapat dibuat File konflik %1$s File lokal Jika Anda memilih kedua versi, nama dari berkas lokal akan ditambahi angka. @@ -218,18 +245,23 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Mengunduh… %1$s terunduh Unggahan + Berkas tertentu dibatalkan saat pengunduhan oleh pengguna + Terjadi kesalahan saat mengunduh berkas Belum diunduh + Terjadi kesalahan tidak terduga saat mengunduh berkas Tutup jendela samping Komunitas Gambar latar belakang tajuk laci Aktivitas Semua berkas + Asisten Disukai Media Folder kelompok Beranda Pemberitahuan Dalam perangkat + Berkas pribadi Baru diubah Dibagikan Berkas terhapus @@ -241,6 +273,7 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Unggah otomatis. E2E belum dipersiapkan Tidak bisa dilakukan tanpa koneksi internet + Asisten Lainnya Catatan Talk @@ -270,6 +303,7 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Terjadi kesalahan dalam memilih tanggal Error saat mengomentari file Galat saat membuat berkas dari templat + Kesalahan menampilkan aksi berkas Error saat mengubah status kunci file Laporan Galat saat menerima file @@ -278,6 +312,7 @@ Otomatis unggah hanya bekerja dengan baik apabila Anda mengeluarkan aplikasi ini Galat saat mengaktifkan kamera Galat memulai pemindaian dokumen Akun + Dibuat Nama pekerjaan Kemajuan Kondisi diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index 30c83eff3f..c3d2d087df 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -37,9 +37,12 @@ ダッシュボードから一つのウィジェットを表示 %s の中を検索 すべて + テキストを入力 失敗 完了 不明 + 入力 + 出力 関連付けられたアカウントが見つかりません! アクセスに失敗しました: %1$s このアカウントはまだこのデバイスに追加されていません diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 78f1f38430..23c92bd053 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -13,6 +13,7 @@ Wyślij/Udostępnij Widok siatki Widok listy + Przywróć kontakty i kalendarz Nowy katalog Przenieś lub kopiuj Otwórz za pomocą @@ -36,10 +37,27 @@ Pokazuje jeden widżet z pulpitu nawigacyjnego Szukaj w %s Wszystkie + Wpisz jakiś tekst + Czy na pewno chcesz usunąć to zadanie? + Usuń zadanie Nie powiodło się + Trwa wczytywanie listy zadań. Proszę czekać + Brak dostępnych zadań. Wybierz typ zadania, aby utworzyć nowe zadanie. + Brak dostępnych zadań dla typu zadania %s. Możesz utworzyć nowe zadanie w prawym dolnym rogu. + W trakcie Zaplanowane Zakończone + Wystąpił błąd podczas tworzenia zadania + Zadanie pomyślnie utworzone + Wystąpił błąd podczas usuwania zadania + Zadanie pomyślnie usunięte + Nie można pobrać listy zadań. Sprawdź swoje połączenie internetowe. + Usuń zadanie + Nie można pobrać typów zadań. Sprawdź swoje połączenie internetowe. + Asystent Nieznany + Wejście + Wyjście Nie znaleziono powiązanego konta! Dostęp nieudany: %1$s Konto nie jest jeszcze dodane na tym urządzeniu @@ -78,9 +96,11 @@ Ustaw własny katalog Wyłącz kontrolę oszczędzania energii Ukryj katalog + Przygotowanie do automatycznego przesyłania Awatar Bezczynny Ustawienia kopii zapasowej + Kopia zapasowa kontaktów i kalendarza Zamknij Wyłącz Twoje urządzenie może mieć włączoną optymalizację baterii. Automatyczne wysyłanie działa poprawnie tylko wtedy, gdy wykluczysz z niej tę aplikację. @@ -152,6 +172,7 @@ Czy na pewno chcesz usunąć %1$s wraz z zawartością? Czy na pewno chcesz usunąć wybrane pozycje i ich zawartość? Tylko lokalnie + Nie można utworzyć okna dialogowego rozwiązywania konfliktów Plik powodujący konflikt %1$s Plik lokalny Jeśli wybierzesz obie wersje, to do nazwy pliku lokalnego zostanie dodany numer. @@ -221,22 +242,28 @@ Pobieranie nieudane, zaloguj się ponownie Pobieranie nie powiodło się Ten plik nie jest już dostępny na serwerze + %1$d%%%2$s %1$d%% Pobieranie %2$s Pobieranie… %1$s pobrano Pobrano + Niektóre pliki zostały anulowane podczas pobierania przez użytkownika + Wystąpił błąd podczas pobierania plików Jeszcze nie pobrane + Wystąpił nieoczekiwany błąd podczas pobierania plików Zamknij pasek boczny Społeczność Tło nagłówka menu rozwijanego Aktywność Wszystkie pliki + Asystent Ulubione Media Katalog grupowy Start Powiadomienia Na urządzeniu + Pliki osobiste Ostatnio modyfikowane Udostępnione Usunięte pliki @@ -248,6 +275,7 @@ Automatyczne wysyłanie E2E jeszcze nie skonfigurowane Niemożliwe bez połączenia z internetem + Asystent Więcej Notatki Talk @@ -840,6 +868,8 @@ Zmiana udostępniania nie powiodła się Wyczyść nieudane wysyłanie Ponów nieudane wysyłanie + Wstrzymaj wszystkie przesyłania + Wznów wszystkie przesyłania Nie można utworzyć pliku lokalnego Wyślij plik z… Wyślij z innej aplikacji @@ -851,6 +881,7 @@ Fragment tekstu plik(.txt) Wprowadź nazwę i typ pliku do wysłania Wyślij pliki + Wszystkie przesyłania zostały wstrzymane Przycisk wysyłania elementu Usuń Brak wysłanych plików @@ -859,6 +890,7 @@ Pamięć lokalna pełna Nie można skopiować pliku do lokalnej pamięci Nie udało się zablokować katalogu + Przesyłanie zostało anulowane przez użytkownika Szyfrowanie jest możliwe tylko przy >= Android 5.0 Brak wystarczającego miejsca, aby skopiować wybrane pliki do katalogu %1$s. Czy chcesz je tam przenieść? Limit przekroczony @@ -876,6 +908,7 @@ Plik nie znaleziony. Czy jesteś pewien, że ten plik istnieje lub poprzedni konflikt został rozwiązany? Nie mogliśmy odnaleźć pliku na serwerze. Inny użytkownik mógł usunąć plik Nazwa katalogu + Spróbuj ponownie przesłać pliki lokalne, które nie powiodły się Wybierz katalog do wysłania Nie udało się wysłać %1$s Wysyłanie nie powiodło się, zaloguj się ponownie @@ -888,6 +921,7 @@ Zachowaj plik w katalogu źródłowym Skasuj plik z katalogu źródłowego do wysłania do tego katalogu + %1$d%%%2$s %1$d%% Wysyłanie %2$s Wysyłanie… Wysłano %1$s @@ -913,6 +947,7 @@ Pobieram wersję serwera… Aplikacja została zatrzymana Ukończono + Ten sam plik znaleziony zdalnie, pomijanie przesyłania Nieznany błąd Wykryto wirusa. Wysyłanie nie może być ukończone! Oczekiwanie na wyjście z trybu oszczędzania energii diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index 2d9d9fcf03..39c4efe7cb 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -56,6 +56,8 @@ Nie je možné načítať typy úloh, skontrolujte svoje internetové pripojenie. Asistent Neznámy + Vstup + Výstup Priradený účet sa nenašiel Prístup zamietnutý: %1$s Účet zatiaľ v zariadení neexistuje @@ -170,6 +172,7 @@ Naozaj chcete odstrániť %1$s a jeho obsah? Naozaj chcete odstrániť vybraté položky a ich obsah? Iba lokálne + Dialógové okno riešenia konfliktov nemožno vytvoriť Konfliktný súbor %1$s Lokálny súbor Ak vyberiete obe verzie, miestny súbor bude mať k svojmu názvu pridané číslo. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a7ebed20a6..40f66f988f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -334,6 +334,9 @@ The account is not added on this device yet Access failed: %1$s + Cancel Login + Please complete login process in your browser + Add to favorites Remove from favourites Set as encrypted diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 997f29df99..3e57417726 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -5316,22 +5316,6 @@ - - - - - - - - - - - - - - - - @@ -5340,62 +5324,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -