From ac47b68119a72fd02e23935111d0ef0cae71a972 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 15 Oct 2021 15:11:57 +0200 Subject: [PATCH 01/28] Bump to versin 1.6.1-SNAPSHOT [ci skip] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5347a92e..7bdd7034 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ allprojects { ext { androidApplicationId = 'org.cryptomator' androidVersionCode = getVersionCode() - androidVersionName = '1.6.0' + androidVersionName = '1.6.1-SNAPSHOT' } repositories { mavenCentral() From 4b26755df3ad6ce7f596315dac525a231aa85cc8 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 15 Oct 2021 15:12:24 +0200 Subject: [PATCH 02/28] Update fastlane dependencies [ci skip] --- Gemfile.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 6ce84c81..790d4ca0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -10,13 +10,13 @@ GEM artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.2.0) - aws-partitions (1.509.0) + aws-partitions (1.516.0) aws-sdk-core (3.121.1) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.239.0) aws-sigv4 (~> 1.1) jmespath (~> 1.0) - aws-sdk-kms (1.48.0) + aws-sdk-kms (1.49.0) aws-sdk-core (~> 3, >= 3.120.0) aws-sigv4 (~> 1.1) aws-sdk-s3 (1.103.0) @@ -40,7 +40,7 @@ GEM dotenv (2.7.6) ed25519 (1.2.4) emoji_regex (3.2.3) - excon (0.86.0) + excon (0.87.0) faraday (1.8.0) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -63,10 +63,10 @@ GEM faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) faraday-rack (1.0.0) - faraday_middleware (1.1.0) + faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.2.5) - fastlane (2.195.0) + fastlane (2.196.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -111,7 +111,7 @@ GEM mime-types (~> 3.3) fastlane-plugin-get_version_name (0.2.2) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.11.0) + google-apis-androidpublisher_v3 (0.12.0) google-apis-core (>= 0.4, < 2.a) google-apis-core (0.4.1) addressable (~> 2.5, >= 2.5.1) @@ -154,14 +154,14 @@ GEM domain_name (~> 0.5) httpclient (2.8.3) jmespath (1.4.0) - json (2.5.1) - jwt (2.2.3) + json (2.6.0) + jwt (2.3.0) memoist (0.16.2) mime-types (3.3.1) mime-types-data (~> 3.2015) mime-types-data (3.2021.0704) mini_magick (4.11.0) - mini_mime (1.1.1) + mini_mime (1.1.2) multi_json (1.15.0) multipart-post (2.0.0) nanaimo (0.3.0) From 2efc38454b03e6b79e8e078efa5f4460c1f9e15e Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Tue, 5 Oct 2021 01:06:23 +0200 Subject: [PATCH 03/28] Upload instantly when auto upload enabled and vault unlocked (#181) --- .../org/cryptomator/presentation/CryptomatorApp.kt | 11 +++++++++++ .../presentation/service/AutoUploadService.java | 2 +- .../presentation/service/PhotoContentJob.kt | 9 +++++++++ presentation/src/main/res/values/strings.xml | 2 ++ presentation/src/main/res/xml/preferences.xml | 6 ++++++ .../cryptomator/util/SharedPreferencesHandler.kt | 13 +++++++++---- 6 files changed, 38 insertions(+), 5 deletions(-) diff --git a/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt b/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt index 630b07bc..120870fc 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt @@ -120,6 +120,17 @@ class CryptomatorApp : MultiDexApplication(), HasComponent }, BIND_AUTO_CREATE) } + fun startAutoUpload() { + val sharedPreferencesHandler = SharedPreferencesHandler(applicationContext()) + if(sharedPreferencesHandler.usePhotoUpload()) { + val vault = applicationComponent.vaultRepository().load(sharedPreferencesHandler.photoUploadVault()) + if(vault.isUnlocked) { + val cloud = applicationComponent.cloudRepository().decryptedViewOf(vault) + applicationContext().startService(AutoUploadService.startAutoUploadIntent(applicationContext(), cloud)) + } + } + } + private fun setupLogging() { setupLoggingFramework() setup() diff --git a/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadService.java b/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadService.java index a56c9050..452934c7 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadService.java +++ b/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadService.java @@ -212,7 +212,7 @@ public class AutoUploadService extends Service { public void onCreate() { super.onCreate(); Timber.tag("AutoUploadService").d("created"); - notification = new AutoUploadNotification(this, 5); + notification = new AutoUploadNotification(this, 0); } @Override diff --git a/presentation/src/main/java/org/cryptomator/presentation/service/PhotoContentJob.kt b/presentation/src/main/java/org/cryptomator/presentation/service/PhotoContentJob.kt index f70972bb..d9d1e929 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/service/PhotoContentJob.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/service/PhotoContentJob.kt @@ -13,6 +13,7 @@ import android.net.Uri import android.os.Handler import android.provider.MediaStore import org.cryptomator.domain.exception.FatalBackendException +import org.cryptomator.presentation.CryptomatorApp import org.cryptomator.presentation.R import org.cryptomator.presentation.util.FileUtil import org.cryptomator.presentation.util.ResourceHelper @@ -38,6 +39,8 @@ class PhotoContentJob : JobService() { runningParams = params + var filesCaptured = false + params.triggeredContentAuthorities?.let { if (params.triggeredContentUris != null) { val ids = getIds(params) @@ -49,6 +52,8 @@ class PhotoContentJob : JobService() { fileUtil.addImageToAutoUploads(dir) Timber.tag("PhotoContentJob").i("Added file to UploadList") Timber.tag("PhotoContentJob").d(String.format("Added file to UploadList %s", dir)) + + filesCaptured = true } catch (e: FatalBackendException) { Timber.tag("PhotoContentJob").e(e, "Failed to add image to auto upload list") } catch (e: SecurityException) { @@ -65,6 +70,10 @@ class PhotoContentJob : JobService() { } } ?: Timber.tag("PhotoContentJob").w("No photos content") + if(filesCaptured && SharedPreferencesHandler(applicationContext).usePhotoUploadInstant()) { + (application as CryptomatorApp).startAutoUpload() + } + handler.post(worker) return false } diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 6fb9018d..8a87b0b0 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -244,6 +244,8 @@ Choose vault for upload Activate Capture images in the background and once the selected vault is unlocked, start upload + Upload instant + Upload directly if the vault is unlocked Upload only using WIFI Upload videos diff --git a/presentation/src/main/res/xml/preferences.xml b/presentation/src/main/res/xml/preferences.xml index c1c98343..be07dbd7 100644 --- a/presentation/src/main/res/xml/preferences.xml +++ b/presentation/src/main/res/xml/preferences.xml @@ -105,6 +105,12 @@ android:summary="@string/screen_settings_section_auto_photo_upload_toggle_summary" android:title="@string/screen_settings_section_auto_photo_upload_toggle" /> + + Date: Thu, 21 Oct 2021 11:19:56 +0200 Subject: [PATCH 04/28] Update gradle to 7.0.3 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ec1cc947..573d4167 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:7.0.2' + classpath 'com.android.tools.build:gradle:7.0.3' classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0' classpath 'com.vanniktech:gradle-android-junit-jacoco-plugin:0.16.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" From 3b641a22d84a1ff129a5d53c7107eb5c74c6d958 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Thu, 21 Oct 2021 11:20:44 +0200 Subject: [PATCH 05/28] Remove unused Context variable from the WebDavClient --- .../data/cloud/webdav/network/ConnectionHandlerFactory.kt | 2 +- .../cloud/webdav/network/ConnectionHandlerHandlerImpl.kt | 5 ++--- .../cryptomator/data/cloud/webdav/network/WebDavClient.kt | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/data/src/main/java/org/cryptomator/data/cloud/webdav/network/ConnectionHandlerFactory.kt b/data/src/main/java/org/cryptomator/data/cloud/webdav/network/ConnectionHandlerFactory.kt index fcf758ca..a0761a89 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/webdav/network/ConnectionHandlerFactory.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/webdav/network/ConnectionHandlerFactory.kt @@ -9,6 +9,6 @@ import javax.inject.Singleton class ConnectionHandlerFactory @Inject constructor(private val context: Context) { fun createConnectionHandler(cloud: WebDavCloud): ConnectionHandlerHandlerImpl { - return ConnectionHandlerHandlerImpl(WebDavCompatibleHttpClient(cloud, context), context) + return ConnectionHandlerHandlerImpl(WebDavCompatibleHttpClient(cloud, context)) } } diff --git a/data/src/main/java/org/cryptomator/data/cloud/webdav/network/ConnectionHandlerHandlerImpl.kt b/data/src/main/java/org/cryptomator/data/cloud/webdav/network/ConnectionHandlerHandlerImpl.kt index b99392f3..49bd6309 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/webdav/network/ConnectionHandlerHandlerImpl.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/webdav/network/ConnectionHandlerHandlerImpl.kt @@ -1,6 +1,5 @@ package org.cryptomator.data.cloud.webdav.network -import android.content.Context import org.cryptomator.data.cloud.webdav.WebDavFolder import org.cryptomator.data.cloud.webdav.WebDavNode import org.cryptomator.domain.CloudFolder @@ -8,9 +7,9 @@ import org.cryptomator.domain.exception.BackendException import java.io.InputStream import javax.inject.Inject -class ConnectionHandlerHandlerImpl @Inject internal constructor(httpClient: WebDavCompatibleHttpClient, context: Context) { +class ConnectionHandlerHandlerImpl @Inject internal constructor(httpClient: WebDavCompatibleHttpClient) { - private val webDavClient: WebDavClient = WebDavClient(context, httpClient) + private val webDavClient: WebDavClient = WebDavClient(httpClient) @Throws(BackendException::class) fun dirList(url: String, listedFolder: WebDavFolder): List { diff --git a/data/src/main/java/org/cryptomator/data/cloud/webdav/network/WebDavClient.kt b/data/src/main/java/org/cryptomator/data/cloud/webdav/network/WebDavClient.kt index 2f55d0e0..7bb6bd4c 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/webdav/network/WebDavClient.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/webdav/network/WebDavClient.kt @@ -1,6 +1,5 @@ package org.cryptomator.data.cloud.webdav.network -import android.content.Context import org.cryptomator.data.cloud.webdav.WebDavFolder import org.cryptomator.data.cloud.webdav.WebDavNode import org.cryptomator.domain.CloudFolder @@ -26,7 +25,7 @@ import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response -internal class WebDavClient(private val context: Context, private val httpClient: WebDavCompatibleHttpClient) { +internal class WebDavClient(private val httpClient: WebDavCompatibleHttpClient) { private val ASCENDING_BY_DEPTH = Comparator { o1: PropfindEntryData, o2: PropfindEntryData -> o1.getDepth() - o2.getDepth() } From 91d1a65ba721c02aef25ddf001003c7003a7c955 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 22 Oct 2021 15:52:02 +0200 Subject: [PATCH 06/28] Update target API to 30 (Android 11) Write external storage got removed due to forced scoped storage. Local storage cloud is now only available using the storage access framework implementation. Migration still needs to be implemented as well as how to recover when the authentications fails in the LocalStorageAuthStrategy. Fixes #251 --- buildsystem/dependencies.gradle | 4 +- .../data/cloud/crypto/CryptoCloud.java | 5 - .../DocumentIdCache.kt | 2 +- .../LocalStorageAccessFile.kt | 2 +- .../LocalStorageAccessFolder.kt | 2 +- ...StorageAccessFrameworkContentRepository.kt | 2 +- .../LocalStorageAccessFrameworkImpl.kt | 27 +-- .../LocalStorageAccessFrameworkNodeFactory.kt | 2 +- .../LocalStorageAccessNode.kt | 2 +- .../LocalStorageContentRepositoryFactory.java | 36 ++-- .../RootLocalStorageAccessFolder.kt | 2 +- .../data/cloud/local/file/LocalFile.kt | 11 -- .../data/cloud/local/file/LocalFolder.kt | 14 -- .../data/cloud/local/file/LocalNode.kt | 9 - .../file/LocalStorageContentRepository.kt | 111 ------------ .../data/cloud/local/file/LocalStorageImpl.kt | 165 ------------------ .../local/file/LocalStorageNodeFactory.kt | 36 ---- .../data/cloud/local/file/RootLocalFolder.kt | 15 -- .../data/repository/CloudRepositoryImpl.java | 3 - .../data/util/NetworkConnectionCheck.kt | 2 +- .../main/java/org/cryptomator/domain/Cloud.kt | 1 - .../org/cryptomator/domain/DropboxCloud.java | 5 - .../cryptomator/domain/GoogleDriveCloud.java | 5 - .../cryptomator/domain/LocalStorageCloud.java | 6 - .../org/cryptomator/domain/OnedriveCloud.java | 5 - .../java/org/cryptomator/domain/PCloud.java | 6 - .../java/org/cryptomator/domain/S3Cloud.java | 6 - .../org/cryptomator/domain/WebDavCloud.java | 5 - .../presenter/AuthenticateCloudPresenter.kt | 24 +-- presentation/src/main/AndroidManifest.xml | 2 - .../presentation/BootAwareReceiver.kt | 3 +- .../presenter/BrowseFilesPresenter.kt | 38 ---- .../presenter/CloudConnectionListPresenter.kt | 5 - .../presenter/ImagePreviewPresenter.kt | 77 ++------ .../presenter/SettingsPresenter.kt | 7 +- .../presenter/UnlockVaultPresenter.kt | 5 +- .../ui/activity/ImagePreviewActivity.kt | 2 +- .../bottomsheet/FolderSettingsBottomSheet.kt | 11 +- .../ui/dialog/UpdateAppAvailableDialog.kt | 7 +- .../fragment/CloudConnectionListFragment.kt | 11 -- .../ui/fragment/SettingsFragment.kt | 5 +- .../fragment_browse_cloud_connections.xml | 28 --- presentation/src/main/res/values/strings.xml | 1 - .../presenter/AuthenticateCloudPresenter.kt | 24 +-- .../util/crypto/CryptoOperationsImpl.java | 10 +- 45 files changed, 90 insertions(+), 661 deletions(-) rename data/src/main/java/org/cryptomator/data/cloud/local/{storageaccessframework => }/DocumentIdCache.kt (93%) rename data/src/main/java/org/cryptomator/data/cloud/local/{storageaccessframework => }/LocalStorageAccessFile.kt (93%) rename data/src/main/java/org/cryptomator/data/cloud/local/{storageaccessframework => }/LocalStorageAccessFolder.kt (94%) rename data/src/main/java/org/cryptomator/data/cloud/local/{storageaccessframework => }/LocalStorageAccessFrameworkContentRepository.kt (98%) rename data/src/main/java/org/cryptomator/data/cloud/local/{storageaccessframework => }/LocalStorageAccessFrameworkImpl.kt (94%) rename data/src/main/java/org/cryptomator/data/cloud/local/{storageaccessframework => }/LocalStorageAccessFrameworkNodeFactory.kt (98%) rename data/src/main/java/org/cryptomator/data/cloud/local/{storageaccessframework => }/LocalStorageAccessNode.kt (76%) rename data/src/main/java/org/cryptomator/data/cloud/local/{storageaccessframework => }/RootLocalStorageAccessFolder.kt (92%) delete mode 100644 data/src/main/java/org/cryptomator/data/cloud/local/file/LocalFile.kt delete mode 100644 data/src/main/java/org/cryptomator/data/cloud/local/file/LocalFolder.kt delete mode 100644 data/src/main/java/org/cryptomator/data/cloud/local/file/LocalNode.kt delete mode 100644 data/src/main/java/org/cryptomator/data/cloud/local/file/LocalStorageContentRepository.kt delete mode 100644 data/src/main/java/org/cryptomator/data/cloud/local/file/LocalStorageImpl.kt delete mode 100644 data/src/main/java/org/cryptomator/data/cloud/local/file/LocalStorageNodeFactory.kt delete mode 100644 data/src/main/java/org/cryptomator/data/cloud/local/file/RootLocalFolder.kt diff --git a/buildsystem/dependencies.gradle b/buildsystem/dependencies.gradle index 4c853160..3d4338a5 100644 --- a/buildsystem/dependencies.gradle +++ b/buildsystem/dependencies.gradle @@ -8,8 +8,8 @@ allprojects { ext { androidBuildToolsVersion = "30.0.2" androidMinSdkVersion = 24 - androidTargetSdkVersion = 29 - androidCompileSdkVersion = 29 + androidTargetSdkVersion = 30 + androidCompileSdkVersion = 30 // android and java libs androidVersion = '4.1.1.4' diff --git a/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoCloud.java b/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoCloud.java index ca6dd52e..eeadb135 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoCloud.java +++ b/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoCloud.java @@ -31,11 +31,6 @@ public class CryptoCloud implements Cloud { return vault.equals(cloud.vault); } - @Override - public boolean predefined() { - return false; - } - @Override public boolean persistent() { return false; diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/DocumentIdCache.kt b/data/src/main/java/org/cryptomator/data/cloud/local/DocumentIdCache.kt similarity index 93% rename from data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/DocumentIdCache.kt rename to data/src/main/java/org/cryptomator/data/cloud/local/DocumentIdCache.kt index b4c9698d..db3abc87 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/DocumentIdCache.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/local/DocumentIdCache.kt @@ -1,4 +1,4 @@ -package org.cryptomator.data.cloud.local.storageaccessframework +package org.cryptomator.data.cloud.local import android.util.LruCache import org.cryptomator.domain.CloudFolder diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessFile.kt b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFile.kt similarity index 93% rename from data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessFile.kt rename to data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFile.kt index cffbb02c..c6bc7971 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessFile.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFile.kt @@ -1,4 +1,4 @@ -package org.cryptomator.data.cloud.local.storageaccessframework +package org.cryptomator.data.cloud.local import android.net.Uri import org.cryptomator.domain.Cloud diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessFolder.kt b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFolder.kt similarity index 94% rename from data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessFolder.kt rename to data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFolder.kt index af3d8027..d147d6b0 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessFolder.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFolder.kt @@ -1,4 +1,4 @@ -package org.cryptomator.data.cloud.local.storageaccessframework +package org.cryptomator.data.cloud.local import android.net.Uri import org.cryptomator.domain.Cloud diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessFrameworkContentRepository.kt b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFrameworkContentRepository.kt similarity index 98% rename from data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessFrameworkContentRepository.kt rename to data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFrameworkContentRepository.kt index 0f21ca53..76dc5456 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessFrameworkContentRepository.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFrameworkContentRepository.kt @@ -1,4 +1,4 @@ -package org.cryptomator.data.cloud.local.storageaccessframework +package org.cryptomator.data.cloud.local import android.content.Context import org.cryptomator.domain.LocalStorageCloud diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessFrameworkImpl.kt b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFrameworkImpl.kt similarity index 94% rename from data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessFrameworkImpl.kt rename to data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFrameworkImpl.kt index bf93abcd..904f8b15 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessFrameworkImpl.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFrameworkImpl.kt @@ -1,4 +1,4 @@ -package org.cryptomator.data.cloud.local.storageaccessframework +package org.cryptomator.data.cloud.local import android.content.ContentResolver import android.content.Context @@ -7,10 +7,10 @@ import android.net.Uri import android.os.Build import android.provider.DocumentsContract import androidx.documentfile.provider.DocumentFile -import org.cryptomator.data.cloud.local.storageaccessframework.LocalStorageAccessFrameworkNodeFactory.file -import org.cryptomator.data.cloud.local.storageaccessframework.LocalStorageAccessFrameworkNodeFactory.folder -import org.cryptomator.data.cloud.local.storageaccessframework.LocalStorageAccessFrameworkNodeFactory.from -import org.cryptomator.data.cloud.local.storageaccessframework.LocalStorageAccessFrameworkNodeFactory.getNodePath +import org.cryptomator.data.cloud.local.LocalStorageAccessFrameworkNodeFactory.file +import org.cryptomator.data.cloud.local.LocalStorageAccessFrameworkNodeFactory.folder +import org.cryptomator.data.cloud.local.LocalStorageAccessFrameworkNodeFactory.from +import org.cryptomator.data.cloud.local.LocalStorageAccessFrameworkNodeFactory.getNodePath import org.cryptomator.data.util.CopyStream import org.cryptomator.data.util.TransferredBytesAwareInputStream import org.cryptomator.data.util.TransferredBytesAwareOutputStream @@ -243,7 +243,8 @@ internal class LocalStorageAccessFrameworkImpl(context: Context, private val mim private fun rename(source: LocalStorageAccessNode, name: String): LocalStorageAccessNode { source.parent?.let { parent -> var newUri = try { - DocumentsContract.renameDocument(contentResolver(), source.uri, name) + requireNotNull(source.uri) + DocumentsContract.renameDocument(contentResolver(), source.uri!!, name) } catch (e: FileNotFoundException) { /* Bug in Android 9 see #460 TLDR; In this renameDocument-method, Android 9 throws a `FileNotFoundException` although the file exists and is also renamed. */ @@ -336,11 +337,13 @@ internal class LocalStorageAccessFrameworkImpl(context: Context, private val mim private fun createNewDocumentSupplier(file: LocalStorageAccessFile): Supplier { return Supplier { - val mimeType = if (mimeTypes.fromFilename(file.name) == null) MimeType.APPLICATION_OCTET_STREAM else mimeTypes.fromFilename(file.name) - try { - DocumentsContract.createDocument(contentResolver(), file.parent.uri, mimeType.toString(), file.name) // FIXME - } catch (e: FileNotFoundException) { - null + file.parent.uri?.let { + val mimeType = if (mimeTypes.fromFilename(file.name) == null) MimeType.APPLICATION_OCTET_STREAM else mimeTypes.fromFilename(file.name) + try { + DocumentsContract.createDocument(contentResolver(), it, mimeType.toString(), file.name) // FIXME + } catch (e: FileNotFoundException) { + null + } } } } @@ -372,7 +375,7 @@ internal class LocalStorageAccessFrameworkImpl(context: Context, private val mim fun delete(node: LocalStorageAccessNode) { requireNotNull(node.uri) try { - DocumentsContract.deleteDocument(contentResolver(), node.uri) + DocumentsContract.deleteDocument(contentResolver(), node.uri!!) } catch (e: FileNotFoundException) { throw NoSuchCloudFileException(node.name) } diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessFrameworkNodeFactory.kt b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFrameworkNodeFactory.kt similarity index 98% rename from data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessFrameworkNodeFactory.kt rename to data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFrameworkNodeFactory.kt index f352c4bb..d65b3761 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessFrameworkNodeFactory.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFrameworkNodeFactory.kt @@ -1,4 +1,4 @@ -package org.cryptomator.data.cloud.local.storageaccessframework +package org.cryptomator.data.cloud.local import android.database.Cursor import android.provider.DocumentsContract diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessNode.kt b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessNode.kt similarity index 76% rename from data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessNode.kt rename to data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessNode.kt index 12ffd6df..aa6fa800 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/LocalStorageAccessNode.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessNode.kt @@ -1,4 +1,4 @@ -package org.cryptomator.data.cloud.local.storageaccessframework +package org.cryptomator.data.cloud.local import android.net.Uri import org.cryptomator.domain.CloudNode diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageContentRepositoryFactory.java b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageContentRepositoryFactory.java index c3ea26b0..b07bfebb 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageContentRepositoryFactory.java +++ b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageContentRepositoryFactory.java @@ -1,9 +1,10 @@ package org.cryptomator.data.cloud.local; -import android.content.Context; +import static org.cryptomator.domain.CloudType.LOCAL; + +import android.content.Context; +import android.content.UriPermission; -import org.cryptomator.data.cloud.local.file.LocalStorageContentRepository; -import org.cryptomator.data.cloud.local.storageaccessframework.LocalStorageAccessFrameworkContentRepository; import org.cryptomator.data.repository.CloudContentRepositoryFactory; import org.cryptomator.domain.Cloud; import org.cryptomator.domain.LocalStorageCloud; @@ -11,15 +12,11 @@ import org.cryptomator.domain.exception.authentication.NoAuthenticationProvidedE import org.cryptomator.domain.repository.CloudContentRepository; import org.cryptomator.util.file.MimeTypes; +import java.util.List; + import javax.inject.Inject; import javax.inject.Singleton; -import static android.Manifest.permission.READ_EXTERNAL_STORAGE; -import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static androidx.core.content.ContextCompat.checkSelfPermission; -import static org.cryptomator.domain.CloudType.LOCAL; - @Singleton public class LocalStorageContentRepositoryFactory implements CloudContentRepositoryFactory { @@ -39,23 +36,14 @@ public class LocalStorageContentRepositoryFactory implements CloudContentReposit @Override public CloudContentRepository cloudContentRepositoryFor(Cloud cloud) { - if (!hasPermissions(WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE)) { - throw new NoAuthenticationProvidedException(cloud); - } - if (((LocalStorageCloud) cloud).rootUri() != null) { - return new LocalStorageAccessFrameworkContentRepository(context, mimeTypes, (LocalStorageCloud) cloud); - } else { - return new LocalStorageContentRepository(context, (LocalStorageCloud) cloud); - } - } - - private boolean hasPermissions(String... permissions) { - for (String permission : permissions) { - if (checkSelfPermission(context, permission) != PERMISSION_GRANTED) { - return false; + List permissions = context.getContentResolver().getPersistedUriPermissions(); + for (UriPermission permission : permissions) { + if(permission.getUri().toString().equals(((LocalStorageCloud) cloud).rootUri())) { + return new LocalStorageAccessFrameworkContentRepository(context, mimeTypes, (LocalStorageCloud) cloud); } } - return true; + + throw new NoAuthenticationProvidedException(cloud); } } diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/RootLocalStorageAccessFolder.kt b/data/src/main/java/org/cryptomator/data/cloud/local/RootLocalStorageAccessFolder.kt similarity index 92% rename from data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/RootLocalStorageAccessFolder.kt rename to data/src/main/java/org/cryptomator/data/cloud/local/RootLocalStorageAccessFolder.kt index bc59d39b..9268ac45 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/local/storageaccessframework/RootLocalStorageAccessFolder.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/local/RootLocalStorageAccessFolder.kt @@ -1,4 +1,4 @@ -package org.cryptomator.data.cloud.local.storageaccessframework +package org.cryptomator.data.cloud.local import android.net.Uri import android.provider.DocumentsContract diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalFile.kt b/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalFile.kt deleted file mode 100644 index 43eb8ad6..00000000 --- a/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalFile.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.cryptomator.data.cloud.local.file - -import org.cryptomator.domain.Cloud -import org.cryptomator.domain.CloudFile -import java.util.Date - -class LocalFile(override val parent: LocalFolder, override val name: String, override val path: String, override val size: Long?, override val modified: Date?) : CloudFile, LocalNode { - - override val cloud: Cloud? - get() = parent.cloud -} diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalFolder.kt b/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalFolder.kt deleted file mode 100644 index 40d60d43..00000000 --- a/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalFolder.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.cryptomator.data.cloud.local.file - -import org.cryptomator.domain.Cloud -import org.cryptomator.domain.CloudFolder - -open class LocalFolder(override val parent: LocalFolder?, override val name: String, override val path: String) : CloudFolder, LocalNode { - - override val cloud: Cloud? - get() = parent?.cloud - - override fun withCloud(cloud: Cloud?): LocalFolder? { - return LocalFolder(parent?.withCloud(cloud), name, path) - } -} diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalNode.kt b/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalNode.kt deleted file mode 100644 index 313b8859..00000000 --- a/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalNode.kt +++ /dev/null @@ -1,9 +0,0 @@ -package org.cryptomator.data.cloud.local.file - -import org.cryptomator.domain.CloudNode - -interface LocalNode : CloudNode { - - override val parent: LocalFolder? - -} diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalStorageContentRepository.kt b/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalStorageContentRepository.kt deleted file mode 100644 index 46c225f1..00000000 --- a/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalStorageContentRepository.kt +++ /dev/null @@ -1,111 +0,0 @@ -package org.cryptomator.data.cloud.local.file - -import android.content.Context -import org.cryptomator.domain.LocalStorageCloud -import org.cryptomator.domain.exception.BackendException -import org.cryptomator.domain.exception.FatalBackendException -import org.cryptomator.domain.exception.NoSuchCloudFileException -import org.cryptomator.domain.repository.CloudContentRepository -import org.cryptomator.domain.usecases.ProgressAware -import org.cryptomator.domain.usecases.cloud.DataSource -import org.cryptomator.domain.usecases.cloud.DownloadState -import org.cryptomator.domain.usecases.cloud.UploadState -import org.cryptomator.util.ExceptionUtil -import java.io.File -import java.io.FileNotFoundException -import java.io.IOException -import java.io.OutputStream - -class LocalStorageContentRepository(context: Context, localStorageCloud: LocalStorageCloud) : CloudContentRepository { - - private val localStorageImpl: LocalStorageImpl = LocalStorageImpl(context, localStorageCloud) - - @Throws(BackendException::class) - override fun root(cloud: LocalStorageCloud): LocalFolder { - return localStorageImpl.root() - } - - override fun resolve(cloud: LocalStorageCloud, path: String): LocalFolder { - return localStorageImpl.resolve(path) - } - - @Throws(BackendException::class) - override fun file(parent: LocalFolder, name: String): LocalFile { - return localStorageImpl.file(parent, name, null) - } - - @Throws(BackendException::class) - override fun file(parent: LocalFolder, name: String, size: Long?): LocalFile { - return localStorageImpl.file(parent, name, size) - } - - @Throws(BackendException::class) - override fun folder(parent: LocalFolder, name: String): LocalFolder { - return localStorageImpl.folder(parent, name) - } - - @Throws(BackendException::class) - override fun exists(node: LocalNode): Boolean { - return localStorageImpl.exists(node) - } - - @Throws(BackendException::class) - override fun list(folder: LocalFolder): List { - return localStorageImpl.list(folder) - } - - @Throws(BackendException::class) - override fun create(folder: LocalFolder): LocalFolder { - return localStorageImpl.create(folder) - } - - @Throws(BackendException::class) - override fun move(source: LocalFolder, target: LocalFolder): LocalFolder { - return localStorageImpl.move(source, target) as LocalFolder - } - - @Throws(BackendException::class) - override fun move(source: LocalFile, target: LocalFile): LocalFile { - return localStorageImpl.move(source, target) as LocalFile - } - - @Throws(BackendException::class) - override fun write(file: LocalFile, data: DataSource, progressAware: ProgressAware, replace: Boolean, size: Long): LocalFile { - return try { - localStorageImpl.write(file, data, progressAware, replace, size) - } catch (e: IOException) { - if (ExceptionUtil.contains(e, FileNotFoundException::class.java)) { - throw NoSuchCloudFileException(file.name) - } - throw FatalBackendException(e) - } - } - - @Throws(BackendException::class) - override fun read(file: LocalFile, encryptedTmpFile: File?, data: OutputStream, progressAware: ProgressAware) { - try { - localStorageImpl.read(file, data, progressAware) - } catch (e: IOException) { - if (ExceptionUtil.contains(e, FileNotFoundException::class.java)) { - throw NoSuchCloudFileException(file.name) - } - throw FatalBackendException(e) - } - } - - @Throws(BackendException::class) - override fun delete(node: LocalNode) { - localStorageImpl.delete(node) - } - - @Throws(BackendException::class) - override fun checkAuthenticationAndRetrieveCurrentAccount(cloud: LocalStorageCloud): String { - return "" - } - - @Throws(BackendException::class) - override fun logout(cloud: LocalStorageCloud) { - // empty - } - -} diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalStorageImpl.kt b/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalStorageImpl.kt deleted file mode 100644 index 18547d8e..00000000 --- a/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalStorageImpl.kt +++ /dev/null @@ -1,165 +0,0 @@ -package org.cryptomator.data.cloud.local.file - -import android.content.Context -import org.cryptomator.data.util.CopyStream -import org.cryptomator.data.util.TransferredBytesAwareInputStream -import org.cryptomator.data.util.TransferredBytesAwareOutputStream -import org.cryptomator.domain.CloudNode -import org.cryptomator.domain.LocalStorageCloud -import org.cryptomator.domain.exception.BackendException -import org.cryptomator.domain.exception.CloudNodeAlreadyExistsException -import org.cryptomator.domain.exception.FatalBackendException -import org.cryptomator.domain.exception.NoSuchCloudFileException -import org.cryptomator.domain.exception.ParentFolderIsNullException -import org.cryptomator.domain.usecases.ProgressAware -import org.cryptomator.domain.usecases.cloud.DataSource -import org.cryptomator.domain.usecases.cloud.DownloadState -import org.cryptomator.domain.usecases.cloud.Progress -import org.cryptomator.domain.usecases.cloud.UploadState -import java.io.File -import java.io.FileInputStream -import java.io.FileOutputStream -import java.io.IOException -import java.io.OutputStream -import java.util.Date - -internal class LocalStorageImpl(private val context: Context, localStorageCloud: LocalStorageCloud) { - - private val root: RootLocalFolder = RootLocalFolder(localStorageCloud) - - fun root(): LocalFolder { - return root - } - - fun resolve(path: String): LocalFolder { - val names = path.substring(root.path.length + 1).split("/").toTypedArray() - var folder: LocalFolder = root - for (name in names) { - folder = folder(folder, name) - } - return folder - } - - fun file(folder: LocalFolder, name: String, size: Long?): LocalFile { - return LocalStorageNodeFactory.file(folder, name, folder.path + '/' + name, size, null) - } - - fun folder(folder: LocalFolder, name: String): LocalFolder { - return LocalStorageNodeFactory.folder(folder, name, folder.path + '/' + name) - } - - fun exists(node: CloudNode): Boolean { - return File(node.path).exists() - } - - @Throws(BackendException::class) - fun list(folder: LocalFolder): List { - val localDirectory = File(folder.path) - if (!exists(folder)) { - throw NoSuchCloudFileException() - } - return localDirectory.listFiles()?.map { file -> LocalStorageNodeFactory.from(folder, file) } - ?: throw FatalBackendException("listFiles() shouldn't return null") - } - - @Throws(BackendException::class) - fun create(folder: LocalFolder): LocalFolder { - folder.parent?.let { parentFolder -> - val createFolder = File(folder.path) - if (createFolder.exists()) { - throw CloudNodeAlreadyExistsException(folder.name) - } - if (!createFolder.mkdirs()) { - throw FatalBackendException("Couldn't create a local folder at " + folder.path) - } - return LocalStorageNodeFactory.folder(parentFolder, createFolder) - } ?: throw ParentFolderIsNullException(folder.name) - } - - @Throws(BackendException::class) - fun move(source: LocalNode, target: LocalNode): LocalNode { - target.parent?.let { - val sourceFile = File(source.path) - val targetFile = File(target.path) - if (targetFile.exists()) { - throw CloudNodeAlreadyExistsException(target.name) - } - if (!sourceFile.exists()) { - throw NoSuchCloudFileException(source.name) - } - if (!sourceFile.renameTo(targetFile)) { - throw FatalBackendException("Couldn't move " + source.path + " to " + target.path) - } - - return LocalStorageNodeFactory.from(it, targetFile) - } ?: throw ParentFolderIsNullException(target.name) - } - - fun delete(node: CloudNode) { - val fileOrDirectory = File(node.path) - if (!deleteRecursive(fileOrDirectory)) { - throw FatalBackendException("Couldn't delete local CloudNode $fileOrDirectory") - } - } - - private fun deleteRecursive(fileOrDirectory: File): Boolean { - if (fileOrDirectory.isDirectory) { - fileOrDirectory.listFiles()?.forEach { - deleteRecursive(it) - } - } - return fileOrDirectory.delete() - } - - @Throws(IOException::class, BackendException::class) - fun write(file: LocalFile, data: DataSource, progressAware: ProgressAware, replace: Boolean, size: Long): LocalFile { - if (!replace && exists(file)) { - throw CloudNodeAlreadyExistsException("CloudNode already exists and replace is false") - } - progressAware.onProgress(Progress.started(UploadState.upload(file))) - val localFile = File(file.path) - FileOutputStream(localFile).use { out -> - data.open(context)?.use { inputStream -> - object : TransferredBytesAwareInputStream(inputStream) { - override fun bytesTransferred(transferred: Long) { - progressAware.onProgress( // - Progress.progress(UploadState.upload(file)) // - .between(0) // - .and(size) // - .withValue(transferred) - ) - } - }.use { CopyStream.copyStreamToStream(it, out) } - } ?: throw FatalBackendException("InputStream shouldn't be null") - } - progressAware.onProgress(Progress.completed(UploadState.upload(file))) - return LocalStorageNodeFactory.file( // - file.parent, // - file.name, // - localFile.path, // - localFile.length(), // - Date(localFile.lastModified()) - ) - } - - @Throws(IOException::class) - fun read(file: LocalFile, data: OutputStream, progressAware: ProgressAware) { - progressAware.onProgress(Progress.started(DownloadState.download(file))) - val localFile = File(file.path) - FileInputStream(localFile).use { inputStream -> - object : TransferredBytesAwareOutputStream(data) { - override fun bytesTransferred(transferred: Long) { - progressAware // - .onProgress( - Progress.progress(DownloadState.download(file)) // - .between(0) // - .and(localFile.length()) // - .withValue(transferred) - ) - } - }.use { out -> CopyStream.copyStreamToStream(inputStream, out) } - } - progressAware.onProgress(Progress.completed(DownloadState.download(file))) - } - -} diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalStorageNodeFactory.kt b/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalStorageNodeFactory.kt deleted file mode 100644 index e6788644..00000000 --- a/data/src/main/java/org/cryptomator/data/cloud/local/file/LocalStorageNodeFactory.kt +++ /dev/null @@ -1,36 +0,0 @@ -package org.cryptomator.data.cloud.local.file - -import java.io.File -import java.util.Date - -internal object LocalStorageNodeFactory { - - @JvmStatic - fun from(parent: LocalFolder, file: File): LocalNode { - return if (file.isDirectory) { - folder(parent, file) - } else { - file( // - parent, // - file.name, // - file.path, // - file.length(), // - Date(file.lastModified()) - ) - } - } - - fun folder(parent: LocalFolder, file: File): LocalFolder { - return folder(parent, file.name, file.path) - } - - @JvmStatic - fun folder(parent: LocalFolder, name: String, path: String): LocalFolder { - return LocalFolder(parent, name, path) - } - - @JvmStatic - fun file(folder: LocalFolder, name: String, path: String, size: Long?, modified: Date?): LocalFile { - return LocalFile(folder, name, path, size, modified) - } -} diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/file/RootLocalFolder.kt b/data/src/main/java/org/cryptomator/data/cloud/local/file/RootLocalFolder.kt deleted file mode 100644 index fde9d439..00000000 --- a/data/src/main/java/org/cryptomator/data/cloud/local/file/RootLocalFolder.kt +++ /dev/null @@ -1,15 +0,0 @@ -package org.cryptomator.data.cloud.local.file - -import android.os.Environment -import org.cryptomator.domain.Cloud -import org.cryptomator.domain.LocalStorageCloud - -class RootLocalFolder(private val localStorageCloud: LocalStorageCloud) : LocalFolder(null, "", Environment.getExternalStorageDirectory().path) { - - override val cloud: Cloud - get() = localStorageCloud - - override fun withCloud(cloud: Cloud?): RootLocalFolder { - return RootLocalFolder(cloud as LocalStorageCloud) - } -} diff --git a/data/src/main/java/org/cryptomator/data/repository/CloudRepositoryImpl.java b/data/src/main/java/org/cryptomator/data/repository/CloudRepositoryImpl.java index bdb422c3..61f1307c 100644 --- a/data/src/main/java/org/cryptomator/data/repository/CloudRepositoryImpl.java +++ b/data/src/main/java/org/cryptomator/data/repository/CloudRepositoryImpl.java @@ -76,9 +76,6 @@ class CloudRepositoryImpl implements CloudRepository { @Override public void delete(Cloud cloud) { - if (cloud.predefined()) { - throw new IllegalArgumentException("Can not delete predefined cloud"); - } if (!cloud.persistent()) { throw new IllegalArgumentException("Can not delete non persistent cloud"); } diff --git a/data/src/main/java/org/cryptomator/data/util/NetworkConnectionCheck.kt b/data/src/main/java/org/cryptomator/data/util/NetworkConnectionCheck.kt index 14332c8d..9ad87420 100644 --- a/data/src/main/java/org/cryptomator/data/util/NetworkConnectionCheck.kt +++ b/data/src/main/java/org/cryptomator/data/util/NetworkConnectionCheck.kt @@ -28,6 +28,6 @@ class NetworkConnectionCheck @Inject internal constructor(private val context: C fun checkWifiOnAndConnected(): Boolean { val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val activeNetwork = connectivityManager.activeNetwork - return connectivityManager.getNetworkCapabilities(activeNetwork).hasTransport(NetworkCapabilities.TRANSPORT_WIFI) + return connectivityManager.getNetworkCapabilities(activeNetwork)?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) == true } } diff --git a/domain/src/main/java/org/cryptomator/domain/Cloud.kt b/domain/src/main/java/org/cryptomator/domain/Cloud.kt index ee1aba13..6c1f1e22 100644 --- a/domain/src/main/java/org/cryptomator/domain/Cloud.kt +++ b/domain/src/main/java/org/cryptomator/domain/Cloud.kt @@ -7,7 +7,6 @@ interface Cloud : Serializable { fun id(): Long? fun type(): CloudType? fun configurationMatches(cloud: Cloud?): Boolean - fun predefined(): Boolean fun persistent(): Boolean fun requiresNetwork(): Boolean } diff --git a/domain/src/main/java/org/cryptomator/domain/DropboxCloud.java b/domain/src/main/java/org/cryptomator/domain/DropboxCloud.java index b8f4fc8a..2178e3c7 100644 --- a/domain/src/main/java/org/cryptomator/domain/DropboxCloud.java +++ b/domain/src/main/java/org/cryptomator/domain/DropboxCloud.java @@ -48,11 +48,6 @@ public class DropboxCloud implements Cloud { return true; } - @Override - public boolean predefined() { - return true; - } - @Override public boolean persistent() { return true; diff --git a/domain/src/main/java/org/cryptomator/domain/GoogleDriveCloud.java b/domain/src/main/java/org/cryptomator/domain/GoogleDriveCloud.java index e8b27ce9..8ebd70f0 100644 --- a/domain/src/main/java/org/cryptomator/domain/GoogleDriveCloud.java +++ b/domain/src/main/java/org/cryptomator/domain/GoogleDriveCloud.java @@ -48,11 +48,6 @@ public class GoogleDriveCloud implements Cloud { return true; } - @Override - public boolean predefined() { - return true; - } - @Override public boolean persistent() { return true; diff --git a/domain/src/main/java/org/cryptomator/domain/LocalStorageCloud.java b/domain/src/main/java/org/cryptomator/domain/LocalStorageCloud.java index ee895359..fb96449c 100644 --- a/domain/src/main/java/org/cryptomator/domain/LocalStorageCloud.java +++ b/domain/src/main/java/org/cryptomator/domain/LocalStorageCloud.java @@ -1,6 +1,5 @@ package org.cryptomator.domain; -import android.os.Build; import android.text.TextUtils; import org.jetbrains.annotations.NotNull; @@ -48,11 +47,6 @@ public class LocalStorageCloud implements Cloud { } - @Override - public boolean predefined() { - return Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP; - } - @Override public boolean persistent() { return true; diff --git a/domain/src/main/java/org/cryptomator/domain/OnedriveCloud.java b/domain/src/main/java/org/cryptomator/domain/OnedriveCloud.java index 5b082012..a56accf0 100644 --- a/domain/src/main/java/org/cryptomator/domain/OnedriveCloud.java +++ b/domain/src/main/java/org/cryptomator/domain/OnedriveCloud.java @@ -43,11 +43,6 @@ public class OnedriveCloud implements Cloud { return CloudType.ONEDRIVE; } - @Override - public boolean predefined() { - return true; - } - @Override public boolean persistent() { return true; diff --git a/domain/src/main/java/org/cryptomator/domain/PCloud.java b/domain/src/main/java/org/cryptomator/domain/PCloud.java index 95164c65..89b01617 100644 --- a/domain/src/main/java/org/cryptomator/domain/PCloud.java +++ b/domain/src/main/java/org/cryptomator/domain/PCloud.java @@ -59,12 +59,6 @@ public class PCloud implements Cloud { return username.equals(cloud.username); } - - @Override - public boolean predefined() { - return false; - } - @Override public boolean persistent() { return true; diff --git a/domain/src/main/java/org/cryptomator/domain/S3Cloud.java b/domain/src/main/java/org/cryptomator/domain/S3Cloud.java index 44268df6..064cc93a 100644 --- a/domain/src/main/java/org/cryptomator/domain/S3Cloud.java +++ b/domain/src/main/java/org/cryptomator/domain/S3Cloud.java @@ -80,12 +80,6 @@ public class S3Cloud implements Cloud { return s3Bucket.equals(cloud.s3Bucket) && s3Endpoint.equals(cloud.s3Endpoint) && s3Region.equals(cloud.s3Region); } - - @Override - public boolean predefined() { - return false; - } - @Override public boolean persistent() { return true; diff --git a/domain/src/main/java/org/cryptomator/domain/WebDavCloud.java b/domain/src/main/java/org/cryptomator/domain/WebDavCloud.java index 2ffba185..ccb21dd6 100644 --- a/domain/src/main/java/org/cryptomator/domain/WebDavCloud.java +++ b/domain/src/main/java/org/cryptomator/domain/WebDavCloud.java @@ -66,11 +66,6 @@ public class WebDavCloud implements Cloud { return certificate; } - @Override - public boolean predefined() { - return false; - } - @Override public boolean persistent() { return true; diff --git a/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt b/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt index abfe6e74..07bce89b 100644 --- a/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt +++ b/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt @@ -1,6 +1,5 @@ package org.cryptomator.presentation.presenter -import android.Manifest import android.accounts.AccountManager import android.widget.Toast import com.dropbox.core.android.Auth @@ -35,6 +34,7 @@ import org.cryptomator.presentation.intent.AuthenticateCloudIntent import org.cryptomator.presentation.intent.Intents import org.cryptomator.presentation.model.CloudModel import org.cryptomator.presentation.model.CloudTypeModel +import org.cryptomator.presentation.model.LocalStorageModel import org.cryptomator.presentation.model.ProgressModel import org.cryptomator.presentation.model.ProgressStateModel import org.cryptomator.presentation.model.S3CloudModel @@ -44,7 +44,6 @@ import org.cryptomator.presentation.ui.activity.view.AuthenticateCloudView import org.cryptomator.presentation.workflow.ActivityResult import org.cryptomator.presentation.workflow.AddExistingVaultWorkflow import org.cryptomator.presentation.workflow.CreateNewVaultWorkflow -import org.cryptomator.presentation.workflow.PermissionsResult import org.cryptomator.presentation.workflow.Workflow import org.cryptomator.util.ExceptionUtil import org.cryptomator.util.crypto.CredentialCryptor @@ -445,20 +444,15 @@ class AuthenticateCloudPresenter @Inject constructor( // private fun startAuthentication(cloud: CloudModel) { authenticationStarted = true - requestPermissions( - PermissionsResultCallbacks.onLocalStorageAuthenticated(cloud), // - R.string.permission_snackbar_auth_local_vault, // - Manifest.permission.READ_EXTERNAL_STORAGE, // - Manifest.permission.WRITE_EXTERNAL_STORAGE - ) - } - } + val permissions = context().contentResolver.persistedUriPermissions + for (permission in permissions) { + if (permission.uri.toString() == (cloud as LocalStorageModel).uri()) { + succeedAuthenticationWith(cloud.toCloud()) + } + } - @Callback - fun onLocalStorageAuthenticated(result: PermissionsResult, cloud: CloudModel) { - if (result.granted()) { - succeedAuthenticationWith(cloud.toCloud()) - } else { + // FIXME think about how to re-request permission + // FIXME change in the FOSS variant too failAuthentication(PermissionNotGrantedException(R.string.permission_snackbar_auth_local_vault)) } } diff --git a/presentation/src/main/AndroidManifest.xml b/presentation/src/main/AndroidManifest.xml index 0e2bbcf7..5b155c10 100644 --- a/presentation/src/main/AndroidManifest.xml +++ b/presentation/src/main/AndroidManifest.xml @@ -7,7 +7,6 @@ - @@ -28,7 +27,6 @@ android:allowBackup="false" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" - android:requestLegacyExternalStorage="true" android:supportsRtl="true" android:theme="@style/AppTheme" android:usesCleartextTraffic="true"> diff --git a/presentation/src/main/java/org/cryptomator/presentation/BootAwareReceiver.kt b/presentation/src/main/java/org/cryptomator/presentation/BootAwareReceiver.kt index b0124eb2..f20baf4a 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/BootAwareReceiver.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/BootAwareReceiver.kt @@ -3,7 +3,6 @@ package org.cryptomator.presentation import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import android.os.Build import org.cryptomator.presentation.service.CryptorsService import org.cryptomator.presentation.service.PhotoContentJob import org.cryptomator.util.SharedPreferencesHandler @@ -18,7 +17,7 @@ class BootAwareReceiver : BroadcastReceiver() { context.stopService(CryptorsService.lockAllIntent(context)) } intent.action.equals(Intent.ACTION_BOOT_COMPLETED, ignoreCase = true) -> { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && SharedPreferencesHandler(context).usePhotoUpload()) { + if (SharedPreferencesHandler(context).usePhotoUpload()) { Timber.tag("BootAwareReceiver").i("Starting AutoUploadJobScheduler") PhotoContentJob.scheduleJob(context) } diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/BrowseFilesPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/BrowseFilesPresenter.kt index 47e03969..391d30a9 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/BrowseFilesPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/BrowseFilesPresenter.kt @@ -4,11 +4,8 @@ import android.Manifest import android.content.ActivityNotFoundException import android.content.Intent import android.net.Uri -import android.os.Build -import android.os.Environment import android.provider.DocumentsContract import android.widget.Toast -import androidx.annotation.RequiresApi import org.cryptomator.domain.CloudFile import org.cryptomator.domain.CloudFolder import org.cryptomator.domain.CloudNode @@ -83,10 +80,8 @@ import org.cryptomator.util.SharedPreferencesHandler import org.cryptomator.util.file.FileCacheUtils import org.cryptomator.util.file.MimeType import org.cryptomator.util.file.MimeTypes -import java.io.File import java.io.FileInputStream import java.io.FileNotFoundException -import java.io.FileOutputStream import java.io.Serializable import java.security.DigestInputStream import java.security.MessageDigest @@ -738,30 +733,6 @@ class BrowseFilesPresenter @Inject constructor( // exportNodesToUserSelectedLocation(selectedCloudFiles, trigger) } - @Callback - fun exportFileToDownloadDirectory(result: PermissionsResult, fileToExport: CloudFileModel, exportOperation: ExportOperation) { - if (result.granted()) { - val downloads = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) - val cryptomatorDownloads = File(downloads, context().getString(R.string.download_subdirectory_name)) - cryptomatorDownloads.mkdirs() - if (cryptomatorDownloads.isDirectory) { - val target = File(cryptomatorDownloads, fileToExport.name) - try { - val downloadFile = DownloadFile.Builder() // - .setDownloadFile(fileToExport.toCloudNode()) // - .setDataSink(FileOutputStream(target)) // - .build() - exportOperation.export(this, listOf(downloadFile)) - } catch (e: FileNotFoundException) { - showError(e) - } - } else { - view?.showError(R.string.screen_file_browser_msg_creating_download_dir_failed) - } - } - } - - @RequiresApi(Build.VERSION_CODES.KITKAT) private fun exportFileToUserSelectedLocation(fileToExport: CloudFileModel, exportOperation: ExportOperation) { val intent = Intent(Intent.ACTION_CREATE_DOCUMENT) intent.addCategory(Intent.CATEGORY_OPENABLE) @@ -789,7 +760,6 @@ class BrowseFilesPresenter @Inject constructor( // } @Callback - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) fun pickedLocalStorageLocation( result: ActivityResult, // nodesToExport: ArrayList>, // @@ -809,7 +779,6 @@ class BrowseFilesPresenter @Inject constructor( // disableSelectionMode() } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private fun collectNodesToExport( parentUri: Uri, // exportOperation: ExportOperation, // @@ -827,7 +796,6 @@ class BrowseFilesPresenter @Inject constructor( // collectFolderContentForExport(parentUri, exportOperation, foldersForRecursiveDirListing, filesToExport) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private fun collectFolderContentForExport( parentUri: Uri, exportOperation: ExportOperation, folders: List, // filesToExport: List @@ -847,7 +815,6 @@ class BrowseFilesPresenter @Inject constructor( // }) } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private fun prepareExportingOf(parentUri: Uri, exportOperation: ExportOperation, filesToExport: List, cloudNodeRecursiveListing: CloudNodeRecursiveListing) { downloadFiles = ArrayList() downloadFiles.addAll(prepareFilesForExport(cloudFileModelMapper.fromModels(filesToExport), parentUri)) @@ -862,12 +829,10 @@ class BrowseFilesPresenter @Inject constructor( // } } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private fun prepareFilesForExport(filesToExport: List, parentUri: Uri): List { return filesToExport.mapTo(ArrayList()) { createDownloadFile(it, parentUri) } } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private fun prepareFolderContentForExport(cloudFolderRecursiveListing: CloudFolderRecursiveListing, parentUri: Uri) { createFolder(parentUri, cloudFolderRecursiveListing.parent.name)?.let { downloadFiles.addAll(prepareFilesForExport(cloudFolderRecursiveListing.files, it)) @@ -877,7 +842,6 @@ class BrowseFilesPresenter @Inject constructor( // } ?: throw FatalBackendException("Failed to create parent folder for export") } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private fun createFolder(parentUri: Uri, folderName: String): Uri? { return try { DocumentsContract.createDocument( // @@ -892,7 +856,6 @@ class BrowseFilesPresenter @Inject constructor( // } } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private fun createDownloadFile(file: CloudFile, documentUri: Uri): DownloadFile { return try { DownloadFile.Builder() // @@ -918,7 +881,6 @@ class BrowseFilesPresenter @Inject constructor( // } } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Throws(IllegalFileNameException::class, NoSuchCloudFileException::class) private fun createNewDocumentUri(parentUri: Uri, fileName: String): Uri { val mimeType = mimeTypes.fromFilename(fileName) ?: MimeType.APPLICATION_OCTET_STREAM diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudConnectionListPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudConnectionListPresenter.kt index ff98ce85..ba4ab6a3 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudConnectionListPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudConnectionListPresenter.kt @@ -3,9 +3,7 @@ package org.cryptomator.presentation.presenter import android.content.ActivityNotFoundException import android.content.Intent import android.net.Uri -import android.os.Build import android.widget.Toast -import androidx.annotation.RequiresApi import org.cryptomator.domain.Cloud import org.cryptomator.domain.LocalStorageCloud import org.cryptomator.domain.PCloud @@ -251,7 +249,6 @@ class CloudConnectionListPresenter @Inject constructor( // } @Callback - @RequiresApi(api = Build.VERSION_CODES.KITKAT) fun pickedLocalStorageLocation(result: ActivityResult) { val rootTreeUriOfLocalStorage = result.intent().data persistUriPermission(rootTreeUriOfLocalStorage) @@ -266,7 +263,6 @@ class CloudConnectionListPresenter @Inject constructor( // }) } - @RequiresApi(api = Build.VERSION_CODES.KITKAT) private fun persistUriPermission(rootTreeUriOfLocalStorage: Uri?) { rootTreeUriOfLocalStorage?.let { context() // @@ -278,7 +274,6 @@ class CloudConnectionListPresenter @Inject constructor( // } } - @RequiresApi(api = Build.VERSION_CODES.KITKAT) private fun releaseUriPermission(uri: String) { context() // .contentResolver // diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/ImagePreviewPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/ImagePreviewPresenter.kt index 31b066d8..393aac0a 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/ImagePreviewPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/ImagePreviewPresenter.kt @@ -3,8 +3,6 @@ package org.cryptomator.presentation.presenter import android.Manifest import android.content.Intent import android.net.Uri -import android.os.Build -import android.os.Environment import org.cryptomator.domain.CloudFile import org.cryptomator.domain.CloudNode import org.cryptomator.domain.di.PerView @@ -30,9 +28,7 @@ import org.cryptomator.presentation.util.ShareFileHelper import org.cryptomator.presentation.workflow.ActivityResult import org.cryptomator.presentation.workflow.PermissionsResult import org.cryptomator.util.ExceptionUtil -import java.io.File import java.io.FileNotFoundException -import java.io.FileOutputStream import java.io.IOException import java.io.InputStream import java.io.OutputStream @@ -58,37 +54,33 @@ class ImagePreviewPresenter @Inject constructor( // @InstanceState lateinit var pageIndexes: ArrayList - fun onExportImageClicked(uri: Uri) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { - copyFileToDownloadDirectory(uri) - } else { - copyFileToUserSelectedLocation(uri) - } + fun exportImageToUserSelectedLocation(uri: Uri) { + val intent = Intent(Intent.ACTION_CREATE_DOCUMENT) + intent.addCategory(Intent.CATEGORY_OPENABLE) + intent.type = "*/*" + intent.putExtra(Intent.EXTRA_TITLE, contentResolverUtil.fileName(uri)) + requestActivityResult(ActivityResultCallbacks.exportImageToUserSelectedLocation(uri.toString()), intent) } - private fun copyFileToDownloadDirectory(uri: Uri) { + @Callback + fun exportImageToUserSelectedLocation(result: ActivityResult, sourceUri: String?) { requestPermissions( - PermissionsResultCallbacks.copyFileToDownloadDirectory(uri.toString()), // - R.string.permission_message_export_file, Manifest.permission.WRITE_EXTERNAL_STORAGE + PermissionsResultCallbacks.exportImageToUserSelectedLocation(result.intent()?.dataString, sourceUri), // + R.string.permission_message_export_file, // + Manifest.permission.READ_EXTERNAL_STORAGE ) } @Callback - fun copyFileToDownloadDirectory(result: PermissionsResult, uriString: String?) { + fun exportImageToUserSelectedLocation(result: PermissionsResult, targetUri: String?, sourceUri: String?) { if (result.granted()) { - val uriFile = Uri.parse(uriString) - val downloads = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) - val cryptomatorDownloads = File(downloads, context().getString(R.string.download_subdirectory_name)) - cryptomatorDownloads.mkdirs() - if (cryptomatorDownloads.isDirectory) { - val target = File(cryptomatorDownloads, contentResolverUtil.fileName(uriFile)) - try { - copyFile(contentResolverUtil.openInputStream(uriFile), FileOutputStream(target)) - } catch (e: FileNotFoundException) { - showError(e) - } - } else { - view?.showError(R.string.screen_file_browser_msg_creating_download_dir_failed) + try { + copyFile( + contentResolverUtil.openInputStream(Uri.parse(sourceUri)), // + contentResolverUtil.openOutputStream(Uri.parse(targetUri)) + ) + } catch (e: FileNotFoundException) { + showError(e) } } } @@ -107,37 +99,6 @@ class ImagePreviewPresenter @Inject constructor( // }) } - private fun copyFileToUserSelectedLocation(uri: Uri) { - val intent = Intent(Intent.ACTION_CREATE_DOCUMENT) - intent.addCategory(Intent.CATEGORY_OPENABLE) - intent.type = "*/*" - intent.putExtra(Intent.EXTRA_TITLE, contentResolverUtil.fileName(uri)) - requestActivityResult(ActivityResultCallbacks.copyFileToUserSelectedLocation(uri.toString()), intent) - } - - @Callback - fun copyFileToUserSelectedLocation(result: ActivityResult, sourceUri: String?) { - requestPermissions( - PermissionsResultCallbacks.copyFileToUserSelectedLocation(result.intent()?.dataString, sourceUri), // - R.string.permission_message_export_file, // - Manifest.permission.READ_EXTERNAL_STORAGE - ) - } - - @Callback - fun copyFileToUserSelectedLocation(result: PermissionsResult, targetUri: String?, sourceUri: String?) { - if (result.granted()) { - try { - copyFile( - contentResolverUtil.openInputStream(Uri.parse(sourceUri)), // - contentResolverUtil.openOutputStream(Uri.parse(targetUri)) - ) - } catch (e: FileNotFoundException) { - showError(e) - } - } - } - fun onShareImageClicked(uri: Uri) { shareFileHelper.shareFile(this, uri) } diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/SettingsPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/SettingsPresenter.kt index f40390d1..43cb4dc4 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/SettingsPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/SettingsPresenter.kt @@ -90,17 +90,14 @@ class SettingsPresenter @Inject internal constructor( requestPermissions( PermissionsResultCallbacks.onLocalStoragePermissionGranted(), // R.string.permission_snackbar_auth_auto_upload, // - Manifest.permission.READ_EXTERNAL_STORAGE, // - Manifest.permission.WRITE_EXTERNAL_STORAGE + Manifest.permission.READ_EXTERNAL_STORAGE ) } @Callback fun onLocalStoragePermissionGranted(result: PermissionsResult) { if (result.granted()) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - scheduleJob(context()) - } + scheduleJob(context()) } else { view?.disableAutoUpload() } diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/UnlockVaultPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/UnlockVaultPresenter.kt index f5b327b2..edea86e7 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/UnlockVaultPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/UnlockVaultPresenter.kt @@ -67,7 +67,7 @@ class UnlockVaultPresenter @Inject constructor( super.destroyed() if (retryUnlockHandler != null) { running = false - retryUnlockHandler?.removeCallbacks(null) + retryUnlockHandler?.removeCallbacksAndMessages(null) } } @@ -140,11 +140,12 @@ class UnlockVaultPresenter @Inject constructor( } } + // FIXME why is this method not used? fun onWindowFocusChanged(hasFocus: Boolean) { if (hasFocus) { if (retryUnlockHandler != null) { running = false - retryUnlockHandler?.removeCallbacks(null) + retryUnlockHandler?.removeCallbacksAndMessages(null) } } } diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/ImagePreviewActivity.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/ImagePreviewActivity.kt index 209f27ea..901b67cb 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/ImagePreviewActivity.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/ImagePreviewActivity.kt @@ -66,7 +66,7 @@ class ImagePreviewActivity : BaseActivity(), ImagePreviewView, ConfirmDeleteClou presenter.onDeleteImageClicked(imagePreviewFiles[imagePreviewSliderAdapter.getIndex(viewPager.currentItem)]) } exportImage.setOnClickListener { - currentImageUri?.let { presenter.onExportImageClicked(it) } + currentImageUri?.let { presenter.exportImageToUserSelectedLocation(it) } } shareImage.setOnClickListener { currentImageUri?.let { presenter.onShareImageClicked(it) } diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/bottomsheet/FolderSettingsBottomSheet.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/bottomsheet/FolderSettingsBottomSheet.kt index 6440caa7..1c3a587f 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/bottomsheet/FolderSettingsBottomSheet.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/bottomsheet/FolderSettingsBottomSheet.kt @@ -1,6 +1,5 @@ package org.cryptomator.presentation.ui.bottomsheet -import android.os.Build import android.os.Bundle import android.view.View import org.cryptomator.generator.BottomSheet @@ -46,12 +45,10 @@ class FolderSettingsBottomSheet : BaseBottomSheet= Build.VERSION_CODES.LOLLIPOP) { - export_folder.visibility = View.VISIBLE - export_folder.setOnClickListener { - callback?.onExportFolderClicked(cloudFolderModel) - dismiss() - } + export_folder.visibility = View.VISIBLE + export_folder.setOnClickListener { + callback?.onExportFolderClicked(cloudFolderModel) + dismiss() } delete_folder.setOnClickListener { callback?.onDeleteNodeClicked(cloudFolderModel) diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/UpdateAppAvailableDialog.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/UpdateAppAvailableDialog.kt index 7f477e70..074113f5 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/UpdateAppAvailableDialog.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/UpdateAppAvailableDialog.kt @@ -1,7 +1,6 @@ package org.cryptomator.presentation.ui.dialog import android.content.DialogInterface -import android.os.Build import android.os.Bundle import android.text.Html import android.view.View @@ -32,11 +31,7 @@ class UpdateAppAvailableDialog : BaseProgressErrorDialog= Build.VERSION_CODES.N) { - tv_message.text = Html.fromHtml(message, Html.FROM_HTML_MODE_COMPACT) - } else { - tv_message.text = Html.fromHtml(message) - } + tv_message.text = Html.fromHtml(message, Html.FROM_HTML_MODE_COMPACT) } override fun enableViewAfterError(): View { diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/CloudConnectionListFragment.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/CloudConnectionListFragment.kt index bf974c6f..57d8a0ed 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/CloudConnectionListFragment.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/CloudConnectionListFragment.kt @@ -1,6 +1,5 @@ package org.cryptomator.presentation.ui.fragment -import android.os.Environment import android.util.TypedValue import android.view.View.GONE import android.view.View.VISIBLE @@ -13,10 +12,7 @@ import org.cryptomator.presentation.presenter.CloudConnectionListPresenter import org.cryptomator.presentation.ui.adapter.CloudConnectionListAdapter import javax.inject.Inject import kotlinx.android.synthetic.main.fragment_browse_cloud_connections.floating_action_button -import kotlinx.android.synthetic.main.fragment_browse_cloud_connections.rv_local_default_cloud import kotlinx.android.synthetic.main.recycler_view_layout.recyclerView -import kotlinx.android.synthetic.main.view_cloud_connection_content.cloudSubText -import kotlinx.android.synthetic.main.view_cloud_connection_content.cloudText import kotlinx.android.synthetic.main.view_empty_cloud_connections.rl_creation_hint @Fragment(R.layout.fragment_browse_cloud_connections) @@ -42,7 +38,6 @@ class CloudConnectionListFragment : BaseFragment() { override fun setupView() { setupRecyclerView() - rv_local_default_cloud.setOnClickListener { cloudConnectionListPresenter.onDefaultLocalCloudConnectionClicked() } floating_action_button.setOnClickListener { cloudConnectionListPresenter.onAddConnectionClicked() } } @@ -71,11 +66,5 @@ class CloudConnectionListFragment : BaseFragment() { fun setSelectedCloudType(selectedCloudType: CloudTypeModel) { this.selectedCloudType = selectedCloudType - - if (CloudTypeModel.LOCAL == selectedCloudType) { - rv_local_default_cloud.visibility = VISIBLE - cloudText.text = getString(R.string.screen_cloud_local_default_storage_title) - cloudSubText.text = Environment.getExternalStorageDirectory().toString() - } } } diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SettingsFragment.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SettingsFragment.kt index 1022f509..d40769ff 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SettingsFragment.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/SettingsFragment.kt @@ -1,6 +1,5 @@ package org.cryptomator.presentation.ui.fragment -import android.os.Build import android.os.Bundle import android.text.SpannableString import android.text.style.ForegroundColorSpan @@ -259,9 +258,7 @@ class SettingsFragment : PreferenceFragmentCompat() { if (enabled) { activity().grantLocalStoragePermissionForAutoUpload() } else { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - PhotoContentJob.cancelJob(activity().applicationContext) - } + PhotoContentJob.cancelJob(activity().applicationContext) } (findPreference(SharedPreferencesHandler.PHOTO_UPLOAD) as SwitchPreferenceCompat?)?.isChecked = enabled } diff --git a/presentation/src/main/res/layout/fragment_browse_cloud_connections.xml b/presentation/src/main/res/layout/fragment_browse_cloud_connections.xml index 4da30d58..c0930487 100644 --- a/presentation/src/main/res/layout/fragment_browse_cloud_connections.xml +++ b/presentation/src/main/res/layout/fragment_browse_cloud_connections.xml @@ -9,38 +9,10 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - - - - - - diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 8a87b0b0..d9312db4 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -167,7 +167,6 @@ Click here to add locations Server doesn\'t seem to be WebDAV compatible Custom locations - Default storage No additional locations available. diff --git a/presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt b/presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt index 8f33fa66..f542dd4d 100644 --- a/presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt +++ b/presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt @@ -1,6 +1,5 @@ package org.cryptomator.presentation.presenter -import android.Manifest import android.accounts.AccountManager import android.content.ActivityNotFoundException import android.widget.Toast @@ -38,6 +37,7 @@ import org.cryptomator.presentation.intent.AuthenticateCloudIntent import org.cryptomator.presentation.intent.Intents import org.cryptomator.presentation.model.CloudModel import org.cryptomator.presentation.model.CloudTypeModel +import org.cryptomator.presentation.model.LocalStorageModel import org.cryptomator.presentation.model.ProgressModel import org.cryptomator.presentation.model.ProgressStateModel import org.cryptomator.presentation.model.S3CloudModel @@ -47,7 +47,6 @@ import org.cryptomator.presentation.ui.activity.view.AuthenticateCloudView import org.cryptomator.presentation.workflow.ActivityResult import org.cryptomator.presentation.workflow.AddExistingVaultWorkflow import org.cryptomator.presentation.workflow.CreateNewVaultWorkflow -import org.cryptomator.presentation.workflow.PermissionsResult import org.cryptomator.presentation.workflow.Workflow import org.cryptomator.util.ExceptionUtil import org.cryptomator.util.crypto.CredentialCryptor @@ -491,20 +490,15 @@ class AuthenticateCloudPresenter @Inject constructor( // private fun startAuthentication(cloud: CloudModel) { authenticationStarted = true - requestPermissions( - PermissionsResultCallbacks.onLocalStorageAuthenticated(cloud), // - R.string.permission_snackbar_auth_local_vault, // - Manifest.permission.READ_EXTERNAL_STORAGE, // - Manifest.permission.WRITE_EXTERNAL_STORAGE - ) - } - } + val permissions = context().contentResolver.persistedUriPermissions + for (permission in permissions) { + if (permission.uri.toString() == (cloud as LocalStorageModel).uri()) { + succeedAuthenticationWith(cloud.toCloud()) + } + } - @Callback - fun onLocalStorageAuthenticated(result: PermissionsResult, cloud: CloudModel) { - if (result.granted()) { - succeedAuthenticationWith(cloud.toCloud()) - } else { + // FIXME think about how to re-request permission + // FIXME change in the FOSS variant too failAuthentication(PermissionNotGrantedException(R.string.permission_snackbar_auth_local_vault)) } } diff --git a/util/src/main/java/org/cryptomator/util/crypto/CryptoOperationsImpl.java b/util/src/main/java/org/cryptomator/util/crypto/CryptoOperationsImpl.java index 85b11a79..04acdceb 100644 --- a/util/src/main/java/org/cryptomator/util/crypto/CryptoOperationsImpl.java +++ b/util/src/main/java/org/cryptomator/util/crypto/CryptoOperationsImpl.java @@ -1,7 +1,6 @@ package org.cryptomator.util.crypto; import android.content.Context; -import android.os.Build; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; @@ -43,13 +42,10 @@ class CryptoOperationsImpl implements CryptoOperations { KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec // .Builder(alias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) // .setBlockModes(KeyProperties.BLOCK_MODE_CBC) // - .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7); + .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) // + .setUserAuthenticationRequired(requireUserAuthentication) // + .setInvalidatedByBiometricEnrollment(requireUserAuthentication); - builder.setUserAuthenticationRequired(requireUserAuthentication); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - builder.setInvalidatedByBiometricEnrollment(requireUserAuthentication); - } generator.init(builder.build()); generator.generateKey(); }; From 7add3e5bed596f7d4a4a73709f5fe2f7f519aebf Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 22 Oct 2021 17:40:08 +0200 Subject: [PATCH 07/28] Delete local storage cloud and set its vault connection to null (#251) --- data/build.gradle | 2 +- .../data/db/UpgradeDatabaseTest.kt | 57 +++++++++++++++++++ .../cryptomator/data/db/DatabaseUpgrades.java | 6 +- .../org/cryptomator/data/db/Upgrade9To10.kt | 30 ++++++++++ 4 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt diff --git a/data/build.gradle b/data/build.gradle index 211a64e4..4d2111a2 100644 --- a/data/build.gradle +++ b/data/build.gradle @@ -82,7 +82,7 @@ android { } greendao { - schemaVersion 9 + schemaVersion 10 } configurations.all { diff --git a/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt b/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt index 6e637898..c494bc2a 100644 --- a/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt +++ b/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt @@ -50,6 +50,7 @@ class UpgradeDatabaseTest { Upgrade6To7().applyTo(db, 6) Upgrade7To8().applyTo(db, 7) Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) + Upgrade9To10().applyTo(db, 9) CloudEntityDao(DaoConfig(db, CloudEntityDao::class.java)).loadAll() VaultEntityDao(DaoConfig(db, VaultEntityDao::class.java)).loadAll() @@ -407,4 +408,60 @@ class UpgradeDatabaseTest { Assert.assertThat(sharedPreferencesHandler.isBetaModeAlreadyShown(), CoreMatchers.`is`(false)) } + + @Test + fun upgrade9To10() { + Upgrade0To1().applyTo(db, 0) + Upgrade1To2().applyTo(db, 1) + Upgrade2To3(context).applyTo(db, 2) + Upgrade3To4().applyTo(db, 3) + Upgrade4To5().applyTo(db, 4) + Upgrade5To6().applyTo(db, 5) + Upgrade6To7().applyTo(db, 6) + Upgrade7To8().applyTo(db, 7) + Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) + + Sql.insertInto("CLOUD_ENTITY") // + .integer("_id", 15) // + .text("TYPE", CloudType.LOCAL.name) // + .text("URL", "url") // + .text("USERNAME", "username") // + .text("WEBDAV_CERTIFICATE", "certificate") // + .text("ACCESS_TOKEN", "accessToken") + .text("S3_BUCKET", "s3Bucket") // + .text("S3_REGION", "s3Region") // + .text("S3_SECRET_KEY", "s3SecretKey") // + .executeOn(db) + + Sql.insertInto("VAULT_ENTITY") // + .integer("_id", 25) // + .integer("FOLDER_CLOUD_ID", 15) // + .text("FOLDER_PATH", "path") // + .text("FOLDER_NAME", "name") // + .text("CLOUD_TYPE", CloudType.LOCAL.name) // + .text("PASSWORD", "password") // + .integer("POSITION", 10) // + .executeOn(db) + + Sql.insertInto("VAULT_ENTITY") // + .integer("_id", 26) // + .integer("FOLDER_CLOUD_ID", 4) // + .text("FOLDER_PATH", "path") // + .text("FOLDER_NAME", "name") // + .text("CLOUD_TYPE", CloudType.LOCAL.name) // + .text("PASSWORD", "password") // + .integer("POSITION", 11) // + .executeOn(db) + + Upgrade9To10().applyTo(db, 9) + + Sql.query("VAULT_ENTITY").executeOn(db).use { + it.moveToFirst() + Assert.assertThat(it.getString(it.getColumnIndex("FOLDER_CLOUD_ID")), CoreMatchers.`is`("15")) + it.moveToNext() + Assert.assertThat(it.getString(it.getColumnIndex("FOLDER_CLOUD_ID")), CoreMatchers.nullValue()) + } + + } + } diff --git a/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrades.java b/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrades.java index 3b6ef827..638c5c76 100644 --- a/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrades.java +++ b/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrades.java @@ -27,7 +27,8 @@ class DatabaseUpgrades { Upgrade5To6 upgrade5To6, // Upgrade6To7 upgrade6To7, // Upgrade7To8 upgrade7To8, // - Upgrade8To9 upgrade8To9) { + Upgrade8To9 upgrade8To9, // + Upgrade9To10 upgrade9To10) { availableUpgrades = defineUpgrades( // upgrade0To1, // @@ -38,7 +39,8 @@ class DatabaseUpgrades { upgrade5To6, // upgrade6To7, // upgrade7To8, // - upgrade8To9); + upgrade8To9, // + upgrade9To10); } private static Comparator reverseOrder() { diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt new file mode 100644 index 00000000..7446aaa1 --- /dev/null +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt @@ -0,0 +1,30 @@ +package org.cryptomator.data.db + +import org.cryptomator.domain.CloudType +import org.greenrobot.greendao.database.Database +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +internal class Upgrade9To10 @Inject constructor() : DatabaseUpgrade(9, 10) { + + override fun internalApplyTo(db: Database, origin: Int) { + db.beginTransaction() + + try { + Sql.update("VAULT_ENTITY") + .set("FOLDER_CLOUD_ID", Sql.toString(null)) + .where("FOLDER_CLOUD_ID", Sql.eq(4)) + .executeOn(db) + + Sql.deleteFrom("CLOUD_ENTITY") + .where("FOLDER_CLOUD_ID", Sql.eq(4)) + .where("TYPE", Sql.eq(CloudType.LOCAL.name)) + .executeOn(db) + + db.setTransactionSuccessful() + } finally { + db.endTransaction() + } + } +} From f39cc8da7ca2ecbdf0dfd182b0ddf65098a61a72 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 22 Oct 2021 17:51:12 +0200 Subject: [PATCH 08/28] Fix delete local cloud (#251) --- .../java/org/cryptomator/data/db/UpgradeDatabaseTest.kt | 7 +++++++ data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt | 5 ++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt b/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt index c494bc2a..6de195db 100644 --- a/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt +++ b/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt @@ -453,6 +453,10 @@ class UpgradeDatabaseTest { .integer("POSITION", 11) // .executeOn(db) + Sql.query("CLOUD_ENTITY").executeOn(db).use { + Assert.assertThat(it.count, CoreMatchers.`is`(5)) + } + Upgrade9To10().applyTo(db, 9) Sql.query("VAULT_ENTITY").executeOn(db).use { @@ -462,6 +466,9 @@ class UpgradeDatabaseTest { Assert.assertThat(it.getString(it.getColumnIndex("FOLDER_CLOUD_ID")), CoreMatchers.nullValue()) } + Sql.query("CLOUD_ENTITY").executeOn(db).use { + Assert.assertThat(it.count, CoreMatchers.`is`(4)) + } } } diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt index 7446aaa1..1ea5269a 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt @@ -1,6 +1,5 @@ package org.cryptomator.data.db -import org.cryptomator.domain.CloudType import org.greenrobot.greendao.database.Database import javax.inject.Inject import javax.inject.Singleton @@ -18,8 +17,8 @@ internal class Upgrade9To10 @Inject constructor() : DatabaseUpgrade(9, 10) { .executeOn(db) Sql.deleteFrom("CLOUD_ENTITY") - .where("FOLDER_CLOUD_ID", Sql.eq(4)) - .where("TYPE", Sql.eq(CloudType.LOCAL.name)) + .where("_id", Sql.eq(4)) + .where("TYPE", Sql.eq("LOCAL")) .executeOn(db) db.setTransactionSuccessful() From 8b51aa63e3afb99257dc0f3301fa2fea652f2607 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 22 Oct 2021 18:09:20 +0200 Subject: [PATCH 09/28] Update vault list even when the last vault got deleted to show no vaults --- .../cryptomator/presentation/presenter/VaultListPresenter.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt index 3e4ece77..c3dc5d5e 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt @@ -46,7 +46,6 @@ import org.cryptomator.presentation.ui.activity.LicenseCheckActivity import org.cryptomator.presentation.ui.activity.view.VaultListView import org.cryptomator.presentation.ui.dialog.AppIsObscuredInfoDialog import org.cryptomator.presentation.ui.dialog.AskForLockScreenDialog -import org.cryptomator.presentation.ui.dialog.BetaConfirmationDialog import org.cryptomator.presentation.ui.dialog.EnterPasswordDialog import org.cryptomator.presentation.ui.dialog.UpdateAppAvailableDialog import org.cryptomator.presentation.ui.dialog.UpdateAppDialog @@ -272,8 +271,8 @@ class VaultListPresenter @Inject constructor( // view?.showVaultCreationHint() } else { view?.hideVaultCreationHint() - view?.renderVaultList(vaultModels) } + view?.renderVaultList(vaultModels) } }) } From a83af094aa85966dc618be9dd59117289bbfd790 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Sun, 24 Oct 2021 21:18:48 +0200 Subject: [PATCH 10/28] Fix sometimes unable to add a pCloud connection which fixes #368 Problem occurs due to a race condition between onNewIntent and onActivityResult: If the browser is closed and Cryptomator resumed before the redirection call is processed by the intent framework of Android which in return calls the AuthenticatePCloudActivity again in the onNewIntent, it finishes in onActivityResult but should wait until onNewIntent is called to process the OAuth result. --- .../ui/activity/AuthenticatePCloudActivity.kt | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/AuthenticatePCloudActivity.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/AuthenticatePCloudActivity.kt index 0ec79514..59b610ee 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/AuthenticatePCloudActivity.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/AuthenticatePCloudActivity.kt @@ -2,6 +2,7 @@ package org.cryptomator.presentation.ui.activity import android.content.Intent import android.net.Uri +import android.os.Handler import android.widget.Toast import org.cryptomator.generator.Activity import org.cryptomator.presentation.BuildConfig @@ -13,6 +14,12 @@ import timber.log.Timber @Activity class AuthenticatePCloudActivity : BaseActivity() { + private val startAuthenticationRequestCode = 1232 + private val redirectTimeoutAfterAuthenticationAndResumed = 1000L + + private var cancelAuthenticationHandler: Handler = Handler() + private var oAuthResultReceived = false + override fun setupView() { val uri = Uri.parse("https://my.pcloud.com/oauth2/authorize") .buildUpon() @@ -21,18 +28,27 @@ class AuthenticatePCloudActivity : BaseActivity() { .appendQueryParameter("redirect_uri", "pcloudoauth://redirect") .build() - startActivityForResult(Intent(Intent.ACTION_VIEW, uri), 25) + startActivityForResult(Intent(Intent.ACTION_VIEW, uri), startAuthenticationRequestCode) } override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) { super.onActivityResult(requestCode, resultCode, intent) - finish() + if (requestCode == startAuthenticationRequestCode) { + cancelAuthenticationHandler.postDelayed({ + if (!oAuthResultReceived) { + Timber.tag("AuthenticatePCloudActivity").i("Authentication canceled or no redirect received after resuming Cryptomator since 1.5s") + Toast.makeText(context(), R.string.error_authentication_failed, Toast.LENGTH_SHORT).show() + finish() + } + }, redirectTimeoutAfterAuthenticationAndResumed) + } } override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) intent.data?.let { - if(it.host == "redirect" && it.scheme == "pcloudoauth") { + if (it.host == "redirect" && it.scheme == "pcloudoauth") { + oAuthResultReceived = true val parameters = parseUrlFragmentParameters(it) val accessToken = parameters["access_token"] val hostname = parameters["hostname"] @@ -41,10 +57,11 @@ class AuthenticatePCloudActivity : BaseActivity() { result.putExtra(CloudConnectionListPresenter.PCLOUD_OAUTH_AUTH_CODE, accessToken) result.putExtra(CloudConnectionListPresenter.PCLOUD_HOSTNAME, hostname) setResult(android.app.Activity.RESULT_OK, result) - finish() } else { Toast.makeText(this, R.string.error_authentication_failed, Toast.LENGTH_LONG).show() + Timber.tag("AuthenticatePCloudActivity").i("Authentication failed as the access token or hostname is null") } + finish() } else { Timber.tag("AuthenticatePCloudActivity").e("Tried to call activity using a different redirect scheme") } @@ -63,4 +80,9 @@ class AuthenticatePCloudActivity : BaseActivity() { } return emptyMap() } + + override fun onDestroy() { + super.onDestroy() + cancelAuthenticationHandler.removeCallbacksAndMessages(null) + } } From 810a9877ca9b115339df48dcfcacc1afa2a292da Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Wed, 27 Oct 2021 22:59:57 +0200 Subject: [PATCH 11/28] Implement local storage migration by removing them with a hint #251 --- .../data/db/UpgradeDatabaseTest.kt | 13 +++-- .../org/cryptomator/data/db/Upgrade9To10.kt | 29 ++++++++++-- .../presenter/VaultListPresenter.kt | 15 ++++-- .../ui/dialog/AppIsObscuredInfoDialog.kt | 6 +-- .../VaultsRemovedDuringMigrationDialog.kt | 47 +++++++++++++++++++ ...dialog_vaults_removed_during_migration.xml | 19 ++++++++ presentation/src/main/res/values/strings.xml | 7 ++- .../util/SharedPreferencesHandler.kt | 27 +++++++++++ 8 files changed, 144 insertions(+), 19 deletions(-) create mode 100644 presentation/src/main/java/org/cryptomator/presentation/ui/dialog/VaultsRemovedDuringMigrationDialog.kt create mode 100644 presentation/src/main/res/layout/dialog_vaults_removed_during_migration.xml diff --git a/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt b/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt index 6de195db..1e0ad4c0 100644 --- a/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt +++ b/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt @@ -50,7 +50,7 @@ class UpgradeDatabaseTest { Upgrade6To7().applyTo(db, 6) Upgrade7To8().applyTo(db, 7) Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10().applyTo(db, 9) + Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) CloudEntityDao(DaoConfig(db, CloudEntityDao::class.java)).loadAll() VaultEntityDao(DaoConfig(db, VaultEntityDao::class.java)).loadAll() @@ -446,7 +446,7 @@ class UpgradeDatabaseTest { Sql.insertInto("VAULT_ENTITY") // .integer("_id", 26) // .integer("FOLDER_CLOUD_ID", 4) // - .text("FOLDER_PATH", "path") // + .text("FOLDER_PATH", "pathOfVault26") // .text("FOLDER_NAME", "name") // .text("CLOUD_TYPE", CloudType.LOCAL.name) // .text("PASSWORD", "password") // @@ -457,18 +457,17 @@ class UpgradeDatabaseTest { Assert.assertThat(it.count, CoreMatchers.`is`(5)) } - Upgrade9To10().applyTo(db, 9) + Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) Sql.query("VAULT_ENTITY").executeOn(db).use { - it.moveToFirst() - Assert.assertThat(it.getString(it.getColumnIndex("FOLDER_CLOUD_ID")), CoreMatchers.`is`("15")) - it.moveToNext() - Assert.assertThat(it.getString(it.getColumnIndex("FOLDER_CLOUD_ID")), CoreMatchers.nullValue()) + Assert.assertThat(it.count, CoreMatchers.`is`(1)) } Sql.query("CLOUD_ENTITY").executeOn(db).use { Assert.assertThat(it.count, CoreMatchers.`is`(4)) } + + Assert.assertThat(sharedPreferencesHandler.vaultsRemovedDuringMigration(), CoreMatchers.`is`(Pair("LOCAL", arrayListOf("pathOfVault26")))) } } diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt index 1ea5269a..01cf79fa 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt @@ -1,23 +1,42 @@ package org.cryptomator.data.db +import org.cryptomator.domain.CloudType +import org.cryptomator.util.SharedPreferencesHandler import org.greenrobot.greendao.database.Database import javax.inject.Inject import javax.inject.Singleton +import timber.log.Timber @Singleton -internal class Upgrade9To10 @Inject constructor() : DatabaseUpgrade(9, 10) { +internal class Upgrade9To10 @Inject constructor(private val sharedPreferencesHandler: SharedPreferencesHandler) : DatabaseUpgrade(9, 10) { + + private val defaultLocalStorageCloudId = 4L override fun internalApplyTo(db: Database, origin: Int) { db.beginTransaction() try { - Sql.update("VAULT_ENTITY") - .set("FOLDER_CLOUD_ID", Sql.toString(null)) - .where("FOLDER_CLOUD_ID", Sql.eq(4)) + Sql.query("VAULT_ENTITY") + .columns(listOf("FOLDER_PATH")) + .where("FOLDER_CLOUD_ID", Sql.eq(defaultLocalStorageCloudId)) + .executeOn(db).use { + val vaultsToBeRemoved = ArrayList() + while (it.moveToNext()) { + val folderPath = it.getString(it.getColumnIndex("FOLDER_PATH")) + vaultsToBeRemoved.add(folderPath) + } + if (vaultsToBeRemoved.isNotEmpty()) { + sharedPreferencesHandler.vaultsRemovedDuringMigration(Pair(CloudType.LOCAL.name, vaultsToBeRemoved)) + Timber.tag("Upgrade9To10").i("Added %s to the removeDuringMigrations", vaultsToBeRemoved) + } + } + + Sql.deleteFrom("VAULT_ENTITY") + .where("FOLDER_CLOUD_ID", Sql.eq(defaultLocalStorageCloudId)) .executeOn(db) Sql.deleteFrom("CLOUD_ENTITY") - .where("_id", Sql.eq(4)) + .where("_id", Sql.eq(defaultLocalStorageCloudId)) .where("TYPE", Sql.eq("LOCAL")) .executeOn(db) diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt index c3dc5d5e..b5e6d288 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt @@ -12,6 +12,7 @@ import org.cryptomator.data.cloud.crypto.CryptoCloud import org.cryptomator.data.util.NetworkConnectionCheck import org.cryptomator.domain.Cloud import org.cryptomator.domain.CloudFolder +import org.cryptomator.domain.CloudType import org.cryptomator.domain.Vault import org.cryptomator.domain.di.PerView import org.cryptomator.domain.exception.license.LicenseNotValidException @@ -49,6 +50,7 @@ import org.cryptomator.presentation.ui.dialog.AskForLockScreenDialog import org.cryptomator.presentation.ui.dialog.EnterPasswordDialog import org.cryptomator.presentation.ui.dialog.UpdateAppAvailableDialog import org.cryptomator.presentation.ui.dialog.UpdateAppDialog +import org.cryptomator.presentation.ui.dialog.VaultsRemovedDuringMigrationDialog import org.cryptomator.presentation.util.FileUtil import org.cryptomator.presentation.workflow.ActivityResult import org.cryptomator.presentation.workflow.AddExistingVaultWorkflow @@ -103,6 +105,12 @@ class VaultListPresenter @Inject constructor( // sharedPreferencesHandler.setScreenLockDialogAlreadyShown() } + sharedPreferencesHandler.vaultsRemovedDuringMigration()?.let { + val cloudNameString = getString(CloudTypeModel.valueOf(CloudType.valueOf(it.first)).displayNameResource) + view?.showDialog(VaultsRemovedDuringMigrationDialog.newInstance(Pair(cloudNameString, it.second))) + sharedPreferencesHandler.vaultsRemovedDuringMigration(null) + } + checkLicense() } @@ -118,9 +126,10 @@ class VaultListPresenter @Inject constructor( // } override fun onError(e: Throwable) { - var license: String? = "" - if (e is LicenseNotValidException) { - license = e.license + val license = if (e is LicenseNotValidException) { + e.license + } else { + "" } val intent = Intent(context(), LicenseCheckActivity::class.java) intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/AppIsObscuredInfoDialog.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/AppIsObscuredInfoDialog.kt index ccf63d03..e01fde74 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/AppIsObscuredInfoDialog.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/AppIsObscuredInfoDialog.kt @@ -13,10 +13,10 @@ import kotlinx.android.synthetic.main.dialog_app_is_obscured_info.tv_app_is_obsc class AppIsObscuredInfoDialog : BaseDialog() { public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog { - builder // + return builder // .setTitle(R.string.dialog_app_is_obscured_info_title) // - .setNeutralButton(R.string.dialog_app_is_obscured_info_neutral_button) { dialog: DialogInterface, _: Int -> dialog.dismiss() } - return builder.create() + .setNeutralButton(R.string.dialog_app_is_obscured_info_neutral_button) { dialog: DialogInterface, _: Int -> dialog.dismiss() } // + .create() } override fun disableDialogWhenObscured(): Boolean { diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/VaultsRemovedDuringMigrationDialog.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/VaultsRemovedDuringMigrationDialog.kt new file mode 100644 index 00000000..0d8de189 --- /dev/null +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/VaultsRemovedDuringMigrationDialog.kt @@ -0,0 +1,47 @@ +package org.cryptomator.presentation.ui.dialog + +import android.app.Activity +import android.content.DialogInterface +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.DialogFragment +import org.cryptomator.generator.Dialog +import org.cryptomator.presentation.R +import kotlinx.android.synthetic.main.dialog_vaults_removed_during_migration.tv_message + +@Dialog(R.layout.dialog_vaults_removed_during_migration) +class VaultsRemovedDuringMigrationDialog : BaseDialog() { + + public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog { + val vaultsRemovedDuringMigration = requireArguments().getSerializable(VAULTS_REMOVED_ARG) as Pair> + + return builder // + .setTitle(String.format(getString(R.string.dialog_vaults_removed_during_migration_title), vaultsRemovedDuringMigration.first)) // + .setNeutralButton(R.string.dialog_vaults_removed_during_migration_neutral_button) { dialog: DialogInterface, _: Int -> dialog.dismiss() } + .create() + } + + public override fun setupView() { + val vaultsRemovedDuringMigration = requireArguments().getSerializable(VAULTS_REMOVED_ARG) as Pair> + + val vaultsRemovedDuringMigrationString = vaultsRemovedDuringMigration + .second + .map { path -> "* $path" } + .reduce { acc, s -> "$acc\n$s" } + + tv_message.text = String.format(getString(R.string.dialog_vaults_removed_during_migration_hint), vaultsRemovedDuringMigrationString) + } + + companion object { + + private const val VAULTS_REMOVED_ARG = "vaultsRemovedArg" + + fun newInstance(vaultsRemovedDuringMigration: Pair>): DialogFragment { + val args = Bundle() + args.putSerializable(VAULTS_REMOVED_ARG, vaultsRemovedDuringMigration) + val fragment = VaultsRemovedDuringMigrationDialog() + fragment.arguments = args + return fragment + } + } +} diff --git a/presentation/src/main/res/layout/dialog_vaults_removed_during_migration.xml b/presentation/src/main/res/layout/dialog_vaults_removed_during_migration.xml new file mode 100644 index 00000000..db8ac720 --- /dev/null +++ b/presentation/src/main/res/layout/dialog_vaults_removed_during_migration.xml @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index d9312db4..9acb5d10 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -166,7 +166,6 @@ @string/screen_vault_list_vault_action_delete Click here to add locations Server doesn\'t seem to be WebDAV compatible - Custom locations No additional locations available. @@ -416,6 +415,12 @@ Another app is displaying something on top of Cryptomator (e.g., a blue light filter or night mode app). For security reasons, Cryptomator is disabled.\n\nHow to enable Cryptomator Close + + Please re-add vaults for %1s cloud + While migrating to this app version we need to remove the following vaults from the app:\n%2s \n\nThose vaults aren\'t removed from the cloud but only from this app. Sorry for the inconvenience and please re-add these vaults to continue working with them. + @string/dialog_unable_to_share_positive_button + + This setting is a security feature and prevents other apps from tricking users into doing things they do not wan\'t to do.\n\nBy disabling, you confirm that you are aware of the risks. Are you sure you want to remove this cloud connection? diff --git a/util/src/main/java/org/cryptomator/util/SharedPreferencesHandler.kt b/util/src/main/java/org/cryptomator/util/SharedPreferencesHandler.kt index eedee837..ac60155f 100644 --- a/util/src/main/java/org/cryptomator/util/SharedPreferencesHandler.kt +++ b/util/src/main/java/org/cryptomator/util/SharedPreferencesHandler.kt @@ -236,6 +236,31 @@ constructor(context: Context) : SharedPreferences.OnSharedPreferenceChangeListen return defaultSharedPreferences.getBoolean(BACKGROUND_UNLOCK_PREPARATION, true) } + fun vaultsRemovedDuringMigration(vaultsToBeRemoved: Pair>?) { + vaultsToBeRemoved?.let { + val vaultsToBeRemovedString = if (it.second.isNotEmpty()) { + it.second.reduce { acc, s -> "$acc,$s" } + } else { + "" + } + defaultSharedPreferences.setValue(VAULTS_REMOVED_DURING_MIGRATION_TYPE, it.first) + defaultSharedPreferences.setValue(VAULTS_REMOVED_DURING_MIGRATION, vaultsToBeRemovedString) + } ?: run { + defaultSharedPreferences.setValue(VAULTS_REMOVED_DURING_MIGRATION_TYPE, null) + defaultSharedPreferences.setValue(VAULTS_REMOVED_DURING_MIGRATION, null) + } + } + + fun vaultsRemovedDuringMigration(): Pair>? { + val vaultsRemovedDuringMigrationType = defaultSharedPreferences.getString(VAULTS_REMOVED_DURING_MIGRATION_TYPE, null) + val vaultsRemovedDuringMigration = defaultSharedPreferences.getString(VAULTS_REMOVED_DURING_MIGRATION, null) + return if(vaultsRemovedDuringMigrationType != null && vaultsRemovedDuringMigration != null) { + Pair(vaultsRemovedDuringMigrationType, ArrayList(vaultsRemovedDuringMigration.split(','))) + } else { + null + } + } + companion object { private const val SCREEN_LOCK_DIALOG_SHOWN = "askForScreenLockDialogShown" @@ -248,6 +273,8 @@ constructor(context: Context) : SharedPreferences.OnSharedPreferenceChangeListen private const val GLOB_SEARCH = "globSearch" private const val KEEP_UNLOCKED_WHILE_EDITING = "keepUnlockedWhileEditing" private const val BACKGROUND_UNLOCK_PREPARATION = "backgroundUnlockPreparation" + private const val VAULTS_REMOVED_DURING_MIGRATION = "vaultsRemovedDuringMigration" + private const val VAULTS_REMOVED_DURING_MIGRATION_TYPE = "vaultsRemovedDuringMigrationType" const val DEBUG_MODE = "debugMode" const val DISABLE_APP_WHEN_OBSCURED = "disableAppWhenObscured" const val SECURE_SCREEN = "secureScreen" From 5a890b452bdd24ff1a8d9c4308901e8c23a11871 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Thu, 28 Oct 2021 16:20:45 +0200 Subject: [PATCH 12/28] Show dialog when trying to add a vault in the root folder of the cloud Fixes #236 --- .../dialog/VaultIsRootFolderOfCloudDialog.kt | 28 +++++++++++++++++++ .../workflow/AddExistingVaultWorkflow.java | 11 ++++++-- .../dialog_vault_is_root_folder_of_cloud.xml | 19 +++++++++++++ presentation/src/main/res/values/strings.xml | 3 +- 4 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 presentation/src/main/java/org/cryptomator/presentation/ui/dialog/VaultIsRootFolderOfCloudDialog.kt create mode 100644 presentation/src/main/res/layout/dialog_vault_is_root_folder_of_cloud.xml diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/VaultIsRootFolderOfCloudDialog.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/VaultIsRootFolderOfCloudDialog.kt new file mode 100644 index 00000000..1e084f01 --- /dev/null +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/VaultIsRootFolderOfCloudDialog.kt @@ -0,0 +1,28 @@ +package org.cryptomator.presentation.ui.dialog + +import android.app.Activity +import android.content.DialogInterface +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.DialogFragment +import org.cryptomator.generator.Dialog +import org.cryptomator.presentation.R + +@Dialog(R.layout.dialog_vault_is_root_folder_of_cloud) +class VaultIsRootFolderOfCloudDialog : BaseDialog() { + + public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog { + return builder // + .setTitle(R.string.dialog_vault_is_root_folder_of_cloud_title) // + .setNeutralButton(R.string.dialog_vaults_removed_during_migration_neutral_button) { dialog: DialogInterface, _: Int -> dialog.dismiss() } + .create() + } + + override fun setupView() {} + + companion object { + + fun newInstance(): DialogFragment { + return VaultIsRootFolderOfCloudDialog() + } + } +} diff --git a/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java b/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java index 80714856..29b03ba4 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java +++ b/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java @@ -18,6 +18,7 @@ import org.cryptomator.presentation.model.ProgressModel; import org.cryptomator.presentation.model.mappers.CloudModelMapper; import org.cryptomator.presentation.presenter.ChooseCloudServicePresenter; import org.cryptomator.presentation.presenter.VaultListPresenter; +import org.cryptomator.presentation.ui.dialog.VaultIsRootFolderOfCloudDialog; import java.io.Serializable; import java.util.Arrays; @@ -116,9 +117,13 @@ public class AddExistingVaultWorkflow extends Workflow result) { CloudFileModel masterkeyFile = result.getResult(); - state().masterkeyFile = masterkeyFile.toCloudNode(); - presenter().getView().showProgress(ProgressModel.GENERIC); - finish(); + if(!masterkeyFile.getPath().equals("/masterkey.cryptomator") && !masterkeyFile.getPath().equals("/vault.cryptomator")) { + state().masterkeyFile = masterkeyFile.toCloudNode(); + presenter().getView().showProgress(ProgressModel.GENERIC); + finish(); + } else { + presenter().getView().showDialog(VaultIsRootFolderOfCloudDialog.Companion.newInstance()); + } } @Override diff --git a/presentation/src/main/res/layout/dialog_vault_is_root_folder_of_cloud.xml b/presentation/src/main/res/layout/dialog_vault_is_root_folder_of_cloud.xml new file mode 100644 index 00000000..eb831c0a --- /dev/null +++ b/presentation/src/main/res/layout/dialog_vault_is_root_folder_of_cloud.xml @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 9acb5d10..d9e1d827 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -415,11 +415,12 @@ Another app is displaying something on top of Cryptomator (e.g., a blue light filter or night mode app). For security reasons, Cryptomator is disabled.\n\nHow to enable Cryptomator Close - Please re-add vaults for %1s cloud While migrating to this app version we need to remove the following vaults from the app:\n%2s \n\nThose vaults aren\'t removed from the cloud but only from this app. Sorry for the inconvenience and please re-add these vaults to continue working with them. @string/dialog_unable_to_share_positive_button + Vault is root folder of the cloud connection + Create a new cloud connection where you select at least the parent folder of this vault folder as the root directory to add this vault. This setting is a security feature and prevents other apps from tricking users into doing things they do not wan\'t to do.\n\nBy disabling, you confirm that you are aware of the risks. From fda29276034282c0b00b2dba288a1b3821857164 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Thu, 28 Oct 2021 16:24:03 +0200 Subject: [PATCH 13/28] Fix neutral button text of VaultIsRootFolderOfCloudDialog --- .../presentation/ui/dialog/VaultIsRootFolderOfCloudDialog.kt | 2 +- presentation/src/main/res/values/strings.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/VaultIsRootFolderOfCloudDialog.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/VaultIsRootFolderOfCloudDialog.kt index 1e084f01..19b83692 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/VaultIsRootFolderOfCloudDialog.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/VaultIsRootFolderOfCloudDialog.kt @@ -13,7 +13,7 @@ class VaultIsRootFolderOfCloudDialog : BaseDialog() { public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog { return builder // .setTitle(R.string.dialog_vault_is_root_folder_of_cloud_title) // - .setNeutralButton(R.string.dialog_vaults_removed_during_migration_neutral_button) { dialog: DialogInterface, _: Int -> dialog.dismiss() } + .setNeutralButton(R.string.dialog_vault_is_root_folder_of_cloud_neutral_button) { dialog: DialogInterface, _: Int -> dialog.dismiss() } .create() } diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index d9e1d827..af52051e 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -421,6 +421,7 @@ Vault is root folder of the cloud connection Create a new cloud connection where you select at least the parent folder of this vault folder as the root directory to add this vault. + @string/dialog_unable_to_share_positive_button This setting is a security feature and prevents other apps from tricking users into doing things they do not wan\'t to do.\n\nBy disabling, you confirm that you are aware of the risks. From 250d7569178a8fbe21a122e9ca4ad09183a859e4 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Thu, 28 Oct 2021 17:41:19 +0200 Subject: [PATCH 14/28] Ask user to re-grant local storage permission when revoked #251 --- .../local/LocalStorageAccessFrameworkImpl.kt | 2 +- .../presenter/AuthenticateCloudPresenter.kt | 36 ++++++++++++++++--- .../presenter/CloudConnectionListPresenter.kt | 4 --- presentation/src/main/res/values/strings.xml | 2 ++ .../presenter/AuthenticateCloudPresenter.kt | 36 ++++++++++++++++--- 5 files changed, 67 insertions(+), 13 deletions(-) diff --git a/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFrameworkImpl.kt b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFrameworkImpl.kt index 904f8b15..762018bf 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFrameworkImpl.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/local/LocalStorageAccessFrameworkImpl.kt @@ -340,7 +340,7 @@ internal class LocalStorageAccessFrameworkImpl(context: Context, private val mim file.parent.uri?.let { val mimeType = if (mimeTypes.fromFilename(file.name) == null) MimeType.APPLICATION_OCTET_STREAM else mimeTypes.fromFilename(file.name) try { - DocumentsContract.createDocument(contentResolver(), it, mimeType.toString(), file.name) // FIXME + DocumentsContract.createDocument(contentResolver(), it, mimeType.toString(), file.name) } catch (e: FileNotFoundException) { null } diff --git a/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt b/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt index 07bce89b..eac080bf 100644 --- a/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt +++ b/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt @@ -1,6 +1,9 @@ package org.cryptomator.presentation.presenter import android.accounts.AccountManager +import android.content.Intent +import android.content.Intent.ACTION_OPEN_DOCUMENT_TREE +import android.provider.DocumentsContract import android.widget.Toast import com.dropbox.core.android.Auth import org.cryptomator.data.cloud.onedrive.OnedriveClientFactory @@ -432,6 +435,7 @@ class AuthenticateCloudPresenter @Inject constructor( // private inner class LocalStorageAuthStrategy : AuthStrategy { private var authenticationStarted = false + override fun supports(cloud: CloudModel): Boolean { return cloud.cloudType() == CloudTypeModel.LOCAL } @@ -444,19 +448,43 @@ class AuthenticateCloudPresenter @Inject constructor( // private fun startAuthentication(cloud: CloudModel) { authenticationStarted = true + + val uri = (cloud as LocalStorageModel).uri() + val permissions = context().contentResolver.persistedUriPermissions for (permission in permissions) { - if (permission.uri.toString() == (cloud as LocalStorageModel).uri()) { + if (permission.uri.toString() == uri) { succeedAuthenticationWith(cloud.toCloud()) } } - // FIXME think about how to re-request permission - // FIXME change in the FOSS variant too - failAuthentication(PermissionNotGrantedException(R.string.permission_snackbar_auth_local_vault)) + Timber.tag("AuthicateCloudPrester").e("Permission revoked, ask to re-pick location") + + Toast.makeText(context(), getString(R.string.permission_revoked_re_request_permission), Toast.LENGTH_LONG).show() + + val openDocumentTree = Intent(ACTION_OPEN_DOCUMENT_TREE).apply { + putExtra(DocumentsContract.EXTRA_INITIAL_URI, uri) + } + + requestActivityResult(ActivityResultCallbacks.rePickedLocalStorageLocation(cloud), openDocumentTree) } } + @Callback + fun rePickedLocalStorageLocation(result: ActivityResult, cloud: LocalStorageModel) { + val rootTreeUriOfLocalStorage = result.intent().data + rootTreeUriOfLocalStorage?.let { + context() // + .contentResolver // + .takePersistableUriPermission( // + it, // + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ) + } + Timber.tag("AuthicateCloudPrester").e("Permission granted again") + succeedAuthenticationWith(cloud.toCloud()) + } + private fun encrypt(password: String): String { return CredentialCryptor // .getInstance(context()) // diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudConnectionListPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudConnectionListPresenter.kt index ba4ab6a3..0a5bbc51 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudConnectionListPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudConnectionListPresenter.kt @@ -289,10 +289,6 @@ class CloudConnectionListPresenter @Inject constructor( // } } - fun onDefaultLocalCloudConnectionClicked() { - finishWithResult(SELECTED_CLOUD, defaultLocalStorageCloud) - } - companion object { const val SELECTED_CLOUD = "selectedCloudConnection" diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index af52051e..8ed2c79e 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -61,6 +61,8 @@ Cryptomator needs storage access to upload files Cryptomator needs storage access to share files + Cryptomator has lost permission to access this location. Please select this folder again to restore the permission. + Settings Search Previous diff --git a/presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt b/presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt index f542dd4d..7e12859b 100644 --- a/presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt +++ b/presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt @@ -2,6 +2,9 @@ package org.cryptomator.presentation.presenter import android.accounts.AccountManager import android.content.ActivityNotFoundException +import android.content.Intent +import android.content.Intent.ACTION_OPEN_DOCUMENT_TREE +import android.provider.DocumentsContract import android.widget.Toast import com.dropbox.core.android.Auth import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential @@ -478,6 +481,7 @@ class AuthenticateCloudPresenter @Inject constructor( // private inner class LocalStorageAuthStrategy : AuthStrategy { private var authenticationStarted = false + override fun supports(cloud: CloudModel): Boolean { return cloud.cloudType() == CloudTypeModel.LOCAL } @@ -490,19 +494,43 @@ class AuthenticateCloudPresenter @Inject constructor( // private fun startAuthentication(cloud: CloudModel) { authenticationStarted = true + + val uri = (cloud as LocalStorageModel).uri() + val permissions = context().contentResolver.persistedUriPermissions for (permission in permissions) { - if (permission.uri.toString() == (cloud as LocalStorageModel).uri()) { + if (permission.uri.toString() == uri) { succeedAuthenticationWith(cloud.toCloud()) } } - // FIXME think about how to re-request permission - // FIXME change in the FOSS variant too - failAuthentication(PermissionNotGrantedException(R.string.permission_snackbar_auth_local_vault)) + Timber.tag("AuthicateCloudPrester").e("Permission revoked, ask to re-pick location") + + Toast.makeText(context(), getString(R.string.permission_revoked_re_request_permission), Toast.LENGTH_LONG).show() + + val openDocumentTree = Intent(ACTION_OPEN_DOCUMENT_TREE).apply { + putExtra(DocumentsContract.EXTRA_INITIAL_URI, uri) + } + + requestActivityResult(ActivityResultCallbacks.rePickedLocalStorageLocation(cloud), openDocumentTree) } } + @Callback + fun rePickedLocalStorageLocation(result: ActivityResult, cloud: LocalStorageModel) { + val rootTreeUriOfLocalStorage = result.intent().data + rootTreeUriOfLocalStorage?.let { + context() // + .contentResolver // + .takePersistableUriPermission( // + it, // + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ) + } + Timber.tag("AuthicateCloudPrester").e("Permission granted again") + succeedAuthenticationWith(cloud.toCloud()) + } + private fun encrypt(password: String): String { return CredentialCryptor // .getInstance(context()) // From 599f58972b33f3f198e4f0f893a51bbdb9668a6e Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Thu, 28 Oct 2021 21:07:56 +0200 Subject: [PATCH 15/28] Update dependencies --- buildsystem/dependencies.gradle | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/buildsystem/dependencies.gradle b/buildsystem/dependencies.gradle index 3d4338a5..c18d9e0f 100644 --- a/buildsystem/dependencies.gradle +++ b/buildsystem/dependencies.gradle @@ -29,7 +29,7 @@ ext { rxAndroidVersion = '2.1.1' rxBindingVersion = '2.2.0' - daggerVersion = '2.39' + daggerVersion = '2.40' gsonVersion = '2.8.8' @@ -52,7 +52,7 @@ ext { // cloud provider libs cryptolibVersion = '2.0.2' - dropboxVersion = '4.0.1' + dropboxVersion = '5.0.0' googleApiServicesVersion = 'v3-rev20210919-1.32.1' googlePlayServicesVersion = '19.2.0' @@ -65,7 +65,7 @@ ext { msgraphVersion = '2.10.0' - minIoVersion = '8.3.0' + minIoVersion = '8.3.3' staxVersion = '1.2.0' // needed for minIO commonsCodecVersion = '1.15' @@ -76,8 +76,8 @@ ext { jUnitVersion = '5.8.1' assertJVersion = '1.7.1' - mockitoVersion = '3.12.4' - mockitoKotlinVersion = '3.2.0' + mockitoVersion = '4.0.0' + mockitoKotlinVersion = '4.0.0' hamcrestVersion = '1.3' dexmakerVersion = '1.0' espressoVersion = '3.4.0' From c2b9d22fdd377a4b1423b5afcd06ff00e0333f7b Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 29 Oct 2021 11:47:11 +0200 Subject: [PATCH 16/28] Bump to versin 1.6.3-beta1 [ci skip] --- .idea/runConfigurations.xml | 13 ------------- build.gradle | 2 +- 2 files changed, 1 insertion(+), 14 deletions(-) delete mode 100755 .idea/runConfigurations.xml diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100755 index e497da99..00000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/build.gradle b/build.gradle index d8caf75d..0d0ce338 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ allprojects { ext { androidApplicationId = 'org.cryptomator' androidVersionCode = getVersionCode() - androidVersionName = '1.6.3-SNAPSHOT' + androidVersionName = '1.6.3-beta1' } repositories { mavenCentral() From 6e1124d6b7b7a8b96466ee064978784d1824ee8b Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 29 Oct 2021 12:03:23 +0200 Subject: [PATCH 17/28] Update release notes [ci skip] --- fastlane/metadata/android/de-DE/changelogs/default.txt | 4 +++- fastlane/metadata/android/en-US/changelogs/default.txt | 4 +++- fastlane/release-notes.html | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/fastlane/metadata/android/de-DE/changelogs/default.txt b/fastlane/metadata/android/de-DE/changelogs/default.txt index f686002a..5cd4a8e1 100644 --- a/fastlane/metadata/android/de-DE/changelogs/default.txt +++ b/fastlane/metadata/android/de-DE/changelogs/default.txt @@ -1 +1,3 @@ -- pCloud-Verbindung können wieder auf allen Geräten hinzugefügt werden \ No newline at end of file +- Fotos können sofort hochgeladen werden, wenn der automatische Fotoupload aktiviert und der Tresor entsperrt ist +- Wenn der Tresor-Order der Stammordner der Cloud ist, kann dieser nun nicht mehr hinzugefügt werden +- Überarbeitung des Zugriffs auf den lokalen Speicher \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/default.txt b/fastlane/metadata/android/en-US/changelogs/default.txt index 6f60085e..2598a701 100644 --- a/fastlane/metadata/android/en-US/changelogs/default.txt +++ b/fastlane/metadata/android/en-US/changelogs/default.txt @@ -1 +1,3 @@ -- Fixed add pCloud connection on some devices \ No newline at end of file +- Upload photos instantly when auto photo upload is enabled and vault is unlocked +- Fixed vault name is empty when it is the root folder of the cloud +- Refactor access to local storage \ No newline at end of file diff --git a/fastlane/release-notes.html b/fastlane/release-notes.html index 0761a6a1..af2c6b90 100644 --- a/fastlane/release-notes.html +++ b/fastlane/release-notes.html @@ -1,3 +1,5 @@
    -
  • Fixed add pCloud connection on some devices
  • +
  • Upload photos instantly when auto photo upload is enabled and vault is unlocked
  • +
  • Fixed vault name is empty when it is the root folder of the cloud
  • +
  • Refactor access to local storage
\ No newline at end of file From b56a63252572c826f3fbb85c2c4abf06cb95aad5 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 29 Oct 2021 12:22:21 +0200 Subject: [PATCH 18/28] New Crowdin updates --- .../src/main/res/values-ar-rSA/strings.xml | 1 - .../src/main/res/values-ca-rES/strings.xml | 2 - .../src/main/res/values-cs-rCZ/strings.xml | 2 - .../src/main/res/values-de-rDE/strings.xml | 9 +- .../src/main/res/values-el-rGR/strings.xml | 7 +- .../src/main/res/values-es-rES/strings.xml | 7 +- .../src/main/res/values-fil-rPH/strings.xml | 260 ++++++++++++++++++ .../src/main/res/values-fr-rFR/strings.xml | 15 +- .../src/main/res/values-hu-rHU/strings.xml | 2 - .../src/main/res/values-it-rIT/strings.xml | 4 +- .../src/main/res/values-ja-rJP/strings.xml | 2 - .../src/main/res/values-ko-rKR/strings.xml | 1 - .../src/main/res/values-mk-rMK/strings.xml | 37 +++ .../src/main/res/values-nl-rNL/strings.xml | 5 +- .../src/main/res/values-pl-rPL/strings.xml | 7 +- .../src/main/res/values-pt-rBR/strings.xml | 2 - .../src/main/res/values-ro-rRO/strings.xml | 2 - .../src/main/res/values-ru-rRU/strings.xml | 7 +- .../src/main/res/values-sk-rSK/strings.xml | 7 +- .../src/main/res/values-sv-rSE/strings.xml | 2 - .../src/main/res/values-tr-rTR/strings.xml | 2 - .../src/main/res/values-zh-rCN/strings.xml | 23 +- .../src/main/res/values-zh-rTW/strings.xml | 42 ++- 23 files changed, 399 insertions(+), 49 deletions(-) create mode 100644 presentation/src/main/res/values-fil-rPH/strings.xml create mode 100644 presentation/src/main/res/values-mk-rMK/strings.xml diff --git a/presentation/src/main/res/values-ar-rSA/strings.xml b/presentation/src/main/res/values-ar-rSA/strings.xml index 6df0e467..33799525 100644 --- a/presentation/src/main/res/values-ar-rSA/strings.xml +++ b/presentation/src/main/res/values-ar-rSA/strings.xml @@ -105,7 +105,6 @@ اختر المسار انقر هنا لإضافة مسار لا يبدو أن الخادم متوافق مع WebDAV - ذاكرة التخزين الافتراضية لا توجد مواقع إضافية متاحة. الرابط diff --git a/presentation/src/main/res/values-ca-rES/strings.xml b/presentation/src/main/res/values-ca-rES/strings.xml index 31c4acd5..a32500da 100644 --- a/presentation/src/main/res/values-ca-rES/strings.xml +++ b/presentation/src/main/res/values-ca-rES/strings.xml @@ -108,8 +108,6 @@ Trieu una destinació Feu clic aquí per afegir destinacions El servidor no sembla que sigui compatible amb WebDAV - Ubicacions personalitzades - Emmagatzematge predefinit No hi ha ubicacions addicionals disponibles. URL diff --git a/presentation/src/main/res/values-cs-rCZ/strings.xml b/presentation/src/main/res/values-cs-rCZ/strings.xml index 2d816fa9..af019c9d 100644 --- a/presentation/src/main/res/values-cs-rCZ/strings.xml +++ b/presentation/src/main/res/values-cs-rCZ/strings.xml @@ -112,8 +112,6 @@ Vyberte umístění Klikněte zde pro přidání umístění Server není kompatibilní s WebDAV - Vlastní umístění - Výchozí úložiště Nejsou k dispozici žádná další umístění. URL diff --git a/presentation/src/main/res/values-de-rDE/strings.xml b/presentation/src/main/res/values-de-rDE/strings.xml index 92223621..4b53c23f 100644 --- a/presentation/src/main/res/values-de-rDE/strings.xml +++ b/presentation/src/main/res/values-de-rDE/strings.xml @@ -16,7 +16,7 @@ Cloud existiert bereits. Installiere eine App, die diesen Dateityp unterstützt. Server nicht gefunden. - Bitte öffne die Einstellungen und setze den Sperrbildschirm von Hand + Bitte öffne die Einstellungen Deines Geräts und stell die Bildschirmsperre von Hand ein Export fehlgeschlagen. Versuche, Sonderzeichen aus den Dateinamen zu entfernen und erneut zu exportieren. Keine Sonderzeichen möglich. Dateinamen können keine Sonderzeichen enthalten. @@ -41,6 +41,7 @@ Zum Exportieren von Dateien benötigt Cryptomator Speicherzugriff Zum Hochladen von Dateien benötigt Cryptomator Speicherzugriff Zum Teilen von Dateien benötigt Cryptomator Speicherzugriff + Cryptomator hat die Berechtigung zum Zugriff auf diesen Ort verloren. Bitte wähle diesen Ordner erneut aus, um die Berechtigung wiederherzustellen. Einstellungen Suche Vorheriges @@ -115,8 +116,6 @@ Ort auswählen Hier klicken um einen neuen Ort hinzufügen Server scheint nicht WebDAV-kompatibel zu sein - Benutzerdefinierte Orte - Standard-Speicher Weitere Orte sind nicht verfügbar. URL @@ -290,6 +289,10 @@ App wird verdeckt Eine App zeigt etwas über Cryptomator an (z.B. ein Blaulichtfilter oder eine Nachtmodus-App). Aus Sicherheitsgründen ist Cryptomator deaktiviert.\n\nWie Cryptomator aktiviert werden kann Schließen + Bitte Tresore für die %1s-Cloud erneut hinzufügen + Während der Migration auf diese App-Version müssen wir folgende Tresore aus der App entfernen:\n%2s \n\nDiese Tresore werden nicht aus der Cloud entfernt, sondern nur aus dieser App. Entschuldigung für die Unannehmlichkeiten. Füge diese Tresore bitte erneut hinzu, um weiter mit ihnen zu arbeiten. + Tresor ist Wurzelverzeichnis der Cloud-Verbindung + Erstelle eine neue Cloud-Verbindung, wo du mindestens den übergeordneten Ordner dieses Tresors als Wurzelverzeichnis auswählst, um diesen Tresor hinzuzufügen. Dies ist eine Sicherheitsfunktion, die andere Anwendungen daran hindert, Nutzer zu ungewollten Aktionen zu verleiten.\n\nDurch Deaktivieren bestätigst du, dass du dir der Risiken bewusst bist. Bist du dir sicher, dass du die Cloud-Verbindung entfernen möchtest? Dieser Vorgang wird die Cloud-Verbindung und alle zugehörigen Tresore löschen. diff --git a/presentation/src/main/res/values-el-rGR/strings.xml b/presentation/src/main/res/values-el-rGR/strings.xml index 52c67792..6c1efe0b 100644 --- a/presentation/src/main/res/values-el-rGR/strings.xml +++ b/presentation/src/main/res/values-el-rGR/strings.xml @@ -41,6 +41,7 @@ Το Cryptomator χρειάζεται πρόσβαση στον αποθηκευτικό χώρο για την εξαγωγή αρχείων Το Cryptomator χρειάζεται πρόσβαση στον αποθηκευτικό χώρο για μεταφόρτωση αρχείων Το Cryptomator χρειάζεται πρόσβαση στον αποθηκευτικό χώρο για κοινή χρήση αρχείων + Το Cryptomator έχει χάσει την άδεια πρόσβασης σε αυτήν την τοποθεσία. Παρακαλώ επιλέξτε ξανά αυτόν το φάκελο για να επαναφέρετε το δικαίωμα. Ρυθμίσεις Αναζήτηση Προηγούμενο @@ -115,8 +116,6 @@ Επιλέξτε μια τοποθεσία Κάντε κλικ εδώ για να προσθέσετε τοποθεσίες Ο διακομιστής δεν φαίνεται να είναι συμβατός με WebDAV - Προσαρμοσμένες τοποθεσίες - Προεπιλεγμένος χώρος αποθήκευσης Δεν υπάρχουν διαθέσιμες πρόσθετες τοποθεσίες. URL @@ -290,6 +289,10 @@ Η εφαρμογή αποκρύπτεται Μια άλλη εφαρμογή εμφανίζει κάτι πάνω από το Cryptomator (π.χ. ένα φίλτρο μπλε φωτός ή μια εφαρμογή νυχτερινής λειτουργίας). Για λόγους ασφαλείας, το Cryptomator είναι απενεργοποιημένο.\n\nΠώς να ενεργοποιήσετε το Cryptomator Κλείσιμο + Παρακαλώ προσθέστε ξανά κρύπτες για %1s cloud + Κατά τη μετάβαση σε αυτήν την έκδοση της εφαρμογής, πρέπει να αφαιρέσουμε τις ακόλουθες κρύπτες από την εφαρμογή:\n%2s\n\nΑυτές οι κρύπτες δεν έχουν αφαιρεθεί από το cloud αλλά μόνο από αυτήν την εφαρμογή. Λυπούμαστε για την ταλαιπωρία και παρακαλούμε προσθέστε ξανά αυτές τις κρύπτες για να συνεχίσετε να εργάζεστε μαζί τους. + Η κρύπτη είναι ριζικός φάκελος της σύνδεσης cloud + Δημιουργήστε μια νέα σύνδεση στο cloud όπου επιλέγετε τουλάχιστον τον γονικό φάκελο αυτού του φακέλου κρύπτης ως ριζικό κατάλογο για να προσθέσετε αυτή την κρύπτη. Αυτή η ρύθμιση είναι μια λειτουργία ασφαλείας και αποτρέπει άλλες εφαρμογές από το να ξεγελάσουν τους χρήστες να κάνουν πράγματα που δεν θέλουν να κάνουν.\n\nΜε την απενεργοποίηση, επιβεβαιώνετε ότι γνωρίζετε τους κινδύνους. Είστε βέβαιοι ότι θέλετε να καταργήσετε αυτή τη σύνδεση cloud; Αυτή η ενέργεια θα αφαιρέσει τη σύνδεση στο cloud και όλες οι κρύπτες αυτού του cloud. diff --git a/presentation/src/main/res/values-es-rES/strings.xml b/presentation/src/main/res/values-es-rES/strings.xml index 16143f6c..d11569c2 100644 --- a/presentation/src/main/res/values-es-rES/strings.xml +++ b/presentation/src/main/res/values-es-rES/strings.xml @@ -41,6 +41,7 @@ Cryptomator necesita acceso al almacenamiento para exportar archivos. Cryptomator necesita acceso al almacenamiento para subir archivos. Cryptomator necesita acceso al almacenamiento para compartir archivos. + Cryptomator ha perdido permiso para acceder a esta ubicación. Seleccione esta carpeta de nuevo para restaurar el permiso. Configuración Buscar Anterior @@ -115,8 +116,6 @@ Elegir ubicación Haz clic aquí para añadir ubicaciones El servidor no parece ser compatible con WebDAV - Ubicaciones personalizadas - Almacenamiento predeterminado No hay ubicaciones extra disponibles. URL @@ -290,6 +289,10 @@ La aplicación está oscura Otra aplicación muestra algo en la parte superior de Cryptomator (por ejemplo, un filtro de luz azul o una aplicación en modo nocturno). Por razones de seguridad, Cryptomator está desactivado.\n\nCómo activar Cryptomator Cerrar + Vuelva a añadir bóvedas para la nube %1s + Mientras se migra a esta versión de la aplicación, necesitamos eliminar las siguientes bóvedas de la aplicación:\n%2s \n\nEsas bóvedas no se eliminan de la nube sino sólo de esta aplicación. Lamentamos las molestias, por favor añada de nuevo estas bóvedas para seguir trabajando con ellas. + La bóveda es la carpeta raíz de la conexión a la nube + Crear una conexión nueva en la nube donde seleccione al menos la carpeta padre de esta carpeta de bóveda como directorio raíz para añadir esta bóveda. Esta opción es una función de seguridad y evita que otras aplicaciones engañen a los usuarios para que hagan cosas que no quieren hacer.\n\nAl desactivar, confirma que es consciente de los riesgos. \"¿Estás seguro de que quieres eliminar esta conexión de nube? Esta acción eliminará la conexión de nube y todas las cajas fuertes de esta nube. diff --git a/presentation/src/main/res/values-fil-rPH/strings.xml b/presentation/src/main/res/values-fil-rPH/strings.xml new file mode 100644 index 00000000..4c5ee108 --- /dev/null +++ b/presentation/src/main/res/values-fil-rPH/strings.xml @@ -0,0 +1,260 @@ + + + + I-encrypt + + Nagkaroon ng error + Bigo ang pagpapatunay + Bigo ang pagtutunay, maaaring maglogin gamit ang %1$s + Walang koneksyon sa network + Mali ang password + Hindi suportado ang vault na ito. Ang vault na ito ay ginawa gamit ang ibang bersyon ng Cryptomator. + Umiiral na ang vault na ito. + Ang file na ito ay hindi pa umiiral. + Naisara na ang vault. + Magdownload ng app na kayang buksan ang file na ito. + Hindi mahanap ang server. + Maaaring buksan ang device settings at sariling itakda ang screen lock + Hindi maaring maglagay ng espesyal na mga karakter. + Hindi maaaring lagyan ng espesyal na karakter ang pangalan ng file. + Hindi maaaring lagyan ng espesyal na karakter ang pangalan ng file. + Hindi naka-install ang Google Play Services + Kinansela ang biometric authentication + Hindi matagpuan ang bucket na ito + Hindi pa suportado ang custom Masterkey location + + + Local storage + + + Settings + Hanapin + Nakaraan + Sunod + A - Z + Z - A + Bago muna + Luma muna + Pinakamalaki muna + Pinakamaliit muna + + + Idagdag sa Cryptomator + Gumawa ng bagong vault + Magdagdag ng umiiral na vault + Tanggalin + Pindutin dito para gumawa ng bagong vault + Matagumpay na napalitan ang password + + Vault + Piliin ang masterkey file + Ilagay dito + Pangalan ng vault: %1$s + Ibahagi kay + Pumili ng destinasyon + Pumili + Walang maibabahagi + Idagdag sa %1$s + Gumawa ng folder + Gumawa ng text file + I-upload ang mga files + Files + Na-export na ang file + Na-export na ang mga files + Ibahagi + Baguhin ang pangalan + I-edit + I-export + Burahin + Buksan gamit ang … + %1$d ang nakapili + Piliin + Piliin lahat + I-refresh + Walang koneksyon + + + files + Natatangi dapat ang pangalan ng mga files, maaari lamang na palitan ang mga may kapareho. + I-save ang lokasyon + I-save + + + Piliin ang location + Pindutin dito upang magdagdag ng lugar + + URL + Username + Password + Kumonekta + Hindi maaaring walang laman ang URL. + Hindi tama ang URL. + Hindi maaaring walang laman ang username. + + Rehiyon + Hindi maaaring walang laman ang bucket + Hindi maaaring walang laman ang endpoint o ang rehiyon + + Hindi maaaring walang pangalan ang vault. + Pangalan ng Vault + Gumawa + + Itakda ang password + Hindi nagtugma ang bagong password sa ni-retype na password. + Tapos na + IMPORTANTE: Walang paraan para maisalba ang iyong datos kapag nakalimutan ang iyong password. + Muling ilagay ang password + Masyadong mahina para gumawa ng vault + Mahina + Patas + Malakas + Higit na malakas + + Pangkalahatan + Cloud services + Biometric authentication + Hanapin + I-lock pagkatapos ng + Kapag ang screen ay disabled + Pumili ng vault pang upload + I-activate + Sundan kami sa Twitter + I-like kami sa Facebook + Ligal + Mga Lisensya + Suporta + Humingi ng tulong + Debug mode + Ipadala ang log file + Mga pahiwatig ng seguridad + Bersyon + Mga advanced na setting + Pabilisin ang pag-unlock + + + + + + Kanselahin + I-unlock + Bagong Password + Palitan ang password + Hindi maaaring walang laman ang lumang password field. + Hindi maaaring walang laman ang bagong password field. + Hindi nagtugma ang bagong password sa ni-retype na password. + + Tanggalin + Mayroon na ng file na ito + Palitan + Umiiral na ang file na may pangalang \'%1$s\'. + Laktawan ang umiiral + Palitan lahat + Palitan ang umiiral + Palitan + Umiiral na ang file na may pangalang \'%1$s\'. Nais mo bang palitan ito? + Ang lahat ng files ay umiiral na. Nais mo bang palitan ang mga ito? + Palitan ang file? + Palitan ang mga file? + OK + Gumawa ng bagong vault + Mag-download ng app na kayang buksan ang file na ito o nais mo bang i-save sa iyong device? + Palitan ang pangalan ng vault + Palitan ang pangalan ng folder + Palitan ang pangalan ng file + Mayroon kang hindi na i-save na pagbabago + Ibaliwala + Sigurado ka ba na nais mong alisin ang vault? + Ang aksyon na ito ay aalisin lamang ang vault sa listahan at hindi ito buburahin. + Pakihintay… + Ineencrypt… + Dinedecrypt… + I-lock + Hindi wasto ang SSL certificate + Hindi wasto ang SSL certificate. Nais mo paring pagkatiwalaan? + Mga detalye + Maaaring panganib ito sa seguridad. Alam ko ang ginagawa ko. + Ang pag-gamit ng HTTP ay hindi ligtas. Kung alam mo ang mga panganib, maaari kang tumuloy gamit ang HTTP. + Gawing HTTPS + Gamiting ang HTTPS? + Atensyon + I-enable + Ang setting na ito ay isang security feature at pinipigilan ang ibang mga apps sa lokohin ang mga gumagamit na gawin ang mga hindi nila gustong gawin.\n\nSa pag-alis nito, kinukumpirma mo na alam mo ang mga panganib. + Atensyon + Isara + Sigurado ka bang gusto mong tanggalin itong cloud connection? + Sigurado ka bang gusto mong burahin ang mga ito? + Sigurado ka bang gusto mong burahin ang file na ito? + Buburahin nito ang lahat ng laman ng folder. Sigurado ka ba na gusto mong burahin ang folder na ito? + Ang biometric authentication feature ay na deactivate na + Dahil wala nang bisa ang susi na ito, deactivated na ang biometric authentication feature. Upang paganahin muli, buksan ang settings ng Cryptomator. + Magbigay ng wastong lisensya + Natuklasan namin na ang nakainstall mong Cryptomator ay hind nanggaling sa Google Play Store. Maaari lamang na magbigay ng wastong lisensya na mabibili sa https://cryptomator.org/android/ + Ang lisensyang binigay ay hindi wasto. Siguraduhing tama ang iyong pagkakalagay. + I-sara + Salamat %1$s sa pagbigay ng wastong lisensya. + I-update ngayon + Mamaya + Ang folder na ito ay isang symbolic link + Hindi maaaring puntahan ang symbolic link na ito + Bumalik + + + + Zero kB + bytes + kB + MB + GB + TB + + segundo + segundo + minuto + minuto + oras + oras + araw + araw + linggo + linggo + buwan + buwan + taon + taon + + Biometric login + Mag-log in gamit ang iyong biometric credential + Gamitin ang vault password + + Vaults na na-unlock: %1$d + Autolock in %1$s + I-lock lahat + Ikansela ang pag-upload + Uploading %1d/%2d + Cache + Kabuuang laki ng cache + Linisin ang Cache + Ang mga pagbabago ay makikita pagkatapos ng pag-restart ng app + + 1 minuto + 2 minuto + 5 minuto + 10 minuto + Hindi kailanman + + 50 MB + 100 MB + 250 MB + 500 MB + 1 GB + 5 GB + + Estilo + Awtomatico (sundan ang system) + Light + Dark + + Isang beses sa isang araw + Isang beses sa isang linggo + Isang beses sa isang buwan + diff --git a/presentation/src/main/res/values-fr-rFR/strings.xml b/presentation/src/main/res/values-fr-rFR/strings.xml index 61ff0e1e..85bcb093 100644 --- a/presentation/src/main/res/values-fr-rFR/strings.xml +++ b/presentation/src/main/res/values-fr-rFR/strings.xml @@ -16,6 +16,7 @@ Cloud existant. Veuillez télécharger une application qui peut ouvrir ce fichier. Serveur introuvable. + Veuillez ouvrir les paramètres de votre appareil et régler le verrouillage de l\'écran à la main L\'exportation a échoué. Essayez de supprimer les caractères spéciaux des noms de fichiers et d\'exporter à nouveau. Ne peut pas contenir de caractères spéciaux. Les noms de fichiers ne peuvent pas contenir de caractères spéciaux. @@ -23,7 +24,11 @@ La vérification de la mise à jour a échoué. Une erreur générale s\'est produite. La vérification de la mise à jour a échoué. Le hachage calculé ne correspond pas au fichier téléchargé La vérification de la mise à jour a échoué. Pas de connexion Internet. + Echec lors du déchiffrement du mot de passe WebDAV, veuillez l\'ajouter une nouvelle fois dans les paramètres + Les services Google Play ne sont pas installés Authentification biométrique avortée + La version spécifiée dans %1$s est différente de %2$s + %1$s ne correspond pas à ce %2$s Erreur générale lors du chargement de la configuration du coffre Le fichier local n\'est plus présent après le retour à Cryptomator. Les éventuels modifications ne peuvent être propagées au nuage. Aucun compartiment de ce type @@ -36,6 +41,7 @@ Cryptomator a besoin de l\'accès au stockage pour exporter des fichiers Cryptomateur a besoin de l\'accès au stockage pour téléverser des fichiers Cryptomator a besoin de l\'accès au stockage pour partager des fichiers + Cryptomator n\'a plus accès à cet emplacement. Merci de resélectionner ce répertoire pour restaurer les droits d\'accès. Paramètres Rechercher Précédent @@ -110,8 +116,6 @@ Choisissez l\'emplacement Cliquez ici pour ajouter des emplacements Le serveur ne semble pas compatible avec WebDAV - Emplacements personnalisés - Stockage par défaut Aucun emplacement supplémentaire disponible. URL @@ -171,6 +175,8 @@ Choisir un coffre-fort pour le téléversement Activer Capturez les images en arrière-plan et une fois que le coffre-fort sélectionné est déverrouillé, lancez le téléversement + Télécharger instantanément + Télécharger directement si le coffre est déverrouillé Téléverser sur réseau WIFI uniquement Téléversement des vidéos Enregistrer les fichiers téléverser automatiquement dans… @@ -215,6 +221,7 @@ Le nouveau mot de passe ne correspond pas au mot de passe retapé. Coffre-fort %1$s introuvable + Le coffre-fort a été renommé, déplacé ou supprimé. Supprimez ce coffre-fort de la liste et ajoutez-le à nouveau pour continuer. Supprimer maintenant ? Supprimer Le fichier existe déjà Remplacer @@ -282,6 +289,10 @@ \'application est masquée Une autre application affiche quelque chose au-dessus de Cryptomator (par exemple, un filtre de lumière bleue ou une application forçant le mode nuit). Pour des raisons de sécurité, Cryptomator est désactivé.\n\nComment activer Cryptomator Fermer + Veuillez rajouter les coffres pour le cloud %1s + Lors de la migration vers cette version de l\'application, nous devons supprimer les coffres suivants de l\'application :\n%2s \n\nCes coffres ne sont pas retirés du cloud mais seulement de cette application. Désolé pour le désagrément et veuillez rajouter ces coffres pour continuer à les utiliser. + Le coffre est le dossier racine de la connexion cloud + Créez une nouvelle connexion cloud où vous sélectionnerez au moins le dossier parent de ce dossier de coffre comme répertoire racine pour ajouter ce coffre. Ce paramètre est une fonction de sécurité qui empêche les autres applications de tromper les utilisateurs en leur faisant faire des choses qu\'ils ne veulent pas faire.\n\nEn le désactivant, vous confirmez que vous êtes conscients des risques. Êtes-vous sûr de vouloir supprimer cette connexion au cloud? Cette action retirera l\'accès à ce cloud et à tous les coffre-fort de celui-ci. diff --git a/presentation/src/main/res/values-hu-rHU/strings.xml b/presentation/src/main/res/values-hu-rHU/strings.xml index 45ef4920..16168718 100644 --- a/presentation/src/main/res/values-hu-rHU/strings.xml +++ b/presentation/src/main/res/values-hu-rHU/strings.xml @@ -61,8 +61,6 @@ Válasszon helyt Kattintson ide a hely hozzáadásához A kiszolgáló nem tűnik WebDAV kompatibilisnek - Egyedi helyek - Alapértelmezett tároló További helyszínek nem állnak rendelkezésre. ULR diff --git a/presentation/src/main/res/values-it-rIT/strings.xml b/presentation/src/main/res/values-it-rIT/strings.xml index 5430db9c..1c93c374 100644 --- a/presentation/src/main/res/values-it-rIT/strings.xml +++ b/presentation/src/main/res/values-it-rIT/strings.xml @@ -24,6 +24,8 @@ Controllo dell\'aggiornamento non riuscito. Si è verificato un errore generale. Controllo di aggiornamento non riuscito. L\'hash calcolato non corrisponde al file caricato Controllo aggiornamento non riuscito. Nessuna connessione internet. + Impossibile decrittografare la password WebDAV, aggiungere nuovamente nelle impostazioni + Google Play Services non installati Autenticazione biometrica interrotta La versione specificata in %1$s è diversa da %2$s %1$s non corrisponde a questo %2$s @@ -113,8 +115,6 @@ Scegli una posizione Clicca qui per aggiungere posizioni Il server non sembra essere compatibile con WebDAV - Posizioni personalizzate - Archiviazione predefinita Nessuna posizione aggiuntiva disponibile. URL diff --git a/presentation/src/main/res/values-ja-rJP/strings.xml b/presentation/src/main/res/values-ja-rJP/strings.xml index 511dd5b8..fb872a01 100644 --- a/presentation/src/main/res/values-ja-rJP/strings.xml +++ b/presentation/src/main/res/values-ja-rJP/strings.xml @@ -110,8 +110,6 @@ 接続先を選択 ここをタップして場所を追加する サーバーに WebDAV との互換性がありません - その他の保存先 - デフォルトの保存先 追加の利用できる保存先はありません。 URL diff --git a/presentation/src/main/res/values-ko-rKR/strings.xml b/presentation/src/main/res/values-ko-rKR/strings.xml index 2d66a615..b1ce8743 100644 --- a/presentation/src/main/res/values-ko-rKR/strings.xml +++ b/presentation/src/main/res/values-ko-rKR/strings.xml @@ -100,7 +100,6 @@ 클라우드 서비스 위치 선택 - 기본 저장소 URL 사용자명 diff --git a/presentation/src/main/res/values-mk-rMK/strings.xml b/presentation/src/main/res/values-mk-rMK/strings.xml new file mode 100644 index 00000000..0c5cc328 --- /dev/null +++ b/presentation/src/main/res/values-mk-rMK/strings.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/presentation/src/main/res/values-nl-rNL/strings.xml b/presentation/src/main/res/values-nl-rNL/strings.xml index bc6bbad7..892e2819 100644 --- a/presentation/src/main/res/values-nl-rNL/strings.xml +++ b/presentation/src/main/res/values-nl-rNL/strings.xml @@ -41,6 +41,7 @@ Cryptomator heeft toegang tot opslag nodig om bestanden te exporteren Cryptomator heeft toegang tot opslag nodig om bestanden te uploaden Cryptomator heeft toegang tot opslag nodig om bestanden te delen + Cryptomator heeft geen toegang meer tot deze locatie. Selecteer de map opnieuw om de toegangsrechten te herstellen. Instellingen Zoeken Vorige @@ -115,8 +116,6 @@ Kies een locatie Klik hier om locaties toe te voegen Server lijkt niet WebDAV compatibel te zijn - Aangepaste locaties - Standaard opslag Geen extra locaties beschikbaar. URL @@ -290,6 +289,8 @@ App is naar de achtergrond gewezen Een andere app toont iets bovenop Cryptomator (bijv. een blauw lichtfilter of nachtmodus). Om veiligheidsredenen is Cryptomator uitgeschakeld.\n\nHoe kunt u Cryptomator inschakelen Sluiten + Voeg de kluis voor %1\'s cloud opnieuw toe + Kluis is hoofdmap van de cloud-verbinding Deze instelling is een beveiligingsfunctie en voorkomt dat andere apps gebruikers misleiden.\n\nDoor deze instelling uit te schakelen bevestig je dat je bewust bent van de risico\'s. Weet je zeker dat je deze cloud verbinding wilt verwijderen? Deze actie zal de cloud-verbinding en alle kluizen van deze cloud verwijderen. diff --git a/presentation/src/main/res/values-pl-rPL/strings.xml b/presentation/src/main/res/values-pl-rPL/strings.xml index f6e210ce..598e1e47 100644 --- a/presentation/src/main/res/values-pl-rPL/strings.xml +++ b/presentation/src/main/res/values-pl-rPL/strings.xml @@ -41,6 +41,7 @@ Cryptomator potrzebuje dostępu do pamięci masowej do eksportu plików Cryptomator potrzebuje dostępu do pamięci masowej, aby przesłać pliki Cryptomator potrzebuje dostępu do pamięci masowej, aby udostępniać pliki + Cryptomator stracił uprawnienia do dostępu do tej lokalizacji. Wybierz ten katalog ponownie, aby przywrócić uprawnienia. Ustawienia Szukaj Poprzedni @@ -117,8 +118,6 @@ Wybierz lokalizację Kliknij tutaj, aby dodać nową lokalizację Serwer wydaje się być niekompatybilny z WebDAV - Niestandardowe lokalizacje - Pamięć domyślna Brak dodatkowych lokalizacji. URL @@ -292,6 +291,10 @@ Aplikacja jest zasłonięta inną Inna aplikacja jest wyświetlana nad Cryptomatorem (na przykład filtr niebieskiego światła, tryb nocny). Dla twojego bezpieczeństwa Cryptomator jest wyłączony.\n\nJak ponownie włączyć aplikację. Zamknij + Proszę ponownie dodać sejfy dla chmury %1s + Podczas migracji do tej wersji aplikacji musimy usunąć następujące sejfy z aplikacji:\n%2s \n\nTe sejfy nie są usuwane z chmury, ale tylko z tej aplikacji. Przepraszamy za niedogodności. Dodaj ponownie te sejfy, aby dalej z nich korzystać. + Sejf jest głównym folderem w połączonej chmurze + Utwórz nowe połączenie z chmurą, gdzie wybierzesz przynajmniej folder nadrzędny tego sejfu jako główny katalog, aby dodać ten sejf. To ustawienie jest funkcją bezpieczeństwa i uniemożliwia innym aplikacjom oszukiwanie użytkowników do robienia rzeczy, których nie chcą robić.\n\nWyłączając je potwierdzasz, że jesteś świadomy ryzyka. Czy na pewno chcesz usunąć to połączenie z serwerem chmury? Ta akcja usunie połączenie z usługą chmury i wszystkimi sejfami w tej chmurze. diff --git a/presentation/src/main/res/values-pt-rBR/strings.xml b/presentation/src/main/res/values-pt-rBR/strings.xml index eda9c8db..c0f431cb 100644 --- a/presentation/src/main/res/values-pt-rBR/strings.xml +++ b/presentation/src/main/res/values-pt-rBR/strings.xml @@ -115,8 +115,6 @@ Selecionar um local Clique aqui para adicionar locais O servidor não parece ser compatível com WebDAV - Locais personalizados - Armazenamento padrão Não há localizações adicionais disponíveis. URL diff --git a/presentation/src/main/res/values-ro-rRO/strings.xml b/presentation/src/main/res/values-ro-rRO/strings.xml index 4da26b64..68547ab6 100644 --- a/presentation/src/main/res/values-ro-rRO/strings.xml +++ b/presentation/src/main/res/values-ro-rRO/strings.xml @@ -111,8 +111,6 @@ Alegeți o locație Faceți clic aici pentru a adăuga locații Serverul nu pare să fie compatibil cu WebDAV - Locații personalizate - Spațiu de stocare prestabilit Nu există locații suplimentare disponibile. Adresa URL diff --git a/presentation/src/main/res/values-ru-rRU/strings.xml b/presentation/src/main/res/values-ru-rRU/strings.xml index eec15f64..2072069b 100644 --- a/presentation/src/main/res/values-ru-rRU/strings.xml +++ b/presentation/src/main/res/values-ru-rRU/strings.xml @@ -41,6 +41,7 @@ У Cryptomator должен быть доступ к хранилищу для экспорта файлов У Cryptomator должен быть доступ к хранилищу для отправки файлов У Cryptomator должен быть доступ к хранилищу для обмена файлами + У Cryptomator больше нет прав доступа к этому местоположению. Выберите эту папку ещё раз, чтобы восстановить права. Настройки Поиск Назад @@ -117,8 +118,6 @@ Выберите местоположение Нажмите, чтобы добавить места Похоже, сервер не совместим с WebDAV - Другие места - Хранилище по умолчанию Нет дополнительных мест. URL @@ -292,6 +291,10 @@ Приложение скрыто Другое приложение отображает что-то поверх Cryptomator (например синий световой фильтр или ночной режим). В целях безопасности Cryptomator отключён.\n\nКак включить Cryptomator Закрыть + Добавьте хранилища заново для облака %1s + Во время переноса в эту версию приложения необходимо удалить следующие хранилища из приложения:\n%2s \n\nЭти хранилища не удаляются из облака, а только из приложения. Извините за неудобства и добавьте снова эти хранилища, чтобы продолжить работу с ними. + Хранилище - это корневая папка подключения к облаку + Создайте новое облачное соединение, в котором вы выберете по крайней мере родительскую папку этой папки хранилища в качестве корневой папки для добавления этого хранилища. Эта настройка связана с безопасностью, она не позволяет другим приложениям обманом вынуждать пользователей делать то, что им не нужно.\n\nОтключив, вы подтверждаете, что знаете о рисках. Вы действительно хотите удалить это облачное соединение? Это действие удалит облако и все хранилища в нём. diff --git a/presentation/src/main/res/values-sk-rSK/strings.xml b/presentation/src/main/res/values-sk-rSK/strings.xml index b86458a8..887d98b6 100644 --- a/presentation/src/main/res/values-sk-rSK/strings.xml +++ b/presentation/src/main/res/values-sk-rSK/strings.xml @@ -41,6 +41,7 @@ Cryptomator vyžaduje prístup k úložisku pre export súborov Cryptomator vyžaduje prístup k úložisku pre nahratie súborov Cryptomator vyžaduje prístup k úložisku pre zdieľanie súborov + Cryptomator stratil oprávnia k prístupu tejto lokality. Prosím vyberte tento akresár znovu pre obnovenie povoleni. Nastavenia Hľadať Predošlý @@ -117,8 +118,6 @@ Vybrať umiestnenie Kliknite sem pre pridanie umiestnení Server zdá sa byť WebDAV kompatibilný - Vlastné umiestnenia - Predvolené úložisko Ďalšie úložiská nie sú dostupné. URL @@ -292,6 +291,10 @@ Aplikácia je zatmavená Ďalšia aplikácia zobrazuje niečo na vrchu Cryptomator-a (ako napr. modré svetlo alebo nočný režim). Z bezpečnostných dôvodov je Cryptomator zakázaný.\n\nAko povoliť Cryptomator Zavrieť + Prosím zadajte znovu trezory pre %1s cloud + Počas migrácie na túto verziu aplikácie potrebujeme odstrániť nasledujúce trezory z aplikácie:\n%2s \n\n Tieto trezory nebudú odstránené z clodu ale len z tejto aplikácie. Prepáčte za nepohodlie a prosím znovu zadajte trezory pre pokračovanie ich používania. + Trezor je koreňovým adresárom cloudového spojenia + Vytvorte nové cloudové pripojenie kde vyberiete minimálne nadradený adresár tohto trezora ako koreňový adresár pre pridanie tohot trezora. Toto nastavenie je bezpečnostná vlastnosť a zabraňuje ostatným aplikáciám klamať užívateľov robiť veci čo nechcú robiť.\n\nVypnutím súhlasíte s tým žeste si vedomí rizika. Ste si istý že chcete odstrániť toto cloudové pripojenie? Táto akcia odstráni pripojenie cloudu a všetky trezory tohto cloudu. diff --git a/presentation/src/main/res/values-sv-rSE/strings.xml b/presentation/src/main/res/values-sv-rSE/strings.xml index 69211145..f096f3ea 100644 --- a/presentation/src/main/res/values-sv-rSE/strings.xml +++ b/presentation/src/main/res/values-sv-rSE/strings.xml @@ -115,8 +115,6 @@ Välj en plats Klicka här för att lägga till platser Servern verkar inte vara WebDAV-kompatibel - Anpassad plats - Förvald lagring Inga ytterligare platser tillgängliga. URL diff --git a/presentation/src/main/res/values-tr-rTR/strings.xml b/presentation/src/main/res/values-tr-rTR/strings.xml index 459b1b6d..b337552a 100644 --- a/presentation/src/main/res/values-tr-rTR/strings.xml +++ b/presentation/src/main/res/values-tr-rTR/strings.xml @@ -115,8 +115,6 @@ Bir yer seçin Konum eklemek için buraya tıklayın Sunucu WebDAV uyumlu görünmüyor - Özel konumlar - Varsayılan depolama Kullanılabilir ek konum yok. URL diff --git a/presentation/src/main/res/values-zh-rCN/strings.xml b/presentation/src/main/res/values-zh-rCN/strings.xml index 129be34c..2589a2db 100644 --- a/presentation/src/main/res/values-zh-rCN/strings.xml +++ b/presentation/src/main/res/values-zh-rCN/strings.xml @@ -1,11 +1,11 @@ - 加密 + 加密保存 - 出错了 - 验证失败 - 身份验证失败,请通过 %1$s 登录 + 突发一个错误 + 身份授权失败 + 身份验证失败,请使用 %1$s 登录 无网络连接 密码错误 文件(夹)已存在 @@ -41,6 +41,7 @@ Cryptomator 需要存储权限以导出文件 Cryptomator 需要存储权限以上传文件 Cryptomator 需要存储权限以共享文件 + Cryptomator 已失去此位置的访问权限,请重新选择此文件夹以恢复。 设置 搜索 上一个 @@ -54,8 +55,8 @@ 大小 (升序) - 添加到 Cryptomator - 新建保险库 + 添加到加密器 + 添加新保险库 添加现有保险库 删除 点击此处新建一个保险库 @@ -114,8 +115,6 @@ 请选择位置 点击此处添加位置 服务器似乎不兼容 WebDAV - 自定义位置 - 默认存储 无可用其他位置 URL @@ -289,6 +288,10 @@ 应用被遮蔽 另一应用正遮罩在 Cryptomator 之上 (例如蓝色光滤镜或夜间模式应用)。出于安全考虑,Cryptomator 已禁用\n\n如何启用 Cryptomator 关闭 + 请重新添加 %1s 的保险库 + 在进行应用版本迁移前,我们需要从应用中移除下列保险库:\n%2s \n\n这些保险库并不会从云端移除,仅仅是针对当前应用版本,抱歉给您带来不便,请重新添加这些保险库以便继续使之生效。 + 保险库是云端的根文件夹 + 创建一个新的云端连接时,您需要选择这个保险库文件夹的父文件夹作为根目录来添加这个保险库。 此为一项安全功能,可防止其他应用诱使用户做出错误操作\n\n如果禁用,即表示您了解其中风险 您确定要移除此云连接吗? 此操作将移除云连接以及与之相关的所有保险库 @@ -395,8 +398,8 @@ 主题 自动 (跟随系统) - 亮色 - 暗色 + 浅色 + 深色 每天一次 每周一次 diff --git a/presentation/src/main/res/values-zh-rTW/strings.xml b/presentation/src/main/res/values-zh-rTW/strings.xml index 5f6a8241..2211f3b7 100644 --- a/presentation/src/main/res/values-zh-rTW/strings.xml +++ b/presentation/src/main/res/values-zh-rTW/strings.xml @@ -10,7 +10,7 @@ 密碼錯誤 該檔案或資料夾已存在。 不支援的加密檔案庫。這個加密檔案庫是用其它版本的 Cryptomator 所建立的。 - 保險箱已經存在。 + 加密檔案庫已經存在。 檔案不存在。 加密檔案庫已鎖定。 雲端硬碟已經存在。 @@ -21,6 +21,8 @@ 檔案名稱不能含有特殊字元。 加密檔案庫的名稱不能含有特殊字元。 檢查更新失敗。發生一般錯誤。 + 尚未安裝 Google Play 服務。 + 沒有該儲存貯體 本機儲存空間 @@ -45,6 +47,7 @@ 移除 加密檔案庫 + 加密檔案庫名稱:%1$s 移動 清空資料夾 分享對象 @@ -62,6 +65,9 @@ 重新命名 編輯 匯出 + 刪除 + 選擇項目 + 選擇 選擇全部 重新整理 重試 @@ -79,9 +85,9 @@ 選擇位置 點擊此處新增位置 - 自訂位置 網址 + 帳號名稱 密碼 連線 網址不能為空白 @@ -92,18 +98,26 @@ 顯示名稱 區域 + 加密檔案庫名稱不可留空。 + 加密檔案庫名稱 + 創建 + 設定密碼 完成 一般 + 非常強 一般 雲端服務 搜尋 即時搜尋 + 自動鎖定 + 當螢幕被鎖定 啟動 上傳影片 + Cryptomator 網站 在 Twitter 上追蹤我們 在臉書上給我們點讚 法律 @@ -111,6 +125,8 @@ 技術支援 請求協助 除錯模式 + 發送失敗 + 安全提示 版本 進階設定 @@ -122,15 +138,32 @@ 取消 解鎖 舊密碼 + 新密碼 + 更改密碼 + 舊密碼不可留空。 + 新密碼不可留空。 移除 檔案已經存在 取代 + 名稱為「%s」的檔案已經存在。 + 跳過已存在項目 全部取代 取代 確認 + 新建加密檔案庫 + 放棄 + 正在删除… + 正在下載… 鎖定 + 注意 + 啟用 + 注意 + 禁用 關閉 + 有可用更新 + 現在更新 + 以後再說 上一頁 @@ -139,10 +172,15 @@ 分鐘 + 檢查更新 + 自動(跟隨系統) 亮色 暗色 + 每日一次 + 每週一次 + 每月一次 From b398a008b00537c01c8bbaddf8dea740ee88652a Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Wed, 3 Nov 2021 16:25:43 +0100 Subject: [PATCH 19/28] Instant upload when connected to WIFI or uploadOnlyUsingWifi is disabled #181 --- .../java/org/cryptomator/presentation/CryptomatorApp.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt b/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt index 120870fc..5abeb02f 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt @@ -122,15 +122,20 @@ class CryptomatorApp : MultiDexApplication(), HasComponent fun startAutoUpload() { val sharedPreferencesHandler = SharedPreferencesHandler(applicationContext()) - if(sharedPreferencesHandler.usePhotoUpload()) { + if (checkToStartAutoImageUpload(sharedPreferencesHandler)) { val vault = applicationComponent.vaultRepository().load(sharedPreferencesHandler.photoUploadVault()) - if(vault.isUnlocked) { + if (vault.isUnlocked) { val cloud = applicationComponent.cloudRepository().decryptedViewOf(vault) applicationContext().startService(AutoUploadService.startAutoUploadIntent(applicationContext(), cloud)) } } } + private fun checkToStartAutoImageUpload(sharedPreferencesHandler: SharedPreferencesHandler): Boolean { + return sharedPreferencesHandler.usePhotoUpload() + && (!sharedPreferencesHandler.autoPhotoUploadOnlyUsingWifi() || applicationComponent.networkConnectionCheck().checkWifiOnAndConnected()) + } + private fun setupLogging() { setupLoggingFramework() setup() From ad8a2ae747a4ceb480661a06e8a8820986ee224f Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Thu, 4 Nov 2021 14:56:04 +0100 Subject: [PATCH 20/28] Set TLS1.3 as enabled protocol in WebDAV-client on Android >= v10 Fixes #374 --- .../data/cloud/webdav/network/SSLSocketFactories.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/data/src/main/java/org/cryptomator/data/cloud/webdav/network/SSLSocketFactories.kt b/data/src/main/java/org/cryptomator/data/cloud/webdav/network/SSLSocketFactories.kt index a26ae086..604e991a 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/webdav/network/SSLSocketFactories.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/webdav/network/SSLSocketFactories.kt @@ -11,7 +11,12 @@ internal object SSLSocketFactories { fun from(trustManager: X509TrustManager): SSLSocketFactory { return try { - val sslContext = SSLContext.getInstance("TLSv1.2") + val tlsVersion = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { + "TLSv1.3" + } else { + "TLSv1.2" + } + val sslContext = SSLContext.getInstance(tlsVersion) sslContext.init(null, arrayOf(trustManager), null) sslContext.socketFactory } catch (e: GeneralSecurityException) { From 6af970486558a8dd7d2eec1edb9b34f2f7715477 Mon Sep 17 00:00:00 2001 From: Cryptobot Date: Fri, 5 Nov 2021 11:39:36 +0100 Subject: [PATCH 21/28] New Crowdin updates (#371) Chinese Traditional; Czech; German; Turkish; Russian; Swedish; Ukrainian; [ci skip] --- .../src/main/res/values-cs-rCZ/strings.xml | 1 + .../src/main/res/values-de-rDE/strings.xml | 6 +- .../src/main/res/values-ru-rRU/strings.xml | 8 +- .../src/main/res/values-sv-rSE/strings.xml | 5 + .../src/main/res/values-tr-rTR/strings.xml | 5 + .../src/main/res/values-uk-rUA/strings.xml | 187 ++++++++++++++++++ .../src/main/res/values-zh-rTW/strings.xml | 75 ++++++- 7 files changed, 279 insertions(+), 8 deletions(-) create mode 100644 presentation/src/main/res/values-uk-rUA/strings.xml diff --git a/presentation/src/main/res/values-cs-rCZ/strings.xml b/presentation/src/main/res/values-cs-rCZ/strings.xml index af019c9d..6541403e 100644 --- a/presentation/src/main/res/values-cs-rCZ/strings.xml +++ b/presentation/src/main/res/values-cs-rCZ/strings.xml @@ -23,6 +23,7 @@ Kontrola aktualizací se nezdařila. Došlo k obecné chybě. Kontrola aktualizace se nezdařila. Hash neodpovídá nahranému souboru Kontrola aktualizací se nezdařila. Žádné připojení k internetu. + Obchod Google Play není nainstalován Ověření pomocí otisků prstů selhalo Obecná chyba při načítání konfigurace trezoru Místní soubor již není přítomen po přepnutí zpět na Cryptomator. Možné změny nelze promítnout zpět do cloudu. diff --git a/presentation/src/main/res/values-de-rDE/strings.xml b/presentation/src/main/res/values-de-rDE/strings.xml index 4b53c23f..7188ee66 100644 --- a/presentation/src/main/res/values-de-rDE/strings.xml +++ b/presentation/src/main/res/values-de-rDE/strings.xml @@ -16,7 +16,7 @@ Cloud existiert bereits. Installiere eine App, die diesen Dateityp unterstützt. Server nicht gefunden. - Bitte öffne die Einstellungen Deines Geräts und stell die Bildschirmsperre von Hand ein + Bitte öffne die Einstellungen Deines Geräts und stelle die Bildschirmsperre von Hand ein Export fehlgeschlagen. Versuche, Sonderzeichen aus den Dateinamen zu entfernen und erneut zu exportieren. Keine Sonderzeichen möglich. Dateinamen können keine Sonderzeichen enthalten. @@ -27,7 +27,7 @@ Beim entschlüsseln des WebDAV-Passworts trat ein Fehler auf. Bitte in den Einstellungen erneut festlegen. Die Google Play Services sind nicht installiert Biometrischer Login abgebrochen - Die in der %1$s-Datei angegebene Version ist nicht identisch mit jener der %2$s-Datei + Die in %1$s angegebene Version ist nicht identisch mit der Version in %2$s %1$s-Datei stimmt nicht mit der %2$s-Datei überein Allgemeiner Fehler beim Laden der Tresorkonfiguration Lokale Datei ist nach dem Zurückwechseln zu Cryptomator nicht mehr vorhanden. Mögliche Änderungen können nicht in die Cloud übertragen werden. @@ -324,7 +324,7 @@ Keine weiteren Bilder anzuzeigen… Anmeldedaten von \'%1$s\' aktualisiert Falls du ein neues pCloud-Konto hinzufügen wolltest, klicke auf diese URL www.pcloud.com, melde dich vom aktuellen Konto ab und klicke in dieser App erneut auf das „+“, um eine neue Cloud-Verbindung zu erstellen. - Cryptomator benötigt Speicherzugriff, um lokale Tresore nutzen zu können + Um lokale Tresore nutzen zu können benötigt Cryptomator Speicherzugriff Cryptomator benötigt Zugriff auf den Speicher um den automatischen Foto-Upload zu nutzen diff --git a/presentation/src/main/res/values-ru-rRU/strings.xml b/presentation/src/main/res/values-ru-rRU/strings.xml index 2072069b..c92bf0ff 100644 --- a/presentation/src/main/res/values-ru-rRU/strings.xml +++ b/presentation/src/main/res/values-ru-rRU/strings.xml @@ -14,11 +14,11 @@ Файл не существует. Хранилище заблокировано. Облако уже существует. - Скачайте приложение, которое может открыть этот файл. + Пожалуйста, скачайте приложение, которое может открыть этот файл. Сервер не найден. - Откройте настройки устройств и установите блокировку экрана вручную - Ошибка экспорта. Попробуйте удалить спецсимволы из имён файлов и экспортировать снова. - Не может содержать спецсимволы. + Откройте настройки устройства и установите блокировку экрана вручную + Не удалось экспортировать. Попробуйте удалить специальные символы из имен файлов и экспортировать снова. + Не может содержать специальные символы. В имени файла не может быть спецсимволов. В имени хранилища не может быть спецсимволов. Не удалось проверить наличие обновления. Общая ошибка. diff --git a/presentation/src/main/res/values-sv-rSE/strings.xml b/presentation/src/main/res/values-sv-rSE/strings.xml index f096f3ea..4aba1383 100644 --- a/presentation/src/main/res/values-sv-rSE/strings.xml +++ b/presentation/src/main/res/values-sv-rSE/strings.xml @@ -41,6 +41,7 @@ Cryptomator behöver åtkomst till lagringsutrymme för att exportera filer Cryptomator behöver åtkomst till lagringsutrymme för att ladda upp filer Cryptomator behöver åtkomst till lagringsutrymme för att dela filer + Cryptomator har förlorat behörighet att komma åt den här platsen. Välj denna mapp igen för att återställa behörigheten. Inställningar Sök Föregående @@ -288,6 +289,10 @@ Appen är täckt En annan app visar något ovanpå Cryptomator (t.ex., ett blått ljusfilter eller nattläge app). Av säkerhetsskäl är Cryptomator inaktiverad.\n\nSå här aktiverar du Cryptomator Stäng + Vänligen lägg till valv igen för %1s molnet + Medan vi migrerar till den här appversionen måste vi ta bort följande valv från appen:\n%2s \n\nDessa valv tas inte bort från molnet utan endast från den här appen. Ledsen för besväret. Du lägger sedan till dessa valv igen för att fortsätta arbeta med dem. + Valvet är rotmapp för molnanslutningen + Skapa en ny molnanslutning där du väljer minst den överordnade mappen i denna valvkatalog som rotkatalog för att lägga till valvet. Den här inställningen är en säkerhetsfunktion och hindrar andra appar från att lura användare att göra saker de inte vill göra.\n\nGenom att inaktivera bekräftar du att du är medveten om riskerna. Är du säker på att du vill ta bort den här molnanslutningen? Denna åtgärd kommer att ta bort molnanslutningen och alla valv i detta moln. diff --git a/presentation/src/main/res/values-tr-rTR/strings.xml b/presentation/src/main/res/values-tr-rTR/strings.xml index b337552a..9731f446 100644 --- a/presentation/src/main/res/values-tr-rTR/strings.xml +++ b/presentation/src/main/res/values-tr-rTR/strings.xml @@ -41,6 +41,7 @@ Cryptomator\'un dosyaları dışa aktarmak için depolama erişimine ihtiyacı var Cryptomator\'un dosyaları yüklemek için depolama erişimine ihtiyacı var Cryptomator\'un dosyaları paylaşmak için depolama erişimine ihtiyacı var + Cryptomator bu konuma erişim iznini kaybetti. İzni geri yüklemek için lütfen bu klasörü tekrar seçin. Ayarlar Ara Önceki @@ -288,6 +289,10 @@ Uygulama gizlendi Cryptomator\'un üstünde çalışan bazı uygulamalar, (örn. Mavi ışık filtresi ve gece modu uygulamaları gibi) içeriği görüntüler! Bu nedenden dolayı, güvenlik amacıyla Cryptomator devre dışı bırakılır!\n\nCryptomator\'u tekrar nasıl etkinleştirebilirim? Kapat + Lütfen %1s bulutu için kasaları yeniden ekleyin + Bu uygulama sürümüne geçiş yaparken aşağıdaki kasaları uygulamadan kaldırmamız gerekiyor:\n%2s \n\nBu kasalar buluttan değil, yalnızca bu uygulamadan kaldırılır. Rahatsızlık için özür dileriz ve onlarla çalışmaya devam etmek için lütfen bu kasaları yeniden ekleyin. + Vault, bulut bağlantısının kök klasörüdür + Bu kasayı eklemek için kök dizin olarak bu kasa klasörünün en azından üst klasörünü seçtiğiniz yeni bir bulut bağlantısı oluşturun. Bu ayar bir güvenlik özelliğidir ve diğer uygulamaların, kullanıcıları kandırmasını engeller.\n\nDevre dışı bırakarak, risklerin farkında olduğunuzu onaylamış olursunuz. Bu bulut bağlantısını kaldırmak istediğinizden emin misiniz? Bu işlem, bulut bağlantısını ve bu bulutun tüm kasalarını kaldıracak. diff --git a/presentation/src/main/res/values-uk-rUA/strings.xml b/presentation/src/main/res/values-uk-rUA/strings.xml new file mode 100644 index 00000000..a51ebabd --- /dev/null +++ b/presentation/src/main/res/values-uk-rUA/strings.xml @@ -0,0 +1,187 @@ + + + + Зашифрувати + + Виникла помилка + Помилка автентифікації + Помилка автентифікації, будь ласка увійдіть за допомогою %1$s + Відсутнє з\'єднання з мережею + Неправильний пароль + Файл чи тека вже існує. + Непідтримуване сховище. Це сховище було створено іншою версією криптоматора. + Сховище вже існує. + Файлу не існує. + Сховище було заблоковано. + Ця хмара вже використовується. + Будь ласка, завантажте додаток, що може відкрити цей файл. + Сервер не знайдено. + Відкрийте налаштування пристрою та встановіть блокування екрану вручну + Не вдалося виконати експорт. Спробуйте видалити спеціальні символи з імен файлів та експортувати знову. + Не може містити спеціальні символи. + Назва файлу не може містити спеціальні символи. + Назва сховища не може містити спеціальні символи. + Помилка перевірки оновлення. Загальна помилка. + Помилка перевірки оновлення. Хеш не збігається з завантаженим файлом + Не вдалося перевірити оновлення. Немає з\'єднання з мережею. + Не вдалося розшифрувати пароль WebDAV, будь ласка, повторно додайте його в налаштування + Google Play Services не встановлені + Біометрична автентифікація скасована + Версія вказана в %1$s відрізняється від %2$s + %1$s не відповідає %2$s + Загальна помилка при завантаженні конфігурації сховища + Локальний файл більше не присутній посля повернення до Cryptomator. Можливі зміни не будуть застосовані до хмари. + Відсутній бакет + Користувацьке розташування Masterkey ще не підтримується + + + Локальне сховище + + + Cryptomator потребує доступу до сховища для експорту файлів + Cryptomator потребує доступу до сховища для завантаження файлів + Cryptomator потребує доступу до сховища щоб ділитися файлами + Криптоматор втратив дозвіл на доступ до цього розташування. Будь ласка, оберіть цю папку ще раз, щоб відновити дозвіл. + Налаштування + Пошук + Попередній + Наступний + Сортування + А - Я + Я - А + Спочатку новіші + Спочатку старіші + Спочатку найбільші + Спершу найменші + + + Додати до Cryptomator + Створити нове сховище + Додати існуюче сховище + Прибрати + Натисніть тут, щоб створити нове сховище + Пароль успішно змінено + + Сховище + Виберіть файл майстер-ключа + Розмістити тут + Назва сховища: %1$s + Перемістити + Порожня тека + змінено %1$s тому + Поділитися за допомогою + Оберіть призначення + Оберіть + Відсутні елементи для поширення + Додати до %1$s + Створити теку + Створити текстовий файл + Завантажити файли + Файли + Файл експортовано + Файли експортовано + Нічого експортувати + Не вдалося створити каталог для завантажень + Поділитись + Перейменувати + Редагувати + Експорт + Видалити + Відкрити з… + Оберіть файли + %1$d обрано + Оберіть + Вибрати все + Оновити + Немає підключення + Повторити + + Успішно збережено + + Зберегти %1$s до… + текст + файл + файли + Імена файлів мають бути унікальними, будь ласка, перейменуйте дублікати. + Місце збереження + Зберегти + Шифрування завершено + + Хмарні служби + + Обрати місцерозташування + Натисніть сюди щоб додати розташування + Схоже, сервер не сумісний з WebDAV + Немає доступних місцерозташувань. + + Адреса посилання + Ім\'я користувача + Пароль + Підключитися + Посилання не може бути порожнім. + Неприпустима URL-адреса. + Поле для імені користувача не може бути порожнім. + Пароль не може бути порожнім. + + Ім\'я для відображення + Ключ доступу + Секретний ключ + Існуючий бакет + Кінцева точка + Регіон + Ім\'я не може бути порожнім + Ключ доступу не може бути порожнім + Секретний ключ не може бути порожнім + Бакет не може бути порожнім + Кінцева точка або регіон не можуть бути порожніми + + Назва сховища не може бути порожньою. + Назва сховища + Створити + + Задати пароль + Пароль не збігається з введеним паролем. + Готово + ВАЖЛИВО: Якщо ви забудете пароль, то не зможете відновити дані. + Введіть пароль ще раз + Занадто слабкий пароль для створення сховища + Слабкий + Середній + Надійний + Дуже надійний + + Основні налаштування + Хмарні сервіси + Біометрична автентифікація + Активувати біометричну автентифікацію + Підтвердити розблокування обличчям (якщо доступно) + Блокувати програму при виникненні екрану + Блокувати перехоплення вводу й відображення інтерфейсу хибного ім\'я користувача + Блокувати знімки екрану + Блокувати знімки екрану в списку нещодавніх та в середині програми + Пошук + \"Живий\" пошук + Оновити результати пошуку при вході в запит + + + + + + Відмінити + Розблокувати + + Прибрати + Заблокувати + Закрити + Назад + + + + + + + + + + + diff --git a/presentation/src/main/res/values-zh-rTW/strings.xml b/presentation/src/main/res/values-zh-rTW/strings.xml index 2211f3b7..785024fe 100644 --- a/presentation/src/main/res/values-zh-rTW/strings.xml +++ b/presentation/src/main/res/values-zh-rTW/strings.xml @@ -16,18 +16,32 @@ 雲端硬碟已經存在。 請下載行動裝置應用程式來打開這個檔案。 找不到伺服器。 + 請打開你的裝置設定,再手動設定螢幕鎖定。 資料匯出失敗。請把檔案名稱中的特殊字元刪除後,再重新匯出資料。 不能含有特殊字元。 檔案名稱不能含有特殊字元。 加密檔案庫的名稱不能含有特殊字元。 檢查更新失敗。發生一般錯誤。 + 更新檢查失敗。計算出的 Hash 與上傳檔案不匹配 + 更新檢查失敗。沒有網絡連接。 + 解密webdav密碼失敗,請在設定中重新添加 尚未安裝 Google Play 服務。 + 生物身份識別驗證中止 + %1$s 中指定的版本不同於 %2$s + %1$s 與 %2$s 不匹配 + 加載保險庫設定時發生錯誤 + 切換回 Cryptomator 後,本地檔案不再存在。期間發生的更改無法傳回雲端。 沒有該儲存貯體 + 尚未支持自定義 MasterKey 位置 本機儲存空間 + Cryptomator 需要存儲訪問權限用以導出文件 + Cryptomator 需要存儲訪問權限用以上傳文件 + Cryptomator 需要存儲訪問權限用以共享文件 + Cryptomator 已失去訪問此位置的許可。請再次選擇此文件夾以恢復權限。 設定 搜尋 上一頁 @@ -45,15 +59,23 @@ 新建加密檔案庫 新增至現有的加密檔案庫 移除 + 點擊此處新建一個加密檔案庫 + 密碼變更成功 加密檔案庫 + 選擇 Masterkey 檔案 + 在此添加 加密檔案庫名稱:%1$s + + 移動 %1$s 到 + 移動 清空資料夾 分享對象 選擇目的地 選擇 沒有東西可分享 + 加入至 %1$s 建立新資料夾 建立新文字檔案 上傳檔案 @@ -61,15 +83,18 @@ 檔案已匯出 所有的檔案皆已匯出 沒有任何東西可匯出。 + 建立檔案目錄失敗 分享 重新命名 編輯 匯出 刪除 選擇項目 + 已選取 %1$d 個項目 選擇 選擇全部 重新整理 + 沒有連接 重試 儲存成功。 @@ -97,13 +122,16 @@ 顯示名稱 區域 + 儲存貯體不可留空 加密檔案庫名稱不可留空。 加密檔案庫名稱 - 創建 + 新建 設定密碼 完成 + 再次輸入密碼 + 密碼強度不足,無法新建加密檔案庫 一般 @@ -111,11 +139,17 @@ 一般 雲端服務 + 生物識別驗證 + 開啓生物識別驗證 + 確認面容解鎖(如果可用) 搜尋 即時搜尋 自動鎖定 當螢幕被鎖定 + 自動上傳像片 + 選擇要上傳的加密檔案庫 啟動 + 僅使用 Wi-Fi 上傳 上傳影片 Cryptomator 網站 在 Twitter 上追蹤我們 @@ -125,14 +159,19 @@ 技術支援 請求協助 除錯模式 + 發送日誌檔案 發送失敗 安全提示 版本 進階設定 + WebDAV 連線 + pCloud 連線 + S3 連線 登錄到 + %1$s 無法完成身份驗證 取消 @@ -142,28 +181,62 @@ 更改密碼 舊密碼不可留空。 新密碼不可留空。 + 新密碼與再次輸入的密碼不匹配 + 找不到名為%1$s的加密檔案庫 移除 檔案已經存在 取代 名稱為「%s」的檔案已經存在。 跳過已存在項目 全部取代 + 替換現有的 取代 + 名為「%1$s」的檔案已經存在。您想要替換它嗎? + 替換檔案? + 要取代檔案嗎? + 無法分享檔案 確認 新建加密檔案庫 + 無法打開%1$s + 重命名加密檔案庫 + 重命名檔案夾 + 重新命名檔案 + 您有未保存的更改 + 您確定要不保存就離開嗎? 放棄 + 文本.txt + 您確定要刪除這個加密檔案庫嗎? + 正在上傳中…… + 正在導出中(%1$d/%2$d) 正在删除… + 正在創建加密檔案庫…… + 正在上傳中…… 正在下載… + 正在加密中…… + 正在移動中…… 鎖定 + 無效的 TLS 憑證 + 詳情 + 更換為 HTTPS + 是否使用 HTTPS? + 設定螢幕鎖定? + 設定螢幕鎖定 注意 啟用 注意 禁用 關閉 + 是否刪除%1$d個項目? + 您確定要刪除這些項目嗎? + 您確定要刪除這個檔案嗎? + 退出 有可用更新 現在更新 + 前往下載網址 以後再說 + 正在下載 + 下載最新版本的 Cryptomator 上一頁 From b163353c1e6eaa99f1c823d3c376e1b87cd824d8 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Thu, 4 Nov 2021 15:42:28 +0100 Subject: [PATCH 22/28] Simplify TrustManager assignment --- .../cloud/webdav/network/WebDavCompatibleHttpClient.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/data/src/main/java/org/cryptomator/data/cloud/webdav/network/WebDavCompatibleHttpClient.kt b/data/src/main/java/org/cryptomator/data/cloud/webdav/network/WebDavCompatibleHttpClient.kt index b6367775..514220f3 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/webdav/network/WebDavCompatibleHttpClient.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/webdav/network/WebDavCompatibleHttpClient.kt @@ -22,7 +22,6 @@ import java.io.IOException import java.nio.charset.StandardCharsets import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.TimeUnit -import javax.net.ssl.X509TrustManager import okhttp3.Authenticator import okhttp3.Cache import okhttp3.CacheControl @@ -69,16 +68,15 @@ internal class WebDavCompatibleHttpClient(cloud: WebDavCloud, context: Context) .addInterceptor(provideOfflineCacheInterceptor(context)) } - val trustManager: X509TrustManager - if (usingWebDavWithSelfSignedCertificate(webDavCloud)) { + val trustManager = if (usingWebDavWithSelfSignedCertificate(webDavCloud)) { val pinningTrustManager = PinningTrustManager(webDavCloud.certificate()) - trustManager = pinningTrustManager builder.hostnameVerifier(pinningTrustManager.hostnameVerifier()) + pinningTrustManager } else { - trustManager = DefaultTrustManager() + DefaultTrustManager() } - builder.sslSocketFactory(SSLSocketFactories.from(trustManager), trustManager) + return builder.build() } From 0c31410cecbf85019e6bcc13ed9a2c917c864e9c Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Thu, 4 Nov 2021 17:22:26 +0100 Subject: [PATCH 23/28] Remove network check for caching as network is forced in WebDAV --- .../network/WebDavCompatibleHttpClient.kt | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/data/src/main/java/org/cryptomator/data/cloud/webdav/network/WebDavCompatibleHttpClient.kt b/data/src/main/java/org/cryptomator/data/cloud/webdav/network/WebDavCompatibleHttpClient.kt index 514220f3..22d912c2 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/webdav/network/WebDavCompatibleHttpClient.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/webdav/network/WebDavCompatibleHttpClient.kt @@ -1,7 +1,6 @@ package org.cryptomator.data.cloud.webdav.network import android.content.Context -import android.net.ConnectivityManager import com.burgstaller.okhttp.AuthenticationCacheInterceptor import com.burgstaller.okhttp.CachingAuthenticatorDecorator import com.burgstaller.okhttp.DispatchingAuthenticator @@ -65,7 +64,7 @@ internal class WebDavCompatibleHttpClient(cloud: WebDavCloud, context: Context) val cache = Cache(LruFileCacheUtil(context).resolve(LruFileCacheUtil.Cache.WEBDAV), lruCacheSize.toLong()) builder.cache(cache) // .addNetworkInterceptor(provideCacheInterceptor()) // - .addInterceptor(provideOfflineCacheInterceptor(context)) + .addInterceptor(provideOfflineCacheInterceptor()) } val trustManager = if (usingWebDavWithSelfSignedCertificate(webDavCloud)) { @@ -80,17 +79,15 @@ internal class WebDavCompatibleHttpClient(cloud: WebDavCloud, context: Context) return builder.build() } - private fun provideOfflineCacheInterceptor(context: Context): Interceptor { + private fun provideOfflineCacheInterceptor(): Interceptor { return Interceptor { chain: Interceptor.Chain -> var request = chain.request() - if (isNetworkAvailable(context)) { - val cacheControl = CacheControl.Builder() // - .maxAge(0, TimeUnit.DAYS) // - .build() - request = request.newBuilder() // - .cacheControl(cacheControl) // - .build() - } + val cacheControl = CacheControl.Builder() // + .maxAge(0, TimeUnit.DAYS) // + .build() + request = request.newBuilder() // + .cacheControl(cacheControl) // + .build() chain.proceed(request) } } @@ -145,12 +142,6 @@ internal class WebDavCompatibleHttpClient(cloud: WebDavCloud, context: Context) private fun usingWebDavWithSelfSignedCertificate(webDavCloud: WebDavCloud): Boolean { return webDavCloud.certificate() != null } - - private fun isNetworkAvailable(context: Context): Boolean { - val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager - val activeNetworkInfo = connectivityManager.activeNetworkInfo - return activeNetworkInfo != null && activeNetworkInfo.isConnected - } } class UserAgentInterceptor : Interceptor { From 2dd1b2ae336d340edd2ebc93d252e141afe6ff42 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 5 Nov 2021 11:43:24 +0100 Subject: [PATCH 24/28] Bump to versin 1.6.3-beta2 [ci skip] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0d0ce338..2115d6d0 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ allprojects { ext { androidApplicationId = 'org.cryptomator' androidVersionCode = getVersionCode() - androidVersionName = '1.6.3-beta1' + androidVersionName = '1.6.3-beta2' } repositories { mavenCentral() From 476a9c56b30fe454640e8993715f926a1a8a8a85 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 5 Nov 2021 11:53:34 +0100 Subject: [PATCH 25/28] Update release notes [ci skip] --- fastlane/metadata/android/de-DE/changelogs/default.txt | 3 ++- fastlane/metadata/android/en-US/changelogs/default.txt | 3 ++- fastlane/release-notes.html | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/fastlane/metadata/android/de-DE/changelogs/default.txt b/fastlane/metadata/android/de-DE/changelogs/default.txt index 5cd4a8e1..bfce1dd3 100644 --- a/fastlane/metadata/android/de-DE/changelogs/default.txt +++ b/fastlane/metadata/android/de-DE/changelogs/default.txt @@ -1,3 +1,4 @@ - Fotos können sofort hochgeladen werden, wenn der automatische Fotoupload aktiviert und der Tresor entsperrt ist - Wenn der Tresor-Order der Stammordner der Cloud ist, kann dieser nun nicht mehr hinzugefügt werden -- Überarbeitung des Zugriffs auf den lokalen Speicher \ No newline at end of file +- Überarbeitung des Zugriffs auf den lokalen Speicher +- Sicherheit von WebDAV-Verbindungen verbessert \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/default.txt b/fastlane/metadata/android/en-US/changelogs/default.txt index 2598a701..6fe62aea 100644 --- a/fastlane/metadata/android/en-US/changelogs/default.txt +++ b/fastlane/metadata/android/en-US/changelogs/default.txt @@ -1,3 +1,4 @@ - Upload photos instantly when auto photo upload is enabled and vault is unlocked - Fixed vault name is empty when it is the root folder of the cloud -- Refactor access to local storage \ No newline at end of file +- Refactored access to local storage +- Enhanced security of WebDAV connections \ No newline at end of file diff --git a/fastlane/release-notes.html b/fastlane/release-notes.html index af2c6b90..74205218 100644 --- a/fastlane/release-notes.html +++ b/fastlane/release-notes.html @@ -1,5 +1,6 @@
  • Upload photos instantly when auto photo upload is enabled and vault is unlocked
  • Fixed vault name is empty when it is the root folder of the cloud
  • -
  • Refactor access to local storage
  • +
  • Refactored access to local storage
  • +
  • Enhanced security of WebDAV connections
\ No newline at end of file From 70b401e2f44f638cd9e5873e82d5510a0d52d5bc Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 5 Nov 2021 12:13:03 +0100 Subject: [PATCH 26/28] Update fastlane dependencies [ci skip] --- Gemfile.lock | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 790d4ca0..603d9da2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -10,17 +10,17 @@ GEM artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.2.0) - aws-partitions (1.516.0) - aws-sdk-core (3.121.1) + aws-partitions (1.525.0) + aws-sdk-core (3.122.0) aws-eventstream (~> 1, >= 1.0.2) - aws-partitions (~> 1, >= 1.239.0) + aws-partitions (~> 1, >= 1.525.0) aws-sigv4 (~> 1.1) jmespath (~> 1.0) - aws-sdk-kms (1.49.0) - aws-sdk-core (~> 3, >= 3.120.0) + aws-sdk-kms (1.51.0) + aws-sdk-core (~> 3, >= 3.122.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.103.0) - aws-sdk-core (~> 3, >= 3.120.0) + aws-sdk-s3 (1.105.0) + aws-sdk-core (~> 3, >= 3.122.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.4) aws-sigv4 (1.4.0) @@ -40,7 +40,7 @@ GEM dotenv (2.7.6) ed25519 (1.2.4) emoji_regex (3.2.3) - excon (0.87.0) + excon (0.88.0) faraday (1.8.0) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -66,7 +66,7 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.2.5) - fastlane (2.196.0) + fastlane (2.197.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -111,7 +111,7 @@ GEM mime-types (~> 3.3) fastlane-plugin-get_version_name (0.2.2) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.12.0) + google-apis-androidpublisher_v3 (0.13.0) google-apis-core (>= 0.4, < 2.a) google-apis-core (0.4.1) addressable (~> 2.5, >= 2.5.1) @@ -122,11 +122,11 @@ GEM retriable (>= 2.0, < 4.a) rexml webrick - google-apis-iamcredentials_v1 (0.7.0) + google-apis-iamcredentials_v1 (0.8.0) google-apis-core (>= 0.4, < 2.a) - google-apis-playcustomapp_v1 (0.5.0) + google-apis-playcustomapp_v1 (0.6.0) google-apis-core (>= 0.4, < 2.a) - google-apis-storage_v1 (0.8.0) + google-apis-storage_v1 (0.9.0) google-apis-core (>= 0.4, < 2.a) google-cloud-core (1.6.0) google-cloud-env (~> 1.0) @@ -142,7 +142,7 @@ GEM google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.0.0) + googleauth (1.1.0) faraday (>= 0.17.3, < 2.0) jwt (>= 1.4, < 3.0) memoist (~> 0.16) @@ -154,12 +154,12 @@ GEM domain_name (~> 0.5) httpclient (2.8.3) jmespath (1.4.0) - json (2.6.0) + json (2.6.1) jwt (2.3.0) memoist (0.16.2) mime-types (3.3.1) mime-types-data (~> 3.2015) - mime-types-data (3.2021.0704) + mime-types-data (3.2021.0901) mini_magick (4.11.0) mini_mime (1.1.2) multi_json (1.15.0) From e97f446e6a662089a859aa889e10bdc9f3eeefb0 Mon Sep 17 00:00:00 2001 From: Cryptobot Date: Thu, 11 Nov 2021 10:03:29 +0100 Subject: [PATCH 27/28] New Crowdin updates (#375) Chinese Traditional; Filipino; Italian; Japanese; Tamil; Telugu; [ci skip] --- .../src/main/res/values-fil-rPH/strings.xml | 16 +++ .../src/main/res/values-it-rIT/strings.xml | 5 + .../src/main/res/values-ja-rJP/strings.xml | 1 + .../src/main/res/values-ta-rIN/strings.xml | 113 ++++++++++++++++++ .../src/main/res/values-te-rIN/strings.xml | 68 +++++++++++ .../src/main/res/values-zh-rTW/strings.xml | 43 +++++++ 6 files changed, 246 insertions(+) create mode 100644 presentation/src/main/res/values-ta-rIN/strings.xml create mode 100644 presentation/src/main/res/values-te-rIN/strings.xml diff --git a/presentation/src/main/res/values-fil-rPH/strings.xml b/presentation/src/main/res/values-fil-rPH/strings.xml index 4c5ee108..8ab823b9 100644 --- a/presentation/src/main/res/values-fil-rPH/strings.xml +++ b/presentation/src/main/res/values-fil-rPH/strings.xml @@ -12,6 +12,7 @@ Umiiral na ang vault na ito. Ang file na ito ay hindi pa umiiral. Naisara na ang vault. + Umiiral na ang cloud na ito. Magdownload ng app na kayang buksan ang file na ito. Hindi mahanap ang server. Maaaring buksan ang device settings at sariling itakda ang screen lock @@ -31,6 +32,7 @@ Hanapin Nakaraan Sunod + Ayusin A - Z Z - A Bago muna @@ -50,6 +52,8 @@ Piliin ang masterkey file Ilagay dito Pangalan ng vault: %1$s + Ilipat + Walang laman na folder Ibahagi kay Pumili ng destinasyon Pumili @@ -67,21 +71,31 @@ I-export Burahin Buksan gamit ang … + Pumilii %1$d ang nakapili Piliin Piliin lahat I-refresh Walang koneksyon + Subukan muli + Matagumpay na nai-save + I-save ang %1$s sa … + text + file files Natatangi dapat ang pangalan ng mga files, maaari lamang na palitan ang mga may kapareho. I-save ang lokasyon I-save + Natapos na ang pag-encrypt + Cloud service Piliin ang location Pindutin dito upang magdagdag ng lugar + Ang server na ito ay mukhang hindi tugma sa WebDAV + Walang ibang lokasyon na magagamit. URL Username @@ -90,7 +104,9 @@ Hindi maaaring walang laman ang URL. Hindi tama ang URL. Hindi maaaring walang laman ang username. + Hindi maaaring walang laman ang password. + Access Key Rehiyon Hindi maaaring walang laman ang bucket Hindi maaaring walang laman ang endpoint o ang rehiyon diff --git a/presentation/src/main/res/values-it-rIT/strings.xml b/presentation/src/main/res/values-it-rIT/strings.xml index 1c93c374..b6e53a95 100644 --- a/presentation/src/main/res/values-it-rIT/strings.xml +++ b/presentation/src/main/res/values-it-rIT/strings.xml @@ -41,6 +41,7 @@ Cryptomator necessita dell\'accesso all\'archivio per esportare i file Cryptomator ha bisogno di accesso all\'archivio per caricare i file Cryptomator ha bisogno di accesso all\'archivio per condividere i file + Cryptomator ha perso il permesso di accedere a questa posizione. Si prega di selezionare nuovamente questa cartella per ripristinare il permesso. Impostazioni Cerca Precedente @@ -288,6 +289,10 @@ L\'app è oscurata Un\'altra app sta mostrando qualcosa sopra Cryptomator (ad esempio, un filtro luce blu o un\'app per la modalità notturna). Per motivi di sicurezza, Cryptomator è disabilitato.\n\nCome abilitare Cryptomator Chiudi + Si prega di ri-aggiungere cassaforti per il cloud %1s + Durante la migrazione a questa versione dell\'app abbiamo avuto bisogno di rimuovere le seguenti cassaforti dall\'app:\n%2s \n\nQueste cassaforti non sono state rimosse dal cloud ma solo da questa app. Siamo spiacenti per l\'inconveniente e si prega di ri-aggiungere queste cassaforti per continuare ad usarle. + La cassaforte è la cartella root della connessione al cloud + Crea una nuova connessione al cloud dove bisogna selezionare almeno la cartella padre di questa cassaforte come cartella radice per aggiungere questa cassaforte. Questa impostazione è una funzione di sicurezza e impedisce ad altre applicazioni di ingannare gli utenti a fare cose che non sono in grado di fare.\n\nDisabilitandola confermi di essere a conoscenza dei rischi. Sei sicuro di voler rimuovere questa connessione cloud? Questa azione rimuoverà la connessione cloud e tutte le cassaforti di questo cloud. diff --git a/presentation/src/main/res/values-ja-rJP/strings.xml b/presentation/src/main/res/values-ja-rJP/strings.xml index fb872a01..0cb3886b 100644 --- a/presentation/src/main/res/values-ja-rJP/strings.xml +++ b/presentation/src/main/res/values-ja-rJP/strings.xml @@ -282,6 +282,7 @@ アプリが重なっています 他のアプリケーションが Cryptomator の上に何かを表示しています (例: ブルーライト フィルターや night mode アプリ)。このため、セキュリティの観点から Cryptomator が無効化されています。\n\nCryptomator を有効にするには 閉じる + %1s クラウンドの金庫を再追加してください この設定は安全のための機能です。他のアプリがユーザーを騙してしまうことを防ぎます。\n\n無効にすることで、 リスクを認識していること に留意する必要があります。 本当にこのクラウド接続を削除しますか? この操作により、クラウド接続とクラウドのすべての金庫が削除されます。 diff --git a/presentation/src/main/res/values-ta-rIN/strings.xml b/presentation/src/main/res/values-ta-rIN/strings.xml new file mode 100644 index 00000000..8297bc5c --- /dev/null +++ b/presentation/src/main/res/values-ta-rIN/strings.xml @@ -0,0 +1,113 @@ + + + + குறியாக்கு + + ஒரு பிழை ஏற்பட்டுள்ளது + அங்கீகரிப்பு தோல்வியுற்றது + நெட்வொர்க் இணைப்பு இல்லை + தவறான கடவுச்சொல் + கோப்பு இருப்பில் இல்லை. + + + உள்ளூர் சேமிப்பகம் + + + அமைப்புகள் + தேடு + முந்தைய + அடுத்து + வரிசைப்படுத்து + + + + நகர்த்து + காலி கோப்புறை + இதனுடன் பகிர் + தேர்ந்தெடு + அனைத்தையும் தேர்ந்தெடு + புதுப்பி + இணைப்பு இல்லை + மீண்டும் முயற்சிக்கவும் + + வெற்றிகரமாக சேமிக்கப்பட்டது + + கோப்பு + கோப்புகள் + சேமி + குறியாக்கம் முடிந்தது + + + + இணையமுகவரி + பயனர்பெயர் + கடவுச்சொல் + இணையமுகவரி வெறுமையாக இருக்க கூடாது. + இணையமுகவரி தவறானது. + பயனர்பெயர் காலியாக இருக்க முடியாது. + கடவுச்சொல் காலியாக இருக்கக்கூடாது. + + புனைப்பெயர் + பகுதி + + + + உயிரியளவுகள் உறுதிசெய்தல் + தேடு + நேரடி தேடல் + இதன்பிறகு செயலியை பூட்டு + செயல்படுத்து + டுவிட்டரில் எங்களைத் தொடருங்கள் + Facebook இல் எங்களை போன்ற + சட்டம் + ஆதரவு + + + + + + கடவுச்சொல் காலியாக இருக்கக்கூடாது. + + நீக்கு + கோப்பு ஏற்கனவே உள்ளது + மாற்று + ஏற்கனவே \'%1$s\' என்ற பெயரில் வெறெரு கோப்பு உள்ளது. + ஏற்கனவே இருப்பதை தவிர்க்கவும் + அனைத்தையும் மாற்று + ஏற்கனவே உள்ளதை மாற்றவும் + மாற்று + கோப்பை மாற்றிடவா? + கோப்புகளை மாற்றிடவா? + சரி + கோப்புறைக்கு மறுபெயரிடு + கோப்பை மறுபெயரிடு + சேமிக்கப்படாத மாற்றங்கள் உள்ளன + திரைப்பூட்டை அமை + கவனிக்க + இயக்கு + கவனிக்க + முடக்கு + மூடு + + + + + நிமிடங்கள் + நாட்கள் + வாரம் + வாரங்கள் + மாதம் + மாதங்கள் + ஆண்டு + + + + + + வெளிச்சம் + இருள் + + தினம் ஒரு முறை + வாரம் ஒரு முறை + மாதம் ஒரு முறை + diff --git a/presentation/src/main/res/values-te-rIN/strings.xml b/presentation/src/main/res/values-te-rIN/strings.xml new file mode 100644 index 00000000..2aa01210 --- /dev/null +++ b/presentation/src/main/res/values-te-rIN/strings.xml @@ -0,0 +1,68 @@ + + + + ఎన్‌క్రిప్ట్ + + + + + + అమర్చు + A - Z + Z - A + కొత్త మొదటి + పాతది ముందు + పెద్దది ముందు + చిన్న ముందు + + + Kripṭōmēṭar‌lō cērcaṇḍi + కొత్త ఖజానాను సృష్టించండి + ఇప్పటికే ఉన్న ఖజానాను తెరవండి + + Itarulaku pampaṇḍi + ఎంచుకోండి + తో పంచు + మార్పు + తొలగించు + మళ్ళీ చేయండి + + + + + + URL + + + సృష్టించు + + పూర్తయింది + పాస్వర్డ్ మళ్ళీ వ్రాయండి + బలంగా లేదు + అది సరే + అది బలంగా ఉంది + అది చాలా బలంగా ఉంది + + వెతకండి + సహాయం + + + + + + ఆపండి + తాళం తెరవండి + + సరే + తప్పు SSL certificate + + + + + + + + + + + diff --git a/presentation/src/main/res/values-zh-rTW/strings.xml b/presentation/src/main/res/values-zh-rTW/strings.xml index 785024fe..c56344c8 100644 --- a/presentation/src/main/res/values-zh-rTW/strings.xml +++ b/presentation/src/main/res/values-zh-rTW/strings.xml @@ -99,6 +99,7 @@ 儲存成功。 + 正在将%1$s保存至…… 文字 檔案 檔案 @@ -209,7 +210,12 @@ 您確定要刪除這個加密檔案庫嗎? 正在上傳中…… 正在導出中(%1$d/%2$d) + 請稍候…… + 正在創建資料夾…… + 正在重命名…… 正在删除… + 正在解鎖加密檔案庫…… + 正在變更密碼…… 正在創建加密檔案庫…… 正在上傳中…… 正在下載… @@ -230,7 +236,12 @@ 是否刪除%1$d個項目? 您確定要刪除這些項目嗎? 您確定要刪除這個檔案嗎? + 提供一個有效的許可證書 + 我們檢測到你沒有使用 Google Play 商店安裝 Cryptomator。提供一個有效的許可證書,證書可以從https://cryptomator.org/android/購買 + 提供的許可證書無效。請確認您輸入無誤。 + 未提供許可證書。請輸入一個有效的許可證書。 退出 + 許可證書確認 有可用更新 現在更新 前往下載網址 @@ -241,14 +252,46 @@ + 0 kB + 位元組 + kB + MB + GB + TB + + + 分鐘 分鐘 + 小時 + 小時 + + + + + + + + 檢查更新 + 立即 + 1分鐘 + 2分鐘 + 5分鐘 + 10分鐘 + 從不 + 50 MB + 100 MB + 250 MB + 500 MB + 1 GB + 5 GB + 樣式 自動(跟隨系統) 亮色 暗色 From 1457eb57d72e6317bc73e5d8ec254a3d9bb17cb0 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Thu, 11 Nov 2021 10:07:31 +0100 Subject: [PATCH 28/28] Bump to versin 1.6.3 [ci skip] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2115d6d0..6fe2b443 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ allprojects { ext { androidApplicationId = 'org.cryptomator' androidVersionCode = getVersionCode() - androidVersionName = '1.6.3-beta2' + androidVersionName = '1.6.3' } repositories { mavenCentral()