From f3817960c64b60c5fb4866e9b3db9cd2ca4fb6e5 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 23 Dec 2020 15:21:43 +0100 Subject: [PATCH 01/32] Update Crowdin configuration file --- crowdin.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 crowdin.yml diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 00000000..188cd214 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,3 @@ +files: + - source: /presentation/src/main/res/values/strings.xml + translation: /presentation/src/main/res/values_%two_letters_code%/strings.xml From 5e8d82014ffa63bee1ff8e96c406fa2216f59149 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 23 Dec 2020 15:26:15 +0100 Subject: [PATCH 02/32] Update Crowdin configuration file --- crowdin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crowdin.yml b/crowdin.yml index 188cd214..5707f656 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,3 +1,3 @@ files: - source: /presentation/src/main/res/values/strings.xml - translation: /presentation/src/main/res/values_%two_letters_code%/strings.xml + translation: /presentation/src/main/res/values-%two_letters_code%/strings.xml From 47c9dba4ee9ac17ddb57a4ad3e959089477dd1b7 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 23 Dec 2020 15:37:01 +0100 Subject: [PATCH 03/32] Update and rename crowdin.yml to .crowdin.yml [ci skip] --- crowdin.yml => .crowdin.yml | 2 ++ 1 file changed, 2 insertions(+) rename crowdin.yml => .crowdin.yml (72%) diff --git a/crowdin.yml b/.crowdin.yml similarity index 72% rename from crowdin.yml rename to .crowdin.yml index 5707f656..7355b42b 100644 --- a/crowdin.yml +++ b/.crowdin.yml @@ -1,3 +1,5 @@ +commit_message: "[ci skip]" +escape_special_characters: 0 files: - source: /presentation/src/main/res/values/strings.xml translation: /presentation/src/main/res/values-%two_letters_code%/strings.xml From 8b70abb93aa6dbbcc3eadd52a3ec65010fc4fd2e Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 23 Dec 2020 15:38:28 +0100 Subject: [PATCH 04/32] Update Crowdin configuration file --- .crowdin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.crowdin.yml b/.crowdin.yml index 7355b42b..d0ae7b74 100644 --- a/.crowdin.yml +++ b/.crowdin.yml @@ -1,5 +1,5 @@ -commit_message: "[ci skip]" escape_special_characters: 0 +commit_message: '[ci skip]' files: - source: /presentation/src/main/res/values/strings.xml translation: /presentation/src/main/res/values-%two_letters_code%/strings.xml From a6a8cae13f0c7d9def1b812d62e8179d130a614b Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Wed, 23 Dec 2020 15:53:46 +0100 Subject: [PATCH 05/32] Add Crowdin badge [ci skip] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 24d0ac6d..de3b224d 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Twitter](https://img.shields.io/badge/twitter-@Cryptomator-blue.svg?style=flat)](http://twitter.com/Cryptomator) [![Community](https://img.shields.io/badge/help-Community-orange.svg)](https://community.cryptomator.org) [![Documentation](https://img.shields.io/badge/help-Docs-orange.svg)](https://docs.cryptomator.org) +[![Crowdin](https://badges.crowdin.net/cryptomator-android/localized.svg)](https://crowdin.com/project/cryptomator-android) Cryptomator offers multi-platform transparent client-side encryption of your files in the cloud. From 9158da82799594c1b82c0cd3a7d2f33696710854 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Wed, 23 Dec 2020 15:58:45 +0100 Subject: [PATCH 06/32] Bump version to 1.5.11-beta1 [ci skip] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 87f09f0c..2b10ad54 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ allprojects { ext { androidApplicationId = 'org.cryptomator' androidVersionCode = getVersionCode() - androidVersionName = '1.5.11-SNAPSHOT' + androidVersionName = '1.5.11-beta1' } repositories { mavenCentral() From 39b4dc34cf0d7c327a99943310a13b2d4825988b Mon Sep 17 00:00:00 2001 From: Gusted Date: Mon, 4 Jan 2021 19:33:52 +0000 Subject: [PATCH 07/32] Update secrets.properties link The current link in `README.md` links to the `master` branch which is non-existent on this repo and would default to the current 'main' branch `develop`. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index de3b224d..c1565868 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ git submodule init && git submodule update // (not necessary if cloned using --r ./gradlew assembleLicenseDebug ``` -Before connecting to Onedrive or Dropbox you have to enter valid API keys in [secrets.properties](https://github.com/cryptomator/android/blob/master/secrets.properties). +Before connecting to Onedrive or Dropbox you have to enter valid API keys in [secrets.properties](https://github.com/cryptomator/android/blob/develop/secrets.properties). ## License From 5b786014ff01b0ab8a16cf06eee495bd4c659a07 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Mon, 11 Jan 2021 15:50:29 +0100 Subject: [PATCH 08/32] Mark untranslatable texts --- presentation/src/main/res/values/strings.xml | 30 ++++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 8a7dbf69..a2485cde 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -4,9 +4,9 @@ - Cryptomator + Cryptomator + @string/app_name Encrypt - @string/app_name An error occurred @@ -36,10 +36,10 @@ Crypto - Dropbox - Google Drive - OneDrive - WebDAV + Dropbox + Google Drive + OneDrive + WebDAV Local storage @@ -219,9 +219,9 @@ Cryptomator website Follow us on Twitter Like us on Facebook - https://cryptomator.org - https://facebook.com/Cryptomator - https://twitter.com/Cryptomator + https://cryptomator.org + https://facebook.com/Cryptomator + https://twitter.com/Cryptomator Legal Licenses @@ -229,12 +229,12 @@ Support Request help - https://cryptomator.org/contact/ + https://cryptomator.org/contact/ Debug mode Send log file Sending failed Security hints - https://docs.cryptomator.org/en/1.5/security/best-practices/ + https://docs.cryptomator.org/en/1.5/security/best-practices/ Version @@ -436,10 +436,10 @@ Cryptomator needs storage access to use auto photo upload - Android Error Report - Summary - Insert a detailed description of what you tried to do or mention your support ticket if you already created one. - Device Info + Android Error Report + Summary + Insert a detailed description of what you tried to do or mention your support ticket if you already created one. + Device Info From be22737d4f4e1eda084851a6e2ff69a8ecae5660 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Mon, 11 Jan 2021 18:12:10 +0100 Subject: [PATCH 09/32] Use ENV variables instead of secrets.properties for Cloud API keys --- .gitignore | 2 -- README.md | 2 +- data/build.gradle | 4 +--- presentation/build.gradle | 6 ++---- presentation/src/main/AndroidManifest.xml | 2 +- secrets.properties | 3 --- 6 files changed, 5 insertions(+), 14 deletions(-) delete mode 100644 secrets.properties diff --git a/.gitignore b/.gitignore index 80427507..a18d2645 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ -secrets.properties - ###IntelliJ### *.iml diff --git a/README.md b/README.md index c1565868..b16bd1fa 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ git submodule init && git submodule update // (not necessary if cloned using --r ./gradlew assembleLicenseDebug ``` -Before connecting to Onedrive or Dropbox you have to enter valid API keys in [secrets.properties](https://github.com/cryptomator/android/blob/develop/secrets.properties). +Before connecting to Onedrive or Dropbox you have to provide valid API keys using environment variables: `ONEDRIVE_API_KEY` or `DROPBOX_API_KEY`. ## License diff --git a/data/build.gradle b/data/build.gradle index 3608ab82..6c1e1cfa 100644 --- a/data/build.gradle +++ b/data/build.gradle @@ -116,7 +116,5 @@ configurations { } static def getApiKey(key) { - Properties props = new Properties() - props.load(new FileInputStream(new File('secrets.properties'))) - return props[key] + return System.getenv().getOrDefault(key, "") } diff --git a/presentation/build.gradle b/presentation/build.gradle index 8eacd80d..99e67443 100644 --- a/presentation/build.gradle +++ b/presentation/build.gradle @@ -31,7 +31,7 @@ android { testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' buildConfigField "String", "DROPBOX_API_KEY", "\"" + getApiKey('DROPBOX_API_KEY') + "\"" - manifestPlaceholders = [DROPBOX_API_KEY_DB: getApiKey('DROPBOX_API_KEY_DB')] + manifestPlaceholders = [DROPBOX_API_KEY: getApiKey('DROPBOX_API_KEY')] } compileOptions { @@ -188,7 +188,5 @@ androidExtensions { } static def getApiKey(key) { - Properties props = new Properties() - props.load(new FileInputStream(new File('secrets.properties'))) - return props[key] + return System.getenv().getOrDefault(key, "") } diff --git a/presentation/src/main/AndroidManifest.xml b/presentation/src/main/AndroidManifest.xml index 1e0c1af0..f7fc763f 100644 --- a/presentation/src/main/AndroidManifest.xml +++ b/presentation/src/main/AndroidManifest.xml @@ -87,7 +87,7 @@ android:configChanges="orientation|keyboard" android:launchMode="singleTask"> - + diff --git a/secrets.properties b/secrets.properties deleted file mode 100644 index b8f2b15a..00000000 --- a/secrets.properties +++ /dev/null @@ -1,3 +0,0 @@ -ONEDRIVE_API_KEY= -DROPBOX_API_KEY= -DROPBOX_API_KEY_DB= From 9d43a2eefd38d0aec18dc9eb5024026d96b5dc07 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Tue, 12 Jan 2021 13:17:27 +0100 Subject: [PATCH 10/32] Crypto cloud name isn't translatable as well --- presentation/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index a2485cde..fa95a7bd 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -35,7 +35,7 @@ - Crypto + Crypto Dropbox Google Drive OneDrive From 41149b960743e38b6831bcdba76f5897a8462e4b Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Tue, 12 Jan 2021 15:23:31 +0100 Subject: [PATCH 11/32] Introduce flavor for F-Droid --- README.md | 2 +- data/build.gradle | 50 ++- .../CloudContentRepositoryFactories.java | 42 +++ .../CloudContentRepositoryFactories.java | 0 .../FixedGoogleAccountCredential.java | 0 .../googledrive/GoogleDriveClientFactory.java | 0 .../GoogleDriveCloudContentRepository.java | 0 ...gleDriveCloudContentRepositoryFactory.java | 0 .../GoogleDriveCloudNodeFactory.java | 0 .../cloud/googledrive/GoogleDriveFile.java | 0 .../cloud/googledrive/GoogleDriveFolder.java | 0 .../cloud/googledrive/GoogleDriveIdCache.java | 0 .../googledrive/GoogleDriveIdCloudNode.java | 0 .../cloud/googledrive/GoogleDriveImpl.java | 1 - .../cloud/googledrive/GoogleDriveNode.java | 0 .../googledrive/RootGoogleDriveFolder.java | 0 ...redBytesAwareGoogleContentInputStream.java | 4 +- presentation/build.gradle | 34 +- .../presenter/AuthenticateCloudPresenter.kt | 338 ++++++++++++++++++ .../presentation/CryptomatorApp.kt | 10 +- .../presenter/ChooseCloudServicePresenter.kt | 6 + .../presenter/CloudSettingsPresenter.kt | 6 +- .../presenter/SettingsPresenter.kt | 10 +- .../presenter/VaultListPresenter.kt | 4 +- .../ui/activity/CloudSettingsActivity.kt | 2 +- .../ui/fragment/SettingsFragment.kt | 30 +- .../presenter/AuthenticateCloudPresenter.kt | 0 27 files changed, 504 insertions(+), 35 deletions(-) create mode 100644 data/src/foss/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java rename data/src/{main => notFoss}/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java (100%) rename data/src/{main => notFoss}/java/org/cryptomator/data/cloud/googledrive/FixedGoogleAccountCredential.java (100%) rename data/src/{main => notFoss}/java/org/cryptomator/data/cloud/googledrive/GoogleDriveClientFactory.java (100%) rename data/src/{main => notFoss}/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepository.java (100%) rename data/src/{main => notFoss}/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepositoryFactory.java (100%) rename data/src/{main => notFoss}/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudNodeFactory.java (100%) rename data/src/{main => notFoss}/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFile.java (100%) rename data/src/{main => notFoss}/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFolder.java (100%) rename data/src/{main => notFoss}/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCache.java (100%) rename data/src/{main => notFoss}/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCloudNode.java (100%) rename data/src/{main => notFoss}/java/org/cryptomator/data/cloud/googledrive/GoogleDriveImpl.java (99%) rename data/src/{main => notFoss}/java/org/cryptomator/data/cloud/googledrive/GoogleDriveNode.java (100%) rename data/src/{main => notFoss}/java/org/cryptomator/data/cloud/googledrive/RootGoogleDriveFolder.java (100%) rename data/src/{main/java/org/cryptomator/data/util => notFoss/java/org/cryptomator/data/cloud/googledrive}/TransferredBytesAwareGoogleContentInputStream.java (90%) create mode 100644 presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt rename presentation/src/{main => notFoss}/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt (100%) diff --git a/README.md b/README.md index b16bd1fa..b0f54d14 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Cryptomator for Android is currently available in the following distribution ch ``` git submodule init && git submodule update // (not necessary if cloned using --recurse-submodules) -./gradlew assembleLicenseDebug +./gradlew assembleApkstoreDebug ``` Before connecting to Onedrive or Dropbox you have to provide valid API keys using environment variables: `ONEDRIVE_API_KEY` or `DROPBOX_API_KEY`. diff --git a/data/build.gradle b/data/build.gradle index 6c1e1cfa..a5939e72 100644 --- a/data/build.gradle +++ b/data/build.gradle @@ -38,9 +38,27 @@ android { dimension "version" } - license { + apkstore { dimension "version" } + + fdroid { + dimension "version" + } + } + + sourceSets { + playstore { + java.srcDirs = ['src/main/java', 'src/main/java/', 'src/notFoss/java', 'src/notFoss/java/'] + } + + apkstore { + java.srcDirs = ['src/main/java', 'src/main/java/', 'src/notFoss/java', 'src/notFoss/java/'] + } + + fdroid { + java.srcDirs = ['src/main/java', 'src/main/java/', 'src/foss/java', 'src/foss/java/'] + } } } @@ -70,17 +88,29 @@ dependencies { implementation dependencies.dagger // cloud implementation dependencies.dropbox - implementation dependencies.googlePlayServicesAuth - implementation(dependencies.googleApiServicesDrive) { - exclude module: 'guava-jdk5' - exclude module: 'httpclient' - } - implementation(dependencies.googleApiClientAndroid) { - exclude module: 'guava-jdk5' - exclude module: 'httpclient' - } implementation dependencies.msgraph + playstoreImplementation dependencies.googlePlayServicesAuth + apkstoreImplementation dependencies.googlePlayServicesAuth + + playstoreImplementation(dependencies.googleApiServicesDrive) { + exclude module: 'guava-jdk5' + exclude module: 'httpclient' + } + apkstoreImplementation(dependencies.googleApiServicesDrive) { + exclude module: 'guava-jdk5' + exclude module: 'httpclient' + } + + playstoreImplementation(dependencies.googleApiClientAndroid) { + exclude module: 'guava-jdk5' + exclude module: 'httpclient' + } + apkstoreImplementation(dependencies.googleApiClientAndroid) { + exclude module: 'guava-jdk5' + exclude module: 'httpclient' + } + // rest implementation dependencies.rxJava implementation dependencies.rxAndroid diff --git a/data/src/foss/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java b/data/src/foss/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java new file mode 100644 index 00000000..277858d2 --- /dev/null +++ b/data/src/foss/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java @@ -0,0 +1,42 @@ +package org.cryptomator.data.cloud; + +import org.cryptomator.data.cloud.crypto.CryptoCloudContentRepositoryFactory; +import org.cryptomator.data.cloud.dropbox.DropboxCloudContentRepositoryFactory; +import org.cryptomator.data.cloud.local.LocalStorageContentRepositoryFactory; +import org.cryptomator.data.cloud.onedrive.OnedriveCloudContentRepositoryFactory; +import org.cryptomator.data.cloud.webdav.WebDavCloudContentRepositoryFactory; +import org.cryptomator.data.repository.CloudContentRepositoryFactory; +import org.jetbrains.annotations.NotNull; + +import java.util.Iterator; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import static java.util.Arrays.asList; + +@Singleton +public class CloudContentRepositoryFactories implements Iterable { + + private final Iterable factories; + + @Inject + public CloudContentRepositoryFactories(DropboxCloudContentRepositoryFactory dropboxFactory, // + OnedriveCloudContentRepositoryFactory oneDriveFactory, // + CryptoCloudContentRepositoryFactory cryptoFactory, // + LocalStorageContentRepositoryFactory localStorageFactory, // + WebDavCloudContentRepositoryFactory webDavFactory) { + + factories = asList(dropboxFactory, // + oneDriveFactory, // + cryptoFactory, // + localStorageFactory, // + webDavFactory); + } + + @NotNull + @Override + public Iterator iterator() { + return factories.iterator(); + } +} diff --git a/data/src/main/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java b/data/src/notFoss/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/CloudContentRepositoryFactories.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/FixedGoogleAccountCredential.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/FixedGoogleAccountCredential.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/FixedGoogleAccountCredential.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/FixedGoogleAccountCredential.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveClientFactory.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveClientFactory.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveClientFactory.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveClientFactory.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepository.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepository.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepository.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepository.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepositoryFactory.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepositoryFactory.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepositoryFactory.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudContentRepositoryFactory.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudNodeFactory.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudNodeFactory.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudNodeFactory.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveCloudNodeFactory.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFile.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFile.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFile.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFile.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFolder.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFolder.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFolder.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveFolder.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCache.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCache.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCache.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCache.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCloudNode.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCloudNode.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCloudNode.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveIdCloudNode.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveImpl.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveImpl.java similarity index 99% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveImpl.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveImpl.java index 48df9744..0ccebe23 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveImpl.java +++ b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveImpl.java @@ -13,7 +13,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.cryptomator.data.util.TransferredBytesAwareGoogleContentInputStream; import org.cryptomator.data.util.TransferredBytesAwareOutputStream; import org.cryptomator.domain.CloudNode; import org.cryptomator.domain.GoogleDriveCloud; diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveNode.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveNode.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/GoogleDriveNode.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveNode.java diff --git a/data/src/main/java/org/cryptomator/data/cloud/googledrive/RootGoogleDriveFolder.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/RootGoogleDriveFolder.java similarity index 100% rename from data/src/main/java/org/cryptomator/data/cloud/googledrive/RootGoogleDriveFolder.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/RootGoogleDriveFolder.java diff --git a/data/src/main/java/org/cryptomator/data/util/TransferredBytesAwareGoogleContentInputStream.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/TransferredBytesAwareGoogleContentInputStream.java similarity index 90% rename from data/src/main/java/org/cryptomator/data/util/TransferredBytesAwareGoogleContentInputStream.java rename to data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/TransferredBytesAwareGoogleContentInputStream.java index f35f4adb..2648efcd 100644 --- a/data/src/main/java/org/cryptomator/data/util/TransferredBytesAwareGoogleContentInputStream.java +++ b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/TransferredBytesAwareGoogleContentInputStream.java @@ -1,7 +1,9 @@ -package org.cryptomator.data.util; +package org.cryptomator.data.cloud.googledrive; import com.google.api.client.http.AbstractInputStreamContent; +import org.cryptomator.data.util.TransferredBytesAwareInputStream; + import java.io.Closeable; import java.io.IOException; import java.io.InputStream; diff --git a/presentation/build.gradle b/presentation/build.gradle index 99e67443..9e7a81b7 100644 --- a/presentation/build.gradle +++ b/presentation/build.gradle @@ -64,9 +64,27 @@ android { dimension "version" } - license { + apkstore { dimension "version" } + + fdroid { + dimension "version" + } + } + + sourceSets { + playstore { + java.srcDirs = ['src/main/java', 'src/main/java/', 'src/notFoss/java', 'src/notFoss/java/'] + } + + apkstore { + java.srcDirs = ['src/main/java', 'src/main/java/', 'src/notFoss/java', 'src/notFoss/java/'] + } + + fdroid { + java.srcDirs = ['src/main/java', 'src/main/java/', 'src/foss/java', 'src/foss/java/'] + } } packagingOptions { @@ -106,11 +124,21 @@ dependencies { // cloud implementation dependencies.dropbox implementation dependencies.msgraph - implementation(dependencies.googleApiServicesDrive) { + + playstoreImplementation(dependencies.googleApiServicesDrive) { exclude module: 'guava-jdk5' exclude module: 'httpclient' } - implementation(dependencies.googleApiClientAndroid) { + apkstoreImplementation(dependencies.googleApiServicesDrive) { + exclude module: 'guava-jdk5' + exclude module: 'httpclient' + } + + playstoreImplementation(dependencies.googleApiClientAndroid) { + exclude module: 'guava-jdk5' + exclude module: 'httpclient' + } + apkstoreImplementation(dependencies.googleApiClientAndroid) { exclude module: 'guava-jdk5' exclude module: 'httpclient' } diff --git a/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt b/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt new file mode 100644 index 00000000..1c76fb07 --- /dev/null +++ b/presentation/src/foss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt @@ -0,0 +1,338 @@ +package org.cryptomator.presentation.presenter + +import android.Manifest +import android.accounts.AccountManager +import com.dropbox.core.android.Auth +import org.cryptomator.data.cloud.onedrive.OnedriveClientFactory +import org.cryptomator.data.cloud.onedrive.graph.ClientException +import org.cryptomator.data.cloud.onedrive.graph.ICallback +import org.cryptomator.data.util.X509CertificateHelper +import org.cryptomator.domain.* +import org.cryptomator.domain.di.PerView +import org.cryptomator.domain.exception.FatalBackendException +import org.cryptomator.domain.exception.NetworkConnectionException +import org.cryptomator.domain.exception.authentication.* +import org.cryptomator.domain.usecases.cloud.AddOrChangeCloudConnectionUseCase +import org.cryptomator.domain.usecases.cloud.GetUsernameUseCase +import org.cryptomator.generator.Callback +import org.cryptomator.presentation.BuildConfig +import org.cryptomator.presentation.R +import org.cryptomator.presentation.exception.ExceptionHandlers +import org.cryptomator.presentation.exception.PermissionNotGrantedException +import org.cryptomator.presentation.intent.AuthenticateCloudIntent +import org.cryptomator.presentation.model.* +import org.cryptomator.presentation.model.mappers.CloudModelMapper +import org.cryptomator.presentation.ui.activity.view.AuthenticateCloudView +import org.cryptomator.presentation.workflow.* +import org.cryptomator.util.ExceptionUtil +import org.cryptomator.util.crypto.CredentialCryptor +import timber.log.Timber +import java.security.cert.CertificateEncodingException +import java.security.cert.CertificateException +import java.security.cert.X509Certificate +import javax.inject.Inject + +@PerView +class AuthenticateCloudPresenter @Inject constructor( // + exceptionHandlers: ExceptionHandlers, // + private val cloudModelMapper: CloudModelMapper, // + private val addOrChangeCloudConnectionUseCase: AddOrChangeCloudConnectionUseCase, // + private val getUsernameUseCase: GetUsernameUseCase, // + private val addExistingVaultWorkflow: AddExistingVaultWorkflow, // + private val createNewVaultWorkflow: CreateNewVaultWorkflow) : Presenter(exceptionHandlers) { + + private val strategies = arrayOf( // + DropboxAuthStrategy(), // + OnedriveAuthStrategy(), // + WebDAVAuthStrategy(), // + LocalStorageAuthStrategy() // + ) + + override fun workflows(): Iterable> { + return listOf(createNewVaultWorkflow, addExistingVaultWorkflow) + } + + override fun resumed() { + val cloud = view?.intent()?.cloud() + val error = view?.intent()?.error() + handleNetworkConnectionExceptionIfRequired(error) + view?.intent()?.let { cloud?.let { cloud -> authStrategyFor(cloud).resumed(it) } } + } + + private fun handleNetworkConnectionExceptionIfRequired(error: AuthenticationException?) { + if (error != null && ExceptionUtil.contains(error, NetworkConnectionException::class.java)) { + view?.showMessage(R.string.error_no_network_connection) + finish() + } + } + + private fun authStrategyFor(cloud: CloudModel): AuthStrategy { + strategies.forEach { strategy -> + if (strategy.supports(cloud)) { + return strategy + } + } + return FailingAuthStrategy() + } + + private fun getUsernameAndSuceedAuthentication(cloud: Cloud) { + getUsernameUseCase.withCloud(cloud).run(object : DefaultResultHandler() { + override fun onSuccess(username: String) { + succeedAuthenticationWith(updateUsernameOf(cloud, username)) + } + + override fun onError(e: Throwable) { + super.onError(e) + finish() + } + }) + } + + private fun updateUsernameOf(cloud: Cloud, username: String): Cloud { + when (cloud.type()) { + CloudType.DROPBOX -> return DropboxCloud.aCopyOf(cloud as DropboxCloud).withUsername(username).build() + CloudType.ONEDRIVE -> return OnedriveCloud.aCopyOf(cloud as OnedriveCloud).withUsername(username).build() + } + throw IllegalStateException("Cloud " + cloud.type() + " is not supported") + } + + private fun succeedAuthenticationWith(cloud: Cloud) { + addOrChangeCloudConnectionUseCase // + .withCloud(cloud) // + .run(object : DefaultResultHandler() { + override fun onSuccess(void: Void?) { + finishWithResult(cloudModelMapper.toModel(cloud)) + } + + override fun onError(e: Throwable) { + super.onError(e) + finish() + } + }) + } + + private fun failAuthentication(cloudName: Int) { + view?.showMessage(String.format(getString(R.string.screen_authenticate_auth_authentication_failed), getString(cloudName))) + finish() + } + + private fun failAuthentication(error: PermissionNotGrantedException) { + finishWithResult(error) + } + + private inner class DropboxAuthStrategy : AuthStrategy { + private var authenticationStarted = false + override fun supports(cloud: CloudModel): Boolean { + return cloud.cloudType() == CloudTypeModel.DROPBOX + } + + override fun resumed(intent: AuthenticateCloudIntent) { + if (authenticationStarted) { + handleAuthenticationResult(intent.cloud()) + } else { + startAuthentication() + } + } + + private fun startAuthentication() { + showProgress(ProgressModel(ProgressStateModel.AUTHENTICATION)) + authenticationStarted = true + Auth.startOAuth2Authentication(context(), BuildConfig.DROPBOX_API_KEY) + view?.skipTransition() + } + + private fun handleAuthenticationResult(cloudModel: CloudModel) { + val authToken = Auth.getOAuth2Token() + if (authToken == null) { + failAuthentication(cloudModel.name()) + } else { + getUsernameAndSuceedAuthentication( // + DropboxCloud.aCopyOf(cloudModel.toCloud() as DropboxCloud) // + .withAccessToken(encrypt(authToken)) // + .build()) + } + } + } + + @Callback(dispatchResultOkOnly = false) + fun onUserRecoveryFinished(result: ActivityResult, cloud: CloudModel) { + if (result.isResultOk) { + succeedAuthenticationWith(cloud.toCloud()) + } else { + failAuthentication(cloud.name()) + } + } + + @Callback(dispatchResultOkOnly = false) + fun onGoogleDriveAuthenticated(result: ActivityResult, cloud: CloudModel) { + if (result.isResultOk) { + val accountName = result.intent()?.extras?.getString(AccountManager.KEY_ACCOUNT_NAME) + succeedAuthenticationWith(GoogleDriveCloud.aCopyOf(cloud.toCloud() as GoogleDriveCloud) // + .withUsername(accountName) // + .withAccessToken(accountName) // + .build()) + } else { + failAuthentication(cloud.name()) + } + } + + private inner class OnedriveAuthStrategy : AuthStrategy { + private var authenticationStarted = false + override fun supports(cloud: CloudModel): Boolean { + return cloud.cloudType() == CloudTypeModel.ONEDRIVE + } + + override fun resumed(intent: AuthenticateCloudIntent) { + if (!authenticationStarted) { + startAuthentication(intent.cloud()) + } + } + + private fun startAuthentication(cloud: CloudModel) { + authenticationStarted = true + val authenticationAdapter = OnedriveClientFactory.instance(context(), (cloud.toCloud() as OnedriveCloud).accessToken()).authenticationAdapter + authenticationAdapter.login(activity(), object : ICallback { + override fun success(accessToken: String?) { + if (accessToken == null) { + Timber.tag("AuthicateCloudPrester").e("Onedrive access token is empty") + failAuthentication(cloud.name()) + } else { + showProgress(ProgressModel(ProgressStateModel.AUTHENTICATION)) + handleAuthenticationResult(cloud, accessToken) + } + } + + override fun failure(ex: ClientException) { + Timber.tag("AuthicateCloudPrester").e(ex) + failAuthentication(cloud.name()) + } + }) + } + + private fun handleAuthenticationResult(cloud: CloudModel, accessToken: String) { + getUsernameAndSuceedAuthentication( // + OnedriveCloud.aCopyOf(cloud.toCloud() as OnedriveCloud) // + .withAccessToken(accessToken) // + .build()) + } + } + + private inner class WebDAVAuthStrategy : AuthStrategy { + override fun supports(cloud: CloudModel): Boolean { + return cloud.cloudType() == CloudTypeModel.WEBDAV + } + + override fun resumed(intent: AuthenticateCloudIntent) { + handleWebDavAuthenticationExceptionIfRequired(intent.cloud() as WebDavCloudModel, intent.error()) + } + + private fun handleWebDavAuthenticationExceptionIfRequired(cloud: WebDavCloudModel, e: AuthenticationException) { + Timber.tag("AuthicateCloudPrester").e(e) + when { + ExceptionUtil.contains(e, WrongCredentialsException::class.java) -> { + failAuthentication(cloud.name()) + } + ExceptionUtil.contains(e, WebDavCertificateUntrustedAuthenticationException::class.java) -> { + handleCertificateUntrustedExceptionIfRequired(cloud, e) + } + ExceptionUtil.contains(e, WebDavServerNotFoundException::class.java) -> { + view?.showMessage(R.string.error_server_not_found) + finish() + } + ExceptionUtil.contains(e, WebDavNotSupportedException::class.java) -> { + view?.showMessage(R.string.screen_cloud_error_webdav_not_supported) + finish() + } + } + } + + private fun handleCertificateUntrustedExceptionIfRequired(cloud: WebDavCloudModel, e: AuthenticationException) { + val untrustedException = ExceptionUtil.extract(e, WebDavCertificateUntrustedAuthenticationException::class.java) + try { + val certificate = X509CertificateHelper.convertFromPem(untrustedException.get().certificate) + view?.showUntrustedCertificateDialog(cloud.toCloud() as WebDavCloud, certificate) + } catch (ex: CertificateException) { + Timber.tag("AuthicateCloudPrester").e(ex) + throw FatalBackendException(ex) + } + } + } + + fun onAcceptWebDavCertificateClicked(cloud: WebDavCloud?, certificate: X509Certificate?) { + try { + val webDavCloudWithAcceptedCert = WebDavCloud.aCopyOf(cloud) // + .withCertificate(X509CertificateHelper.convertToPem(certificate)) // + .build() + finishWithResultAndExtra(cloudModelMapper.toModel(webDavCloudWithAcceptedCert), // + WEBDAV_ACCEPTED_UNTRUSTED_CERTIFICATE, // + true) + } catch (e: CertificateEncodingException) { + Timber.tag("AuthicateCloudPrester").e(e) + throw FatalBackendException(e) + } + } + + fun onAcceptWebDavCertificateDenied() { + finish() + } + + private inner class LocalStorageAuthStrategy : AuthStrategy { + private var authenticationStarted = false + override fun supports(cloud: CloudModel): Boolean { + return cloud.cloudType() == CloudTypeModel.LOCAL + } + + override fun resumed(intent: AuthenticateCloudIntent) { + if (!authenticationStarted) { + startAuthentication(intent.cloud()) + } + } + + 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) + } + } + + @Callback + fun onLocalStorageAuthenticated(result: PermissionsResult, cloud: CloudModel) { + if (result.granted()) { + succeedAuthenticationWith(cloud.toCloud()) + } else { + failAuthentication(PermissionNotGrantedException(R.string.permission_snackbar_auth_local_vault)) + } + } + + private fun encrypt(password: String): String { + return CredentialCryptor // + .getInstance(context()) // + .encrypt(password) + } + + private inner class FailingAuthStrategy : AuthStrategy { + override fun supports(cloud: CloudModel): Boolean { + return false + } + + override fun resumed(intent: AuthenticateCloudIntent) { + view?.showError(R.string.error_authentication_failed) + finish() + } + } + + private interface AuthStrategy { + fun supports(cloud: CloudModel): Boolean + fun resumed(intent: AuthenticateCloudIntent) + } + + companion object { + const val WEBDAV_ACCEPTED_UNTRUSTED_CERTIFICATE = "acceptedUntrustedCertificate" + } + + init { + unsubscribeOnDestroy(addOrChangeCloudConnectionUseCase, getUsernameUseCase) + } +} diff --git a/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt b/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt index acd019cc..685dbc73 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt @@ -42,8 +42,14 @@ class CryptomatorApp : MultiDexApplication(), HasComponent override fun onCreate() { super.onCreate() setupLogging() - - val flavor = if (BuildConfig.FLAVOR == "license") "License Edition" else "Google Play Edition" + val flavor = when (BuildConfig.FLAVOR) { + "apkstore" -> { + "APK Store Edition" + } + "fdroid" -> { + "F-Droid Edition" + } else -> "Google Play Edition" + } Timber.tag("App").i("Cryptomator v%s (%d) \"%s\" started on android %s / API%d using a %s", // BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, flavor, // Build.VERSION.RELEASE, Build.VERSION.SDK_INT, // diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/ChooseCloudServicePresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/ChooseCloudServicePresenter.kt index afabda80..9091c8a6 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/ChooseCloudServicePresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/ChooseCloudServicePresenter.kt @@ -5,6 +5,7 @@ import org.cryptomator.domain.di.PerView import org.cryptomator.domain.exception.FatalBackendException import org.cryptomator.domain.usecases.cloud.GetCloudsUseCase import org.cryptomator.generator.Callback +import org.cryptomator.presentation.BuildConfig import org.cryptomator.presentation.R import org.cryptomator.presentation.exception.ExceptionHandlers import org.cryptomator.presentation.intent.Intents @@ -32,6 +33,11 @@ class ChooseCloudServicePresenter @Inject constructor( // override fun resumed() { val cloudTypeModels: MutableList = ArrayList(listOf(*CloudTypeModel.values())) cloudTypeModels.remove(CloudTypeModel.CRYPTO) + + if(BuildConfig.FLAVOR == "fdroid") { + cloudTypeModels.remove(CloudTypeModel.GOOGLE_DRIVE) + } + view?.render(cloudTypeModels) } diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudSettingsPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudSettingsPresenter.kt index 4b2b6f99..c8893477 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudSettingsPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/CloudSettingsPresenter.kt @@ -9,6 +9,7 @@ import org.cryptomator.domain.usecases.cloud.GetAllCloudsUseCase import org.cryptomator.domain.usecases.cloud.GetCloudsUseCase import org.cryptomator.domain.usecases.cloud.LogoutCloudUseCase import org.cryptomator.generator.Callback +import org.cryptomator.presentation.BuildConfig import org.cryptomator.presentation.R import org.cryptomator.presentation.exception.ExceptionHandlers import org.cryptomator.presentation.intent.Intents @@ -114,7 +115,10 @@ class CloudSettingsPresenter @Inject constructor( // private inner class CloudsSubscriber : DefaultResultHandler>() { override fun onSuccess(clouds: List) { - val cloudModel = cloudModelMapper.toModels(clouds).filter { isSingleLoginCloud(it) }.toMutableList() // + val cloudModel = cloudModelMapper.toModels(clouds) // + .filter { isSingleLoginCloud(it) } // + .filter { cloud -> !(BuildConfig.FLAVOR == "fdroid" && cloud.cloudType() == CloudTypeModel.GOOGLE_DRIVE)} // + .toMutableList() // .also { it.add(aWebdavCloud()) it.add(aLocalCloud()) 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 be850874..18e824ef 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/SettingsPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/SettingsPresenter.kt @@ -66,9 +66,13 @@ class SettingsPresenter @Inject internal constructor( } private fun errorReportEmailBody(): String { - var variant = "PlayStore" - if (BuildConfig.FLAVOR == "license") { - variant = "ApkStore" + val variant = when (BuildConfig.FLAVOR) { + "apkstore" -> { + "APK Store" + } + "fdroid" -> { + "F-Droid" + } else -> "Google Play" } return StringBuilder().append("## ").append(context().getString(R.string.error_report_subject)).append("\n\n") // .append("### ").append(context().getString(R.string.error_report_section_summary)).append('\n') // 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 4e85e0aa..74a3d225 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt @@ -105,12 +105,12 @@ class VaultListPresenter @Inject constructor( // } private fun checkLicense() { - if (BuildConfig.FLAVOR == "license") { + if (BuildConfig.FLAVOR == "apkstore" || BuildConfig.FLAVOR == "fdroid") { licenseCheckUseCase // .withLicense("") // .run(object : NoOpResultHandler() { override fun onSuccess(licenseCheck: LicenseCheck) { - if (sharedPreferencesHandler.doUpdate()) { + if (BuildConfig.FLAVOR == "apkstore" && sharedPreferencesHandler.doUpdate()) { checkForAppUpdates() } } diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/CloudSettingsActivity.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/CloudSettingsActivity.kt index 51ee01c5..311966a2 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/CloudSettingsActivity.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/CloudSettingsActivity.kt @@ -21,7 +21,7 @@ class CloudSettingsActivity : BaseActivity(), CloudSettingsView { setSupportActionBar(toolbar) } - override fun createFragment(): Fragment? = CloudSettingsFragment() + override fun createFragment(): Fragment = CloudSettingsFragment() override fun render(cloudModels: List) { cloudSettingsFragment().showClouds(cloudModels) 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 08694de5..f27a3af0 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 @@ -148,18 +148,28 @@ class SettingsFragment : PreferenceFragmentCompat() { } private fun setupLicense() { - if (BuildConfig.FLAVOR == "license") { - findPreference(SharedPreferencesHandler.MAIL)?.title = format(getString(R.string.screen_settings_license_mail), sharedPreferencesHandler.mail()) - setupUpdateCheck() - } else { - preferenceScreen.removePreference(findPreference(LICENSE_ITEM_KEY)) - - val versionCategory = findPreference("versionCategory") as PreferenceCategory? - versionCategory?.removePreference(findPreference(UPDATE_CHECK_ITEM_KEY)) - versionCategory?.removePreference(findPreference(UPDATE_INTERVAL_ITEM_KEY)) + when (BuildConfig.FLAVOR) { + "apkstore" -> { + findPreference(SharedPreferencesHandler.MAIL)?.title = format(getString(R.string.screen_settings_license_mail), sharedPreferencesHandler.mail()) + setupUpdateCheck() + } + "fdroid" -> { + findPreference(SharedPreferencesHandler.MAIL)?.title = format(getString(R.string.screen_settings_license_mail), sharedPreferencesHandler.mail()) + removeUpdateCheck() + } + else -> { + preferenceScreen.removePreference(findPreference(LICENSE_ITEM_KEY)) + removeUpdateCheck() + } } } + private fun removeUpdateCheck() { + val versionCategory = findPreference("versionCategory") as PreferenceCategory? + versionCategory?.removePreference(findPreference(UPDATE_CHECK_ITEM_KEY)) + versionCategory?.removePreference(findPreference(UPDATE_INTERVAL_ITEM_KEY)) + } + fun setupUpdateCheck() { val preference = findPreference(UPDATE_CHECK_ITEM_KEY) @@ -195,7 +205,7 @@ class SettingsFragment : PreferenceFragmentCompat() { findPreference(SharedPreferencesHandler.PHOTO_UPLOAD)?.onPreferenceChangeListener = useAutoPhotoUploadChangedListener findPreference(SharedPreferencesHandler.USE_LRU_CACHE)?.onPreferenceChangeListener = useLruChangedListener findPreference(SharedPreferencesHandler.LRU_CACHE_SIZE)?.onPreferenceChangeListener = useLruChangedListener - if (BuildConfig.FLAVOR == "license") { + if (BuildConfig.FLAVOR == "apkstore") { findPreference(UPDATE_CHECK_ITEM_KEY)?.onPreferenceClickListener = updateCheckClickListener } } diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt b/presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt similarity index 100% rename from presentation/src/main/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt rename to presentation/src/notFoss/java/org/cryptomator/presentation/presenter/AuthenticateCloudPresenter.kt From fe775d092bbefb257fc2aed61dfa01c9f47b9b46 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Thu, 14 Jan 2021 10:38:13 +0100 Subject: [PATCH 12/32] Follow system color scheme with the curved line when vault list is empty --- .../presentation/ui/layout/VaultListCoordinatorLayout.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/layout/VaultListCoordinatorLayout.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/layout/VaultListCoordinatorLayout.kt index 1664b382..254b9d96 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/layout/VaultListCoordinatorLayout.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/layout/VaultListCoordinatorLayout.kt @@ -2,7 +2,6 @@ package org.cryptomator.presentation.ui.layout import android.content.Context import android.graphics.Canvas -import android.graphics.Color import android.graphics.Paint import android.graphics.RectF import android.util.AttributeSet @@ -50,12 +49,12 @@ class VaultListCoordinatorLayout : CoordinatorLayout { .to(leftOfFloatingActionButton - dpToPixels(3f), topOfFloatingActionButton + dpToPixels(5f)) // .spanningAnAngleOf(60.0f) // .build() // - .draw(canvas, strokeBlackWithWidthOf1f()) + .draw(canvas, strokeLineWithWidthOf1f()) } - private fun strokeBlackWithWidthOf1f(): Paint { + private fun strokeLineWithWidthOf1f(): Paint { val paint = Paint() - paint.color = Color.BLACK + paint.color = context.getColor(R.color.textColorPrimary) paint.strokeWidth = dpToPixels(1f) paint.isAntiAlias = true paint.style = Paint.Style.STROKE From 357fb85ae0173118ec471a68073a1c3d5c573488 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 15 Jan 2021 12:36:04 +0100 Subject: [PATCH 13/32] #245 Fix issue accessing WebDAV using HTTP introduced in 1.5.11-beta1 --- presentation/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/presentation/src/main/AndroidManifest.xml b/presentation/src/main/AndroidManifest.xml index f7fc763f..6c71db05 100644 --- a/presentation/src/main/AndroidManifest.xml +++ b/presentation/src/main/AndroidManifest.xml @@ -30,6 +30,7 @@ android:label="@string/app_name" android:supportsRtl="true" android:requestLegacyExternalStorage="true" + android:usesCleartextTraffic="true" android:theme="@style/AppTheme"> Date: Fri, 15 Jan 2021 20:39:46 +0100 Subject: [PATCH 14/32] Prepare for reproducible builds --- .../generator/IntentProcessor.java | 1 + .../generator/model/ActivitiesModel.java | 12 +-- .../generator/model/ActivityModel.java | 7 +- .../generator/model/FragmentModel.java | 7 +- .../generator/model/FragmentsModel.java | 12 +-- .../generator/model/InstanceStateModel.java | 18 +++-- .../generator/model/InstanceStatesModel.java | 4 +- .../generator/model/IntentBuilderModel.java | 43 +++++++--- .../generator/model/IntentReaderModel.java | 45 ++++++++--- .../generator/model/IntentsModel.java | 18 ++--- .../cryptomator/generator/utils/Method.java | 7 +- .../org/cryptomator/generator/utils/Type.java | 16 +++- msa-auth-for-android | 2 +- presentation/build.gradle | 10 ++- presentation/proguard-rules.pro | 81 ------------------- subsampling-scale-image-view | 2 +- 16 files changed, 144 insertions(+), 141 deletions(-) delete mode 100644 presentation/proguard-rules.pro diff --git a/generator/src/main/java/org/cryptomator/generator/IntentProcessor.java b/generator/src/main/java/org/cryptomator/generator/IntentProcessor.java index 87dc3dbd..3c25d90d 100644 --- a/generator/src/main/java/org/cryptomator/generator/IntentProcessor.java +++ b/generator/src/main/java/org/cryptomator/generator/IntentProcessor.java @@ -34,6 +34,7 @@ public class IntentProcessor extends BaseProcessor { intentsModelBuilder.add(generateIntentReader((TypeElement) element)); } if (!intentAnnotatedElements.isEmpty()) { + intentAnnotatedElements.sort((e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString())); generateIntents(intentsModelBuilder.build(), intentAnnotatedElements); } } diff --git a/generator/src/main/java/org/cryptomator/generator/model/ActivitiesModel.java b/generator/src/main/java/org/cryptomator/generator/model/ActivitiesModel.java index 4a8187e6..d594ac97 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/ActivitiesModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/ActivitiesModel.java @@ -1,21 +1,21 @@ package org.cryptomator.generator.model; -import java.util.ArrayList; -import java.util.List; +import java.util.Set; +import java.util.TreeSet; public class ActivitiesModel { - private final List activities; + private final Set activities; public static ActivitiesModel.Builder builder() { return new Builder(); } - private ActivitiesModel(List activities) { + private ActivitiesModel(Set activities) { this.activities = activities; } - public List getActivities() { + public Set getActivities() { return activities; } @@ -29,7 +29,7 @@ public class ActivitiesModel { public static class Builder { - private final List activities = new ArrayList<>(); + private final Set activities = new TreeSet<>(); private Builder() { } diff --git a/generator/src/main/java/org/cryptomator/generator/model/ActivityModel.java b/generator/src/main/java/org/cryptomator/generator/model/ActivityModel.java index c565f05a..4aac9b55 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/ActivityModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/ActivityModel.java @@ -12,7 +12,7 @@ import javax.lang.model.element.TypeElement; import static java.util.stream.Collectors.toList; -public class ActivityModel { +public class ActivityModel implements Comparable { private final String qualifiedName; @@ -128,4 +128,9 @@ public class ActivityModel { public String getPresenterIntentFieldName() { return presenterIntentFieldName; } + + @Override + public int compareTo(ActivityModel activityModel) { + return this.qualifiedName.compareTo(activityModel.qualifiedName); + } } diff --git a/generator/src/main/java/org/cryptomator/generator/model/FragmentModel.java b/generator/src/main/java/org/cryptomator/generator/model/FragmentModel.java index b7f55631..d1d58aeb 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/FragmentModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/FragmentModel.java @@ -6,7 +6,7 @@ import org.cryptomator.generator.utils.Type; import java.util.Optional; -public class FragmentModel { +public class FragmentModel implements Comparable { private final String qualifiedName; @@ -45,4 +45,9 @@ public class FragmentModel { public boolean isHasPresenter() { return hasPresenter; } + + @Override + public int compareTo(FragmentModel fragmentModel) { + return this.qualifiedName.compareTo(fragmentModel.qualifiedName); + } } diff --git a/generator/src/main/java/org/cryptomator/generator/model/FragmentsModel.java b/generator/src/main/java/org/cryptomator/generator/model/FragmentsModel.java index 7ca076f6..b4864115 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/FragmentsModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/FragmentsModel.java @@ -1,21 +1,21 @@ package org.cryptomator.generator.model; -import java.util.ArrayList; -import java.util.List; +import java.util.Set; +import java.util.TreeSet; public class FragmentsModel { - private final List fragments; + private final Set fragments; public static FragmentsModel.Builder builder() { return new Builder(); } - private FragmentsModel(List fragments) { + private FragmentsModel(Set fragments) { this.fragments = fragments; } - public List getFragments() { + public Set getFragments() { return fragments; } @@ -29,7 +29,7 @@ public class FragmentsModel { public static class Builder { - private final List fragments = new ArrayList<>(); + private final Set fragments = new TreeSet<>(); private Builder() { } diff --git a/generator/src/main/java/org/cryptomator/generator/model/InstanceStateModel.java b/generator/src/main/java/org/cryptomator/generator/model/InstanceStateModel.java index 2e0f3f53..4d18696e 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/InstanceStateModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/InstanceStateModel.java @@ -4,18 +4,18 @@ import org.cryptomator.generator.ProcessorException; import org.cryptomator.generator.utils.Field; import org.cryptomator.generator.utils.Type; -import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; -import java.util.List; import java.util.Map; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; import javax.lang.model.element.Element; public class InstanceStateModel { private final String javaPackage; - private final Map types = new HashMap<>(); + private final Map types = new TreeMap<>(); public InstanceStateModel(String javaPackage) { this.javaPackage = javaPackage; @@ -47,7 +47,7 @@ public class InstanceStateModel { public static class InstanceStateType { - private final List fields = new ArrayList<>(); + private final SortedSet fields = new TreeSet<>(); private final String qualifiedName; public InstanceStateType(Type type) { @@ -62,12 +62,12 @@ public class InstanceStateModel { return qualifiedName; } - public List getFields() { + public SortedSet getFields() { return fields; } } - public static class InstanceStateField { + public static class InstanceStateField implements Comparable { private static int nextBundleKey = 0; @@ -142,6 +142,10 @@ public class InstanceStateModel { return field.element(); } + @Override + public int compareTo(InstanceStateField instanceStateField) { + return this.bundleKey.compareTo(instanceStateField.bundleKey); + } } } diff --git a/generator/src/main/java/org/cryptomator/generator/model/InstanceStatesModel.java b/generator/src/main/java/org/cryptomator/generator/model/InstanceStatesModel.java index 41703b5b..6b628a5e 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/InstanceStatesModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/InstanceStatesModel.java @@ -2,13 +2,13 @@ package org.cryptomator.generator.model; import org.cryptomator.generator.utils.Field; -import java.util.HashMap; import java.util.Map; +import java.util.TreeMap; import java.util.stream.Stream; public class InstanceStatesModel { - private final Map instanceStatesByPackage = new HashMap<>(); + private final Map instanceStatesByPackage = new TreeMap<>(); public void add(Field field) { String packageName = field.declaringType().packageName(); diff --git a/generator/src/main/java/org/cryptomator/generator/model/IntentBuilderModel.java b/generator/src/main/java/org/cryptomator/generator/model/IntentBuilderModel.java index e0c468cb..019c159b 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/IntentBuilderModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/IntentBuilderModel.java @@ -3,9 +3,12 @@ package org.cryptomator.generator.model; import org.cryptomator.generator.Intent; import org.cryptomator.generator.Optional; -import java.util.List; +import java.util.Comparator; import java.util.Map; +import java.util.Set; +import java.util.TreeSet; import java.util.function.Predicate; +import java.util.stream.Collectors; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; @@ -14,16 +17,15 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; import static java.lang.Character.toLowerCase; -import static java.util.stream.Collectors.toList; -public class IntentBuilderModel { +public class IntentBuilderModel implements Comparable { private final String javaPackage; private final String className; private final String targetActivity; private final String targetActivitySimpleName; private final String buildMethodName; - private final List parameters; + private final Set parameters; public IntentBuilderModel(TypeElement type) { this.javaPackage = javaPackage(type); @@ -47,9 +49,21 @@ public class IntentBuilderModel { } private static String targetActivity(TypeElement type) { - return type.getAnnotationMirrors().stream().filter(is(Intent.class)).findFirst().get().getElementValues().entrySet().stream().map(entry -> (Map.Entry) entry) - .filter(entry -> "value".equals(entry.getKey().getSimpleName().toString())).map(Map.Entry::getValue).map(AnnotationValue::getValue).map(DeclaredType.class::cast).map(DeclaredType::asElement) - .map(TypeElement.class::cast).findFirst().get().getQualifiedName().toString(); + return type // + .getAnnotationMirrors() // + .stream() // + .filter(is(Intent.class)) // + .findFirst().get().getElementValues().entrySet() // + .stream() // + .map(entry -> (Map.Entry) entry) // + .filter(entry -> "value".equals(entry.getKey().getSimpleName().toString())) // + .map(Map.Entry::getValue) // + .map(AnnotationValue::getValue) // + .map(DeclaredType.class::cast) // + .map(DeclaredType::asElement) // + .map(TypeElement.class::cast) // + .findFirst().get() // + .getQualifiedName().toString(); } private static Predicate is(Class type) { @@ -66,8 +80,14 @@ public class IntentBuilderModel { return toLowerCase(name.charAt(0)) + name.substring(1); } - private static List parameters(TypeElement type) { - return type.getEnclosedElements().stream().filter(ExecutableElement.class::isInstance).map(ExecutableElement.class::cast).map(ParameterModel::new).collect(toList()); + private static Set parameters(TypeElement type) { + return type // + .getEnclosedElements() // + .stream() // + .filter(ExecutableElement.class::isInstance) // + .map(ExecutableElement.class::cast) // + .map(ParameterModel::new) // + .collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(ParameterModel::getName)))); } private static String buildMethodName(TypeElement type) { @@ -101,6 +121,11 @@ public class IntentBuilderModel { return buildMethodName; } + @Override + public int compareTo(IntentBuilderModel intentBuilderModel) { + return (this.javaPackage + this.className).compareTo(intentBuilderModel.javaPackage + intentBuilderModel.className); + } + public static class ParameterModel { private final String nameWithFirstCharUppercase; diff --git a/generator/src/main/java/org/cryptomator/generator/model/IntentReaderModel.java b/generator/src/main/java/org/cryptomator/generator/model/IntentReaderModel.java index 62c59abf..7e3095dd 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/IntentReaderModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/IntentReaderModel.java @@ -3,9 +3,12 @@ package org.cryptomator.generator.model; import org.cryptomator.generator.Intent; import org.cryptomator.generator.Optional; -import java.util.List; +import java.util.Comparator; import java.util.Map; +import java.util.Set; +import java.util.TreeSet; import java.util.function.Predicate; +import java.util.stream.Collectors; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; @@ -13,16 +16,14 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; -import static java.util.stream.Collectors.toList; - -public class IntentReaderModel { +public class IntentReaderModel implements Comparable { private final String javaPackage; private final String className; private final String targetActivity; private final String intentInterface; private final String readMethodName; - private final List parameters; + private final Set parameters; public IntentReaderModel(TypeElement type) { this.intentInterface = type.getQualifiedName().toString(); @@ -46,9 +47,22 @@ public class IntentReaderModel { } private static String targetActivity(TypeElement type) { - return type.getAnnotationMirrors().stream().filter(is(Intent.class)).findFirst().get().getElementValues().entrySet().stream().map(entry -> (Map.Entry) entry) - .filter(entry -> "value".equals(entry.getKey().getSimpleName().toString())).map(Map.Entry::getValue).map(AnnotationValue::getValue).map(DeclaredType.class::cast).map(DeclaredType::asElement) - .map(TypeElement.class::cast).findFirst().get().getQualifiedName().toString(); + return type // + .getAnnotationMirrors() // + .stream() // + .filter(is(Intent.class)) // + .findFirst().get().getElementValues().entrySet() // + .stream() // + .map(entry -> (Map.Entry) entry) // + .filter(entry -> "value".equals(entry.getKey().getSimpleName().toString())) // + .map(Map.Entry::getValue) // + .map(AnnotationValue::getValue) // + .map(DeclaredType.class::cast) // + .map(DeclaredType::asElement) // + .map(TypeElement.class::cast) // + .findFirst().get() // + .getQualifiedName() // + .toString(); } private static Predicate is(Class type) { @@ -59,8 +73,14 @@ public class IntentReaderModel { }; } - private static List parameters(TypeElement type) { - return type.getEnclosedElements().stream().filter(ExecutableElement.class::isInstance).map(ExecutableElement.class::cast).map(ParameterModel::new).collect(toList()); + private static Set parameters(TypeElement type) { + return type // + .getEnclosedElements() // + .stream() // + .filter(ExecutableElement.class::isInstance) // + .map(ExecutableElement.class::cast) // + .map(ParameterModel::new) // + .collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(ParameterModel::getName)))); } private static String readMethodName(TypeElement type) { @@ -94,6 +114,11 @@ public class IntentReaderModel { return readMethodName; } + @Override + public int compareTo(IntentReaderModel intentReaderModel) { + return (this.javaPackage + this.className).compareTo(intentReaderModel.javaPackage + intentReaderModel.className); + } + public static class ParameterModel { private final String name; diff --git a/generator/src/main/java/org/cryptomator/generator/model/IntentsModel.java b/generator/src/main/java/org/cryptomator/generator/model/IntentsModel.java index 13fe9129..af384366 100644 --- a/generator/src/main/java/org/cryptomator/generator/model/IntentsModel.java +++ b/generator/src/main/java/org/cryptomator/generator/model/IntentsModel.java @@ -1,27 +1,27 @@ package org.cryptomator.generator.model; -import java.util.ArrayList; -import java.util.List; +import java.util.Set; +import java.util.TreeSet; public class IntentsModel { - private final List builders; - private final List readers; + private final Set builders; + private final Set readers; public static IntentsModel.Builder builder() { return new Builder(); } - private IntentsModel(List builders, List readers) { + private IntentsModel(Set builders, Set readers) { this.builders = builders; this.readers = readers; } - public List getBuilders() { + public Set getBuilders() { return builders; } - public List getReaders() { + public Set getReaders() { return readers; } @@ -35,8 +35,8 @@ public class IntentsModel { public static class Builder { - private final List builders = new ArrayList<>(); - private final List readers = new ArrayList<>(); + private final Set builders = new TreeSet<>(); + private final Set readers = new TreeSet<>(); private Builder() { } diff --git a/generator/src/main/java/org/cryptomator/generator/utils/Method.java b/generator/src/main/java/org/cryptomator/generator/utils/Method.java index 4966517f..82eb56db 100644 --- a/generator/src/main/java/org/cryptomator/generator/utils/Method.java +++ b/generator/src/main/java/org/cryptomator/generator/utils/Method.java @@ -9,7 +9,7 @@ import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeKind; -public class Method { +public class Method implements Comparable { private final Utils utils; private final ExecutableElement delegate; @@ -75,4 +75,9 @@ public class Method { public Type declaringType() { return new Type(utils, (TypeElement) delegate.getEnclosingElement()); } + + @Override + public int compareTo(Method method) { + return this.delegate.getSimpleName().toString().compareTo(method.delegate.getSimpleName().toString()); + } } diff --git a/generator/src/main/java/org/cryptomator/generator/utils/Type.java b/generator/src/main/java/org/cryptomator/generator/utils/Type.java index 61f115d4..884b1a9f 100644 --- a/generator/src/main/java/org/cryptomator/generator/utils/Type.java +++ b/generator/src/main/java/org/cryptomator/generator/utils/Type.java @@ -14,7 +14,7 @@ import static javax.lang.model.element.ElementKind.FIELD; import static javax.lang.model.type.TypeKind.ARRAY; import static javax.lang.model.type.TypeKind.NONE; -public class Type { +public class Type implements Comparable { private final TypeMirror mirror; private final Optional element; @@ -89,6 +89,7 @@ public class Type { return element // .map(type -> type.getEnclosedElements().stream() // .filter(ExecutableElement.class::isInstance) // + .sorted((e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString())) // .map(ExecutableElement.class::cast) // .filter(Method::isConstructor) // .map(executableElement -> new Method(utils, executableElement))) @@ -99,20 +100,22 @@ public class Type { return element // .map(type -> type.getEnclosedElements().stream() // .filter(ExecutableElement.class::isInstance) // + .sorted((e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString())) // .map(ExecutableElement.class::cast) // .filter(Method::isRegularMethod) // .map(executableElement -> new Method(utils, executableElement))) - .orElse(Stream.empty()); // + .orElse(Stream.empty()); } public Stream fields() { return element // .map(type -> type.getEnclosedElements().stream() // .filter(VariableElement.class::isInstance) // + .sorted((e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString())) // .map(VariableElement.class::cast) // .filter(variable -> variable.getKind() == FIELD) // - .map(variableElement -> new Field(utils, variableElement))) - .orElse(Stream.empty()); // + .map(variableElement -> new Field(utils, variableElement))) // + .orElse(Stream.empty()); } @Override @@ -133,6 +136,11 @@ public class Type { return mirror.hashCode(); } + @Override + public int compareTo(Type type) { + return this.qualifiedName().compareTo(type.qualifiedName()); + } + public Optional enclosingType() { if (mirror instanceof DeclaredType) { return Optional.ofNullable(((DeclaredType) mirror).getEnclosingType()) // diff --git a/msa-auth-for-android b/msa-auth-for-android index eca34e84..fe4e0458 160000 --- a/msa-auth-for-android +++ b/msa-auth-for-android @@ -1 +1 @@ -Subproject commit eca34e843a1ca2d7953f0d7c22efe72572ce7dc1 +Subproject commit fe4e04589043cb18011cae80aec7eab09b46ed44 diff --git a/presentation/build.gradle b/presentation/build.gradle index 9e7a81b7..cc4353e9 100644 --- a/presentation/build.gradle +++ b/presentation/build.gradle @@ -47,12 +47,18 @@ android { buildTypes { release { - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + crunchPngs false + minifyEnabled false + shrinkResources false + useProguard false } debug { signingConfig signingConfigs.debug + + crunchPngs false + minifyEnabled false + shrinkResources false testCoverageEnabled false } } diff --git a/presentation/proguard-rules.pro b/presentation/proguard-rules.pro deleted file mode 100644 index 8702417d..00000000 --- a/presentation/proguard-rules.pro +++ /dev/null @@ -1,81 +0,0 @@ --useuniqueclassmembernames - -# greenDAO 3, http://greenrobot.org/greendao/documentation/technical-faq --keepclassmembers class * extends org.greenrobot.greendao.AbstractDao { - public static java.lang.String TABLENAME; -} --keep class **$Properties {*;} --dontwarn org.greenrobot.greendao.database.** --dontwarn net.sqlcipher.database.** --dontwarn rx.** - -# RxJava, https://github.com/artem-zinnatullin/RxJavaProGuardRules/blob/master/rxjava-proguard-rules/proguard-rules.txt --dontwarn sun.misc.** --keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { - long producerIndex; - long consumerIndex; -} --keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef { - rx.internal.util.atomic.LinkedQueueNode producerNode; -} --keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef { - rx.internal.util.atomic.LinkedQueueNode consumerNode; -} - -# Google API Client, https://github.com/google/google-api-java-client/blob/dev/google-api-client-assembly/proguard-google-api-client.txt --keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault --keepclassmembers class * { - @com.google.api.client.util.Key ; -} --dontwarn com.google.api.client.extensions.android.** --dontwarn com.google.api.client.googleapis.extensions.android.** --dontwarn com.google.api.client.googleapis.testing.TestUtils --dontwarn com.google.android.gms.** - -# okhttp3 --dontwarn okhttp3.** --dontwarn okio.** - -# Others --dontwarn org.slf4j.** --dontwarn com.dropbox.core.** --dontwarn com.fernandocejas.frodo.core.** --dontwarn com.google.errorprone.annotations.** --dontwarn com.google.common.util.concurrent.FuturesGetChecked** --keepclassmembers class com.microsoft.graph.http.GraphServiceException { - int mResponseCode; -} --keep class com.nulabinc.zxcvbn.** - -# https://stackoverflow.com/a/47555897/1759462 --dontwarn afu.org.checkerframework.** --dontwarn org.checkerframework.** - -# https://github.com/microsoftgraph/msgraph-sdk-java/issues/258#issue-452030712 --keep class com.microsoft.** { *; } --keep class com.microsoft.** --keep interface com.microsoft.** { *; } --keepclasseswithmembernames class com.microsoft.** { *; } - --keep class com.sun.** { *; } --keep class com.sun.** --keep interface com.sun.** { *; } - -# https://github.com/jwtk/jjwt --keepattributes InnerClasses - --keep class io.jsonwebtoken.** { *; } --keepnames class io.jsonwebtoken.* { *; } --keepnames interface io.jsonwebtoken.* { *; } - --keep class org.bouncycastle.** { *; } --keepnames class org.bouncycastle.** { *; } --dontwarn org.bouncycastle.** - --keep class android.net.http.** { *; } --keep interface org.apache.** { *; } --keep enum org.apache.** { *; } --keep class org.apache.** { *; } --keep class org.apache.commons.** { *; } --keep class org.apache.http.** { *; } --keep class org.apache.harmony.** {*;} diff --git a/subsampling-scale-image-view b/subsampling-scale-image-view index 951e3924..c3c247b6 160000 --- a/subsampling-scale-image-view +++ b/subsampling-scale-image-view @@ -1 +1 @@ -Subproject commit 951e3924349ec1607ed06663d32ec918abf09076 +Subproject commit c3c247b63cb72a4f7f9ddc3272820e1ce636e56d From f686b0cabb38fbeddda846c98e70d2b0054a7457 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 15 Jan 2021 20:45:44 +0100 Subject: [PATCH 15/32] Add shell script to enable demo mode for e.g. creating screenshots [ci skip] --- demo-mode.sh | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100755 demo-mode.sh diff --git a/demo-mode.sh b/demo-mode.sh new file mode 100755 index 00000000..9f70ba43 --- /dev/null +++ b/demo-mode.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +adb shell settings put global sysui_demo_allowed 1 + +adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1200 +adb shell am broadcast -a com.android.systemui.demo -e command network -e mobile show -e level 4 -e datatype false +adb shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false +adb shell am broadcast -a com.android.systemui.demo -e command battery -e plugged false -e level 100 From 3e6a3f88b3dd34bf9e55c0e3af5b836ce317f2e5 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 15 Jan 2021 21:25:25 +0100 Subject: [PATCH 16/32] Simplify issue template [ci skip] --- .../CODE_OF_CONDUCT.md | 0 CONTRIBUTING.md => .github/CONTRIBUTING.md | 6 +- .github/ISSUE_TEMPLATE/bug.md | 14 +- .github/ISSUE_TEMPLATE/config.yml | 8 ++ .github/ISSUE_TEMPLATE/feature.md | 14 +- .github/SECURITY.md | 124 ++++++++++++++++++ SUPPORT.md => .github/SUPPORT.md | 0 .github/workflows/triageBugs.yml | 31 +++-- 8 files changed, 166 insertions(+), 31 deletions(-) rename CODE_OF_CONDUCT.md => .github/CODE_OF_CONDUCT.md (100%) rename CONTRIBUTING.md => .github/CONTRIBUTING.md (72%) create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/SECURITY.md rename SUPPORT.md => .github/SUPPORT.md (100%) diff --git a/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md similarity index 100% rename from CODE_OF_CONDUCT.md rename to .github/CODE_OF_CONDUCT.md diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 72% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md index 63e774b2..7baabb71 100644 --- a/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -4,12 +4,12 @@ - Ensure you're running the latest version of Cryptomator. - Ensure the bug is related to the Android version of Cryptomator. Bugs concerning the Cryptomator desktop application and iOS app can be reported on the [Cryptomator issues list](https://github.com/cryptomator/cryptomator/issues) and [Cryptomator for iOS issues list](https://github.com/cryptomator/cryptomator-ios/issues) respectively. -- Ensure the bug was not [already reported](https://github.com/cryptomator/cryptomator-android/issues). You can also check out our [FAQ](https://community.cryptomator.org/c/faq). -- If you're unable to find an open issue addressing the problem, [submit a new one](https://github.com/cryptomator/cryptomator-android/issues/new). +- Ensure the bug was not [already reported](https://github.com/cryptomator/android/issues). You can also check out our [FAQ](https://community.cryptomator.org/c/faq). +- If you're unable to find an open issue addressing the problem, [submit a new one](https://github.com/cryptomator/android/issues/new). ## Code of Conduct -Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](https://github.com/cryptomator/cryptomator-android/blob/master/CODE_OF_CONDUCT.md). +Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](https://github.com/cryptomator/android/blob/develop/.github/CODE_OF_CONDUCT.md). ## Above all, thank you for your contributions diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index f4f8e9d8..53d94eee 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -5,18 +5,12 @@ labels: type:bug --- - ### Description diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..94f5f512 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Help & Support + url: https://community.cryptomator.org/ + about: You will find answers in our community forum + - name: User Manual + url: https://docs.cryptomator.org/ + about: Read the Cryptomator documentation here diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md index 42a54e93..91b7c00b 100644 --- a/.github/ISSUE_TEMPLATE/feature.md +++ b/.github/ISSUE_TEMPLATE/feature.md @@ -5,16 +5,12 @@ labels: type:feature-request --- + ### Summary [One paragraph explanation of the feature.] @@ -29,4 +25,4 @@ Of course, we also expect you to search for existing similar feature requests fi ### Additional Context -[Add any other context or screenshots about the feature request here.] \ No newline at end of file +[Add any other context or screenshots about the feature request here.] diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 00000000..1bcb1adc --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,124 @@ +# Security Policy + +## Reporting a Vulnerability + +For reporting security-related vulnerabilities or exploits that [haven't been reported yet](https://github.com/cryptomator/android/labels/type%3Asecurity-issue), contact us at: security@cryptomator.org + +
+PGP Key + +``` +-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: GPGTools - https://gpgtools.org + +mQINBFbgeicBEADM9AcU6DTgM5KZnBaJc6x9DBLr+TCMHntTt7YM9GLTlO2Z43Jt +oYoyqdRWAY28veqpLEFgRvvVD3fdBj/KUOxF1cr2JsErwXqbjwaLq0o/0KIXz7UK +a6pQSemZKfpOtJrfacofOTwvG6AuG9uakBYNMyxuojyOkoh3xsYS1KZ7TwPgCdET +t8/zva41Pa5kh5+GeSZJdCuygG6ynPBJEpmK5V7Qizvics5fziXecF+QaFZijafv +YahfxokvF9pXCQTmV4m57NQma9uK0w83U9nJCPjEd+x3wK0Hxrc1ojy8ZFTA1YND +AQg/MTABgHbQQkXDQhjS/TloOObqtbMBqNSbcSXpaR4teaCWKBl1MSq00nJLj8db +vPJGqfg7UbXhlALggp029/kskYlR5SmbxWquLbl0Xre3fDHuHEiWcJL6MS3454Wt +Mno13/4UhOlRFh5g0pLmPz7seOTJjDqc9abn/RXOLq0+3qX0gC0bDm5aCE5dQ2MV +FMbrrlw/dZESNLZvtB3gOsramSry1R3HVZ0QJ2vMaF2cxewebqcYbuecUNj6bxpv +5LEhEmqz6dG1meLLWDsvQLPEUWEIJnfpBiDSm342yxJq4pXnVF+aqAQsCL3FpmvZ +2j0FgFOs7iXOcFUJIiR0xUmWPk1NWYcUowqmRW8pMM9nFUzFF99iggPznwARAQAB +tC1DcnlwdG9tYXRvciBTdXBwb3J0IDxzdXBwb3J0QGNyeXB0b21hdG9yLm9yZz6J +AkAEEwEKACoCGwMFCQcrKAAFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AFAleu2cQC +GQEACgkQI7Xb75TU2B3+7A/7BKRWdo5/moCCEbBzYQ7vRMLFdwmjFFlSZ7aGC0fP +YHdeUwxPbO0cATwmNpGMma7rBn1FDg3Vto6/wottGxm+XIRwlyY84CD1VZAihZ/e +WvjOO28/7VgRy6PGKzlhpDSoT8GwFOgO69e7bEff1Zj562RZe7nXc4tDivILMB++ +KgmmSgtddygmNQCS3RD3KssGo+l+cSjsg09F5WAJ6nQe8Jq2hICq+o/P6UXPI5lX +bhvWYDn4/8sRHsIlGpQYYDDe0fz7IQKuSLAHpF5upNDxj6dYb05F8PPVrk6MW6nL +/kf1fZ27DlLN5/NFvhhBRuwxxoAFqPS7Iel3z7L0JkRUYmGLVB5m9Cqiw6FK8JRv +OtvakdDoKb5lVAoN5NeBfNBSqEcXVF/EdfTfIyyo7hZRA6xFMEVbmYbzt0sj0djV +ZOey2TOFrTCpkHfUUDgKvk5sn+F3u8mmPIbqquEzlFJSFjcyiYYDv22rg1In+zKV +Xmw4BFZRDS6IVSQRGlskRGJBixCaGyDYxHXXT2cg4Rk9uiCX11+0E9qlAsg6xPe6 +rnaYDT8dU0AFyVpDpshflXH3kVQSpiqZS3jkAk1/54ODO8pE80Zrnd5m5AMuNcmX ++9MkZKE+h0882UskDs1dyt26GU2hoy4lAeRUaut7zIK/WO6nnuLaTvGWT95RDz+q +kD2JAiIEEwEKAAwFAleu2iYFgweGH4AACgkQZnuGbqgkCgnmCA//U22uhyEC/Tp3 +Cbt5lctQmqbgMbjRBaHQyW52tPFMaq8vXMbo/5TTtVC6xsp2PJT84cxAd8KX8hWq +cPtF4wWCJGng/AzyxQ5dWfGvA/ll32ygjtJN3P/AvA9KlhG+6XYmS8cPkBkJBi6B +2yCdZT1cXc/TPAFzjgAwz7K9g3awG0OeOc/CXymH0DD/snkiwKQoucStolYywZGc +GszjMQgeT4zOc1wtEz24uL3dMNDlDcQMAh56YvK2oB0iMYmAFyX/IS+f2bM9paXi +HX+mg/z53iwgf5ZXbslNDbMTJ5GNksjEGjCFfDHAdNdgT+lcW4l2U7q4PYUaN4LA +DE9j2OlOlQ9qjucOgoCStirnTP7XHd4p31lgdz8+THOQowB5Ji95OkiNQAFCfxBt +mcA/bWnJZQDm7L8RVzHovBpAaK6vUjxEvR+DXdESSzyZwkpsZwGZcyqGRT26R1/L +JE5WvjKufNc5v3Cat320MjyrLZwVGRgvEpDMoCw3nTWl9AtOj5vgaakEWr7AnqET +xk7UFbYmdTlQqkWuLKubz9Rx/FbrBmvd6vwTHy1Dfl6QyMWNCClatgN00Hxped/6 +CErg+R/RXd8apGxnOuWDqoujPn5LOHzgJolp1Ox16nTiZe2G+LbDr3hqRFi1wW6w +ioMB4KpkdA03uyxJSWmDEMiR1l3Oxom0KUNyeXB0b21hdG9yIFByZXNzIDxwcmVz +c0BjcnlwdG9tYXRvci5vcmc+iQI9BBMBCgAnBQJXrtnDAhsDBQkHKygABQsJCAcD +BRUKCQgLBRYCAwEAAh4BAheAAAoJECO12++U1NgdQYMQAKCIzNJF8rURQcFLSv3J +sPBjRy2HCzCWm21MuhU+bsaZx7U9M9dgEjzLfxN9s19VsBH3WKLgok2FgiYSGka3 +6Oy/P8VFLFmHs7dS9i2fro2eF7i4zj/ZD/9t0jM4ZIgLpbzr5sTBld292nsfXGob +xOJeOx3oWYyR2FO9VQxXjC3JvJyZkFgoy0tauS4Mvii4cF56wJGcxDTbe1s7UaRC +a/fh4zgISZSBE3rYhCawkN4mqMDM5RDjrdtjKUPWk345HcjjQ4Wos8xw4YbGbNr9 +Pc7m2URYJJ0jFM4tnoRF6cmA3bT9tm8pcOFg+K/ycVrltVEy+A8Wj8UGjyP1uI1t +EqWHN3LZpIGfW0w9AGrw7OUI9czXcukfngj/DsOU3WMBDIM8pW9+zBpr75yIS6lz +C0IqksLXSqX0b/Rby4O+wb6UZ1ZFkaim2GGtAZV+nGXtdnEXSNFiP7ykzjZ02m/1 +7CKyj3VmdAgT56zEIypFSfxm9gOWsJPmfhSyuE8bFyoitgNxpheZk6xZy4upVMPR +WK3hutScU0yDv2HVCiA3o3Ggy42nmz9HpGF6W2DmBx4bhMaVs6I2VFyKdQzmJD/3 +FCWjwz8PiEgVGHGPnD+WdPFLhrc/44gF4h/VuLjkubtULGuTVvgjeTIJ5LR1Gmwc +YOk6eD7MAJPzJVj5/PYFtIbKiQIiBBMBCgAMBQJXrtonBYMHhh+AAAoJEGZ7hm6o +JAoJBh4P/1w88YMTKUHpFTfJEwH2hK36BZN96Bf/k+vP7n1Xxp3NheInJblHFOt/ +ccsup6am+APrk8gGtlIVmtVc3nO8WMsWxfJxGDecyRsNbessnODv/llyg3tzVU/H +tLk7gLiK0TcIsOLfeNXGTxRRSKWjVFsNfuixNCzzHa7tFq6ddVn9VRZ8fqJB2p21 +OogWSDqUo9q9Wfb4RkYHguDx+8Jzoo/MxR1TSt8gUO2xDvEbqgeQiMCLF8R0lO3Y +zz0FrpyOsFU1CxVp+wo55bWv1UdwgQKQt4o0m5/zDJ2RAtscXpd4YcTE+XxKeK+4 +qhihhkhLGpKsxzK5m9/qwMbodHwoBCBzfalkUR9xOq9yQIeEoC8XYL62NqB3BCSU +KfWFIHxUkE9WH5zHWaV+bhrlNgk7nz3xBfPf1P2mNIc1VUHoNqOZOmWwz2VaKLSW +f3GIqx9wGythFbLdXmUoC3W//DDYgQnvImvkncMqQ5nRHPf8uHcLQK5WZyIxpgWT +eKon5G/cj0BTptcBhapMwSIyfaC5FV7so0/CkOA6R9Fyq2VpGoHy7XPhFS+6ieLi +KUWhCvbuf2deWbSaJ0peMdzy1p72UXwrsEM0M3Fz+Jd8zvCaFzf5Fx27+pAAdlfg +4bT3/2gSf7S+cU3+DnYOH0NeRt2Z2mjEKg9OwttTO/oDboQHdZlrtDRDcnlwdG9t +YXRvciBTZWN1cml0eS1UZWFtIDxzZWN1cml0eUBjcnlwdG9tYXRvci5vcmc+iQI9 +BBMBCgAnBQJXrtnWAhsDBQkHKygABQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJ +ECO12++U1NgddzoQAI78+Nvm6VvNuptXJjEmrpHRyKCnHF9wH5kxvF8WZCgpOkJ4 +vONmyS+9ZlepnT83MpGm/MzdIMCnDJmDmqmA5ISBRcD7k9Gjzz5rPKwE2zDyo0M0 +wF1L2UEUqAlcvE0e4twZcP2DGoNqdSf6IaWsXhQMb1a/rTMsoGZLuTB8kCbv6Ntl +ULahcRToTB2shsbZjzE896P6X5hDCfGWl0Jhcbf53pnXX1dOsEw3et9AGru1IUMs +UGM+wpgTwagRj+XB/WY1x9IznKtiHTq83Fvt+3bkg0+NIcV3GDqXDIUtqIwy8gDd +4KgBU+LkyxXFDa4OxLc53n6b+Iy1nDosM+SiqSzdCCgEs/dY1tQBn/7P1GT18dEe +tFgeH/c6wLvEpDIc9urAsYXf8H+1uy7glWpWTq8DE0yhCr4adjCqlIsVHQQO4UUW +NfqMGEFpJ+3HjSSwnvDGY78lLQh5d4vqWV435aNaMqZg0gJIA0FtiP1fRtmT73BG +N/tBNiBxretFR4B+x/TWqPd5iJV7/MAn/pa1WSOcaxzJrVUsjXdgLQCqcHWd4/w1 +f4DU9cJjl3sxZlMdAlg8Q1bF+pmjQQ4WKZkqMtwpoUilfVXmL42ay1LBCgW68/uJ +OTyGfp8ntUsbbm5raGsny3TLqnacyG9hxcPGNTzD1+MrbUvfsc7+4U0dCZTuiQIi +BBMBCgAMBQJXrtonBYMHhh+AAAoJEGZ7hm6oJAoJ1DQP/R+1drZiZQU45ChMbfTb +XQjJRsUOGZp3PTWtx4KrVFvE8ea0PF+DZX5gLJYIU+iZmPXRpzFu6dKPbcZ7RfRt +5RRH102zDZzijt2CQd7YLO8wxUFoWX9X7DGgxXEcNjl9kFVmnyHgiTwTzuZ0Zy4y +PvoiwrhcZmXEYbOeV40gLFie6wuzz5IIcs01e30xIs+1/1gwmgI5UnG3jveUgmcj +f/lvg3POKiwrY5Uzw1FSruJx21X06wTpDcfOACID4L7aY9eg2B/qL2Xj8nuhejqG ++1AVTMk2o6pxkvevHmxYQfEpuWGCw0RCBn9ObWwz6Zn5J9pjGbMrM+b1/M2Ouv3N +cpoGgCSahKNsRMKO7RMrBG0jtLcasPSgZFYPJSZAAb+YhxKUbpPHzDIwTEjgM7CL +gKSyRTKyp5IoFK53bpXL/ZIjkAhMvyDult6+BL6vI0+h3BBA9I0FF2Qhe139xLv/ +DS7aDiYAE9vGMGoeCBfxJPwUsDU3hrGe/wgL7fR6nmN7R2QffisBHKHsklORy9t3 +w3YFRd5sBAxv+EOcdkgXEmqKOfVQ8KU9adQcxPDGMAK/esjVwxUxsaf2PF5noxxW +3zL2ureUO/mMoH5Cwr0BuM3HFb82t1JJd4IXlLEyNvDMFMwD2d7h37bGK7Y5hEsl +zL7Dm+wQRY8sxg4QOZHbJjQXuQINBFbgeicBEADnkxGSEL1zwACaiVqADKC6/pgO +MMWjxoENBT6r8Vnp1D5hfNDkEi9iXUpCEO6nzywBf3/4c4Yk1wBOBZ7YWyWXMf4v +2g1evxELO5z1UlAwna6HSl7G0omIBqzz1Er5IS7C9WEZM8ZggwcuswCrbxfz4+fN +t7cCL5QyOvuxez+vrn+VIgLQzKm+LV4Wc+OFbHIys+0saQUhItKO0/CsXGc8R314 +jdN5UsZk/MUdPPAs+6OCr8d3PpJvR6IST76TtN8aDjSS9T6em7dwdGFEwCGww3Jc +xrAkvvUmSlscz+rnvHA5DYQGK6NXLenB40sVQVfch1r1VqwvlzA0u7OovjwM8+7u ++DaBQ0YejbdnC7yfeE91LmZkG6jRKfvTJkv18tjNsgZsVmM13xzP67fCFIB9M+lN +t9zEldGKHVwm+06FHIWJsBDRgrquNb9xd1vgHHeIbJvKf+LqZhVrbKVEneG34Km+ +ndtb+mvcGc0fOoMU9lYrFaxAWl8oU9BchC9IyjcPZB445R+AhfTuoHSUViSCo6IO +TG0hQsJuNoKmDAU8l5sTsiFXuXBOo1wK8gTkRnhZHduZrZIjJXvT7efz1knLQ6eG +prZHf4CtbgHyAe2XZabetWtCsFcPbOjC7ezNK57UvVH98h2GkckxOM00BESMCTee +kYy7uG0v0rrajzHY1wARAQABiQIlBBgBCgAPBQJW4HonAhsMBQkHKygAAAoJECO1 +2++U1NgdyAsQAKZUVA6pY225BASkeNiW31L7K4VeRYpAdFkiRex2zQFtj9Vovfi1 +JeTs0fRm35dUsQraf1bkhsjEdPVZ3gD324/baauFO04KX+soyQvK/tUq8KO+5ALt +Ul5aAljuSwxfJWFpApv+Mbf7gOjm+77jirs7pgG/gCow/mkRlmKTwAmn2DXjkckC +2EH0mqmh5pdoNWKO7WeTFFbUmESsPcnB2FwTpEjHFvgHll+rmKpXZTgFYN4dDhhm +HsL/SCf/Nw+YIsuvErQ9TJVdJDLG8ZYatruk7dZZMPtFxvxM1Q36gDIpPEOKPkvm +dMXg6jHaIdYIaoMpzXFaXsQMdRuMtzbcA+CdwXVY55qGLtfmM/QuEiIJdDeeh7iB ++VAMyEFOOpi8IFhixaeMoZAmrKDqOkzPcMJVklLYq8N+b9p5JszYNwZEbpyWCACM +6K+iJzlWzW/OPZttGLJBgYuSYIJIuG80Cx5m5m1e5RAgQ1iT8nbfrS+gYttwP48J +V7SXQg7QugxG9l1vlK4VjnXiOFulJ7V0e/VyUBpJp3qHcCxFq3RnxVwlIqKZh+jm +Q1bk0H0Xodd27nQITfDP5ullByGW2Jrjs6SsXeR3jl9+t0XQfInU1L9d/wSOkMjL +9IMUt06lV4vB/WP2xioqLZiZ4eAi0E+lWkFxjZsgNs2xbOAYRThMB8a5 +=W1Ri +-----END PGP PUBLIC KEY BLOCK----- +``` +
diff --git a/SUPPORT.md b/.github/SUPPORT.md similarity index 100% rename from SUPPORT.md rename to .github/SUPPORT.md diff --git a/.github/workflows/triageBugs.yml b/.github/workflows/triageBugs.yml index f3354fb1..5f18126c 100644 --- a/.github/workflows/triageBugs.yml +++ b/.github/workflows/triageBugs.yml @@ -6,20 +6,33 @@ on: jobs: closeTemplateViolation: - name: Close bug reports that violate the issue template + name: Validate bug report against issue template runs-on: ubuntu-latest + if: contains(github.event.issue.labels.*.name, 'type:bug') steps: - - if: | - contains(github.event.issue.labels.*.name, 'type:bug') - && ( - !contains(github.event.issue.body, '') - || !contains(github.event.issue.body, '### Description') - ) - name: Close Issue + - name: Check "Description" + if: | + !contains(github.event.issue.body, env.MUST_CONTAIN) + || contains(toJson(github.event.issue.body), env.MUST_NOT_CONTAIN) + run: exit 1 + env: + MUST_CONTAIN: '### Description' + MUST_NOT_CONTAIN: '### Description\r\n\r\n[Summarize your problem.]\r\n\r\n### System Setup' + - name: Check "Steps to Reproduce" + if: | + !contains(github.event.issue.body, env.MUST_CONTAIN) + || contains(toJson(github.event.issue.body), env.MUST_NOT_CONTAIN) + run: exit 1 + env: + MUST_CONTAIN: '### Steps to Reproduce' + MUST_NOT_CONTAIN: '### Steps to Reproduce\r\n\r\n1. [First step]\r\n2. [Second step]\r\n3. [and so on…]\r\n\r\n#### Expected Behavior' + - name: Close issue if one of the checks failed + if: ${{ failure() }} uses: peter-evans/close-issue@v1 with: comment: | This bug report did ignore our issue template. 😞 Auto-closing this issue, since it is most likely not useful. - _This decision was made by a bot. If you think the bot is wrong, let us know and we'll reopen this issue._ \ No newline at end of file + _This decision was made by a bot. If you think the bot is wrong, let us know and we'll reopen this issue._ + From 69705ddfc76a0fd19bb67a149c6010017f5316bf Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Tue, 19 Jan 2021 15:33:26 +0100 Subject: [PATCH 17/32] #249 fix app crashes on startup in RTL (right to left) mode --- .../ui/layout/VaultListCoordinatorLayout.kt | 68 +++++++++++++++---- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/layout/VaultListCoordinatorLayout.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/layout/VaultListCoordinatorLayout.kt index 254b9d96..ffa345b7 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/layout/VaultListCoordinatorLayout.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/layout/VaultListCoordinatorLayout.kt @@ -9,6 +9,7 @@ import android.util.DisplayMetrics import android.view.View import androidx.coordinatorlayout.widget.CoordinatorLayout import org.cryptomator.presentation.R +import timber.log.Timber import kotlin.math.cos import kotlin.math.sin @@ -43,13 +44,27 @@ class VaultListCoordinatorLayout : CoordinatorLayout { val floatingActionButton = findViewById(R.id.fab_vault) val centerXOfHint = (vaultCreationHint.left + vaultCreationHint.right) / 2f val bottomOfHint = vaultCreationHint.bottom.toFloat() - val leftOfFloatingActionButton = floatingActionButton.left.toFloat() val topOfFloatingActionButton = floatingActionButton.top.toFloat() - arcFrom(centerXOfHint + dpToPixels(10f), bottomOfHint + dpToPixels(5f)) // - .to(leftOfFloatingActionButton - dpToPixels(3f), topOfFloatingActionButton + dpToPixels(5f)) // - .spanningAnAngleOf(60.0f) // - .build() // - .draw(canvas, strokeLineWithWidthOf1f()) + + when (val layoutDirection = resources.configuration.layoutDirection) { + View.LAYOUT_DIRECTION_LTR -> { + arcFrom(centerXOfHint + dpToPixels(10f), bottomOfHint + dpToPixels(5f), layoutDirection) // + .to(floatingActionButton.left.toFloat() - dpToPixels(3f), topOfFloatingActionButton + dpToPixels(5f)) // + .spanningAnAngleOf(60.0f) // + .build() // + .draw(canvas, strokeLineWithWidthOf1f()) + } + View.LAYOUT_DIRECTION_RTL -> { + arcFrom(floatingActionButton.right.toFloat() - dpToPixels(3f), bottomOfHint + dpToPixels(5f), layoutDirection) // + .to(centerXOfHint + dpToPixels(10f), topOfFloatingActionButton + dpToPixels(5f)) // + .spanningAnAngleOf(60.0f) // + .build() // + .draw(canvas, strokeLineWithWidthOf1f()) + } + else -> { + Timber.tag("VaultListCoordinatorLay").e("Layout direction not supported, skip drawing arc") + } + } } private fun strokeLineWithWidthOf1f(): Paint { @@ -65,7 +80,7 @@ class VaultListCoordinatorLayout : CoordinatorLayout { return dp * pixelsPerDp } - private class ArcBuilder(val x1: Float, val y1: Float) { + private class ArcBuilder(val x1: Float, val y1: Float, val layoutDirection: Int) { var angle = 0f var x2 = 0f var y2 = 0f @@ -94,6 +109,7 @@ class VaultListCoordinatorLayout : CoordinatorLayout { private val bottom: Float private val start: Float private val angle: Float = b.angle + private val layoutDirection: Int = b.layoutDirection fun draw(canvas: Canvas, paint: Paint) { val rect = RectF() @@ -106,23 +122,51 @@ class VaultListCoordinatorLayout : CoordinatorLayout { } init { - start = 180f - angle val sin = sin(TWO_PI * angle / 360).toFloat() val cos = cos(TWO_PI * angle / 360).toFloat() val widthCorrection = 1f / cos val heightCorrection = 1f / sin val w = (b.x2 - b.x1) * 2 * widthCorrection val h = (b.y2 - b.y1) * 2 * heightCorrection - left = b.x1 - right = b.x1 + w + + start = when (layoutDirection) { + View.LAYOUT_DIRECTION_LTR -> { + 180f - angle + } + View.LAYOUT_DIRECTION_RTL -> { + 0f + } + else -> throw IllegalStateException("Not supported layout direction") + } + + left = when (layoutDirection) { + View.LAYOUT_DIRECTION_LTR -> { + b.x1 + } + View.LAYOUT_DIRECTION_RTL -> { + b.x2 - w + } + else -> throw IllegalStateException("Not supported layout direction") + } + + right = when (layoutDirection) { + View.LAYOUT_DIRECTION_LTR -> { + b.x1 + w + } + View.LAYOUT_DIRECTION_RTL -> { + b.x2 + } + else -> throw IllegalStateException("Not supported layout direction") + } + top = b.y1 - h / 2 bottom = b.y1 + h / 2 } } companion object { - private fun arcFrom(x1: Float, y1: Float): ArcBuilder { - return ArcBuilder(x1, y1) + private fun arcFrom(x1: Float, y1: Float, layoutDirection: Int): ArcBuilder { + return ArcBuilder(x1, y1, layoutDirection) } } } From 9f5b2c44ddd26313ff3dfd56008cc4a01efe10df Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Tue, 19 Jan 2021 15:37:37 +0100 Subject: [PATCH 18/32] Improve UI for RTL mode --- presentation/src/main/res/layout/content_create_vault.xml | 4 ++-- presentation/src/main/res/layout/dialog_ask_for_http.xml | 2 -- .../res/layout/dialog_biometric_auth_key_invalidated.xml | 4 ++-- .../src/main/res/layout/dialog_bottom_sheet_add_vault.xml | 2 -- .../main/res/layout/dialog_bottom_sheet_cloud_settings.xml | 2 -- .../main/res/layout/dialog_bottom_sheet_file_settings.xml | 2 -- .../main/res/layout/dialog_bottom_sheet_folder_settings.xml | 2 -- .../main/res/layout/dialog_bottom_sheet_vault_action.xml | 2 -- .../main/res/layout/dialog_bottom_sheet_vault_settings.xml | 2 -- .../main/res/layout/dialog_confirm_delete_cloud_node.xml | 4 ++-- .../layout/dialog_delete_cloud_connection_with_vaults.xml | 4 ++-- presentation/src/main/res/layout/dialog_existing_file.xml | 4 ++-- .../src/main/res/layout/dialog_handle_ssl_certificate.xml | 2 -- .../src/main/res/layout/dialog_no_screen_lock_set.xml | 2 -- presentation/src/main/res/layout/dialog_upload_loading.xml | 4 ++-- .../main/res/layout/dialog_vault_delete_confirmation.xml | 4 ++-- .../src/main/res/layout/item_biometric_auth_vault.xml | 2 -- .../main/res/layout/item_browse_cloud_model_connections.xml | 2 -- presentation/src/main/res/layout/item_browse_files_node.xml | 4 ---- presentation/src/main/res/layout/item_cloud_setting.xml | 2 -- presentation/src/main/res/layout/item_shared_files.xml | 2 -- presentation/src/main/res/layout/item_vault.xml | 6 ++---- .../src/main/res/layout/view_default_local_cloud.xml | 2 -- presentation/src/main/res/layout/view_dialog_error.xml | 4 ++-- .../main/res/layout/view_dialog_intermediate_progress.xml | 4 ++-- presentation/src/main/res/layout/view_dialog_progress.xml | 4 ++-- presentation/src/main/res/values-night/styles.xml | 4 ++-- presentation/src/main/res/values/styles.xml | 4 ++-- subsampling-scale-image-view | 2 +- 29 files changed, 27 insertions(+), 61 deletions(-) diff --git a/presentation/src/main/res/layout/content_create_vault.xml b/presentation/src/main/res/layout/content_create_vault.xml index f6ee74b9..a403b834 100644 --- a/presentation/src/main/res/layout/content_create_vault.xml +++ b/presentation/src/main/res/layout/content_create_vault.xml @@ -5,8 +5,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" - android:paddingLeft="@dimen/activity_horizontal_margin" - android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingStart="@dimen/activity_horizontal_margin" + android:paddingEnd="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context=".ui.activity.CreateVaultActivity" diff --git a/presentation/src/main/res/layout/dialog_ask_for_http.xml b/presentation/src/main/res/layout/dialog_ask_for_http.xml index c6317724..45a05eb1 100644 --- a/presentation/src/main/res/layout/dialog_ask_for_http.xml +++ b/presentation/src/main/res/layout/dialog_ask_for_http.xml @@ -22,8 +22,6 @@ android:layout_below="@id/tv_security_hint" android:checked="true" android:paddingEnd="16dp" - android:paddingLeft="16dp" - android:paddingRight="16dp" android:paddingStart="16dp" android:text="@string/dialog_http_security_checkbox" /> diff --git a/presentation/src/main/res/layout/dialog_biometric_auth_key_invalidated.xml b/presentation/src/main/res/layout/dialog_biometric_auth_key_invalidated.xml index 8b55cc52..6b765109 100644 --- a/presentation/src/main/res/layout/dialog_biometric_auth_key_invalidated.xml +++ b/presentation/src/main/res/layout/dialog_biometric_auth_key_invalidated.xml @@ -4,8 +4,8 @@ android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" - android:paddingLeft="@dimen/activity_horizontal_margin" - android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingStart="@dimen/activity_horizontal_margin" + android:paddingEnd="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> diff --git a/presentation/src/main/res/layout/dialog_bottom_sheet_vault_action.xml b/presentation/src/main/res/layout/dialog_bottom_sheet_vault_action.xml index 488d687c..89e44ff0 100644 --- a/presentation/src/main/res/layout/dialog_bottom_sheet_vault_action.xml +++ b/presentation/src/main/res/layout/dialog_bottom_sheet_vault_action.xml @@ -18,8 +18,6 @@ android:ellipsize="middle" android:gravity="center_vertical" android:paddingEnd="16dp" - android:paddingLeft="16dp" - android:paddingRight="16dp" android:paddingStart="16dp" android:singleLine="true" android:textSize="16sp" diff --git a/presentation/src/main/res/layout/dialog_bottom_sheet_vault_settings.xml b/presentation/src/main/res/layout/dialog_bottom_sheet_vault_settings.xml index 51e5360b..442d76b2 100644 --- a/presentation/src/main/res/layout/dialog_bottom_sheet_vault_settings.xml +++ b/presentation/src/main/res/layout/dialog_bottom_sheet_vault_settings.xml @@ -22,8 +22,6 @@ android:layout_width="@dimen/thumbnail_size" android:layout_height="@dimen/thumbnail_size" android:layout_marginEnd="16dp" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" android:layout_marginStart="16dp" /> diff --git a/presentation/src/main/res/layout/dialog_no_screen_lock_set.xml b/presentation/src/main/res/layout/dialog_no_screen_lock_set.xml index 45aaa0c7..7ab9fee8 100644 --- a/presentation/src/main/res/layout/dialog_no_screen_lock_set.xml +++ b/presentation/src/main/res/layout/dialog_no_screen_lock_set.xml @@ -22,8 +22,6 @@ android:layout_marginTop="27dp" android:checked="true" android:paddingEnd="16dp" - android:paddingLeft="16dp" - android:paddingRight="16dp" android:paddingStart="16dp" android:text="@string/dialog_no_screen_lock_checkbox" /> diff --git a/presentation/src/main/res/layout/dialog_upload_loading.xml b/presentation/src/main/res/layout/dialog_upload_loading.xml index 94be5025..79cd0eda 100644 --- a/presentation/src/main/res/layout/dialog_upload_loading.xml +++ b/presentation/src/main/res/layout/dialog_upload_loading.xml @@ -12,8 +12,8 @@ android:id="@+id/file_upload" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingLeft="16dp" - android:paddingRight="16dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" android:paddingBottom="8dp" android:textSize="20sp" /> diff --git a/presentation/src/main/res/layout/dialog_vault_delete_confirmation.xml b/presentation/src/main/res/layout/dialog_vault_delete_confirmation.xml index e8c44be2..66c2889a 100644 --- a/presentation/src/main/res/layout/dialog_vault_delete_confirmation.xml +++ b/presentation/src/main/res/layout/dialog_vault_delete_confirmation.xml @@ -8,8 +8,8 @@ android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" - android:paddingLeft="@dimen/activity_horizontal_margin" - android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingStart="@dimen/activity_horizontal_margin" + android:paddingEnd="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> @@ -30,8 +28,6 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginEnd="16dp" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" android:layout_marginStart="16dp" android:layout_marginTop="16dp" android:layout_toEndOf="@id/cloudNodeImage" diff --git a/presentation/src/main/res/layout/item_cloud_setting.xml b/presentation/src/main/res/layout/item_cloud_setting.xml index 8011b74c..6a26fddb 100644 --- a/presentation/src/main/res/layout/item_cloud_setting.xml +++ b/presentation/src/main/res/layout/item_cloud_setting.xml @@ -16,8 +16,6 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginEnd="16dp" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" android:layout_marginStart="16dp" android:layout_toEndOf="@+id/cloudImage" android:orientation="vertical"> diff --git a/presentation/src/main/res/layout/item_shared_files.xml b/presentation/src/main/res/layout/item_shared_files.xml index 2c8c6763..8632a73c 100644 --- a/presentation/src/main/res/layout/item_shared_files.xml +++ b/presentation/src/main/res/layout/item_shared_files.xml @@ -17,8 +17,6 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginEnd="16dp" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" android:layout_marginStart="16dp" android:layout_toEndOf="@+id/fileImage" android:ellipsize="middle" diff --git a/presentation/src/main/res/layout/item_vault.xml b/presentation/src/main/res/layout/item_vault.xml index 5ce193a6..5d5a861f 100644 --- a/presentation/src/main/res/layout/item_vault.xml +++ b/presentation/src/main/res/layout/item_vault.xml @@ -17,8 +17,6 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginEnd="16dp" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" android:layout_marginStart="16dp" android:layout_toEndOf="@+id/cloudImage" android:layout_toStartOf="@+id/unlockedImage" @@ -52,8 +50,8 @@ android:layout_toStartOf="@+id/settings" android:background="?android:attr/selectableItemBackground" android:paddingBottom="10dp" - android:paddingLeft="14dp" - android:paddingRight="14dp" + android:paddingStart="14dp" + android:paddingEnd="14dp" android:paddingTop="10dp" android:src="@drawable/vault_unlocked" app:tint="@color/colorPrimary" diff --git a/presentation/src/main/res/layout/view_default_local_cloud.xml b/presentation/src/main/res/layout/view_default_local_cloud.xml index b6e693e6..21250ce5 100644 --- a/presentation/src/main/res/layout/view_default_local_cloud.xml +++ b/presentation/src/main/res/layout/view_default_local_cloud.xml @@ -19,8 +19,6 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginEnd="16dp" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" android:layout_marginStart="16dp" android:layout_marginTop="16dp" android:layout_toEndOf="@id/iv_cloud_model_image" /> diff --git a/presentation/src/main/res/layout/view_dialog_error.xml b/presentation/src/main/res/layout/view_dialog_error.xml index 9f828d34..16a38167 100644 --- a/presentation/src/main/res/layout/view_dialog_error.xml +++ b/presentation/src/main/res/layout/view_dialog_error.xml @@ -5,8 +5,8 @@ android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal" - android:paddingLeft="16dp" - android:paddingRight="16dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" android:visibility="gone"> diff --git a/presentation/src/main/res/values-night/styles.xml b/presentation/src/main/res/values-night/styles.xml index 48f2ba33..8581a6e2 100644 --- a/presentation/src/main/res/values-night/styles.xml +++ b/presentation/src/main/res/values-night/styles.xml @@ -66,8 +66,8 @@ 48dp 16sp match_parent - 16dp - 16dp + 16dp + 16dp 16dp 32dp true diff --git a/presentation/src/main/res/values/styles.xml b/presentation/src/main/res/values/styles.xml index 3def9466..a09be1b3 100644 --- a/presentation/src/main/res/values/styles.xml +++ b/presentation/src/main/res/values/styles.xml @@ -66,8 +66,8 @@ 48dp 16sp match_parent - 16dp - 16dp + 16dp + 16dp 16dp 32dp true diff --git a/subsampling-scale-image-view b/subsampling-scale-image-view index c3c247b6..e9d0f187 160000 --- a/subsampling-scale-image-view +++ b/subsampling-scale-image-view @@ -1 +1 @@ -Subproject commit c3c247b63cb72a4f7f9ddc3272820e1ce636e56d +Subproject commit e9d0f18740f00f55195811373791ea826f3c6ba3 From e68c22d0f3b1694db9f7638fda6631df22c75928 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Wed, 20 Jan 2021 11:01:00 +0100 Subject: [PATCH 19/32] Reformat code [ci skip] --- buildsystem/dependencies.gradle | 215 ++++++++++++++++---------------- 1 file changed, 108 insertions(+), 107 deletions(-) diff --git a/buildsystem/dependencies.gradle b/buildsystem/dependencies.gradle index 2d941c03..8a8ec546 100644 --- a/buildsystem/dependencies.gradle +++ b/buildsystem/dependencies.gradle @@ -1,154 +1,155 @@ allprojects { - repositories { - jcenter() - } + repositories { + jcenter() + } } ext { - androidBuildToolsVersion = "29.0.2" - androidMinSdkVersion = 23 - androidTargetSdkVersion = 29 - androidCompileSdkVersion = 29 + androidBuildToolsVersion = "29.0.2" + androidMinSdkVersion = 23 + androidTargetSdkVersion = 29 + androidCompileSdkVersion = 29 - // android and java libs - androidVersion = '4.1.1.4' - multidexVersion = '2.0.1' - javaxAnnotationVersion = '1.0' + // android and java libs + androidVersion = '4.1.1.4' + multidexVersion = '2.0.1' + javaxAnnotationVersion = '1.0' - // support lib - androidSupportAnnotationsVersion = '1.1.0' - androidSupportAppcompatVersion = '1.2.0' // check https://stackoverflow.com/questions/41025200/android-view-inflateexception-error-inflating-class-android-webkit-webview/57968071#57968071 !!!!!! - androidSupportDesignVersion = '1.2.1' + // support lib + androidSupportAnnotationsVersion = '1.1.0' + androidSupportAppcompatVersion = '1.2.0' + // check https://stackoverflow.com/questions/41025200/android-view-inflateexception-error-inflating-class-android-webkit-webview/57968071#57968071 !!!!!! + androidSupportDesignVersion = '1.2.1' - // app frameworks and utilities + // app frameworks and utilities - rxJavaVersion = '2.2.20' - rxAndroidVersion = '2.1.1' - rxBindingVersion = '2.2.0' + rxJavaVersion = '2.2.20' + rxAndroidVersion = '2.1.1' + rxBindingVersion = '2.2.0' - daggerVersion = '2.30.1' + daggerVersion = '2.30.1' - gsonVersion = '2.8.6' + gsonVersion = '2.8.6' - okHttpVersion = '4.9.0' - okHttpDigestVersion = '2.5' + okHttpVersion = '4.9.0' + okHttpDigestVersion = '2.5' - velocityVersion = '1.7' + velocityVersion = '1.7' - timberVersion = '4.7.1' + timberVersion = '4.7.1' - zxcvbnVersion = '1.3.1' + zxcvbnVersion = '1.3.1' - scaleImageViewVersion = '3.10.0' + scaleImageViewVersion = '3.10.0' - lruFileCacheVersion = '1.0' + lruFileCacheVersion = '1.0' - // KEEP IN SYNC WITH GENERATOR VERSION IN root build.gradle - greenDaoVersion = '3.3.0' + // KEEP IN SYNC WITH GENERATOR VERSION IN root build.gradle + greenDaoVersion = '3.3.0' - // cloud provider libs + // cloud provider libs // do not update to 1.4.0 until dropping minsdk 4.x - cryptolibVersion = '1.3.0' + cryptolibVersion = '1.3.0' - dropboxVersion = '3.1.5' + dropboxVersion = '3.1.5' - googleApiServicesVersion = 'v3-rev197-1.25.0' - googlePlayServicesVersion = '19.0.0' - googleClientVersion = '1.31.1' + googleApiServicesVersion = 'v3-rev197-1.25.0' + googlePlayServicesVersion = '19.0.0' + googleClientVersion = '1.31.1' - msgraphVersion = '2.5.0' - msaAuthVersion = '0.10.0' + msgraphVersion = '2.5.0' + msaAuthVersion = '0.10.0' - commonsCodecVersion = '1.15' + commonsCodecVersion = '1.15' recyclerViewFastScrollVersion = '2.0.1' - // testing dependencies + // testing dependencies - jUnitVersion = '5.7.0' + jUnitVersion = '5.7.0' jUnit4Version = '4.13.1' - assertJVersion = '1.7.1' - mockitoVersion = '3.6.28' + assertJVersion = '1.7.1' + mockitoVersion = '3.6.28' mockitoInlineVersion = '3.6.28' - hamcrestVersion = '1.3' - dexmakerVersion = '1.0' - espressoVersion = '3.3.0' - testingSupportLibVersion = '0.1' - runnerVersion = '1.3.0' - rulesVersion = '1.3.0' - contributionVersion = '3.3.0' - uiautomatorVersion = '2.2.0' + hamcrestVersion = '1.3' + dexmakerVersion = '1.0' + espressoVersion = '3.3.0' + testingSupportLibVersion = '0.1' + runnerVersion = '1.3.0' + rulesVersion = '1.3.0' + contributionVersion = '3.3.0' + uiautomatorVersion = '2.2.0' - androidxCoreVersion = '1.3.2' - androidxFragmentVersion = '1.2.5' - androidxViewpagerVersion = '1.0.0' - androidxSwiperefreshVersion = '1.1.0' - androidxPreferenceVersion = '1.0.0' // 1.1.0 and 1.1.2 does have a bug with the text size - androidxRecyclerViewVersion = '1.1.0' - androidxDocumentfileVersion = '1.0.1' + androidxCoreVersion = '1.3.2' + androidxFragmentVersion = '1.2.5' + androidxViewpagerVersion = '1.0.0' + androidxSwiperefreshVersion = '1.1.0' + androidxPreferenceVersion = '1.0.0' // 1.1.0 and 1.1.2 does have a bug with the text size + androidxRecyclerViewVersion = '1.1.0' + androidxDocumentfileVersion = '1.0.1' androidxBiometricVersion = '1.0.1' androidxTestCoreVersion = '1.3.0' - jsonWebTokenApiVersion = '0.11.2' + jsonWebTokenApiVersion = '0.11.2' - dependencies = [ - android : "com.google.android:android:${androidVersion}", - androidAnnotations : "androidx.annotation:annotation:${androidSupportAnnotationsVersion}", - appcompat : "androidx.appcompat:appcompat:${androidSupportAppcompatVersion}", - androidxBiometric : "androidx.biometric:biometric:${androidxBiometricVersion}", + dependencies = [ + android : "com.google.android:android:${androidVersion}", + androidAnnotations : "androidx.annotation:annotation:${androidSupportAnnotationsVersion}", + appcompat : "androidx.appcompat:appcompat:${androidSupportAppcompatVersion}", + androidxBiometric : "androidx.biometric:biometric:${androidxBiometricVersion}", androidxCore : "androidx.core:core-ktx:${androidxCoreVersion}", - androidxFragment : "androidx.fragment:fragment-ktx:${androidxFragmentVersion}", - androidxViewpager : "androidx.viewpager:viewpager:${androidxViewpagerVersion}", - androidxSwiperefresh : "androidx.swiperefreshlayout:swiperefreshlayout:${androidxSwiperefreshVersion}", - androidxPreference : "androidx.preference:preference:${androidxPreferenceVersion}", - documentFile : "androidx.documentfile:documentfile:${androidxDocumentfileVersion}", - recyclerView : "androidx.recyclerview:recyclerview:${androidxRecyclerViewVersion}", + androidxFragment : "androidx.fragment:fragment-ktx:${androidxFragmentVersion}", + androidxViewpager : "androidx.viewpager:viewpager:${androidxViewpagerVersion}", + androidxSwiperefresh : "androidx.swiperefreshlayout:swiperefreshlayout:${androidxSwiperefreshVersion}", + androidxPreference : "androidx.preference:preference:${androidxPreferenceVersion}", + documentFile : "androidx.documentfile:documentfile:${androidxDocumentfileVersion}", + recyclerView : "androidx.recyclerview:recyclerview:${androidxRecyclerViewVersion}", androidxTestCore : "androidx.test:core:${androidxTestCoreVersion}", - commonsCodec : "commons-codec:commons-codec:${commonsCodecVersion}", - cryptolib : "org.cryptomator:cryptolib:${cryptolibVersion}", - dagger : "com.google.dagger:dagger:${daggerVersion}", - daggerCompiler : "com.google.dagger:dagger-compiler:${daggerVersion}", - design : "com.google.android.material:material:${androidSupportDesignVersion}", - dropbox : "com.dropbox.core:dropbox-core-sdk:${dropboxVersion}", - espresso : "androidx.test.espresso:espresso-core:${espressoVersion}", - googleApiClientAndroid: "com.google.api-client:google-api-client-android:${googleClientVersion}", - googleApiServicesDrive: "com.google.apis:google-api-services-drive:${googleApiServicesVersion}", - googlePlayServicesAuth: "com.google.android.gms:play-services-auth:${googlePlayServicesVersion}", - greenDao : "org.greenrobot:greendao:${greenDaoVersion}", - gson : "com.google.code.gson:gson:${gsonVersion}", - hamcrest : "org.hamcrest:hamcrest-all:${hamcrestVersion}", - javaxAnnotation : "javax.annotation:jsr250-api:${javaxAnnotationVersion}", - junit : "org.junit.jupiter:junit-jupiter:${jUnitVersion}", + commonsCodec : "commons-codec:commons-codec:${commonsCodecVersion}", + cryptolib : "org.cryptomator:cryptolib:${cryptolibVersion}", + dagger : "com.google.dagger:dagger:${daggerVersion}", + daggerCompiler : "com.google.dagger:dagger-compiler:${daggerVersion}", + design : "com.google.android.material:material:${androidSupportDesignVersion}", + dropbox : "com.dropbox.core:dropbox-core-sdk:${dropboxVersion}", + espresso : "androidx.test.espresso:espresso-core:${espressoVersion}", + googleApiClientAndroid: "com.google.api-client:google-api-client-android:${googleClientVersion}", + googleApiServicesDrive: "com.google.apis:google-api-services-drive:${googleApiServicesVersion}", + googlePlayServicesAuth: "com.google.android.gms:play-services-auth:${googlePlayServicesVersion}", + greenDao : "org.greenrobot:greendao:${greenDaoVersion}", + gson : "com.google.code.gson:gson:${gsonVersion}", + hamcrest : "org.hamcrest:hamcrest-all:${hamcrestVersion}", + javaxAnnotation : "javax.annotation:jsr250-api:${javaxAnnotationVersion}", + junit : "org.junit.jupiter:junit-jupiter:${jUnitVersion}", junitApi : "org.junit.jupiter:junit-jupiter-api:${jUnitVersion}", junitEngine : "org.junit.jupiter:junit-jupiter-engine:${jUnitVersion}", junitParams : "org.junit.jupiter:junit-jupiter-params:${jUnitVersion}", junit4 : "org.junit.jupiter:junit-jupiter:${jUnit4Version}", junit4Engine : "org.junit.vintage:junit-vintage-engine:${jUnitVersion}", - msgraph : "com.microsoft.graph:microsoft-graph:${msgraphVersion}", - msaAuth : "com.microsoft.graph:msa-auth-for-android-adapter:${msaAuthVersion}", - mockito : "org.mockito:mockito-core:${mockitoVersion}", + msgraph : "com.microsoft.graph:microsoft-graph:${msgraphVersion}", + msaAuth : "com.microsoft.graph:msa-auth-for-android-adapter:${msaAuthVersion}", + mockito : "org.mockito:mockito-core:${mockitoVersion}", mockitoInline : "org.mockito:mockito-inline:${mockitoInlineVersion}", - multidex : "androidx.multidex:multidex:${multidexVersion}", - okHttp : "com.squareup.okhttp3:okhttp:${okHttpVersion}", - okHttpDigest : "com.burgstaller:okhttp-digest:${okHttpDigestVersion}", + multidex : "androidx.multidex:multidex:${multidexVersion}", + okHttp : "com.squareup.okhttp3:okhttp:${okHttpVersion}", + okHttpDigest : "com.burgstaller:okhttp-digest:${okHttpDigestVersion}", recyclerViewFastScroll: "com.simplecityapps:recyclerview-fastscroll:${recyclerViewFastScrollVersion}", rxJava : "io.reactivex.rxjava2:rxjava:${rxJavaVersion}", - rxAndroid : "io.reactivex.rxjava2:rxandroid:${rxAndroidVersion}", - rxBinding : "com.jakewharton.rxbinding2:rxbinding:${rxBindingVersion}", - testingSupportLib : "com.android.support.test:testing-support-lib:${testingSupportLibVersion}", - timber : "com.jakewharton.timber:timber:${timberVersion}", - velocity : "org.apache.velocity:velocity:${velocityVersion}", - runner : "androidx.test:runner:${runnerVersion}", - rules : "androidx.test:rules:${rulesVersion}", - contribution : "androidx.test.espresso:espresso-contrib:${contributionVersion}", - uiAutomator : "androidx.test.uiautomator:uiautomator:${uiautomatorVersion}", - zxcvbn : "com.nulab-inc:zxcvbn:${zxcvbnVersion}", - scaleImageView : "com.davemorrissey.labs:subsampling-scale-image-view:${scaleImageViewVersion}", - lruFileCache : "com.tomclaw.cache:cache:${lruFileCacheVersion}", - jsonWebTokenApi : "io.jsonwebtoken:jjwt-api:${jsonWebTokenApiVersion}", - jsonWebTokenImpl : "io.jsonwebtoken:jjwt-impl:${jsonWebTokenApiVersion}", - jsonWebTokenJson : "io.jsonwebtoken:jjwt-orgjson:${jsonWebTokenApiVersion}" - ] + rxAndroid : "io.reactivex.rxjava2:rxandroid:${rxAndroidVersion}", + rxBinding : "com.jakewharton.rxbinding2:rxbinding:${rxBindingVersion}", + testingSupportLib : "com.android.support.test:testing-support-lib:${testingSupportLibVersion}", + timber : "com.jakewharton.timber:timber:${timberVersion}", + velocity : "org.apache.velocity:velocity:${velocityVersion}", + runner : "androidx.test:runner:${runnerVersion}", + rules : "androidx.test:rules:${rulesVersion}", + contribution : "androidx.test.espresso:espresso-contrib:${contributionVersion}", + uiAutomator : "androidx.test.uiautomator:uiautomator:${uiautomatorVersion}", + zxcvbn : "com.nulab-inc:zxcvbn:${zxcvbnVersion}", + scaleImageView : "com.davemorrissey.labs:subsampling-scale-image-view:${scaleImageViewVersion}", + lruFileCache : "com.tomclaw.cache:cache:${lruFileCacheVersion}", + jsonWebTokenApi : "io.jsonwebtoken:jjwt-api:${jsonWebTokenApiVersion}", + jsonWebTokenImpl : "io.jsonwebtoken:jjwt-impl:${jsonWebTokenApiVersion}", + jsonWebTokenJson : "io.jsonwebtoken:jjwt-orgjson:${jsonWebTokenApiVersion}" + ] } From f83768ea4a28917288abe26bd2d327c0768799dc Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Wed, 20 Jan 2021 14:08:36 +0100 Subject: [PATCH 20/32] Update dependencies --- buildsystem/dependencies.gradle | 8 ++++---- .../data/cloud/googledrive/GoogleDriveClientFactory.java | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/buildsystem/dependencies.gradle b/buildsystem/dependencies.gradle index 8a8ec546..800f7e70 100644 --- a/buildsystem/dependencies.gradle +++ b/buildsystem/dependencies.gradle @@ -27,7 +27,7 @@ ext { rxAndroidVersion = '2.1.1' rxBindingVersion = '2.2.0' - daggerVersion = '2.30.1' + daggerVersion = '2.31' gsonVersion = '2.8.6' @@ -56,7 +56,7 @@ ext { googleApiServicesVersion = 'v3-rev197-1.25.0' googlePlayServicesVersion = '19.0.0' - googleClientVersion = '1.31.1' + googleClientVersion = '1.31.2' msgraphVersion = '2.5.0' msaAuthVersion = '0.10.0' @@ -70,8 +70,8 @@ ext { jUnitVersion = '5.7.0' jUnit4Version = '4.13.1' assertJVersion = '1.7.1' - mockitoVersion = '3.6.28' - mockitoInlineVersion = '3.6.28' + mockitoVersion = '3.7.7' + mockitoInlineVersion = '3.7.7' hamcrestVersion = '1.3' dexmakerVersion = '1.0' espressoVersion = '3.3.0' diff --git a/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveClientFactory.java b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveClientFactory.java index 6775d7e8..02532be4 100644 --- a/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveClientFactory.java +++ b/data/src/notFoss/java/org/cryptomator/data/cloud/googledrive/GoogleDriveClientFactory.java @@ -2,8 +2,8 @@ package org.cryptomator.data.cloud.googledrive; import android.content.Context; -import com.google.api.client.extensions.android.http.AndroidHttp; -import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.drive.Drive; import com.google.api.services.drive.DriveScopes; @@ -24,7 +24,7 @@ class GoogleDriveClientFactory { try { FixedGoogleAccountCredential credential = FixedGoogleAccountCredential.usingOAuth2(context, Collections.singleton(DriveScopes.DRIVE)); credential.setAccountName(accountName); - return new Drive.Builder(AndroidHttp.newCompatibleTransport(), JacksonFactory.getDefaultInstance(), credential) // + return new Drive.Builder(new NetHttpTransport(), GsonFactory.getDefaultInstance(), credential) // .setApplicationName("Cryptomator-Android/" + BuildConfig.VERSION_NAME) // .build(); } catch (Exception e) { From 527dde9304ac0b71a1074326038104d6080c64b7 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Wed, 20 Jan 2021 15:50:16 +0100 Subject: [PATCH 21/32] Update dependencies and clean up [ci skip] --- buildsystem/dependencies.gradle | 4 ++-- .../main/java/org/cryptomator/presentation/util/FileUtil.kt | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/buildsystem/dependencies.gradle b/buildsystem/dependencies.gradle index 800f7e70..887935d5 100644 --- a/buildsystem/dependencies.gradle +++ b/buildsystem/dependencies.gradle @@ -27,7 +27,7 @@ ext { rxAndroidVersion = '2.1.1' rxBindingVersion = '2.2.0' - daggerVersion = '2.31' + daggerVersion = '2.31.1' gsonVersion = '2.8.6' @@ -49,7 +49,7 @@ ext { // cloud provider libs - // do not update to 1.4.0 until dropping minsdk 4.x + // do not update to 1.4.0 until minsdk is 7.x (or desugaring works better) otherwise it will crash on 6.x cryptolibVersion = '1.3.0' dropboxVersion = '3.1.5' diff --git a/presentation/src/main/java/org/cryptomator/presentation/util/FileUtil.kt b/presentation/src/main/java/org/cryptomator/presentation/util/FileUtil.kt index 8996966a..402b1c95 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/util/FileUtil.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/util/FileUtil.kt @@ -17,10 +17,9 @@ import java.io.* import java.util.* import javax.inject.Inject -class FileUtil @Inject constructor(private val context: Context, mimeTypes: MimeTypes) { +class FileUtil @Inject constructor(private val context: Context, private val mimeTypes: MimeTypes) { private var decryptedFileStorage: File = File(context.cacheDir, "decrypted") - private val mimeTypes: MimeTypes = mimeTypes fun cleanup() { cleanupDir(context.cacheDir) From 0c04d16df0854e9be562bf0e565bfeace2e5bb30 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Wed, 20 Jan 2021 16:32:28 +0100 Subject: [PATCH 22/32] Support further schemes to enter the license Most of the app doesn't allow custom scheme URLs. Now we support the following schemes: * https://android.cryptomator.org/app/license#foo (preferred) * https://android.cryptomator.org/app/license/foo * cryptomator://license/foo (legacy) --- presentation/src/main/AndroidManifest.xml | 25 +++++++++++++------ .../presenter/LicenseCheckPresenter.kt | 4 +-- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/presentation/src/main/AndroidManifest.xml b/presentation/src/main/AndroidManifest.xml index 6c71db05..72983265 100644 --- a/presentation/src/main/AndroidManifest.xml +++ b/presentation/src/main/AndroidManifest.xml @@ -28,10 +28,10 @@ android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" - android:supportsRtl="true" android:requestLegacyExternalStorage="true" - android:usesCleartextTraffic="true" - android:theme="@style/AppTheme"> + android:supportsRtl="true" + android:theme="@style/AppTheme" + android:usesCleartextTraffic="true"> @@ -122,15 +122,26 @@ - + + android:host="*" + android:scheme="cryptomator" /> + + + + + + + + diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/LicenseCheckPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/LicenseCheckPresenter.kt index 8a321d0f..278a6dfb 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/LicenseCheckPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/LicenseCheckPresenter.kt @@ -16,8 +16,8 @@ class LicenseCheckPresenter @Inject internal constructor( private val sharedPreferencesHandler: SharedPreferencesHandler) : Presenter(exceptionHandlers) { fun validate(data: Uri?) { - if (data != null) { - val license = data.lastPathSegment ?: "" + data?.let { + val license = it.fragment ?: it.lastPathSegment ?: "" view?.showOrUpdateLicenseDialog(license) doLicenseCheckUsecase .withLicense(license) From 8e60975cf539b49b029b7a81f5bc031c3ec7511b Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Wed, 20 Jan 2021 18:36:28 +0100 Subject: [PATCH 23/32] Fix crash when opening EmptyDirFileDialog or viewing the used licenses --- .../cryptomator/presentation/ui/fragment/LicensesFragment.kt | 5 ++--- .../src/main/res/layout/activity_empty_dir_file_info.xml | 1 + presentation/src/main/res/layout/activity_licenses.xml | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/LicensesFragment.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/LicensesFragment.kt index e9be9f18..72250c0f 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/LicensesFragment.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/LicensesFragment.kt @@ -1,11 +1,10 @@ package org.cryptomator.presentation.ui.fragment import android.os.Bundle -import androidx.preference.PreferenceFragment - +import androidx.preference.PreferenceFragmentCompat import org.cryptomator.presentation.R -class LicensesFragment : PreferenceFragment() { +class LicensesFragment : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.licenses) } diff --git a/presentation/src/main/res/layout/activity_empty_dir_file_info.xml b/presentation/src/main/res/layout/activity_empty_dir_file_info.xml index 33c9c3a1..d7fb3ca0 100644 --- a/presentation/src/main/res/layout/activity_empty_dir_file_info.xml +++ b/presentation/src/main/res/layout/activity_empty_dir_file_info.xml @@ -11,6 +11,7 @@ android:layout_height="wrap_content" /> Date: Wed, 20 Jan 2021 18:44:17 +0100 Subject: [PATCH 24/32] #252 Install Debug App in parallel with Release App --- README.md | 6 +++++- data/build.gradle | 11 ++++++++++- presentation/build.gradle | 16 +++++++++++++--- presentation/src/debug/res/values/strings.xml | 6 ++++++ presentation/src/main/AndroidManifest.xml | 12 +++++------- presentation/src/main/res/xml/preferences.xml | 8 ++++---- 6 files changed, 43 insertions(+), 16 deletions(-) create mode 100644 presentation/src/debug/res/values/strings.xml diff --git a/README.md b/README.md index b0f54d14..7c855339 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,11 @@ git submodule init && git submodule update // (not necessary if cloned using --r ./gradlew assembleApkstoreDebug ``` -Before connecting to Onedrive or Dropbox you have to provide valid API keys using environment variables: `ONEDRIVE_API_KEY` or `DROPBOX_API_KEY`. +Before connecting to Onedrive or Dropbox you have to provide valid API keys using environment variables: +For build type + +* **release**: `ONEDRIVE_API_KEY` or `DROPBOX_API_KEY`. +* **debug**: `ONEDRIVE_API_KEY_DEBUG` or `DROPBOX_API_KEY_DEBUG`. ## License diff --git a/data/build.gradle b/data/build.gradle index a5939e72..6eb0df5d 100644 --- a/data/build.gradle +++ b/data/build.gradle @@ -17,7 +17,6 @@ android { buildConfigField 'int', 'VERSION_CODE', "${globalConfiguration["androidVersionCode"]}" buildConfigField "String", "VERSION_NAME", "\"${globalConfiguration["androidVersionName"]}\"" - buildConfigField "String", "ONEDRIVE_API_KEY", "\"" + getApiKey('ONEDRIVE_API_KEY') + "\"" } compileOptions { @@ -31,6 +30,16 @@ android { ignoreWarnings true } + buildTypes { + release { + buildConfigField "String", "ONEDRIVE_API_KEY", "\"" + getApiKey('ONEDRIVE_API_KEY') + "\"" + } + + debug { + buildConfigField "String", "ONEDRIVE_API_KEY", "\"" + getApiKey('ONEDRIVE_API_KEY_DEBUG') + "\"" + } + } + flavorDimensions "version" productFlavors { diff --git a/presentation/build.gradle b/presentation/build.gradle index cc4353e9..81a1ea40 100644 --- a/presentation/build.gradle +++ b/presentation/build.gradle @@ -29,9 +29,6 @@ android { multiDexEnabled true testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' - - buildConfigField "String", "DROPBOX_API_KEY", "\"" + getApiKey('DROPBOX_API_KEY') + "\"" - manifestPlaceholders = [DROPBOX_API_KEY: getApiKey('DROPBOX_API_KEY')] } compileOptions { @@ -51,6 +48,11 @@ android { minifyEnabled false shrinkResources false useProguard false + + buildConfigField "String", "DROPBOX_API_KEY", "\"" + getApiKey('DROPBOX_API_KEY') + "\"" + manifestPlaceholders = [DROPBOX_API_KEY: getApiKey('DROPBOX_API_KEY')] + + resValue "string", "app_id", androidApplicationId } debug { @@ -60,6 +62,14 @@ android { minifyEnabled false shrinkResources false testCoverageEnabled false + + buildConfigField "String", "DROPBOX_API_KEY", "\"" + getApiKey('DROPBOX_API_KEY_DEBUG') + "\"" + manifestPlaceholders = [DROPBOX_API_KEY: getApiKey('DROPBOX_API_KEY_DEBUG')] + + applicationIdSuffix ".debug" + versionNameSuffix '-DEBUG' + + resValue "string", "app_id", androidApplicationId + applicationIdSuffix } } diff --git a/presentation/src/debug/res/values/strings.xml b/presentation/src/debug/res/values/strings.xml new file mode 100644 index 00000000..1ad426c7 --- /dev/null +++ b/presentation/src/debug/res/values/strings.xml @@ -0,0 +1,6 @@ + + + + Debug Cryptomator + + diff --git a/presentation/src/main/AndroidManifest.xml b/presentation/src/main/AndroidManifest.xml index 72983265..882a5e27 100644 --- a/presentation/src/main/AndroidManifest.xml +++ b/presentation/src/main/AndroidManifest.xml @@ -102,19 +102,17 @@ - - - - - - + + + + + - diff --git a/presentation/src/main/res/xml/preferences.xml b/presentation/src/main/res/xml/preferences.xml index 73acc427..06bf28c2 100644 --- a/presentation/src/main/res/xml/preferences.xml +++ b/presentation/src/main/res/xml/preferences.xml @@ -21,7 +21,7 @@ + android:targetPackage="@string/app_id" /> @@ -32,7 +32,7 @@ + android:targetPackage="@string/app_id" /> @@ -117,7 +117,7 @@ + android:targetPackage="@string/app_id" /> @@ -204,7 +204,7 @@ + android:targetPackage="@string/app_id" /> From 559455aac677915931796f855a9798d2d0ba03fb Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Thu, 21 Jan 2021 12:04:35 +0100 Subject: [PATCH 25/32] Add Contributing and Code of Conduct into README --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 7c855339..9688ee01 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,14 @@ For build type * **release**: `ONEDRIVE_API_KEY` or `DROPBOX_API_KEY`. * **debug**: `ONEDRIVE_API_KEY_DEBUG` or `DROPBOX_API_KEY_DEBUG`. +## Contributing to Cryptomator for Android + +Please read our [contribution guide](.github/CONTRIBUTING.md), if you would like to report a bug, ask a question, translate the app or help us with coding. + +## Code of Conduct + +Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](.github/CODE_OF_CONDUCT.md). + ## License This project is dual-licensed under the GPLv3 for FOSS projects as well as a commercial license for independent software vendors and resellers. If you want to modify this application under different conditions, feel free to contact our support team. From 24651e90953f0966f2d4c3cbf134955bda0313bb Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Thu, 21 Jan 2021 12:10:44 +0100 Subject: [PATCH 26/32] Use redirect_uri to get access token from OneDrive --- README.md | 6 +++--- data/build.gradle | 2 ++ .../data/cloud/onedrive/graph/MicrosoftOAuth2Endpoint.java | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9688ee01..48aafde9 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,11 @@ git submodule init && git submodule update // (not necessary if cloned using --r ./gradlew assembleApkstoreDebug ``` -Before connecting to Onedrive or Dropbox you have to provide valid API keys using environment variables: +Before connecting to OneDrive or Dropbox you have to provide valid API keys using environment variables: For build type -* **release**: `ONEDRIVE_API_KEY` or `DROPBOX_API_KEY`. -* **debug**: `ONEDRIVE_API_KEY_DEBUG` or `DROPBOX_API_KEY_DEBUG`. +* **release**: `DROPBOX_API_KEY` or `ONEDRIVE_API_KEY` and `ONEDRIVE_API_REDIRCT_URI` +* **debug**: `DROPBOX_API_KEY_DEBUG` or `ONEDRIVE_API_KEY_DEBUG` and `ONEDRIVE_API_REDIRCT_URI_DEBUG` ## Contributing to Cryptomator for Android diff --git a/data/build.gradle b/data/build.gradle index 6eb0df5d..d9b3ca1c 100644 --- a/data/build.gradle +++ b/data/build.gradle @@ -33,10 +33,12 @@ android { buildTypes { release { buildConfigField "String", "ONEDRIVE_API_KEY", "\"" + getApiKey('ONEDRIVE_API_KEY') + "\"" + buildConfigField "String", "ONEDRIVE_API_REDIRCT_URI", "\"" + getApiKey('ONEDRIVE_API_REDIRCT_URI') + "\"" } debug { buildConfigField "String", "ONEDRIVE_API_KEY", "\"" + getApiKey('ONEDRIVE_API_KEY_DEBUG') + "\"" + buildConfigField "String", "ONEDRIVE_API_REDIRCT_URI", "\"" + getApiKey('ONEDRIVE_API_REDIRCT_URI_DEBUG') + "\"" } } diff --git a/data/src/main/java/org/cryptomator/data/cloud/onedrive/graph/MicrosoftOAuth2Endpoint.java b/data/src/main/java/org/cryptomator/data/cloud/onedrive/graph/MicrosoftOAuth2Endpoint.java index 168bb6de..5adb24a9 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/onedrive/graph/MicrosoftOAuth2Endpoint.java +++ b/data/src/main/java/org/cryptomator/data/cloud/onedrive/graph/MicrosoftOAuth2Endpoint.java @@ -4,6 +4,8 @@ import android.net.Uri; import com.microsoft.services.msa.OAuthConfig; +import org.cryptomator.data.BuildConfig; + class MicrosoftOAuth2Endpoint implements OAuthConfig { /** * The current instance of this class @@ -12,7 +14,7 @@ class MicrosoftOAuth2Endpoint implements OAuthConfig { /** * The current instance of this class - * + * * @return The instance */ static MicrosoftOAuth2Endpoint getInstance() { @@ -26,7 +28,7 @@ class MicrosoftOAuth2Endpoint implements OAuthConfig { @Override public Uri getDesktopUri() { - return Uri.parse("urn:ietf:wg:oauth:2.0:oob"); + return Uri.parse(BuildConfig.ONEDRIVE_API_REDIRCT_URI); } @Override From 85aa265b169226b2cad439f360ebf87e285e0b4c Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 22 Jan 2021 12:09:02 +0100 Subject: [PATCH 27/32] Fix auto PhotoContentJob in debug build variant --- .../org/cryptomator/presentation/service/PhotoContentJob.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 8250f256..68ee0e5a 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/service/PhotoContentJob.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/service/PhotoContentJob.kt @@ -15,7 +15,9 @@ import android.provider.MediaStore import android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI import androidx.annotation.RequiresApi import org.cryptomator.domain.exception.FatalBackendException +import org.cryptomator.presentation.R import org.cryptomator.presentation.util.FileUtil +import org.cryptomator.presentation.util.ResourceHelper import org.cryptomator.util.file.MimeTypeMap_Factory import org.cryptomator.util.file.MimeTypes import timber.log.Timber @@ -121,7 +123,7 @@ class PhotoContentJob : JobService() { private const val PHOTOS_CONTENT_JOB = 23 init { - val builder = JobInfo.Builder(PHOTOS_CONTENT_JOB, ComponentName("org.cryptomator", PhotoContentJob::class.java.name)) + val builder = JobInfo.Builder(PHOTOS_CONTENT_JOB, ComponentName(ResourceHelper.getString(R.string.app_id), PhotoContentJob::class.java.name)) builder.addTriggerContentUri(JobInfo.TriggerContentUri(EXTERNAL_CONTENT_URI, FLAG_NOTIFY_FOR_DESCENDANTS)) builder.addTriggerContentUri(JobInfo.TriggerContentUri(MEDIA_URI, FLAG_NOTIFY_FOR_DESCENDANTS)) jobInfo = builder.build() From 8ae7d06c49267f865886c26a98bcb080c74536f4 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 22 Jan 2021 15:25:15 +0100 Subject: [PATCH 28/32] Update dependencies --- build.gradle | 2 +- buildsystem/dependencies.gradle | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 87f09f0c..fc0461cc 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.1' + classpath 'com.android.tools.build:gradle:4.1.2' classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0' classpath 'com.fernandocejas.frodo:frodo-plugin:0.8.3' classpath 'com.vanniktech:gradle-android-junit-jacoco-plugin:0.16.0' diff --git a/buildsystem/dependencies.gradle b/buildsystem/dependencies.gradle index 887935d5..8a95adc0 100644 --- a/buildsystem/dependencies.gradle +++ b/buildsystem/dependencies.gradle @@ -27,7 +27,7 @@ ext { rxAndroidVersion = '2.1.1' rxBindingVersion = '2.2.0' - daggerVersion = '2.31.1' + daggerVersion = '2.31.2' gsonVersion = '2.8.6' @@ -38,7 +38,7 @@ ext { timberVersion = '4.7.1' - zxcvbnVersion = '1.3.1' + zxcvbnVersion = '1.3.3' scaleImageViewVersion = '3.10.0' From 5f428b59639cb69441c42b73ab3c828a613d1f46 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Tue, 26 Jan 2021 07:18:15 +0100 Subject: [PATCH 29/32] #250 Recover AutoUploadFilesStore due to class obfuscation AutoUploadFilesStore, which handles serializing the paths marked to upload, is obfuscated in version 1.5.10 and 1.5.11-beta1, each differently. This causes deserialisation to fail in 1.5.11-beta1 which is now fixed for the next version. --- .../org/cryptomator/presentation/e/c.java | 57 ++++++++++++ .../org/cryptomator/presentation/i/a.java | 57 ++++++++++++ .../cryptomator/presentation/util/FileUtil.kt | 91 +++++++++++-------- 3 files changed, 168 insertions(+), 37 deletions(-) create mode 100644 presentation/src/main/java/org/cryptomator/presentation/e/c.java create mode 100644 presentation/src/main/java/org/cryptomator/presentation/i/a.java diff --git a/presentation/src/main/java/org/cryptomator/presentation/e/c.java b/presentation/src/main/java/org/cryptomator/presentation/e/c.java new file mode 100644 index 00000000..8cba6ec2 --- /dev/null +++ b/presentation/src/main/java/org/cryptomator/presentation/e/c.java @@ -0,0 +1,57 @@ +package org.cryptomator.presentation.e; + +import java.io.Serializable; +import java.util.Set; + +/** + * This file is the obfuscated AutoUploadFilesStore of Cryptomator in version 1.5.10 + * and is used to recover it in version 1.5.11 and 1.5.11-beta2 + * + * TODO Delete as soon as possible + * + * See more information: https://github.com/cryptomator/android/issues/250 + */ + +public final class c implements Serializable { + + public static final a Qb = new a(); + private static final long serialVersionUID = -2190476748996271234L; + + private final Set vlb; + + public c(Set paramSet) { + this.vlb = paramSet; + } + + public boolean equals(Object paramObject) { + if (this != paramObject) { + if (paramObject instanceof c) { + Object paramObject2 = ((c)paramObject).vlb; + return (this.vlb == null) ? ((paramObject2 == null)) : this.vlb.equals(paramObject2); + } + return false; + } + return true; + } + + public int hashCode() { + Set set = this.vlb; + return (set != null) ? set.hashCode() : 0; + } + + public final Set mE() { + return this.vlb; + } + + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("AutoUploadFilesStore(uris="); + stringBuilder.append(this.vlb); + stringBuilder.append(")"); + return stringBuilder.toString(); + } + + public static final class a { + private a() {} + } +} diff --git a/presentation/src/main/java/org/cryptomator/presentation/i/a.java b/presentation/src/main/java/org/cryptomator/presentation/i/a.java new file mode 100644 index 00000000..9444f86d --- /dev/null +++ b/presentation/src/main/java/org/cryptomator/presentation/i/a.java @@ -0,0 +1,57 @@ +package org.cryptomator.presentation.i; + +import java.io.Serializable; +import java.util.Set; + +/** + * This file is the obfuscated AutoUploadFilesStore of Cryptomator in version 1.5.11-beta1 + * and is used to recover it in version 1.5.11-beta2 + * + * TODO Delete as soon as possible + * + * See more information: https://github.com/cryptomator/android/issues/250 + */ + +public final class a implements Serializable { + + private static final long serialVersionUID = 5147365921479820025L; + private final Set b; + + public a(Set paramSet) { + this.b = paramSet; + } + + public final Set b() { + return this.b; + } + + public boolean equals(Object paramObject) { + if (this != paramObject) { + if (paramObject instanceof a) { + Object paramObject2 = ((a)paramObject).b; + return (this.b == null) ? ((paramObject2 == null)) : this.b.equals(paramObject2); + } + return false; + } + return true; + } + + public int hashCode() { + int bool; + Set set = this.b; + if (set != null) { + bool = set.hashCode(); + } else { + bool = 0; + } + return bool; + } + + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("AutoUploadFilesStore(uris="); + stringBuilder.append(this.b); + stringBuilder.append(")"); + return stringBuilder.toString(); + } +} diff --git a/presentation/src/main/java/org/cryptomator/presentation/util/FileUtil.kt b/presentation/src/main/java/org/cryptomator/presentation/util/FileUtil.kt index 402b1c95..a0a24cfa 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/util/FileUtil.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/util/FileUtil.kt @@ -125,7 +125,9 @@ class FileUtil @Inject constructor(private val context: Context, private val mim fun getImagePreviewFiles(path: String): ImagePreviewFilesStore { try { - ObjectInputStream(FileInputStream(path)).use { objectInputStream -> return objectInputStream.readObject() as ImagePreviewFilesStore } + ObjectInputStream(FileInputStream(path)).use { objectInputStream -> + return objectInputStream.readObject() as ImagePreviewFilesStore + } } catch (e: ClassNotFoundException) { Timber // .tag("FileUtil") // @@ -139,40 +141,39 @@ class FileUtil @Inject constructor(private val context: Context, private val mim } } - fun addImageToAutoUploads(path: String) { - val file = File(decryptedFileStorage, AUTO_UPLOAD_IMAGE__FILE_NAMES) - val paths = getAutoUploadFilesStore(file).uris + path - addImageToAutoUploads(paths) + fun addImageToAutoUploads(path: String): AutoUploadFilesStore { + val paths = getAutoUploadFilesStore().uris + path + return addImageToAutoUploads(paths) } - private fun addImageToAutoUploads(paths: Set) { - addImageToAutoUploads(AutoUploadFilesStore(paths)) + private fun addImageToAutoUploads(paths: Set): AutoUploadFilesStore { + return addImageToAutoUploads(AutoUploadFilesStore(paths)) } @Synchronized - private fun addImageToAutoUploads(autoUploadFilesStore: AutoUploadFilesStore) { + private fun addImageToAutoUploads(autoUploadFilesStore: AutoUploadFilesStore): AutoUploadFilesStore { try { decryptedFileStorage.mkdir() + val file = File(decryptedFileStorage, AUTO_UPLOAD_IMAGE__FILE_NAMES) - val out: ObjectOutput = ObjectOutputStream(FileOutputStream(file.path)) - out.writeObject(autoUploadFilesStore) - out.close() + + ObjectOutputStream(FileOutputStream(file.path)).use { objectOutputStream -> + objectOutputStream.writeObject(autoUploadFilesStore) + objectOutputStream.close() + } + + return autoUploadFilesStore } catch (e: IOException) { Timber // .tag("FileUtil") // .e(e, "Failed to store image preview file list for PreviewActivity") + throw FatalBackendException(e) } } - @get:Throws(FatalBackendException::class) - val autoUploadFilesStore: AutoUploadFilesStore - get() { - val file = File(decryptedFileStorage, AUTO_UPLOAD_IMAGE__FILE_NAMES) - return getAutoUploadFilesStore(file) - } - @Synchronized - private fun getAutoUploadFilesStore(file: File): AutoUploadFilesStore { + fun getAutoUploadFilesStore(): AutoUploadFilesStore { + val file = File(decryptedFileStorage, AUTO_UPLOAD_IMAGE__FILE_NAMES) if (!file.exists()) { return AutoUploadFilesStore(HashSet()) } @@ -183,20 +184,9 @@ class FileUtil @Inject constructor(private val context: Context, private val mim return autoUploadFilesStore } } catch (e: InvalidClassException) { - Timber // - .tag("FileUtil") // - .e(e, "This is a bug in Cryptomator version 1.4.1, only fix is to delete the AutoUploadFilesStore but no image inside so no problem") - if (!file.delete()) { - Timber // - .tag("FileUtil") // - .e("Failed to delete AutoUploadFilesStore") - } - throw FatalBackendException(e) - } catch (e: ClassNotFoundException) { - Timber // - .tag("FileUtil") // - .e(e, "Failed to read image preview file from list for PreviewActivity") - throw FatalBackendException(e) + return tryRecoverAutoUploadFilesStoreDueToFileObfuscation(file) + } catch (e: ClassCastException) { + return tryRecoverAutoUploadFilesStoreDueToFileObfuscation(file) } catch (e: IOException) { Timber .tag("FileUtil") @@ -205,20 +195,47 @@ class FileUtil @Inject constructor(private val context: Context, private val mim } } + /** + * This method tries to recover the AutoUploadFilesStore which was obfuscated in version 1.5.10 and 1.5.11-beta1, each differently + */ + private fun tryRecoverAutoUploadFilesStoreDueToFileObfuscation(file: File): AutoUploadFilesStore { + Timber.tag("FileUtil").i("Try to recover AutoUploadFilesStore using class c or a") + try { + ObjectInputStream(FileInputStream(file)).use { objectInputStream -> + val uploadPaths = when (val obj = objectInputStream.readObject()) { + is org.cryptomator.presentation.e.c -> obj.mE() // version 1.5.10 + is org.cryptomator.presentation.i.a -> obj.b() // version 1.5.11-beta1 + else -> null + } + when { + uploadPaths != null -> { + Timber.tag("FileUtil").i("Nailed it! Successfully recovered AutoUploadFilesStore!") + file.delete() + return AutoUploadFilesStore(uploadPaths) + } + else -> throw FatalBackendException("Failed to recover AutoUploadFilesStore") + } + } + } catch (e: Exception) { + throw FatalBackendException("Failed to recover AutoUploadFilesStore", e) + } + } + @Synchronized - fun removeImagesFromAutoUploads(names: Set) { - val autoUploadFilesStore = autoUploadFilesStore + fun removeImagesFromAutoUploads(names: Set): AutoUploadFilesStore { + val autoUploadFilesStore = getAutoUploadFilesStore() var paths = autoUploadFilesStore.uris if (autoUploadFilesStore.uris.isEmpty()) { - return + return autoUploadFilesStore } val dirPath = File(autoUploadFilesStore.uris.iterator().next()).parent names.forEach { name -> paths = paths.minus(String.format("%s/%s", dirPath, name)) } - addImageToAutoUploads(paths) + + return addImageToAutoUploads(paths) } class FileInfo(val name: String, mimeTypes: MimeTypes) { From 2054b9ba1d8ac5c4d9347f90350c8e42e118feb9 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Tue, 26 Jan 2021 07:37:26 +0100 Subject: [PATCH 30/32] New translations strings.xml --- .../src/main/res/values-de/strings.xml | 206 ++---------------- .../src/main/res/values-es/strings.xml | 132 +++-------- .../src/main/res/values-fr/strings.xml | 206 ++---------------- .../src/main/res/values-he/strings.xml | 37 ++++ .../src/main/res/values-tr/strings.xml | 178 --------------- 5 files changed, 103 insertions(+), 656 deletions(-) create mode 100644 presentation/src/main/res/values-he/strings.xml diff --git a/presentation/src/main/res/values-de/strings.xml b/presentation/src/main/res/values-de/strings.xml index 4eb68f4a..6af46287 100644 --- a/presentation/src/main/res/values-de/strings.xml +++ b/presentation/src/main/res/values-de/strings.xml @@ -1,11 +1,7 @@ - - Cryptomator Verschlüsseln - @string/app_name - Ein Fehler ist aufgetreten Authentifizierung fehlgeschlagen @@ -29,134 +25,92 @@ Beim entschlüsseln des WebDAV-Passworts trat ein Fehler auf. Bitte in den Einstellungen erneut festlegen. Die Play Services sind nicht installiert Biometrischer Login abgebrochen - - - Crypto - Dropbox - Google Drive - OneDrive - WebDAV Lokaler Speicher - - Erlauben Sie Cryptomator Zugriff auf Ihren Speicher, um eine Datei zu exportieren Erlauben Sie Cryptomator Zugriff auf Ihren Speicher, um eine Datei hochzuladen Erlauben Sie Cryptomator Zugriff auf Ihren Speicher, um eine Datei zu teilen - Einstellungen Suche - Weiter Vorheriges - + Weiter Sortieren - A - Z - Z - A Neueste zuerst Älteste zuerst Größte zuerst Kleinste zuerst - - Zu Cryptomator hinzufügen Neuen Tresor anlegen Vorhandenen Tresor hinzufügen - @string/screen_file_browser_node_action_rename Entfernen Hier einen neuen Tresor erstellen Passwort wurde erfolgreich geändert - Tresor - Neuen Tresor anlegen Masterkey-Datei auswählen - @string/screen_vault_list_action_create_new_vault Hier ablegen Tresorname: %1$s - Verschieben - Verschieben von %1$s nach %2$d Elemente verschieben nach - + Verschieben Leerer Ordner - %1$s geändert vor %1$s - Teilen mit Wählen Sie einen Ablageort aus Auswählen Nichts zum teilen - Zu %1$s hinzufügen Ordner erstellen Text-Datei erstellen Dateien hochladen Dateien - Datei exportiert + Dateien exportiert Nichts zum exportieren Download-Verzeichnis konnte nicht erstellt werden - Teilen Umbenennen Bearbeiten - @string/screen_file_browser_move_button_text Exportieren Löschen Öffnen mit… - - Keine Verbindung - Wiederholen - Elemente auswählen %1$d ausgewählt Elemente auswählen Alle elemente auswählen Aktualisieren - - Dateien exportiert - + Keine Verbindung + Wiederholen Erfolgreich gespeichert - Speicher %1$s unter… - text Datei Dateien Dateinamen müssen eindeutig sein, bitte benennen Sie die Duplikate um. - @string/screen_share_files_content_files Speicherort Speichern Dateien verschlüsselt text.txt - Cloud-Dienst - @string/screen_vault_list_action_add_existing_vault - @string/screen_vault_list_action_create_new_vault - + Neuen Tresor anlegen Ort auswählen - @string/screen_file_browser_node_action_edit_text - @string/screen_vault_list_vault_action_delete Hier einen neuen Ort hinzufügen Server scheint nicht WebDAV-kompatibel zu sein Benutzerdefinierte Orte Standard-Speicher Weitere Orte sind nicht verfügbar. - - @string/cloud_names_webdav - URL Benutzername Passwort Verbinden @@ -164,31 +118,23 @@ URL ist ungültig. Benutzername muss ausgefüllt werden. Passwort muss ausgefüllt werden. - - @string/screen_vault_list_action_create_new_vault Tresorname muss ausgefüllt werden. Tresorname Erstellen - Passwort setzen Passwort muss ausgefüllt werden. Passwort stimmt nicht mit dem wiederholten Passwort überein. Fertig WICHTIG: Wenn Sie Ihr Passwort vergessen, gibt es keine Möglichkeit die Daten zu entschlüsseln. - @string/screen_webdav_settings_password_label Passwort wiederholen - Sehr Schwach Schwach Mittel Stark Sehr Stark - - @string/snack_bar_action_title_settings - Allgemein Cloud-Dienste Biometrischer Login @@ -196,95 +142,62 @@ Nach Entsperrung mittels dem Gesichts, bestätigen (falls verfügbar) App blockieren, wenn verdeckt Bildschirm-Sicherheit - Search + Suche Live-Suche Suche mit Glob-Muster - Automatisch sperren Sperren nach Bei deaktiviertem Bildschirm - Automatisches Photo-Hochladen Tresor auswählen für das Hochladen Aktivieren Nur mit WLAN hochladen - Bilder abspeichern in… - Uns folgen Cryptomator-Website Folgen Sie uns auf Twitter Liken Sie uns auf Facebook - https://cryptomator.org/de - https://twitter.com/Cryptomator - https://facebook.com/Cryptomator - Rechtliches Lizenzen Lizenztexte - - Support Hilfe anfordern - https://cryptomator.org/de/contact/ Debug-Modus Log-Datei senden Senden fehlgeschlagen Sicherheitshinweise - https://docs.cryptomator.org/en/1.5/security/best-practices/ - Version Halte Tresore geöffnet während dem Editieren einer Datei - + Erweiterte Eigenschaften + Vorbereitungen zum Entsperren im Hintergrund - @string/screen_settings_cloud_settings_label WebDAV-Verbindungen Lokale Speicherorte Einloggen in Abmelden von - - Erweiterte Eigenschaften - Vorbereitungen zum Entsperren im Hintergrund - - @string/screen_settings_licenses_label - - + %1$s-Authentifizierung fehlgeschlagen. - \'%1$s\' nicht erreichbar Cryptomator hat erkannt, dass dieser Ordner nicht erreichbar ist. Möglicherweise wurde dieser durch eine andere Anwendung gelöscht oder wurde durch eine fehlerhafte Synchronisation mit der Cloud verursacht.\n\nVersuchen Sie die Verzeichnisdatei über Ihren Cloud-Anbieter auf eine vorhergehende Version, die nicht leer ist, wiederherzustellen. Die betroffene Datei ist:\n%1$s\n\nFalls dies nicht funktioniert, könnten Sie Sanitizer verwenden, um Ihren Tresor auf Fehler zu überprüfen und möglicherweise Daten wiederherzustellen. Mehr über Sanitizer - - Abbrechen - - @string/screen_file_browser_action_create_folder - @string/screen_enter_vault_name_button_text - - @string/screen_webdav_settings_password_label Entsperren - - Altes Passwort Neues Passwort - @string/screen_set_password_retype_password_label Passwort ändern Altes Passwort muss ausgefüllt werden. Neues Passwort muss ausgefüllt werden. Neue Passwort stimmt nicht mit dem wiederholten Passwort überein. - Tresor %1$s nicht gefunden Der Tresor wurde umbenannt, verschoben oder gelöscht. Entfernen Sie diesen aus der Tresorliste und fügen Sie ihn erneut hinzu um fortzufahren. Tresor jetzt entfernen? Entfernen - Datei existiert bereits Ersetzen Eine Datei namens \'%1$s\' existiert bereits. - Existierende überspringen Alle ersetzen Existierende ersetzen @@ -294,49 +207,28 @@ %d Dateien existieren bereits. Sollen diese ersetzt werden? Datei ersetzen? Dateien ersetzen? - Teilen nicht möglich Sie haben keinen Tresor eingerichtet. Bitte legen Sie zuerst einen Tresor mit der Cryptomator-App an. - OK Tresor erstellen - %1$s kann nicht geöffnet werden - @string/screen_file_browser_node_action_export Bitte installieren Sie eine App, die diese Datei öffnen kann. Möchten Sie die Datei stattdessen auf dem Gerät speichern? - Tresor umbenennen - @string/screen_file_browser_node_action_rename - Ordner umbenennen Datei umbenennen - @string/screen_file_browser_node_action_rename - Sie haben ungespeicherte Änderungen Möchten Sie wirklich beenden, ohne zu speichern? Verwerfen @string/dialog_button_cancel - - @string/screen_file_browser_action_create_new_text_file - @string/screen_enter_vault_name_button_text - @string/dialog_button_cancel @string/screen_share_files_new_text_file - - @string/screen_file_browser_node_action_delete Sind Sie sicher, dass sie den Tresor entfernen wollen? Dieser Vorgang wird den Tresor nur aus dieser Liste entfernen und nicht tatsächlich löschen. - Lade hoch… - @string/dialog_button_cancel Datei %1$d von %2$d - Exportiere (%1$d/%2$d) - @string/dialog_button_cancel - Bitte warten… Erstelle Ordner… Erstelle Text-Datei… Authentifizierung… - Benenne um… Lösche… Entsperre Tresor… @@ -348,105 +240,63 @@ Entschlüssele… Verschiebe… Sperren - Ungültiges SSL-Zertifikat Das SSL-Zertifikat ist ungültig. Wollen Sie diesem trotzdem vertrauen? - Details Dies könnte ein Sicherheitsrisiko sein. Ich weiß was ich tue. - Die Verwendung von HTTP ist unsicher. Wir empfehlen stattdessen die Nutzung von HTTPS. Wenn Sie sich der Risiken bewusst sind, können Sie mit HTTP fortfahren. Zu HTTPS ändern HTTPS nutzen? - Kein Sperrbildschirm ist gesetzt. Um Ihre Passwörter sicher speichern zu können, setzen Sie bitte mit OK ein Muster oder ein Passwort. Sperrbildschirm setzen? Sperrbildschirm setzen - Kein Fingerabdruck/Gesicht im System Legen Sie mindestens einen Fingerabdruck/Gesicht im System an, um diesen Dienst nutzen zu können. - In diesem Modus könnten sensible Daten in eine Log-Datei auf diesem Gerät geschrieben werden (z.B. Dateinamen und Pfade). Ausgeschlossen davon sind u.a. Passwörter und Cookies.\n\nDenken Sie daran, den Debug-Modus so schnell wie möglich wieder zu deaktivieren. Achtung Aktivieren - @string/dialog_button_cancel - Dies ist eine Sicherheitsfunktion und verhindert, dass andere Apps Nutzer dazu bringen, Dinge zu tun, die sie nicht tun wollen.\n\nDurch die Deaktivierung bestätigen Sie, dass Sie sich der Risiken bewusst sind. Achtung Deaktivieren - @string/dialog_button_cancel - 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 - Dies ist eine Sicherheitsfunktion und verhindert, dass andere Apps Nutzer dazu bringen, Dinge zu tun, die sie nicht tun wollen.\n\nDurch die Deaktivierung bestätigen Sie, dass Sie sich der Risiken bewusst sind. - Sind Sie sicher, dass sie den Cloud-Dienst entfernen wollen? Dieser Vorgang wird den Cloud-Dienst und desen zugehörigen Tresor löschen. - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel - - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel %1$d Elemente löschen? Sind Sie sicher, dass Sie diese Elemente löschen wollen? Sind Sie sicher, dass Sie diese Datei löschen wollen? Dieser Vorgang wird den gesamten Ordnerinhalt löschen. Sind Sie sicher, dass Sie diesen Ordner löschen wollen? - Biometrischer Login deaktiviert Da der Schlüssel nicht mehr zur Verfügung steht, wurde der Biometrischer Login deaktiviert. Zur Reaktivierung öffnen Sie die Cryptomator-Einstellungen. - @string/dialog_unable_to_share_positive_button - - Beta-Version - Das ist eine Beta-Version, die das Tresor-Format 7 unterstützt. Bitte nicht mit einem produktiv eingesetzten Tresor verwenden oder dafür sorgen, dass gute Sicherungen vorhanden sind. - APK-Store Lizenz Cryptomator wurde ohne Google Play Store installiert. Geben Sie eine gültige Lizenz ein, falls nicht bereits vorhanden, kann sie unter folgender URL erworben werden: https://cryptomator.org/android/ Die eingegebene Lizenz ist nicht gültig. Stellen Sie sicher, dass sie korrekt eingegeben wurde. Keine Lizenz vorhanden. Geben Sie eine gültige Lizenz ein. - @string/dialog_unable_to_share_positive_button Beenden - - Danke für die Eingabe Ihrer gültige Lizenz %1$s. Lizenzbestätigung - @string/dialog_unable_to_share_positive_button - + Danke für die Eingabe Ihrer gültige Lizenz %1$s. Neue Version verfügbar Cryptomator mit auf den aktuellen Stand aktualisieren. Mit OK wird die neueste Version heruntergeladen. Daraufhin werden Sie aufgefordert sie zu installieren. Jetzt aktualisieren Download-Seite öffnen Später Download in Ausführung - Lade die aktuelle Version von Cryptomator herunter - Dieser Ordner ist ein symbolischer Link Sie können nicht in diesen symbolischen Link navigieren Zurück - Verzeichniss kann nicht geladen werden Der Ordner \'%1$s\' in der Cloud hat keine Verzeichniss-Datei. Es könnte sein, dass der Ordner auf einem anderen Gerät erstellt wurde und noch nicht vollständig mit der Cloud synchronisiert ist. Bitte überprüfen, ob die folgende Datei in der Cloud existiert:\n%2$s - @string/dialog_sym_link_back_button - + Beta-Version + Das ist eine Beta-Version, die das Tresor-Format 7 unterstützt. Bitte nicht mit einem produktiv eingesetzten Tresor verwenden oder dafür sorgen, dass gute Sicherungen vorhanden sind. Cryptomator benötigt Zugriff auf den Speicher um lokale Tresore zu nutzen Cryptomator benötigt Zugriff auf den Speicher um den automatischen Foto-Upload zu nutzen - - Android Fehlerbericht - Zusammenfassung - Beschreiben Sie ausführlich, was sie in der App getan haben oder verweisen Sie auf ein existierendes Support-Ticket. - Geräteinfo - - Null kB Bytes - kB - MB - GB - TB - Sekunde Sekunden @@ -462,52 +312,38 @@ Monate Jahr Jahre - Biometrischer Login Tresor mittels Biometrie entsperren Tresor-Passwort verwenden - Automatischer Upload nicht möglich - Tresore entsperrt: %1$d Auto-Lock in %1$s Alle sperren - Hochladen abbrechen Automatisches Foto-Hochladen läuft Lade hoch %1d/%2d - - %1$d Bilder wurden in den Tresor hochgeladen Automatisches Foto-Hochladen beendet - + %1$d Bilder wurden in den Tresor hochgeladen Fehler beim automatischen Photo-Hochladen Generaller Fehler während dem Hochladen. Ausgewählter Ordner für das Photo-Hochladen existiert nicht mehr. In der Einstellungen neuen auswählen Tresor gesperrt während dem hochladen, zum weiteren Hochladen entsperren - - @string/dialog_button_cancel - Tresor bleibt entsperrt bis die Datei nicht mehr editiert wird Datei mit Schreibrechten geöffnet - + Tresor bleibt entsperrt bis die Datei nicht mehr editiert wird Neueste Version installiert - Zwischenspeicher - Zwischenspeicher leeren Zwischenspeichergröße insgesamt - @string/screen_settings_section_auto_photo_upload_toggle + Zwischenspeicher leeren Änderungen werden nach einem Neustart der App aktiv Registriert für - %1$s Intervall der Aktualisierungsprüfung Nach Aktualisierungen suchen Letzte Ausführung %1$s Noch nie Noch nie ~ Wenn aus technischen Gründen keine Update-Prüfung durchgeführt werden kann, können Updates manuell über die Website https://cryptomator.org/android/ heruntergeladen und installiert werden. - Zwischenspeichergröße pro Cloud - Sofort 1 Minute @@ -515,25 +351,15 @@ 5 Minuten 10 Minuten Nie - - 50 MB - 100 MB - 250 MB - 500 MB - 1 GB - 5 GB - Design Automatisch (System-Einstellung verwenden) Hell Dunkel - Einmal am Tag Einmal pro Woche Einmal im Monat @string/lock_timeout_never - diff --git a/presentation/src/main/res/values-es/strings.xml b/presentation/src/main/res/values-es/strings.xml index 43bd2c24..b871bcd9 100644 --- a/presentation/src/main/res/values-es/strings.xml +++ b/presentation/src/main/res/values-es/strings.xml @@ -1,10 +1,7 @@ - Cryptomator Cifrar - @string/app_name - Se ha producido un error Ha fallado la autenticación @@ -17,43 +14,31 @@ La nube ya existe. Por favor, descarga una aplicación que pueda abrir este archivo. Servidor no encontrado. - - - Crypto - Dropbox - Google Drive - OneDrive - WebDAV + + Almacenamiento local - - + + Cryptomator necesita acceso al almacenamiento para exportar archivos. Cryptomator necesita acceso al almacenamiento para subir archivos. Cryptomator necesita acceso al almacenamiento para compartir archivos. Configuración - - + + Añadir a Cryptomator Crear nueva caja fuerte Añadir caja fuerte existente - @string/screen_file_browser_node_action_rename Eliminar Haz clic aquí para crear una caja fuerte Contraseña cambiada con éxito - Caja fuerte - @string/screen_vault_list_action_add_existing_vault Seleccionar archivo masterkey - @string/screen_vault_list_action_create_new_vault Dejar aquí Nombre de caja fuerte: %1$s Mover Carpeta vacía - "%1$s + \"%1$s modificado hace %1$s Compartir con Elegir destino @@ -68,45 +53,31 @@ Compartir Renombrar Editar - @string/screen_file_browser_move_button_text Exportar Eliminar Sin conexión Reintentar - Guardado correctamente - Guardar %1$s en… texto archivo archivos Los nombres de archivo deben ser únicos. Renombra los duplicados. - @string/screen_share_files_content_files Guardar ubicación Guardar Cifrado completado - @string/dialog_file_name_placeholder - Servicio de nube - @string/screen_vault_list_action_add_existing_vault - @string/screen_vault_list_action_create_new_vault - Elegir ubicación - @string/screen_file_browser_node_action_edit_text - @string/screen_vault_list_vault_action_delete Haz clic aquí para añadir ubicaciones El servidor no parece ser compatible con WebDAV Ubicaciones personalizadas Almacenamiento predeterminado No hay ubicaciones extra disponibles. - - @string/cloud_names_webdav - URL Nombre de usuario Contraseña Conectar @@ -114,78 +85,53 @@ La URL no es válida. El nombre de usuario no puede estar vacio. La contraseña no puede estar vacía. - - @string/screen_vault_list_action_create_new_vault El nombre de la caja fuerte no puede estar vacío. Nombre de la caja fuerte Crear - Establecer contraseña - @string/screen_webdav_settings_msg_password_must_not_be_empty Las contraseñas no coinciden. Completado IMPORTANTE: si olvida su contraseña no habrá manera de recuperar los datos. - @string/screen_webdav_settings_password_label Reescriba la contraseña - - @string/snack_bar_action_title_settings - General Servicios de nube - @string/screen_webdav_settings_done_button_text Web de Cryptomator Síguenos en Twitter Danos me gusta en Facebook - https://cryptomator.org - https://facebook.com/Cryptomator - https://twitter.com/Cryptomator - Legal Licencias Términos de la licencia Soporte Solicitar ayuda - https://cryptomator.org/contact/ Modo de depuración Enviar archivo de trazas Error en el envío Versión - - @string/screen_settings_cloud_settings_label Conexiones de WebDAV Ubicaciones de almacenamiento local Iniciar sesión en Cerrar sesión de - - @string/screen_settings_licenses_label - - + No se pudo autenticar en %1$s. - No se llega a %1$s Cryptomator ha detectado que no se llega a esta carpeta - Más detalles sobre Sanitizer - - Cancelar - @string/screen_file_browser_action_create_folder - @string/screen_enter_vault_name_button_text - @string/screen_webdav_settings_password_label Desbloquear Antigua contraseña Nueva contraseña - @string/screen_set_password_retype_password_label Cambiar contraseña La antigua contraseña no puede estar vacía. La nueva contraseña no puede estar vacía. Las nuevas contraseñas no coinciden. + + Eliminar El archivo ya existe Reemplazar Ya existe un archivo llamado %1$s. @@ -195,34 +141,25 @@ Reemplazar Ya existe un archivo llamado %1$s. ¿Quieres reemplazarlo? Todos los archivos existen ya. ¿Quieres reemplazarlos? - "%d archivos existen ya. ¿Quieres reemplazarlos? - "¿Reemplazar archivo? - "¿Reemplazar archivos? + \"%d archivos existen ya. ¿Quieres reemplazarlos? + \"¿Reemplazar archivo? + \"¿Reemplazar archivos? No se puede compartir archivos No ha configurado ninguna caja fuerte. Cree antes una nueva caja fuerte con la aplicación Cryptomator. Aceptar Crear caja fuerte No se puede abrir %1$s - @string/screen_file_browser_node_action_export Descarga una aplicación que pueda abrir el archivo o, ¿quieres guardarlo en el dispositivo? Renombrar caja fuerte - @string/screen_file_browser_node_action_rename Renombrar carpeta Renombrar archivo - @string/screen_file_browser_node_action_rename Tienes cambios sin guardar - "¿De verdad quieres salir sin guardar? + \"¿De verdad quieres salir sin guardar? Descartar - @string/screen_share_files_save_button_text - @string/screen_file_browser_action_create_new_text_file - @string/screen_enter_vault_name_button_text - @string/dialog_button_cancel texto.txt - @string/screen_file_browser_node_action_delete - "¿Estás seguro de que quieres eliminar esta caja fuerte? + \"¿Estás seguro de que quieres eliminar esta caja fuerte? Esta acción solo eliminará la caja fuerte de esta lista y no la borrará físicamente. Sube… - @string/dialog_button_cancel Espera, por favor… Creando carpeta… Creando archivo de texto… @@ -241,37 +178,21 @@ El certificado SSL no es válido. ¿Quiere confiar en él de todas formas? El uso de HTTP no es seguro. Recomendamos usar HTTPS en su lugar. Si conoce los riesgos puede seguir usando HTTP. Cambiar a HTTPS - "¿Usar HTPPS? + \"¿Usar HTPPS? No se ha establecido el bloqueo de pantalla. Para almacenar las credenciales de forma segura, establece con Aceptar un patrón o contraseña. - "¿Establecer bloqueo de pantalla? + \"¿Establecer bloqueo de pantalla? Establecer bloqueo de pantalla Aviso Activar - @string/dialog_button_cancel - "¿Estás seguro de que quieres eliminar esta conexión de nube? + Aviso + \"¿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. - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel - "¿Estás seguro de que quieres borrar este archivo? + \"¿Estás seguro de que quieres borrar este archivo? Esto borrará todo el contenido de la carpeta. ¿Estás seguro de que quiere borrar esta carpeta? - - Informe de error de Android - Sumario - Introduce una descripción corta de lo has intentado hacer o indica el ticket de soporte si ya habías creado uno. - Información del dispositivo - - + + Cero kB - bytes - kB - MB - GB - TB - segundo segundos @@ -287,17 +208,20 @@ meses año años - + Cajas fuertes desbloqueadas: %1$d Autobloqueo en %1$s Bloquear todas - + \"%1$s 1 minuto 2 minutos 5 minutos 10 minutos Nunca - + + + + Nunca diff --git a/presentation/src/main/res/values-fr/strings.xml b/presentation/src/main/res/values-fr/strings.xml index 92575f57..ccdf0340 100644 --- a/presentation/src/main/res/values-fr/strings.xml +++ b/presentation/src/main/res/values-fr/strings.xml @@ -1,11 +1,7 @@ - - Cryptomator Chiffrer - @string/app_name - Une erreur est survenue Échec de l\'authentification @@ -29,29 +25,18 @@ Le mot de passe WebDAV n\'a pas été déchiffré, veuillez l\'ajouter une nouvelle fois dans les paramètres Services Google play non installés Authentification biométrique avortée - - - Crypto - Dropbox - Google Drive - OneDrive - WebDAV Stockage local - - 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 - Paramètres Rechercher Précédent Suivant - Trier par A - Z Z - A @@ -59,105 +44,74 @@ Plus ancien Taille décroissante Taille croissante - - Ajouter à Cryptomator Créer un nouveau coffre-fort Ajouter un coffre-fort existant - @string/screen_file_browser_node_action_rename Retirer Cliquez ici pour créer un nouveau coffre-fort Mot de passe modifié avec succès - Coffre - - @string/screen_vault_list_action_add_existing_vault Sélectionné le fichier de clé principal - @string/screen_vault_list_action_create_new_vault Placé ici Nom du coffre-fort: %1$s - Déplacé %1$s vers Déplacer des éléments de %2$s vers - Déplacer - Dossier vide %1$s Modifié il y à %1$s - Partager avec Choisissez la destination Choisir Rien à partager - Ajouter le %1$s Créer le dossier Créer le fichier texte Televerser des fichiers Fichiers - Fichier exporté Fichiers exportés Rien à exporter - Échec de la création du répertoire de téléchargement - Ouvrir avec… - Partager Renommer Éditer - @string/screen_file_browser_move_button_text Exporter Supprimer - + Ouvrir avec… Sélectionnez les éléments %1$d sélectionné Sélectionner… Tout sélectionner Rafraîchir - Aucune connection Réessayer - Enregistré avec succès - Enregistré %1$s vers… texte fichier fichiers - Les noms de fichiers doivent être uniques, veuillez renommer les doublons - @string/screen_share_files_content_files Enregistrer l\'emplacement Enregistrer Chiffrement terminé - @string/dialog_file_name_placeholder - Service cloud - @string/screen_vault_list_action_add_existing_vault - @string/screen_vault_list_action_create_new_vault - Choisissez l\'emplacement - @string/screen_file_browser_node_action_edit_text - @string/screen_vault_list_vault_action_delete 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. - - @string/cloud_names_webdav URL Nom d\'utilisateur Mot de passe @@ -166,31 +120,22 @@ URL invalide. Le nom d\'utilisateur ne peut pas être vide. Le mot de passe ne peut pas être vide. - - @string/screen_vault_list_action_create_new_vault Le nom du coffre-fort ne peut pas être vide. Nom du coffre-fort Créer - Définir le mot de passe - @string/screen_webdav_settings_msg_password_must_not_be_empty Le mot de passe ne correspond pas au mot de passe retapé. Terminé IMPORTANT: Si vous oubliez votre mot de passe, il n\'y aura aucun moyen de récupérer vos données. - @string/screen_webdav_settings_password_label Retaper le mot de passe - Très faible Faible Acceptable Fort Très fort - - @string/snack_bar_action_title_settings - Général Service cloud Authentification biométrique @@ -198,94 +143,63 @@ Confirmer le déverrouillage par reconnaissance faciale (si disponible) Bloquer l\'application lorsqu\'elle est masquée Sécurité de l\'écran - Recherche Recherche en direct Recherche avec le modèle glob - Verrouillage automatique Verrouillage après Lorsque l\'écran est éteint - Téléversement automatique de photo Choisir un coffre-fort pour le téléversement Activer Téléverser sur réseau WIFI uniquement - Enregistrer les fichiers du téléversement automatique dans… - - @string/screen_webdav_settings_done_button_text Site web de Cryptomator Suivez-nous sur Twitter Aimez notre page Facebook - https://cryptomator.org - https://facebook.com/Cryptomator - https://twitter.com/Cryptomator - Légal - Licenses + Licences Termes de la licence - - Support + Support technique Demander de l\'aide - https://cryptomator.org/contact/ Mode débogage Envoyer un fichier journal L\'envoi a échoué Conseils de sécurité - https://docs.cryptomator.org/en/1.5/security/best-practices/ - Version - Gardez les coffres déverrouillés lors de la modification des fichiers - + Paramètres Avancés + Préparations du déverrouillage en arrière-plan - @string/screen_settings_cloud_settings_label Connexions WebDAV Emplacements du stockage local Se connecter à Se déconnecter de - - @string/screen_settings_licenses_label - %1$s n\'a pas pu être authentifié. - \'%1$s\' inaccessible Cryptomator a détecté que ce dossier est inaccessible. Il a peut-être été supprimé par une autre application ou une synchronisation cloud défectueuse pourrait en être la cause.\n\nEssayez de restaurer le fichier de répertoire via votre fournisseur de cloud dans une version précédente qui n\'est pas vide. Le fichier en question est:\n%1$s\n\nSi cela ne fonctionne pas, vous pouvez utiliser Sanitizer pour rechercher des problèmes dans votre coffre-fort et éventuellement restaurer vos données. Plus de détails sur Sanitizer - - Annuler - - @string/screen_file_browser_action_create_folder - @string/screen_enter_vault_name_button_text - - @string/screen_webdav_settings_password_label Déverrouiller - Ancien mot de passe Nouveau mot de passe - @string/screen_set_password_retype_password_label Changer le mot de passe L\'ancien mot de passe ne peut pas être vide. Le nouveau mot de passe ne peut pas être vide. 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 Un fichier nommé \'%1$s\' existe déjà. - Ignorer l\'existant Remplacer tout Remplacer existant @@ -295,44 +209,24 @@ %d fichiers existent déjà. Voulez-vous les remplacer? Remplacer le fichier? Remplacer les fichiers? - Impossible de partager des fichiers Vous n\'avez pas configuré de coffre-fort. Veuillez d\'abord créer un nouveau coffre-fort avec l\'application Cryptomator. OK Créer un coffre-fort - Impossible d\'ouvrir %1$s - @string/screen_file_browser_node_action_export Veuillez télécharger une application qui peut ouvrir ce fichier ou souhaitez-vous l\'enregistrer sur votre appareil? - Renommer le coffre-fort - @string/screen_file_browser_node_action_rename - Renommer le dossier Renommer le fichier - @string/screen_file_browser_node_action_rename - Vous avez des modifications non enregistrés Désirez-vous vraiment quitter sans enregistrer? Abandonner - @string/screen_share_files_save_button_text - - @string/screen_file_browser_action_create_new_text_file - @string/screen_enter_vault_name_button_text - @string/dialog_button_cancel texte.txt - - @string/screen_file_browser_node_action_delete Êtes-vous sûr de vouloir retirer ce coffre-fort? Cette action ne fera que retirer le coffre-fort de cette liste sans le supprimer physiquement. - Téléversement… - @string/dialog_button_cancel Fichier %1$d à %2$d - Exportation (%1$d/%2$d) - @string/dialog_button_cancel - Patientez s\'il vous plaît… Création du dossier… Création du fichier texte… @@ -348,104 +242,68 @@ Déchiffrement… Déplacement… Verouiller - Certificat SSL invalide Le certificat SSL n\'est pas valide. Vous voulez quand même lui faire confiance? Détails Cela pourrait constituer un risque pour la sécurité. Je sais ce que je fais. - L\'utilisation du HTTP n\'est pas sûre. Nous recommandons d\'utiliser plutôt le HTTPS. Si vous connaissez les risques, vous pouvez continuer à utiliser HTTP. Passage au HTTPS Utiliser le HTTPS? - Aucun verrouillage de l\'écran n\'est activé. Pour stocker vos informations d\'identification de manière sécurisée, définissez un schéma ou un mot de passe avec OK. Régler le verrouillage de l\'écran? Régler le verrouillage de l\'écran - Aucune authentification de base n\'est configurée dans le système Inscrivez au moins un doigt/visage pour utiliser ce service. - Dans ce mode, les données sensibles peuvent être écrites dans un fichier journal sur votre appareil (par exemple, les noms de fichiers et les chemins d\'accès). Les mots de passe, cookies, etc. sont explicitement exclus.\n\nN\'oubliez pas de désactiver le mode de débogage dès que possible. - Attention + Avertissement Activer - @string/dialog_button_cancel - 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. - Attention + Avertissement Désactiver - @string/dialog_button_cancel - \'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 - 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. - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel - - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel Supprimé %1$d éléments? Êtes-vous sûr de vouloir supprimer ces éléments? Êtes-vous sûr de vouloir supprimer ce fichier? Cela supprimera tout le contenu du dossier. Êtes-vous sûr de vouloir supprimer ce dossier? - Fonctionnalité d\'authentification biométrique désactivée La clé ayant été invalidée, la fonctionnalité d\'authentification biométrique a été désactivée. Pour la réactiver, ouvrez les paramètres de Cryptomator. - @string/dialog_unable_to_share_positive_button - Fournir une licence valide Nous avons détecté que vous avez installé Cryptomator sans utiliser le Play Store de Google. Fournissez une licence valide, qui peut être achetée sur https://cryptomator.org/android/ La licence fournie n\'est pas valide. Vérifiez que vous l\'avez saisie correctement. Aucune licence n\'est fournie. Veuillez saisir une licence valide. - @string/dialog_unable_to_share_positive_button Sortie - Confirmation de la licence Merci %1$s d\'avoir fourni votre licence valide. - @string/dialog_unable_to_share_positive_button - + Mise à jour disponible Mettez à jour Cryptomator vers la dernière version. En appuyant sur OK, nous téléchargerons l\'application en arrière-plan et vous proposerons de l\'installer. Mettre à jour maintenant Accéder au site de téléchargements Plus tard - Téléchargement en cours Téléchargement de la dernière version de Cryptomator - Le dossier est un lien symbolique Vous ne pouvez pas naviguer dans ce lien symbolique Retour - Impossible de charger le contenu du répertoire Le dossier cloud \'%1$s\' n\'a pas de fichier de répertoire. Il se peut que le dossier ait été créé sur un autre appareil et qu\'il n\'ait pas encore été entièrement synchronisé avec le cloud. Veuillez vérifier dans votre cloud si le fichier suivant existe: \n%2$s - @string/dialog_sym_link_back_button - Version bêta Il s\'agit d\'une version bêta qui introduit la prise en charge du format de coffre-fort vault 7. Veuillez vous assurer que vous n\'utilisez pas votre coffre-fort principal pour les tests ou que vous disposez d\'une bonne stratégie de sauvegarde. - Cryptomator a besoin de l\'accès au stockage pour utiliser les coffres locaux Cryptomator a besoin de l\'accès au stockage pour effectuer le téléversement automatique de photos - - Rapport d\'erreur Android - Résumé - Insérez une courte description de ce que vous avez essayé de faire ou mentionnez votre ticket d\'assistance si vous en avez déjà créé un. - Informations sur l\'appareil - - - Zero kB - bytes - kB - MB - GB - TB - + Zéro Ko + octets + ko + Mo + Go + To seconde secondes @@ -461,54 +319,39 @@ mois année années - Identification biométrique Connectez-vous à l\'aide de votre identifiant biométrique Utiliser le mot de passe du coffre-fort - - "Impossible de téléverser automatiquement les fichiers" - + Impossible de téléverser automatiquement les fichiers Coffre-fort déverrouillées: %1$d Verrouillage automatique dans %1$s Tout verrouiller - Annuler le téléversement Téléversement auto de photos en cours Téléversement %1d/%2d - Téléversement auto des photos terminé %1$d images téléversées dans le coffre-fort - Échec du téléversement auto des photos Une erreur générale s\'est produite lors du téléversement. Le dossier sélectionné pour le téléversement n\'est plus disponible. Accédez aux paramètres et choisissez-en un nouveau Coffre-fort verrouillé pendant le téléchargement, veuillez rouvrir le coffre-fort pour continuer - - @string/dialog_button_cancel Ouvrir un fichier accessible en écriture Le coffre-fort reste déverrouillé jusqu\'à la fin des modifications - Dernière version installée - Cache - @string/screen_settings_section_auto_photo_upload_toggle Taille totale du cache Vider le cache Les changements seront appliqués lors du prochain démarrage de l\'application - Enregistré pour %1$s - Intervalle de vérification des mises à jour Vérifier les mises à jour Dernière exécution %1$s @string/lock_timeout_never Jamais ~ Si la vérification de mise à jour ne peut être effectué pour des raisons techniques, les mises à jour peuvent être téléchargées et installées manuellement à partir du site https://cryptomator.org/android/. - Taille du cache par cloud - Instantané 1 minute @@ -516,26 +359,21 @@ 5 minutes 10 minutes Jamais - - 50 MB - 100 MB - 250 MB - 500 MB - 1 GB - 5 GB - + 50 Mo + 100 Mo + 250 Mo + 500 Mo + 1 Go + 5 Go - Style + Aspect Automatique (suivre le système) Clair Sombre - Une fois par jour Une fois par semaine Une fois par mois - Mise à jour disponible @string/lock_timeout_never - diff --git a/presentation/src/main/res/values-he/strings.xml b/presentation/src/main/res/values-he/strings.xml new file mode 100644 index 00000000..e5a9e06b --- /dev/null +++ b/presentation/src/main/res/values-he/strings.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/presentation/src/main/res/values-tr/strings.xml b/presentation/src/main/res/values-tr/strings.xml index be04b658..c74cf321 100644 --- a/presentation/src/main/res/values-tr/strings.xml +++ b/presentation/src/main/res/values-tr/strings.xml @@ -1,11 +1,7 @@ - - Cryptomator Şifrele - @string/app_name - Bir hata oluştu Kullanıcı adı veya şifre yanlış @@ -29,136 +25,90 @@ WebDAV şifresi çözülemedi, lütfen ayarlara yeniden ekleyin Play Hizmetleri yüklü değil Biyometrik kimlik doğrulama iptal edildi - - - Kripto - Dropbox - Google Drive - OneDrive - WebDAV Yerel depolama - - 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 - Ayarlar Ara Önceki Sonraki - Sırala - A - Z - Z - A Önce en yenisi Önce en eskisi Önce en büyüğü Önce en küçüğü - - Cryptomator\'a ekle Yeni kasa oluştur Mevcut kasayı ekle - @string/screen_file_browser_node_action_rename Kaldır Kasa oluşturmak/eklemek için burayı tıklayın Şifre başarıyla değiştirildi - Kasa - - @string/screen_vault_list_action_add_existing_vault Ana anahtar dosyasını seçin - @string/screen_vault_list_action_create_new_vault Buraya kaydet Kasa adı: %1$s - %1$s öğesini şuraya taşı %2$d öğeyi şuraya taşı - Taşı - Boş - %1$s %1$s önce değiştirildi - İle paylaş Bir varış noktası seçin Seç Paylaşacak bir şey yok - %1$s listesine ekle Klasör oluştur Metin dosyası oluştur Dosya yükle Dosyalar - Dosya başarıyla dışa aktarıldı Dosyalar başarıyla dışa aktarıldı Dışa aktarılacak bir şey yok - İndirme dizini oluşturulamadı - Paylaş Yeniden adlandır Düzenle - @string/screen_file_browser_move_button_text Dışa aktar Sil Bununla aç… - Öğeleri seç %1$d seçildi Seç… Tümünü seç Yenile - Bağlantı yok Yeniden dene - Başarıyla kaydedildi - %1$s kaydet… Metin Dosya Dosyalar - Dosya adları benzersiz olmalıdır, lütfen kopyaları yeniden adlandırın. - @string/screen_share_files_content_files Konumu kaydet Kaydet Şifreleme tamamlandı - @string/dialog_file_name_placeholder - Bulut hizmeti - @string/screen_vault_list_action_add_existing_vault - @string/screen_vault_list_action_create_new_vault - Bir yer seçin - @string/screen_file_browser_node_action_edit_text - @string/screen_vault_list_vault_action_delete Konum eklemek için + butonunu tıklayın Sunucu WebDAV uyumlu görünmüyor Özel konumlar Varsayılan depolama Kullanılabilir ek konum yok. - - @string/cloud_names_webdav - URL Kullanıcı adı Parola Bağlan @@ -166,31 +116,22 @@ URL geçersiz. Kullanıcı adı boş olamaz. Parola boş olamaz. - - @string/screen_vault_list_action_create_new_vault Kasa adı boş olamaz. Kasa adı Oluştur - Şifreyi belirle - @string/screen_webdav_settings_msg_password_must_not_be_empty Parola, yeniden yazılan parolayla eşleşmiyor. Bitti ÖNEMLİ UYARI: Parolanızı unutursanız, verilerinizi kurtarmanın herhangi bir yolu yoktur. - @string/screen_webdav_settings_password_label Yeni şifreyi tekrar yazın - Çok zayıf Güçsüz Makul Kuvvetli Çok güçlü - - @string/snack_bar_action_title_settings - Genel Kaydetme konumları Biyometrik kimlik doğrulama @@ -201,93 +142,60 @@ Arama Canlı arama Glob kalıbı kullanarak ara - Otomatik Kilitleme Kilitleme zamanı Ekran devre dışı bırakıldığında - Otomatik Fotoğraf Yükleme Yükleme için kasa seçin Etkinleştir Yalnızca WIFI kullanarak yükle - Otomatik yükleme… - - @string/screen_webdav_settings_done_button_text Cryptomator web sitesi Bizi Twitter\'da takip edin Bizi Facebook\'ta beğenin - https://cryptomator.org - https://facebook.com/Cryptomator - https://twitter.com/Cryptomator - Yasal Lisanslar Lisans şartları - Destek Yardım isteyin - https://cryptomator.org/contact/ Hata ayıklama modu Günlük dosyası gönder Gönderim başarısız oldu Güvenlik ipuçları - https://docs.cryptomator.org/en/1.5/security/best-practices/ - Sürüm - Düzenlerken kasa kilidi açık - Gelişmiş Ayarlar Arka planda kilit açma - - @string/screen_settings_cloud_settings_label WebDAV bağlantıları Yerel depolama konumları Giriş Oturumunu kapat - - @string/screen_settings_licenses_label - %1$s kimliği doğrulanamadı. - \'%1$s\' ulaşılamaz Cryptomator bu klasöre erişilemediğini tespit etti. Dizin dosyasını bulut sağlayıcınız aracılığıyla boş olmayan önceki bir sürüme geri yüklemeyi deneyin. Söz konusu dosya:\n%1$s\n\nBu işe yaramazsa, kasanızı sorunlar için kontrol etmek ve muhtemelen verilerinizi geri yüklemek için Sanitizer\'ı kullanabilirsiniz. Sanitizer Hakkında Daha Fazla Bilgi - - İptal - - @string/screen_file_browser_action_create_folder - @string/screen_enter_vault_name_button_text - - @string/screen_webdav_settings_password_label Kilidi Aç - Eski şifre Yeni şifre - @string/screen_set_password_retype_password_label Şifreyi değiştir Eski şifre boş olamaz. Yeni şifre boş olamaz. Yeni parola, parola tekrarı ile eşleşmiyor. - %1$s kasası bulunamadı Kasa yeniden adlandırılmış, taşınmış veya silinmiş olabilir. Bu kasayı listeden çıkarın ve devam etmek için tekrar ekleyin. Şimdi kaldırılsın mı? Kaldır - Dosya zaten mevcut Değiştir \'%1$s\' adlı bir dosya zaten var. - Var olanı atla Tümünü değiştir Var olanı değiştir @@ -297,44 +205,24 @@ %d dosya zaten var. Onları değiştirmek ister misin? Dosya değiştirilsin mi? Dosyalar değiştirilsin mi? - Dosyalar paylaşılamıyor Daha önce herhangi bir kasa oluşturmadınız! Önce Cryptomator uygulamasıyla yeni bir kasa oluşturun lütfen. Tamam Kasa oluştur - %1$s açılamıyor - @string/screen_file_browser_node_action_export Lütfen bu dosyayı açabilecek bir uygulama indirin veya cihazınıza kaydetmek ister misiniz? - Kasayı yeniden adlandır - @string/screen_file_browser_node_action_rename - Dosyayı yeniden adlandır Dosyayı yeniden adlandır - @string/screen_file_browser_node_action_rename - Kaydedilmemiş değişiklikleriniz mevcut Kaydetmeden çıkmak istiyor musunuz? Gözardı et - @string/screen_share_files_save_button_text - - @string/screen_file_browser_action_create_new_text_file - @string/screen_enter_vault_name_button_text - @string/dialog_button_cancel metin.txt - - @string/screen_file_browser_node_action_delete Bu kasayı kaldırmak istediğinizden emin misiniz? Bu işlem kasayı yalnızca bu listeden kaldıracak ve fiziksel olarak silmeyecektir. - Yükleniyor… - @string/dialog_button_cancel %1$d / %2$d dosyası - Dışa aktarılıyor (%1$d/%2$d) - @string/dialog_button_cancel - Lütfen bekleyin… Klasör oluşturuluyor… Metin dosyası oluşturuluyor… @@ -350,105 +238,65 @@ Şifre çözülüyor… Taşınıyor… Kilitle - Geçersiz SSL sertifikası SSL sertifikası geçersiz. Yine de güvenmek istiyor musun? Detaylar Bu bir güvenlik riski olabilir! Ne yaptığımı biliyorum. - HTTP\'nin kullanımı güvensizdir. Bunun yerine HTTPS kullanmanızı öneririz. Riskleri biliyorsanız, HTTP ile devam edebilirsiniz. HTTPS\'ye geç HTTPS kullanılsın mı? - Ekran kilidi ayarlanmadı. Kimlik bilgilerinizi güvenli bir şekilde saklamak için, Tamam ile bir kalıp veya şifre ayarlayınız. Ekran kilidi ayarlansın mı? Ekran kilidini ayarla - Sistemde temel kimlik doğrulama kurulumu yok Bu hizmeti kullanmak için en az bir parmağınızı/yüzünüzü kaydedin. - Bu modda, hassas veriler cihazınızdaki bir günlük dosyasına (örn. Dosya adları ve yolları) yazılabilir. Şifreler, tanımlama vb. bilgiler hariç tutulmuştur.\n\nHata ayıklama modunu mümkün olan en kısa sürede devre dışı bırakmayı unutmayın. Dikkat Etkinleştir - @string/dialog_button_cancel - 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. Dikkat Devre dışı bırak - @string/dialog_button_cancel - 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 - 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. - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel - - @string/screen_file_browser_node_action_delete - @string/dialog_button_cancel %1$d öğe silinsin mi? Bu öğeleri silmek istediğinizden emin misiniz? Bu dosyayı silmek istediğinizden emin misiniz? Klasördeki tüm içerikler silinecek! Bu klasörü silmek istediğinizden emin misiniz? - Biyometrik kimlik doğrulama özelliği devre dışı bırakıldı Anahtar geçersiz olduğu için biyometrik kimlik doğrulama özelliği devre dışı bırakıldı. Yeniden etkinleştirmek için Cryptomator ayarlarını açın. - @string/dialog_unable_to_share_positive_button - Geçerli bir lisans sağlayın Cryptomator\'u Google Play Store kullanmadan yüklediğinizi tespit ettik. https://cryptomator.org/android/ adresinden satın alınabilecek geçerli bir lisans edinin lütfen. Sağlanan lisans geçerli değil. Doğru girdiğinizden emin olun. Lisans verilmemiştir. Lütfen geçerli bir lisans girin. - @string/dialog_unable_to_share_positive_button Çıkış - Lisans onayı Geçerli lisansınızı sağladığınız için teşekkür ederiz %1$s. - @string/dialog_unable_to_share_positive_button - Güncelleme uygun Cryptomator\'ı en son sürüme güncellemek için Tamam\'a dokunun lütfen. Uygulamayı arka planda indireceğiz ve sizden yüklemenizi isteyeceğiz. Şimdi güncelle İndirme sitesine git Sonra - Çalışmayı indir Cryptomator\'ın son sürümünü indir - Klasör sembolik bir bağlantıdır Bu sembolik bağlantıya gidemezsin Geri - Dizinin içeriği yüklenemiyor \'%1$s\' bulut klasörünün bir dizin dosyası yok. Klasör başka bir cihazda oluşturulmuş ve henüz buluta tam olarak senkronize edilmemiş olabilir. Lütfen aşağıdaki dosyanın mevcut olup olmadığını kontrol edin:\n%2$s - @string/dialog_sym_link_back_button - Beta sürümü Bu, kasa formatı 7 desteğini tanıtan bir beta sürümüdür. Lütfen test için önemli kasanızı kullanmadığınızdan veya iyi bir yedekleme stratejisine sahip olmadığınızdan emin olun. - Cryptomator\'un yerel kasaları kullanmak için depolama erişimine ihtiyacı var Cryptomator\'un otomatik fotoğraf yüklemesi için depolama erişimine ihtiyacı var - - Android Error Report - Summary - Insert a short description of what you tried to do or mention your support ticket if you already created one. - Device Info - - Sıfır KB bayt KB - MB - GB - TB - sn sn @@ -464,54 +312,38 @@ ay yıl yıl - Biyometrik giriş Biyometrik kimlik bilgilerinizi kullanarak giriş yapın Kasa şifresini kullan - Dosyaları otomatik olarak yükleyemiyor - Kasaların Kilidi Açıldı: %1$d %1$s içinde otomatik kilitlenecek Tümünü kilitle - Yüklemeyi iptal et Otomatik fotoğraf yükleme çalışıyor %1d/%2d yükleniyor - Otomatik fotoğraf yükleme tamamlandı Kasaya %1$d görüntü yüklendi - Otomatik fotoğraf yükleme başarısız oldu Yükleme sırasında genel hata oluştu. Yükleme için seçilen klasör artık mevcut değil! Ayarlara gidin ve yeni bir tane seçin Kasa yükleme sırasında kilitlendi, devam etmek için kasayı yeniden açın lütfen - - @string/dialog_button_cancel Yazılabilir dosyayı aç Düzenleme tamamlanana kadar, uygulamalar kasası kilidi açık kalır - En son sürüm yüklendi - Önbellek - @string/screen_settings_section_auto_photo_upload_toggle Toplam önbellek boyutu Önbelleği temizle Değişiklikler, uygulama yeniden başlatıldığında uygulanacak - Kayıtlı - %1$s - Kontrol aralığını güncelle Güncellemeleri kontrol et Son çalıştırma %1$s @string/lock_timeout_never Teknik nedenlerle güncelleme kontrolü yapılamıyorsa, güncellemeler, https://cryptomator.org/android/ web sitesinden manuel olarak indirilebilir ve yüklenebilir. - Bulut başına önbellek boyutu - Anında 1 dakika @@ -519,25 +351,15 @@ 5 dakika 10 dakika Asla - - 50 MB - 100 MB - 250 MB - 500 MB - 1 GB - 5 GB - Görünüm modu Otomatik Aydınlık Karanlık - Günde bir Haftada bir Ayda bir @string/lock_timeout_never - From 16d8e937a69bb1ef1e795072876e678073ccc35a Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Tue, 26 Jan 2021 09:14:02 +0100 Subject: [PATCH 31/32] Bump version to 1.5.11-beta2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ed4312fa..557a76bc 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ allprojects { ext { androidApplicationId = 'org.cryptomator' androidVersionCode = getVersionCode() - androidVersionName = '1.5.11-beta1' + androidVersionName = '1.5.11-beta2' } repositories { mavenCentral() From 2051928dc481f47b5bd5f5ce81f4ca0670d2276c Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Mon, 8 Feb 2021 15:35:08 +0100 Subject: [PATCH 32/32] Bump version to 1.5.11 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 557a76bc..10bcf17f 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ allprojects { ext { androidApplicationId = 'org.cryptomator' androidVersionCode = getVersionCode() - androidVersionName = '1.5.11-beta2' + androidVersionName = '1.5.11' } repositories { mavenCentral()