diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100755 index e497da999..000000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 6ce84c81e..603d9da25 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.509.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.48.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.86.0) + excon (0.88.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.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.11.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,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.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.1) + mini_mime (1.1.2) multi_json (1.15.0) multipart-post (2.0.0) nanaimo (0.3.0) diff --git a/build.gradle b/build.gradle index 06b97f395..6fe2b443b 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" @@ -39,7 +39,7 @@ allprojects { ext { androidApplicationId = 'org.cryptomator' androidVersionCode = getVersionCode() - androidVersionName = '1.6.2' + androidVersionName = '1.6.3' } repositories { mavenCentral() diff --git a/buildsystem/dependencies.gradle b/buildsystem/dependencies.gradle index 4c853160e..c18d9e0fd 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' @@ -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' diff --git a/data/build.gradle b/data/build.gradle index 211a64e47..4d2111a27 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 6e6378989..1e0ad4c0a 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(sharedPreferencesHandler).applyTo(db, 9) CloudEntityDao(DaoConfig(db, CloudEntityDao::class.java)).loadAll() VaultEntityDao(DaoConfig(db, VaultEntityDao::class.java)).loadAll() @@ -407,4 +408,66 @@ 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", "pathOfVault26") // + .text("FOLDER_NAME", "name") // + .text("CLOUD_TYPE", CloudType.LOCAL.name) // + .text("PASSWORD", "password") // + .integer("POSITION", 11) // + .executeOn(db) + + Sql.query("CLOUD_ENTITY").executeOn(db).use { + Assert.assertThat(it.count, CoreMatchers.`is`(5)) + } + + Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) + + Sql.query("VAULT_ENTITY").executeOn(db).use { + 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/cloud/crypto/CryptoCloud.java b/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoCloud.java index ca6dd52ec..eeadb1358 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 @@ private boolean configurationMatches(CryptoCloud 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 b4c9698d9..db3abc87f 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 cffbb02c9..c6bc79712 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 af3d80271..d147d6b0d 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 0f21ca535..76dc5456b 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 bf93abcdf..762018bfa 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) + } 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 f352c4bb7..d65b3761d 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 12ffd6dfe..aa6fa8008 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 c3ea26b00..b07bfebbb 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 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.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 boolean supports(Cloud cloud) { @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 bc59d39be..9268ac451 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 43eb8ad69..000000000 --- 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 40d60d438..000000000 --- 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 313b88599..000000000 --- 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 46c225f1a..000000000 --- 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 18547d8e7..000000000 --- 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 e6788644a..000000000 --- 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 fde9d4398..000000000 --- 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/cloud/webdav/network/ConnectionHandlerFactory.kt b/data/src/main/java/org/cryptomator/data/cloud/webdav/network/ConnectionHandlerFactory.kt index fcf758ca7..a0761a895 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 b99392f3d..49bd6309a 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/SSLSocketFactories.kt b/data/src/main/java/org/cryptomator/data/cloud/webdav/network/SSLSocketFactories.kt index a26ae086c..604e991a1 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) { 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 2f55d0e0f..7bb6bd4c9 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() } 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 b6367775a..22d912c2f 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 @@ -22,7 +21,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 @@ -66,33 +64,30 @@ 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: 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() } - 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) } } @@ -147,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 { 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 3b6ef8271..638c5c76e 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 @@ public DatabaseUpgrades( // Upgrade5To6 upgrade5To6, // Upgrade6To7 upgrade6To7, // Upgrade7To8 upgrade7To8, // - Upgrade8To9 upgrade8To9) { + Upgrade8To9 upgrade8To9, // + Upgrade9To10 upgrade9To10) { availableUpgrades = defineUpgrades( // upgrade0To1, // @@ -38,7 +39,8 @@ public 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 000000000..01cf79fa5 --- /dev/null +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt @@ -0,0 +1,48 @@ +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(private val sharedPreferencesHandler: SharedPreferencesHandler) : DatabaseUpgrade(9, 10) { + + private val defaultLocalStorageCloudId = 4L + + override fun internalApplyTo(db: Database, origin: Int) { + db.beginTransaction() + + try { + 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(defaultLocalStorageCloudId)) + .where("TYPE", Sql.eq("LOCAL")) + .executeOn(db) + + db.setTransactionSuccessful() + } finally { + db.endTransaction() + } + } +} 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 bdb422c39..61f1307c3 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 @@ public Cloud store(Cloud cloud) { @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 14332c8d7..9ad874201 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 ee1aba135..6c1f1e22e 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 b8f4fc8a4..2178e3c75 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 boolean configurationMatches(Cloud 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 e8b27ce93..8ebd70f0e 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 boolean configurationMatches(Cloud 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 ee895359f..fb96449c6 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 @@ private boolean configurationMatches(LocalStorageCloud 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 5b0820125..a56accf0f 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 CloudType type() { 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 95164c653..89b016177 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 @@ private boolean configurationMatches(PCloud 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 44268df63..064cc93ad 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 @@ private boolean configurationMatches(S3Cloud 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 2ffba1855..ccb21dd6d 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 String certificate() { return certificate; } - @Override - public boolean predefined() { - return false; - } - @Override public boolean persistent() { return true; diff --git a/fastlane/metadata/android/de-DE/changelogs/default.txt b/fastlane/metadata/android/de-DE/changelogs/default.txt index f686002aa..bfce1dd33 100644 --- a/fastlane/metadata/android/de-DE/changelogs/default.txt +++ b/fastlane/metadata/android/de-DE/changelogs/default.txt @@ -1 +1,4 @@ -- 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 +- 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 6f60085e1..6fe62aeab 100644 --- a/fastlane/metadata/android/en-US/changelogs/default.txt +++ b/fastlane/metadata/android/en-US/changelogs/default.txt @@ -1 +1,4 @@ -- 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 +- 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 0761a6a16..74205218e 100644 --- a/fastlane/release-notes.html +++ b/fastlane/release-notes.html @@ -1,3 +1,6 @@
    -
  • 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
  • +
  • Refactored access to local storage
  • +
  • Enhanced security of WebDAV connections
\ No newline at end of file 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 abfe6e745..eac080bf4 100644 --- a/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt +++ b/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt @@ -1,7 +1,9 @@ package org.cryptomator.presentation.presenter -import android.Manifest 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 @@ -35,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 @@ -44,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 @@ -433,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 } @@ -445,22 +448,41 @@ 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 uri = (cloud as LocalStorageModel).uri() + + val permissions = context().contentResolver.persistedUriPermissions + for (permission in permissions) { + if (permission.uri.toString() == uri) { + succeedAuthenticationWith(cloud.toCloud()) + } + } + + 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 onLocalStorageAuthenticated(result: PermissionsResult, cloud: CloudModel) { - if (result.granted()) { - succeedAuthenticationWith(cloud.toCloud()) - } else { - failAuthentication(PermissionNotGrantedException(R.string.permission_snackbar_auth_local_vault)) + 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 { diff --git a/presentation/src/main/AndroidManifest.xml b/presentation/src/main/AndroidManifest.xml index 0e2bbcf73..5b155c10d 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 b0124eb2d..f20baf4a1 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/CryptomatorApp.kt b/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt index 630b07bc8..5abeb02ff 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt @@ -120,6 +120,22 @@ class CryptomatorApp : MultiDexApplication(), HasComponent }, BIND_AUTO_CREATE) } + fun startAutoUpload() { + val sharedPreferencesHandler = SharedPreferencesHandler(applicationContext()) + if (checkToStartAutoImageUpload(sharedPreferencesHandler)) { + val vault = applicationComponent.vaultRepository().load(sharedPreferencesHandler.photoUploadVault()) + 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() 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 47e039690..391d30a9e 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 ff98ce85d..0a5bbc51c 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 // @@ -294,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/java/org/cryptomator/presentation/presenter/ImagePreviewPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/ImagePreviewPresenter.kt index 31b066d8e..393aac0ad 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,74 +54,25 @@ 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) - } - } - - private fun copyFileToDownloadDirectory(uri: Uri) { - requestPermissions( - PermissionsResultCallbacks.copyFileToDownloadDirectory(uri.toString()), // - R.string.permission_message_export_file, Manifest.permission.WRITE_EXTERNAL_STORAGE - ) - } - - @Callback - fun copyFileToDownloadDirectory(result: PermissionsResult, uriString: 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) - } - } - } - - private fun copyFile(source: InputStream?, target: OutputStream?) { - if (source == null || target == null) { - throw FatalBackendException("Input- or OutputStream is null") - } - copyDataUseCase // - .withSource(source) // - .andTarget(target) // - .run(object : DefaultResultHandler() { - override fun onFinished() { - view?.showMessage(R.string.screen_file_browser_msg_file_exported) - } - }) - } - - private fun copyFileToUserSelectedLocation(uri: 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.copyFileToUserSelectedLocation(uri.toString()), intent) + requestActivityResult(ActivityResultCallbacks.exportImageToUserSelectedLocation(uri.toString()), intent) } @Callback - fun copyFileToUserSelectedLocation(result: ActivityResult, sourceUri: String?) { + fun exportImageToUserSelectedLocation(result: ActivityResult, sourceUri: String?) { requestPermissions( - PermissionsResultCallbacks.copyFileToUserSelectedLocation(result.intent()?.dataString, sourceUri), // + PermissionsResultCallbacks.exportImageToUserSelectedLocation(result.intent()?.dataString, sourceUri), // R.string.permission_message_export_file, // Manifest.permission.READ_EXTERNAL_STORAGE ) } @Callback - fun copyFileToUserSelectedLocation(result: PermissionsResult, targetUri: String?, sourceUri: String?) { + fun exportImageToUserSelectedLocation(result: PermissionsResult, targetUri: String?, sourceUri: String?) { if (result.granted()) { try { copyFile( @@ -138,6 +85,20 @@ class ImagePreviewPresenter @Inject constructor( // } } + private fun copyFile(source: InputStream?, target: OutputStream?) { + if (source == null || target == null) { + throw FatalBackendException("Input- or OutputStream is null") + } + copyDataUseCase // + .withSource(source) // + .andTarget(target) // + .run(object : DefaultResultHandler() { + override fun onFinished() { + view?.showMessage(R.string.screen_file_browser_msg_file_exported) + } + }) + } + 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 f40390d17..43cb4dc4b 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 f5b327b28..edea86e7d 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/presenter/VaultListPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt index 3e4ece770..b5e6d288d 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 @@ -46,10 +47,10 @@ 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 +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 @@ -104,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() } @@ -119,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 @@ -272,8 +280,8 @@ class VaultListPresenter @Inject constructor( // view?.showVaultCreationHint() } else { view?.hideVaultCreationHint() - view?.renderVaultList(vaultModels) } + view?.renderVaultList(vaultModels) } }) } 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 a56c90506..452934c75 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 @@ private CloudFile writeCloudFile(String fileName, CancelAwareDataSource dataSour 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 f70972bb2..d9d1e929b 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/java/org/cryptomator/presentation/ui/activity/ImagePreviewActivity.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/ImagePreviewActivity.kt index 209f27ead..901b67cb0 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 6440caa74..1c3a587ff 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/AppIsObscuredInfoDialog.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/AppIsObscuredInfoDialog.kt index ccf63d031..e01fde74c 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/UpdateAppAvailableDialog.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/UpdateAppAvailableDialog.kt index 7f477e709..074113f53 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/dialog/VaultIsRootFolderOfCloudDialog.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/VaultIsRootFolderOfCloudDialog.kt new file mode 100644 index 000000000..19b836928 --- /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_vault_is_root_folder_of_cloud_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/ui/dialog/VaultsRemovedDuringMigrationDialog.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/dialog/VaultsRemovedDuringMigrationDialog.kt new file mode 100644 index 000000000..0d8de1892 --- /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/java/org/cryptomator/presentation/ui/fragment/CloudConnectionListFragment.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/CloudConnectionListFragment.kt index bf974c6fc..57d8a0ede 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 1022f509f..d40769ff7 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/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java b/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java index 80714856e..29b03ba4d 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.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 @@ void cloudServiceAuthenticated(ActivityResult result) { @Callback void cryptomatorFileChosen(SerializableResult 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 000000000..eb831c0aa --- /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/layout/dialog_vaults_removed_during_migration.xml b/presentation/src/main/res/layout/dialog_vaults_removed_during_migration.xml new file mode 100644 index 000000000..db8ac7208 --- /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/layout/fragment_browse_cloud_connections.xml b/presentation/src/main/res/layout/fragment_browse_cloud_connections.xml index 4da30d58a..c0930487c 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-ar-rSA/strings.xml b/presentation/src/main/res/values-ar-rSA/strings.xml index 6df0e4675..33799525b 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 31c4acd5e..a32500daf 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 2d816fa94..6541403ec 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. @@ -112,8 +113,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 92223621c..7188ee666 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 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. @@ -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. @@ -321,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-el-rGR/strings.xml b/presentation/src/main/res/values-el-rGR/strings.xml index 52c677929..6c1efe0b8 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 16143f6cb..d11569c25 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 000000000..8ab823b9a --- /dev/null +++ b/presentation/src/main/res/values-fil-rPH/strings.xml @@ -0,0 +1,276 @@ + + + + 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. + 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 + 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 + Ayusin + 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 + Ilipat + Walang laman na folder + 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 … + 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 + Password + Kumonekta + 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 + + 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 61ff0e1eb..85bcb0935 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 45ef49205..16168718c 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 5430db9c4..b6e53a951 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 @@ -39,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 @@ -113,8 +116,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 @@ -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 511dd5b84..0cb3886b2 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 @@ -284,6 +282,7 @@ アプリが重なっています 他のアプリケーションが Cryptomator の上に何かを表示しています (例: ブルーライト フィルターや night mode アプリ)。このため、セキュリティの観点から Cryptomator が無効化されています。\n\nCryptomator を有効にするには 閉じる + %1s クラウンドの金庫を再追加してください この設定は安全のための機能です。他のアプリがユーザーを騙してしまうことを防ぎます。\n\n無効にすることで、 リスクを認識していること に留意する必要があります。 本当にこのクラウド接続を削除しますか? この操作により、クラウド接続とクラウドのすべての金庫が削除されます。 diff --git a/presentation/src/main/res/values-ko-rKR/strings.xml b/presentation/src/main/res/values-ko-rKR/strings.xml index 2d66a6157..b1ce8743c 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 000000000..0c5cc3282 --- /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 bc6bbad74..892e28197 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 f6e210ce9..598e1e471 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 eda9c8db5..c0f431cb3 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 4da26b64c..68547ab6f 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 eec15f649..c92bf0ff7 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 @@ Файл не существует. Хранилище заблокировано. Облако уже существует. - Скачайте приложение, которое может открыть этот файл. + Пожалуйста, скачайте приложение, которое может открыть этот файл. Сервер не найден. - Откройте настройки устройств и установите блокировку экрана вручную - Ошибка экспорта. Попробуйте удалить спецсимволы из имён файлов и экспортировать снова. - Не может содержать спецсимволы. + Откройте настройки устройства и установите блокировку экрана вручную + Не удалось экспортировать. Попробуйте удалить специальные символы из имен файлов и экспортировать снова. + Не может содержать специальные символы. В имени файла не может быть спецсимволов. В имени хранилища не может быть спецсимволов. Не удалось проверить наличие обновления. Общая ошибка. @@ -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 b86458a8e..887d98b6c 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 69211145e..4aba1383a 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 @@ -115,8 +116,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 @@ -290,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-ta-rIN/strings.xml b/presentation/src/main/res/values-ta-rIN/strings.xml new file mode 100644 index 000000000..8297bc5c1 --- /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 000000000..2aa012105 --- /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-tr-rTR/strings.xml b/presentation/src/main/res/values-tr-rTR/strings.xml index 459b1b6da..9731f446d 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 @@ -115,8 +116,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 @@ -290,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 000000000..a51ebabd5 --- /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-rCN/strings.xml b/presentation/src/main/res/values-zh-rCN/strings.xml index 129be34c6..2589a2db9 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 5f6a82418..c56344c89 100644 --- a/presentation/src/main/res/values-zh-rTW/strings.xml +++ b/presentation/src/main/res/values-zh-rTW/strings.xml @@ -10,22 +10,38 @@ 密碼錯誤 該檔案或資料夾已存在。 不支援的加密檔案庫。這個加密檔案庫是用其它版本的 Cryptomator 所建立的。 - 保險箱已經存在。 + 加密檔案庫已經存在。 檔案不存在。 加密檔案庫已鎖定。 雲端硬碟已經存在。 請下載行動裝置應用程式來打開這個檔案。 找不到伺服器。 + 請打開你的裝置設定,再手動設定螢幕鎖定。 資料匯出失敗。請把檔案名稱中的特殊字元刪除後,再重新匯出資料。 不能含有特殊字元。 檔案名稱不能含有特殊字元。 加密檔案庫的名稱不能含有特殊字元。 檢查更新失敗。發生一般錯誤。 + 更新檢查失敗。計算出的 Hash 與上傳檔案不匹配 + 更新檢查失敗。沒有網絡連接。 + 解密webdav密碼失敗,請在設定中重新添加 + 尚未安裝 Google Play 服務。 + 生物身份識別驗證中止 + %1$s 中指定的版本不同於 %2$s + %1$s 與 %2$s 不匹配 + 加載保險庫設定時發生錯誤 + 切換回 Cryptomator 後,本地檔案不再存在。期間發生的更改無法傳回雲端。 + 沒有該儲存貯體 + 尚未支持自定義 MasterKey 位置 本機儲存空間 + Cryptomator 需要存儲訪問權限用以導出文件 + Cryptomator 需要存儲訪問權限用以上傳文件 + Cryptomator 需要存儲訪問權限用以共享文件 + Cryptomator 已失去訪問此位置的許可。請再次選擇此文件夾以恢復權限。 設定 搜尋 上一頁 @@ -43,14 +59,23 @@ 新建加密檔案庫 新增至現有的加密檔案庫 移除 + 點擊此處新建一個加密檔案庫 + 密碼變更成功 加密檔案庫 + 選擇 Masterkey 檔案 + 在此添加 + 加密檔案庫名稱:%1$s + + 移動 %1$s 到 + 移動 清空資料夾 分享對象 選擇目的地 選擇 沒有東西可分享 + 加入至 %1$s 建立新資料夾 建立新文字檔案 上傳檔案 @@ -58,16 +83,23 @@ 檔案已匯出 所有的檔案皆已匯出 沒有任何東西可匯出。 + 建立檔案目錄失敗 分享 重新命名 編輯 匯出 + 刪除 + 選擇項目 + 已選取 %1$d 個項目 + 選擇 選擇全部 重新整理 + 沒有連接 重試 儲存成功。 + 正在将%1$s保存至…… 文字 檔案 檔案 @@ -79,9 +111,9 @@ 選擇位置 點擊此處新增位置 - 自訂位置 網址 + 帳號名稱 密碼 連線 網址不能為空白 @@ -91,19 +123,36 @@ 顯示名稱 區域 + 儲存貯體不可留空 + 加密檔案庫名稱不可留空。 + 加密檔案庫名稱 + 新建 + 設定密碼 完成 + 再次輸入密碼 + 密碼強度不足,無法新建加密檔案庫 一般 + 非常強 一般 雲端服務 + 生物識別驗證 + 開啓生物識別驗證 + 確認面容解鎖(如果可用) 搜尋 即時搜尋 + 自動鎖定 + 當螢幕被鎖定 + 自動上傳像片 + 選擇要上傳的加密檔案庫 啟動 + 僅使用 Wi-Fi 上傳 上傳影片 + Cryptomator 網站 在 Twitter 上追蹤我們 在臉書上給我們點讚 法律 @@ -111,38 +160,143 @@ 技術支援 請求協助 除錯模式 + 發送日誌檔案 + 發送失敗 + 安全提示 版本 進階設定 + WebDAV 連線 + pCloud 連線 + S3 連線 登錄到 + %1$s 無法完成身份驗證 取消 解鎖 舊密碼 + 新密碼 + 更改密碼 + 舊密碼不可留空。 + 新密碼不可留空。 + 新密碼與再次輸入的密碼不匹配 + 找不到名為%1$s的加密檔案庫 移除 檔案已經存在 取代 + 名稱為「%s」的檔案已經存在。 + 跳過已存在項目 全部取代 + 替換現有的 取代 + 名為「%1$s」的檔案已經存在。您想要替換它嗎? + 替換檔案? + 要取代檔案嗎? + 無法分享檔案 確認 + 新建加密檔案庫 + 無法打開%1$s + 重命名加密檔案庫 + 重命名檔案夾 + 重新命名檔案 + 您有未保存的更改 + 您確定要不保存就離開嗎? + 放棄 + 文本.txt + 您確定要刪除這個加密檔案庫嗎? + 正在上傳中…… + 正在導出中(%1$d/%2$d) + 請稍候…… + 正在創建資料夾…… + 正在重命名…… + 正在删除… + 正在解鎖加密檔案庫…… + 正在變更密碼…… + 正在創建加密檔案庫…… + 正在上傳中…… + 正在下載… + 正在加密中…… + 正在移動中…… 鎖定 + 無效的 TLS 憑證 + 詳情 + 更換為 HTTPS + 是否使用 HTTPS? + 設定螢幕鎖定? + 設定螢幕鎖定 + 注意 + 啟用 + 注意 + 禁用 關閉 + 是否刪除%1$d個項目? + 您確定要刪除這些項目嗎? + 您確定要刪除這個檔案嗎? + 提供一個有效的許可證書 + 我們檢測到你沒有使用 Google Play 商店安裝 Cryptomator。提供一個有效的許可證書,證書可以從https://cryptomator.org/android/購買 + 提供的許可證書無效。請確認您輸入無誤。 + 未提供許可證書。請輸入一個有效的許可證書。 + 退出 + 許可證書確認 + 有可用更新 + 現在更新 + 前往下載網址 + 以後再說 + 正在下載 + 下載最新版本的 Cryptomator 上一頁 + 0 kB + 位元組 + kB + MB + GB + TB + + + 分鐘 分鐘 + 小時 + 小時 + + + + + + + + + 檢查更新 + 立即 + 1分鐘 + 2分鐘 + 5分鐘 + 10分鐘 + 從不 + 50 MB + 100 MB + 250 MB + 500 MB + 1 GB + 5 GB + 樣式 + 自動(跟隨系統) 亮色 暗色 + 每日一次 + 每週一次 + 每月一次 diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 6fb9018de..8ed2c79e6 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 @@ -166,8 +168,6 @@ @string/screen_vault_list_vault_action_delete Click here to add locations Server doesn\'t seem to be WebDAV compatible - Custom locations - Default storage No additional locations available. @@ -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 @@ -415,6 +417,14 @@ 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. + @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/presentation/src/main/res/xml/preferences.xml b/presentation/src/main/res/xml/preferences.xml index c1c983434..be07dbd79 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" /> + + >?) { + 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" @@ -244,11 +273,14 @@ 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" const val SCREEN_STYLE_MODE = "screenStyleMode" const val PHOTO_UPLOAD = "photoUpload" + const val PHOTO_UPLOAD_INSTANT = "photoUploadInstant" const val PHOTO_UPLOAD_ONLY_USING_WIFI = "photoUploadOnlyUsingWifi" const val PHOTO_UPLOAD_VAULT = "photoUploadVault" const val PHOTO_UPLOAD_FOLDER = "photoUploadFolder" 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 85b11a79a..04acdceb1 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 @@ public KeyGenerator initializeKeyGenerator(Context context, final String alias) 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(); };