Reformat code using new Kotlin formatting rule
This commit is contained in:
parent
bb07076ba8
commit
5c024dbda9
@ -88,7 +88,8 @@ public class CryptoCloudFactory {
|
||||
case MASTERKEY_SCHEME: {
|
||||
return new MasterkeyCryptoCloudProvider(cloudContentRepository, cryptoCloudContentRepositoryFactory, secureRandom);
|
||||
}
|
||||
default: throw new IllegalStateException(String.format("Provider with scheme %s not supported", unverifiedVaultConfigOptional.get().getKeyId().getScheme()));
|
||||
default:
|
||||
throw new IllegalStateException(String.format("Provider with scheme %s not supported", unverifiedVaultConfigOptional.get().getKeyId().getScheme()));
|
||||
}
|
||||
} else {
|
||||
return new MasterkeyCryptoCloudProvider(cloudContentRepository, cryptoCloudContentRepositoryFactory, secureRandom);
|
||||
|
@ -162,7 +162,7 @@ public class MasterkeyCryptoCloudProvider implements CryptoCloudProvider {
|
||||
|
||||
private CloudFile masterkeyFile(CloudFolder vaultLocation, UnverifiedVaultConfig unverifiedVaultConfig) throws BackendException {
|
||||
String path = unverifiedVaultConfig.getKeyId().getSchemeSpecificPart();
|
||||
if(!path.equals(MASTERKEY_FILE_NAME)) {
|
||||
if (!path.equals(MASTERKEY_FILE_NAME)) {
|
||||
throw new UnsupportedMasterkeyLocationException(unverifiedVaultConfig);
|
||||
}
|
||||
return cloudContentRepository.file(vaultLocation, path);
|
||||
|
@ -28,13 +28,13 @@ class VaultConfig private constructor(builder: VaultConfigBuilder) {
|
||||
|
||||
fun toToken(rawKey: ByteArray): String {
|
||||
return Jwts.builder()
|
||||
.setHeaderParam(JSON_KEY_ID, keyId.toASCIIString()) //
|
||||
.setId(id) //
|
||||
.claim(JSON_KEY_VAULTFORMAT, vaultFormat) //
|
||||
.claim(JSON_KEY_CIPHERCONFIG, cipherCombo.name) //
|
||||
.claim(JSON_KEY_SHORTENING_THRESHOLD, shorteningThreshold) //
|
||||
.signWith(Keys.hmacShaKeyFor(rawKey)) //
|
||||
.compact()
|
||||
.setHeaderParam(JSON_KEY_ID, keyId.toASCIIString()) //
|
||||
.setId(id) //
|
||||
.claim(JSON_KEY_VAULTFORMAT, vaultFormat) //
|
||||
.claim(JSON_KEY_CIPHERCONFIG, cipherCombo.name) //
|
||||
.claim(JSON_KEY_SHORTENING_THRESHOLD, shorteningThreshold) //
|
||||
.signWith(Keys.hmacShaKeyFor(rawKey)) //
|
||||
.compact()
|
||||
}
|
||||
|
||||
class VaultConfigBuilder {
|
||||
@ -101,18 +101,18 @@ class VaultConfig private constructor(builder: VaultConfigBuilder) {
|
||||
fun verify(rawKey: ByteArray, unverifiedVaultConfig: UnverifiedVaultConfig): VaultConfig {
|
||||
return try {
|
||||
val parser = Jwts //
|
||||
.parserBuilder() //
|
||||
.setSigningKey(rawKey) //
|
||||
.require(JSON_KEY_VAULTFORMAT, unverifiedVaultConfig.vaultFormat) //
|
||||
.build() //
|
||||
.parseClaimsJws(unverifiedVaultConfig.jwt)
|
||||
.parserBuilder() //
|
||||
.setSigningKey(rawKey) //
|
||||
.require(JSON_KEY_VAULTFORMAT, unverifiedVaultConfig.vaultFormat) //
|
||||
.build() //
|
||||
.parseClaimsJws(unverifiedVaultConfig.jwt)
|
||||
|
||||
val vaultConfigBuilder = createVaultConfig() //
|
||||
.keyId(unverifiedVaultConfig.keyId)
|
||||
.id(parser.header[JSON_KEY_ID] as String) //
|
||||
.cipherCombo(VaultCipherCombo.valueOf(parser.body.get(JSON_KEY_CIPHERCONFIG, String::class.java))) //
|
||||
.vaultFormat(unverifiedVaultConfig.vaultFormat) //
|
||||
.shorteningThreshold(parser.body[JSON_KEY_SHORTENING_THRESHOLD] as Int)
|
||||
.keyId(unverifiedVaultConfig.keyId)
|
||||
.id(parser.header[JSON_KEY_ID] as String) //
|
||||
.cipherCombo(VaultCipherCombo.valueOf(parser.body.get(JSON_KEY_CIPHERCONFIG, String::class.java))) //
|
||||
.vaultFormat(unverifiedVaultConfig.vaultFormat) //
|
||||
.shorteningThreshold(parser.body[JSON_KEY_SHORTENING_THRESHOLD] as Int)
|
||||
|
||||
VaultConfig(vaultConfigBuilder)
|
||||
} catch (e: Exception) {
|
||||
|
@ -33,6 +33,30 @@ class S3ClientFactory {
|
||||
return new HttpLoggingInterceptor(message -> Timber.tag("OkHttp").d(message), context);
|
||||
}
|
||||
|
||||
private static Interceptor provideOfflineCacheInterceptor(final Context context) {
|
||||
return chain -> {
|
||||
Request request = chain.request();
|
||||
|
||||
if (isNetworkAvailable(context)) {
|
||||
final CacheControl cacheControl = new CacheControl.Builder() //
|
||||
.maxAge(0, TimeUnit.DAYS) //
|
||||
.build();
|
||||
|
||||
request = request.newBuilder() //
|
||||
.cacheControl(cacheControl) //
|
||||
.build();
|
||||
}
|
||||
|
||||
return chain.proceed(request);
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isNetworkAvailable(final Context context) {
|
||||
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
|
||||
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
|
||||
}
|
||||
|
||||
public MinioClient getClient(S3Cloud cloud, Context context) {
|
||||
if (apiClient == null) {
|
||||
apiClient = createApiClient(cloud, context);
|
||||
@ -66,30 +90,6 @@ class S3ClientFactory {
|
||||
.build();
|
||||
}
|
||||
|
||||
private static Interceptor provideOfflineCacheInterceptor(final Context context) {
|
||||
return chain -> {
|
||||
Request request = chain.request();
|
||||
|
||||
if (isNetworkAvailable(context)) {
|
||||
final CacheControl cacheControl = new CacheControl.Builder() //
|
||||
.maxAge(0, TimeUnit.DAYS) //
|
||||
.build();
|
||||
|
||||
request = request.newBuilder() //
|
||||
.cacheControl(cacheControl) //
|
||||
.build();
|
||||
}
|
||||
|
||||
return chain.proceed(request);
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isNetworkAvailable(final Context context) {
|
||||
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
|
||||
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
|
||||
}
|
||||
|
||||
private String decrypt(String password, Context context) {
|
||||
return CredentialCryptor //
|
||||
.getInstance(context) //
|
||||
|
@ -1,14 +1,7 @@
|
||||
package org.cryptomator.data.cloud.s3;
|
||||
|
||||
public enum S3CloudApiErrorCodes {
|
||||
ACCESS_DENIED("AccessDenied"),
|
||||
ACCOUNT_PROBLEM("AccountProblem"),
|
||||
INTERNAL_ERROR("InternalError"),
|
||||
INVALID_ACCESS_KEY_ID("InvalidAccessKeyId"),
|
||||
INVALID_BUCKET_NAME("InvalidBucketName"),
|
||||
INVALID_OBJECT_STATE("InvalidObjectState"),
|
||||
NO_SUCH_BUCKET("NoSuchBucket"),
|
||||
NO_SUCH_KEY("NoSuchKey");
|
||||
ACCESS_DENIED("AccessDenied"), ACCOUNT_PROBLEM("AccountProblem"), INTERNAL_ERROR("InternalError"), INVALID_ACCESS_KEY_ID("InvalidAccessKeyId"), INVALID_BUCKET_NAME("InvalidBucketName"), INVALID_OBJECT_STATE("InvalidObjectState"), NO_SUCH_BUCKET("NoSuchBucket"), NO_SUCH_KEY("NoSuchKey");
|
||||
|
||||
private final String value;
|
||||
|
||||
|
@ -3,9 +3,7 @@ package org.cryptomator.data.cloud.s3;
|
||||
public class S3CloudApiExceptions {
|
||||
|
||||
public static boolean isAccessProblem(String errorCode) {
|
||||
return errorCode.equals(S3CloudApiErrorCodes.ACCESS_DENIED.getValue())
|
||||
|| errorCode.equals(S3CloudApiErrorCodes.ACCOUNT_PROBLEM.getValue())
|
||||
|| errorCode.equals(S3CloudApiErrorCodes.INVALID_ACCESS_KEY_ID.getValue());
|
||||
return errorCode.equals(S3CloudApiErrorCodes.ACCESS_DENIED.getValue()) || errorCode.equals(S3CloudApiErrorCodes.ACCOUNT_PROBLEM.getValue()) || errorCode.equals(S3CloudApiErrorCodes.INVALID_ACCESS_KEY_ID.getValue());
|
||||
}
|
||||
|
||||
public static boolean isNoSuchBucketException(String errorCode) {
|
||||
|
@ -63,7 +63,7 @@ class S3CloudContentRepository extends InterceptingCloudContentRepository<S3Clou
|
||||
if (S3CloudApiExceptions.isAccessProblem(errorCode)) {
|
||||
throw new WrongCredentialsException(cloud);
|
||||
}
|
||||
} else if(e instanceof ForbiddenException) {
|
||||
} else if (e instanceof ForbiddenException) {
|
||||
throw new WrongCredentialsException(cloud);
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ class S3Impl {
|
||||
public boolean exists(S3Node node) throws BackendException {
|
||||
String key = node.getKey();
|
||||
try {
|
||||
if(!(node instanceof RootS3Folder)) {
|
||||
if (!(node instanceof RootS3Folder)) {
|
||||
client().statObject(StatObjectArgs.builder().bucket(cloud.s3Bucket()).object(key).build());
|
||||
return true;
|
||||
} else {
|
||||
@ -256,7 +256,7 @@ class S3Impl {
|
||||
|
||||
Date lastModified = objectWriteResponse.headers().getDate("Last-Modified");
|
||||
|
||||
if(lastModified == null) {
|
||||
if (lastModified == null) {
|
||||
StatObjectResponse statObjectResponse = client().statObject(StatObjectArgs //
|
||||
.builder() //
|
||||
.bucket(cloud.s3Bucket()) //
|
||||
|
@ -14,19 +14,19 @@ internal class Upgrade2To3 @Inject constructor(private val context: Context) : D
|
||||
db.beginTransaction()
|
||||
try {
|
||||
Sql.query("CLOUD_ENTITY")
|
||||
.columns(listOf("ACCESS_TOKEN"))
|
||||
.where("TYPE", Sql.eq("DROPBOX"))
|
||||
.executeOn(db).use {
|
||||
if (it.moveToFirst()) {
|
||||
Sql.update("CLOUD_ENTITY")
|
||||
.set("ACCESS_TOKEN", Sql.toString(encrypt(it.getString(it.getColumnIndex("ACCESS_TOKEN")))))
|
||||
.where("TYPE", Sql.eq("DROPBOX"));
|
||||
}
|
||||
.columns(listOf("ACCESS_TOKEN"))
|
||||
.where("TYPE", Sql.eq("DROPBOX"))
|
||||
.executeOn(db).use {
|
||||
if (it.moveToFirst()) {
|
||||
Sql.update("CLOUD_ENTITY")
|
||||
.set("ACCESS_TOKEN", Sql.toString(encrypt(it.getString(it.getColumnIndex("ACCESS_TOKEN")))))
|
||||
.where("TYPE", Sql.eq("DROPBOX"));
|
||||
}
|
||||
}
|
||||
|
||||
Sql.update("CLOUD_ENTITY")
|
||||
.set("ACCESS_TOKEN", Sql.toString(encrypt(onedriveToken())))
|
||||
.where("TYPE", Sql.eq("ONEDRIVE"));
|
||||
.set("ACCESS_TOKEN", Sql.toString(encrypt(onedriveToken())))
|
||||
.where("TYPE", Sql.eq("ONEDRIVE"));
|
||||
|
||||
db.setTransactionSuccessful()
|
||||
} finally {
|
||||
@ -36,8 +36,8 @@ internal class Upgrade2To3 @Inject constructor(private val context: Context) : D
|
||||
|
||||
private fun encrypt(token: String?): String? {
|
||||
return if (token == null) null else CredentialCryptor //
|
||||
.getInstance(context) //
|
||||
.encrypt(token)
|
||||
.getInstance(context) //
|
||||
.encrypt(token)
|
||||
}
|
||||
|
||||
private fun onedriveToken(): String? {
|
||||
|
@ -25,42 +25,42 @@ internal class Upgrade3To4 @Inject constructor() : DatabaseUpgrade(3, 4) {
|
||||
private fun addPositionToVaultSchema(db: Database) {
|
||||
Sql.alterTable("VAULT_ENTITY").renameTo("VAULT_ENTITY_OLD").executeOn(db)
|
||||
Sql.createTable("VAULT_ENTITY") //
|
||||
.id() //
|
||||
.optionalInt("FOLDER_CLOUD_ID") //
|
||||
.optionalText("FOLDER_PATH") //
|
||||
.optionalText("FOLDER_NAME") //
|
||||
.requiredText("CLOUD_TYPE") //
|
||||
.optionalText("PASSWORD") //
|
||||
.optionalInt("POSITION") //
|
||||
.foreignKey("FOLDER_CLOUD_ID", "CLOUD_ENTITY", ForeignKeyBehaviour.ON_DELETE_SET_NULL) //
|
||||
.executeOn(db)
|
||||
.id() //
|
||||
.optionalInt("FOLDER_CLOUD_ID") //
|
||||
.optionalText("FOLDER_PATH") //
|
||||
.optionalText("FOLDER_NAME") //
|
||||
.requiredText("CLOUD_TYPE") //
|
||||
.optionalText("PASSWORD") //
|
||||
.optionalInt("POSITION") //
|
||||
.foreignKey("FOLDER_CLOUD_ID", "CLOUD_ENTITY", ForeignKeyBehaviour.ON_DELETE_SET_NULL) //
|
||||
.executeOn(db)
|
||||
|
||||
Sql.insertInto("VAULT_ENTITY") //
|
||||
.select("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "PASSWORD", "CLOUD_ENTITY.TYPE") //
|
||||
.columns("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "PASSWORD", "CLOUD_TYPE") //
|
||||
.from("VAULT_ENTITY_OLD") //
|
||||
.join("CLOUD_ENTITY", "VAULT_ENTITY_OLD.FOLDER_CLOUD_ID") //
|
||||
.executeOn(db)
|
||||
.select("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "PASSWORD", "CLOUD_ENTITY.TYPE") //
|
||||
.columns("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "PASSWORD", "CLOUD_TYPE") //
|
||||
.from("VAULT_ENTITY_OLD") //
|
||||
.join("CLOUD_ENTITY", "VAULT_ENTITY_OLD.FOLDER_CLOUD_ID") //
|
||||
.executeOn(db)
|
||||
|
||||
Sql.dropIndex("IDX_VAULT_ENTITY_FOLDER_PATH_FOLDER_CLOUD_ID").executeOn(db)
|
||||
|
||||
Sql.createUniqueIndex("IDX_VAULT_ENTITY_FOLDER_PATH_FOLDER_CLOUD_ID") //
|
||||
.on("VAULT_ENTITY") //
|
||||
.asc("FOLDER_PATH") //
|
||||
.asc("FOLDER_CLOUD_ID") //
|
||||
.executeOn(db)
|
||||
.on("VAULT_ENTITY") //
|
||||
.asc("FOLDER_PATH") //
|
||||
.asc("FOLDER_CLOUD_ID") //
|
||||
.executeOn(db)
|
||||
|
||||
Sql.dropTable("VAULT_ENTITY_OLD").executeOn(db)
|
||||
}
|
||||
|
||||
private fun initVaultPositionUsingCurrentSortOrder(db: Database) {
|
||||
CloudEntityDao(DaoConfig(db, VaultEntityDao::class.java)) //
|
||||
.loadAll() //
|
||||
.map {
|
||||
Sql.update("VAULT_ENTITY") //
|
||||
.where("_id", Sql.eq(it.id)) //
|
||||
.set("POSITION", Sql.toInteger(it.id - 1)) //
|
||||
.executeOn(db)
|
||||
}
|
||||
.loadAll() //
|
||||
.map {
|
||||
Sql.update("VAULT_ENTITY") //
|
||||
.where("_id", Sql.eq(it.id)) //
|
||||
.set("POSITION", Sql.toInteger(it.id - 1)) //
|
||||
.executeOn(db)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,19 +21,19 @@ internal class Upgrade4To5 @Inject constructor() : DatabaseUpgrade(4, 5) {
|
||||
Sql.alterTable("CLOUD_ENTITY").renameTo("CLOUD_ENTITY_OLD").executeOn(db)
|
||||
|
||||
Sql.createTable("CLOUD_ENTITY") //
|
||||
.id() //
|
||||
.requiredText("TYPE") //
|
||||
.optionalText("ACCESS_TOKEN") //
|
||||
.optionalText("URL") //
|
||||
.optionalText("USERNAME") //
|
||||
.optionalText("WEBDAV_CERTIFICATE") //
|
||||
.executeOn(db);
|
||||
.id() //
|
||||
.requiredText("TYPE") //
|
||||
.optionalText("ACCESS_TOKEN") //
|
||||
.optionalText("URL") //
|
||||
.optionalText("USERNAME") //
|
||||
.optionalText("WEBDAV_CERTIFICATE") //
|
||||
.executeOn(db);
|
||||
|
||||
Sql.insertInto("CLOUD_ENTITY") //
|
||||
.select("_id", "TYPE", "ACCESS_TOKEN", "WEBDAV_URL", "USERNAME", "WEBDAV_CERTIFICATE") //
|
||||
.columns("_id", "TYPE", "ACCESS_TOKEN", "URL", "USERNAME", "WEBDAV_CERTIFICATE") //
|
||||
.from("CLOUD_ENTITY_OLD") //
|
||||
.executeOn(db)
|
||||
.select("_id", "TYPE", "ACCESS_TOKEN", "WEBDAV_URL", "USERNAME", "WEBDAV_CERTIFICATE") //
|
||||
.columns("_id", "TYPE", "ACCESS_TOKEN", "URL", "USERNAME", "WEBDAV_CERTIFICATE") //
|
||||
.from("CLOUD_ENTITY_OLD") //
|
||||
.executeOn(db)
|
||||
|
||||
recreateVaultEntity(db)
|
||||
|
||||
@ -43,30 +43,30 @@ internal class Upgrade4To5 @Inject constructor() : DatabaseUpgrade(4, 5) {
|
||||
private fun recreateVaultEntity(db: Database) {
|
||||
Sql.alterTable("VAULT_ENTITY").renameTo("VAULT_ENTITY_OLD").executeOn(db)
|
||||
Sql.createTable("VAULT_ENTITY") //
|
||||
.id() //
|
||||
.optionalInt("FOLDER_CLOUD_ID") //
|
||||
.optionalText("FOLDER_PATH") //
|
||||
.optionalText("FOLDER_NAME") //
|
||||
.requiredText("CLOUD_TYPE") //
|
||||
.optionalText("PASSWORD") //
|
||||
.optionalInt("POSITION") //
|
||||
.foreignKey("FOLDER_CLOUD_ID", "CLOUD_ENTITY", Sql.SqlCreateTableBuilder.ForeignKeyBehaviour.ON_DELETE_SET_NULL) //
|
||||
.executeOn(db)
|
||||
.id() //
|
||||
.optionalInt("FOLDER_CLOUD_ID") //
|
||||
.optionalText("FOLDER_PATH") //
|
||||
.optionalText("FOLDER_NAME") //
|
||||
.requiredText("CLOUD_TYPE") //
|
||||
.optionalText("PASSWORD") //
|
||||
.optionalInt("POSITION") //
|
||||
.foreignKey("FOLDER_CLOUD_ID", "CLOUD_ENTITY", Sql.SqlCreateTableBuilder.ForeignKeyBehaviour.ON_DELETE_SET_NULL) //
|
||||
.executeOn(db)
|
||||
|
||||
Sql.insertInto("VAULT_ENTITY") //
|
||||
.select("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "PASSWORD", "POSITION", "CLOUD_ENTITY.TYPE") //
|
||||
.columns("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "PASSWORD", "POSITION", "CLOUD_TYPE") //
|
||||
.from("VAULT_ENTITY_OLD") //
|
||||
.join("CLOUD_ENTITY", "VAULT_ENTITY_OLD.FOLDER_CLOUD_ID") //
|
||||
.executeOn(db)
|
||||
.select("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "PASSWORD", "POSITION", "CLOUD_ENTITY.TYPE") //
|
||||
.columns("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "PASSWORD", "POSITION", "CLOUD_TYPE") //
|
||||
.from("VAULT_ENTITY_OLD") //
|
||||
.join("CLOUD_ENTITY", "VAULT_ENTITY_OLD.FOLDER_CLOUD_ID") //
|
||||
.executeOn(db)
|
||||
|
||||
Sql.dropIndex("IDX_VAULT_ENTITY_FOLDER_PATH_FOLDER_CLOUD_ID").executeOn(db)
|
||||
|
||||
Sql.createUniqueIndex("IDX_VAULT_ENTITY_FOLDER_PATH_FOLDER_CLOUD_ID") //
|
||||
.on("VAULT_ENTITY") //
|
||||
.asc("FOLDER_PATH") //
|
||||
.asc("FOLDER_CLOUD_ID") //
|
||||
.executeOn(db)
|
||||
.on("VAULT_ENTITY") //
|
||||
.asc("FOLDER_PATH") //
|
||||
.asc("FOLDER_CLOUD_ID") //
|
||||
.executeOn(db)
|
||||
|
||||
Sql.dropTable("VAULT_ENTITY_OLD").executeOn(db)
|
||||
}
|
||||
|
@ -21,22 +21,22 @@ internal class Upgrade5To6 @Inject constructor() : DatabaseUpgrade(5, 6) {
|
||||
Sql.alterTable("CLOUD_ENTITY").renameTo("CLOUD_ENTITY_OLD").executeOn(db)
|
||||
|
||||
Sql.createTable("CLOUD_ENTITY") //
|
||||
.id() //
|
||||
.requiredText("TYPE") //
|
||||
.optionalText("ACCESS_TOKEN") //
|
||||
.optionalText("URL") //
|
||||
.optionalText("USERNAME") //
|
||||
.optionalText("WEBDAV_CERTIFICATE") //
|
||||
.optionalText("S3_BUCKET") //
|
||||
.optionalText("S3_REGION") //
|
||||
.optionalText("S3_SECRET_KEY") //
|
||||
.executeOn(db);
|
||||
.id() //
|
||||
.requiredText("TYPE") //
|
||||
.optionalText("ACCESS_TOKEN") //
|
||||
.optionalText("URL") //
|
||||
.optionalText("USERNAME") //
|
||||
.optionalText("WEBDAV_CERTIFICATE") //
|
||||
.optionalText("S3_BUCKET") //
|
||||
.optionalText("S3_REGION") //
|
||||
.optionalText("S3_SECRET_KEY") //
|
||||
.executeOn(db);
|
||||
|
||||
Sql.insertInto("CLOUD_ENTITY") //
|
||||
.select("_id", "TYPE", "ACCESS_TOKEN", "URL", "USERNAME", "WEBDAV_CERTIFICATE") //
|
||||
.columns("_id", "TYPE", "ACCESS_TOKEN", "URL", "USERNAME", "WEBDAV_CERTIFICATE") //
|
||||
.from("CLOUD_ENTITY_OLD") //
|
||||
.executeOn(db)
|
||||
.select("_id", "TYPE", "ACCESS_TOKEN", "URL", "USERNAME", "WEBDAV_CERTIFICATE") //
|
||||
.columns("_id", "TYPE", "ACCESS_TOKEN", "URL", "USERNAME", "WEBDAV_CERTIFICATE") //
|
||||
.from("CLOUD_ENTITY_OLD") //
|
||||
.executeOn(db)
|
||||
|
||||
recreateVaultEntity(db)
|
||||
|
||||
@ -46,30 +46,30 @@ internal class Upgrade5To6 @Inject constructor() : DatabaseUpgrade(5, 6) {
|
||||
private fun recreateVaultEntity(db: Database) {
|
||||
Sql.alterTable("VAULT_ENTITY").renameTo("VAULT_ENTITY_OLD").executeOn(db)
|
||||
Sql.createTable("VAULT_ENTITY") //
|
||||
.id() //
|
||||
.optionalInt("FOLDER_CLOUD_ID") //
|
||||
.optionalText("FOLDER_PATH") //
|
||||
.optionalText("FOLDER_NAME") //
|
||||
.requiredText("CLOUD_TYPE") //
|
||||
.optionalText("PASSWORD") //
|
||||
.optionalInt("POSITION") //
|
||||
.foreignKey("FOLDER_CLOUD_ID", "CLOUD_ENTITY", Sql.SqlCreateTableBuilder.ForeignKeyBehaviour.ON_DELETE_SET_NULL) //
|
||||
.executeOn(db)
|
||||
.id() //
|
||||
.optionalInt("FOLDER_CLOUD_ID") //
|
||||
.optionalText("FOLDER_PATH") //
|
||||
.optionalText("FOLDER_NAME") //
|
||||
.requiredText("CLOUD_TYPE") //
|
||||
.optionalText("PASSWORD") //
|
||||
.optionalInt("POSITION") //
|
||||
.foreignKey("FOLDER_CLOUD_ID", "CLOUD_ENTITY", Sql.SqlCreateTableBuilder.ForeignKeyBehaviour.ON_DELETE_SET_NULL) //
|
||||
.executeOn(db)
|
||||
|
||||
Sql.insertInto("VAULT_ENTITY") //
|
||||
.select("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "PASSWORD", "POSITION", "CLOUD_ENTITY.TYPE") //
|
||||
.columns("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "PASSWORD", "POSITION", "CLOUD_TYPE") //
|
||||
.from("VAULT_ENTITY_OLD") //
|
||||
.join("CLOUD_ENTITY", "VAULT_ENTITY_OLD.FOLDER_CLOUD_ID") //
|
||||
.executeOn(db)
|
||||
.select("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "PASSWORD", "POSITION", "CLOUD_ENTITY.TYPE") //
|
||||
.columns("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "PASSWORD", "POSITION", "CLOUD_TYPE") //
|
||||
.from("VAULT_ENTITY_OLD") //
|
||||
.join("CLOUD_ENTITY", "VAULT_ENTITY_OLD.FOLDER_CLOUD_ID") //
|
||||
.executeOn(db)
|
||||
|
||||
Sql.dropIndex("IDX_VAULT_ENTITY_FOLDER_PATH_FOLDER_CLOUD_ID").executeOn(db)
|
||||
|
||||
Sql.createUniqueIndex("IDX_VAULT_ENTITY_FOLDER_PATH_FOLDER_CLOUD_ID") //
|
||||
.on("VAULT_ENTITY") //
|
||||
.asc("FOLDER_PATH") //
|
||||
.asc("FOLDER_CLOUD_ID") //
|
||||
.executeOn(db)
|
||||
.on("VAULT_ENTITY") //
|
||||
.asc("FOLDER_PATH") //
|
||||
.asc("FOLDER_CLOUD_ID") //
|
||||
.executeOn(db)
|
||||
|
||||
Sql.dropTable("VAULT_ENTITY_OLD").executeOn(db)
|
||||
}
|
||||
|
@ -21,20 +21,20 @@ internal class Upgrade6To7 @Inject constructor() : DatabaseUpgrade(6, 7) {
|
||||
Sql.alterTable("UPDATE_CHECK_ENTITY").renameTo("UPDATE_CHECK_ENTITY_OLD").executeOn(db)
|
||||
|
||||
Sql.createTable("UPDATE_CHECK_ENTITY") //
|
||||
.id() //
|
||||
.optionalText("LICENSE_TOKEN") //
|
||||
.optionalText("RELEASE_NOTE") //
|
||||
.optionalText("VERSION") //
|
||||
.optionalText("URL_TO_APK") //
|
||||
.optionalText("APK_SHA256") //
|
||||
.optionalText("URL_TO_RELEASE_NOTE") //
|
||||
.executeOn(db)
|
||||
.id() //
|
||||
.optionalText("LICENSE_TOKEN") //
|
||||
.optionalText("RELEASE_NOTE") //
|
||||
.optionalText("VERSION") //
|
||||
.optionalText("URL_TO_APK") //
|
||||
.optionalText("APK_SHA256") //
|
||||
.optionalText("URL_TO_RELEASE_NOTE") //
|
||||
.executeOn(db)
|
||||
|
||||
Sql.insertInto("UPDATE_CHECK_ENTITY") //
|
||||
.select("_id", "LICENSE_TOKEN", "RELEASE_NOTE", "VERSION", "URL_TO_APK", "URL_TO_RELEASE_NOTE") //
|
||||
.columns("_id", "LICENSE_TOKEN", "RELEASE_NOTE", "VERSION", "URL_TO_APK", "URL_TO_RELEASE_NOTE") //
|
||||
.from("UPDATE_CHECK_ENTITY_OLD") //
|
||||
.executeOn(db)
|
||||
.select("_id", "LICENSE_TOKEN", "RELEASE_NOTE", "VERSION", "URL_TO_APK", "URL_TO_RELEASE_NOTE") //
|
||||
.columns("_id", "LICENSE_TOKEN", "RELEASE_NOTE", "VERSION", "URL_TO_APK", "URL_TO_RELEASE_NOTE") //
|
||||
.from("UPDATE_CHECK_ENTITY_OLD") //
|
||||
.executeOn(db)
|
||||
|
||||
Sql.dropTable("UPDATE_CHECK_ENTITY_OLD").executeOn(db)
|
||||
}
|
||||
|
@ -26,8 +26,7 @@ public class UpdateCheckEntity extends DatabaseEntity {
|
||||
}
|
||||
|
||||
@Generated(hash = 67239496)
|
||||
public UpdateCheckEntity(Long id, String licenseToken, String releaseNote, String version, String urlToApk, String apkSha256,
|
||||
String urlToReleaseNote) {
|
||||
public UpdateCheckEntity(Long id, String licenseToken, String releaseNote, String version, String urlToApk, String apkSha256, String urlToReleaseNote) {
|
||||
this.id = id;
|
||||
this.licenseToken = licenseToken;
|
||||
this.releaseNote = releaseNote;
|
||||
|
@ -182,7 +182,9 @@ public class VaultEntity extends DatabaseEntity {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
/** called by internal mechanisms, do not call yourself. */
|
||||
/**
|
||||
* called by internal mechanisms, do not call yourself.
|
||||
*/
|
||||
@Generated(hash = 674742652)
|
||||
public void __setDaoSession(DaoSession daoSession) {
|
||||
this.daoSession = daoSession;
|
||||
|
@ -120,7 +120,7 @@ public class UpdateCheckRepositoryImpl implements UpdateCheckRepository {
|
||||
|
||||
String apkSha256 = calculateSha256(file);
|
||||
|
||||
if(!apkSha256.equals(entity.getApkSha256())) {
|
||||
if (!apkSha256.equals(entity.getApkSha256())) {
|
||||
file.delete();
|
||||
throw new HashMismatchUpdateCheckException(String.format( //
|
||||
"Sha of calculated hash (%s) doesn't match the specified one (%s)", //
|
||||
@ -138,9 +138,9 @@ public class UpdateCheckRepositoryImpl implements UpdateCheckRepository {
|
||||
private String calculateSha256(File file) throws GeneralUpdateErrorException {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
try(DigestInputStream digestInputStream = new DigestInputStream(context.getContentResolver().openInputStream(Uri.fromFile(file)), digest)) {
|
||||
try (DigestInputStream digestInputStream = new DigestInputStream(context.getContentResolver().openInputStream(Uri.fromFile(file)), digest)) {
|
||||
byte[] buffer = new byte[8192];
|
||||
while(digestInputStream.read(buffer) > -1) {
|
||||
while (digestInputStream.read(buffer) > -1) {
|
||||
}
|
||||
}
|
||||
return new String(Hex.encodeHex(digest.digest()));
|
||||
|
@ -3,4 +3,5 @@ package org.cryptomator.domain.exception.vaultconfig;
|
||||
import org.cryptomator.domain.exception.BackendException;
|
||||
|
||||
public class VaultKeyInvalidException extends BackendException {
|
||||
|
||||
}
|
||||
|
@ -20,7 +20,8 @@ class ChangePassword {
|
||||
private final Vault vault;
|
||||
private final Optional<UnverifiedVaultConfig> unverifiedVaultConfig;
|
||||
private final String oldPassword;
|
||||
private final String newPassword;;
|
||||
private final String newPassword;
|
||||
;
|
||||
|
||||
public ChangePassword(CloudRepository cloudRepository, //
|
||||
@Parameter Vault vault, //
|
||||
|
@ -14,9 +14,8 @@ class UnlockVaultUsingMasterkey {
|
||||
|
||||
private final CloudRepository cloudRepository;
|
||||
private final VaultOrUnlockToken vaultOrUnlockToken;
|
||||
private Optional<UnverifiedVaultConfig> unverifiedVaultConfig;
|
||||
private final String password;
|
||||
|
||||
private Optional<UnverifiedVaultConfig> unverifiedVaultConfig;
|
||||
private volatile boolean cancelled;
|
||||
private final Flag cancelledFlag = new Flag() {
|
||||
@Override
|
||||
|
@ -61,21 +61,22 @@ import timber.log.Timber
|
||||
|
||||
@PerView
|
||||
class AuthenticateCloudPresenter @Inject constructor( //
|
||||
exceptionHandlers: ExceptionHandlers, //
|
||||
private val cloudModelMapper: CloudModelMapper, //
|
||||
private val addOrChangeCloudConnectionUseCase: AddOrChangeCloudConnectionUseCase, //
|
||||
private val getCloudsUseCase: GetCloudsUseCase, //
|
||||
private val getUsernameUseCase: GetUsernameUseCase, //
|
||||
private val addExistingVaultWorkflow: AddExistingVaultWorkflow, //
|
||||
private val createNewVaultWorkflow: CreateNewVaultWorkflow) : Presenter<AuthenticateCloudView>(exceptionHandlers) {
|
||||
exceptionHandlers: ExceptionHandlers, //
|
||||
private val cloudModelMapper: CloudModelMapper, //
|
||||
private val addOrChangeCloudConnectionUseCase: AddOrChangeCloudConnectionUseCase, //
|
||||
private val getCloudsUseCase: GetCloudsUseCase, //
|
||||
private val getUsernameUseCase: GetUsernameUseCase, //
|
||||
private val addExistingVaultWorkflow: AddExistingVaultWorkflow, //
|
||||
private val createNewVaultWorkflow: CreateNewVaultWorkflow
|
||||
) : Presenter<AuthenticateCloudView>(exceptionHandlers) {
|
||||
|
||||
private val strategies = arrayOf( //
|
||||
DropboxAuthStrategy(), //
|
||||
OnedriveAuthStrategy(), //
|
||||
PCloudAuthStrategy(), //
|
||||
WebDAVAuthStrategy(), //
|
||||
S3AuthStrategy(), //
|
||||
LocalStorageAuthStrategy() //
|
||||
DropboxAuthStrategy(), //
|
||||
OnedriveAuthStrategy(), //
|
||||
PCloudAuthStrategy(), //
|
||||
WebDAVAuthStrategy(), //
|
||||
S3AuthStrategy(), //
|
||||
LocalStorageAuthStrategy() //
|
||||
)
|
||||
|
||||
override fun workflows(): Iterable<Workflow<*>> {
|
||||
@ -128,17 +129,17 @@ class AuthenticateCloudPresenter @Inject constructor( //
|
||||
|
||||
private fun succeedAuthenticationWith(cloud: Cloud) {
|
||||
addOrChangeCloudConnectionUseCase //
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onSuccess(void: Void?) {
|
||||
finishWithResult(cloudModelMapper.toModel(cloud))
|
||||
}
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onSuccess(void: Void?) {
|
||||
finishWithResult(cloudModelMapper.toModel(cloud))
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
super.onError(e)
|
||||
finish()
|
||||
}
|
||||
})
|
||||
override fun onError(e: Throwable) {
|
||||
super.onError(e)
|
||||
finish()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun failAuthentication(cloudName: Int) {
|
||||
@ -180,9 +181,10 @@ class AuthenticateCloudPresenter @Inject constructor( //
|
||||
failAuthentication(cloudModel.name())
|
||||
} else {
|
||||
getUsernameAndSuceedAuthentication( //
|
||||
DropboxCloud.aCopyOf(cloudModel.toCloud() as DropboxCloud) //
|
||||
.withAccessToken(encrypt(authToken)) //
|
||||
.build())
|
||||
DropboxCloud.aCopyOf(cloudModel.toCloud() as DropboxCloud) //
|
||||
.withAccessToken(encrypt(authToken)) //
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -200,10 +202,12 @@ class AuthenticateCloudPresenter @Inject constructor( //
|
||||
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) //
|
||||
succeedAuthenticationWith(
|
||||
GoogleDriveCloud.aCopyOf(cloud.toCloud() as GoogleDriveCloud) //
|
||||
.withUsername(accountName) //
|
||||
.withAccessToken(accountName) //
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
} else {
|
||||
failAuthentication(cloud.name())
|
||||
}
|
||||
@ -245,9 +249,10 @@ class AuthenticateCloudPresenter @Inject constructor( //
|
||||
|
||||
private fun handleAuthenticationResult(cloud: CloudModel, accessToken: String) {
|
||||
getUsernameAndSuceedAuthentication( //
|
||||
OnedriveCloud.aCopyOf(cloud.toCloud() as OnedriveCloud) //
|
||||
.withAccessToken(accessToken) //
|
||||
.build())
|
||||
OnedriveCloud.aCopyOf(cloud.toCloud() as OnedriveCloud) //
|
||||
.withAccessToken(accessToken) //
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,9 +270,10 @@ class AuthenticateCloudPresenter @Inject constructor( //
|
||||
if (!authenticationStarted) {
|
||||
startAuthentication()
|
||||
Toast.makeText(
|
||||
context(),
|
||||
String.format(getString(R.string.error_authentication_failed_re_authenticate), intent.cloud().username()),
|
||||
Toast.LENGTH_LONG).show()
|
||||
context(),
|
||||
String.format(getString(R.string.error_authentication_failed_re_authenticate), intent.cloud().username()),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
@ -280,15 +286,18 @@ class AuthenticateCloudPresenter @Inject constructor( //
|
||||
private fun startAuthentication() {
|
||||
authenticationStarted = true
|
||||
val authIntent: Intent = AuthorizationActivity.createIntent(
|
||||
context(),
|
||||
AuthorizationRequest.create()
|
||||
.setType(AuthorizationRequest.Type.TOKEN)
|
||||
.setClientId(BuildConfig.PCLOUD_CLIENT_ID)
|
||||
.setForceAccessApproval(true)
|
||||
.addPermission("manageshares")
|
||||
.build())
|
||||
requestActivityResult(ActivityResultCallbacks.pCloudReAuthenticationFinished(), //
|
||||
authIntent)
|
||||
context(),
|
||||
AuthorizationRequest.create()
|
||||
.setType(AuthorizationRequest.Type.TOKEN)
|
||||
.setClientId(BuildConfig.PCLOUD_CLIENT_ID)
|
||||
.setForceAccessApproval(true)
|
||||
.addPermission("manageshares")
|
||||
.build()
|
||||
)
|
||||
requestActivityResult(
|
||||
ActivityResultCallbacks.pCloudReAuthenticationFinished(), //
|
||||
authIntent
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -300,19 +309,19 @@ class AuthenticateCloudPresenter @Inject constructor( //
|
||||
when (result) {
|
||||
AuthorizationResult.ACCESS_GRANTED -> {
|
||||
val accessToken: String = CredentialCryptor //
|
||||
.getInstance(context()) //
|
||||
.encrypt(authData.token)
|
||||
.getInstance(context()) //
|
||||
.encrypt(authData.token)
|
||||
val pCloudSkeleton: PCloud = PCloud.aPCloud() //
|
||||
.withAccessToken(accessToken)
|
||||
.withUrl(authData.apiHost)
|
||||
.build();
|
||||
.withAccessToken(accessToken)
|
||||
.withUrl(authData.apiHost)
|
||||
.build();
|
||||
getUsernameUseCase //
|
||||
.withCloud(pCloudSkeleton) //
|
||||
.run(object : DefaultResultHandler<String>() {
|
||||
override fun onSuccess(username: String?) {
|
||||
prepareForSavingPCloud(PCloud.aCopyOf(pCloudSkeleton).withUsername(username).build())
|
||||
}
|
||||
})
|
||||
.withCloud(pCloudSkeleton) //
|
||||
.run(object : DefaultResultHandler<String>() {
|
||||
override fun onSuccess(username: String?) {
|
||||
prepareForSavingPCloud(PCloud.aCopyOf(pCloudSkeleton).withUsername(username).build())
|
||||
}
|
||||
})
|
||||
}
|
||||
AuthorizationResult.ACCESS_DENIED -> {
|
||||
Timber.tag("CloudConnListPresenter").e("Account access denied")
|
||||
@ -331,20 +340,22 @@ class AuthenticateCloudPresenter @Inject constructor( //
|
||||
|
||||
fun prepareForSavingPCloud(cloud: PCloud) {
|
||||
getCloudsUseCase //
|
||||
.withCloudType(cloud.type()) //
|
||||
.run(object : DefaultResultHandler<List<Cloud>>() {
|
||||
override fun onSuccess(clouds: List<Cloud>) {
|
||||
clouds.firstOrNull {
|
||||
(it as PCloud).username() == cloud.username()
|
||||
}?.let {
|
||||
it as PCloud
|
||||
succeedAuthenticationWith(PCloud.aCopyOf(it) //
|
||||
.withUrl(cloud.url())
|
||||
.withAccessToken(cloud.accessToken())
|
||||
.build())
|
||||
} ?: succeedAuthenticationWith(cloud)
|
||||
}
|
||||
})
|
||||
.withCloudType(cloud.type()) //
|
||||
.run(object : DefaultResultHandler<List<Cloud>>() {
|
||||
override fun onSuccess(clouds: List<Cloud>) {
|
||||
clouds.firstOrNull {
|
||||
(it as PCloud).username() == cloud.username()
|
||||
}?.let {
|
||||
it as PCloud
|
||||
succeedAuthenticationWith(
|
||||
PCloud.aCopyOf(it) //
|
||||
.withUrl(cloud.url())
|
||||
.withAccessToken(cloud.accessToken())
|
||||
.build()
|
||||
)
|
||||
} ?: succeedAuthenticationWith(cloud)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private inner class WebDAVAuthStrategy : AuthStrategy {
|
||||
@ -392,11 +403,13 @@ class AuthenticateCloudPresenter @Inject constructor( //
|
||||
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)
|
||||
.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)
|
||||
@ -421,9 +434,10 @@ class AuthenticateCloudPresenter @Inject constructor( //
|
||||
if (!authenticationStarted) {
|
||||
startAuthentication(intent.cloud())
|
||||
Toast.makeText(
|
||||
context(),
|
||||
String.format(getString(R.string.error_authentication_failed), intent.cloud().username()),
|
||||
Toast.LENGTH_LONG).show()
|
||||
context(),
|
||||
String.format(getString(R.string.error_authentication_failed), intent.cloud().username()),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
@ -454,10 +468,12 @@ class AuthenticateCloudPresenter @Inject constructor( //
|
||||
|
||||
private fun startAuthentication(cloud: CloudModel) {
|
||||
authenticationStarted = true
|
||||
requestPermissions(PermissionsResultCallbacks.onLocalStorageAuthenticated(cloud), //
|
||||
R.string.permission_snackbar_auth_local_vault, //
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE, //
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
requestPermissions(
|
||||
PermissionsResultCallbacks.onLocalStorageAuthenticated(cloud), //
|
||||
R.string.permission_snackbar_auth_local_vault, //
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE, //
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -472,8 +488,8 @@ class AuthenticateCloudPresenter @Inject constructor( //
|
||||
|
||||
private fun encrypt(password: String): String {
|
||||
return CredentialCryptor //
|
||||
.getInstance(context()) //
|
||||
.encrypt(password)
|
||||
.getInstance(context()) //
|
||||
.encrypt(password)
|
||||
}
|
||||
|
||||
private inner class FailingAuthStrategy : AuthStrategy {
|
||||
|
@ -97,9 +97,10 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".ui.activity.UnlockVaultActivity"
|
||||
android:theme="@style/TransparentAlertDialogCustom"
|
||||
android:label=""/>
|
||||
<activity
|
||||
android:name=".ui.activity.UnlockVaultActivity"
|
||||
android:label=""
|
||||
android:theme="@style/TransparentAlertDialogCustom" />
|
||||
<activity android:name=".ui.activity.EmptyDirIdFileInfoActivity" />
|
||||
|
||||
<!-- Settings -->
|
||||
|
@ -51,10 +51,12 @@ class CryptomatorApp : MultiDexApplication(), HasComponent<ApplicationComponent>
|
||||
}
|
||||
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, //
|
||||
Build.MODEL)
|
||||
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, //
|
||||
Build.MODEL
|
||||
)
|
||||
Timber.tag("App").d("appId %s", BuildConfig.APPLICATION_ID)
|
||||
|
||||
launchServices()
|
||||
@ -105,10 +107,11 @@ class CryptomatorApp : MultiDexApplication(), HasComponent<ApplicationComponent>
|
||||
Timber.tag("App").i("Auto upload service connected")
|
||||
autoUploadServiceBinder = service as AutoUploadService.Binder
|
||||
autoUploadServiceBinder.init( //
|
||||
applicationComponent.cloudContentRepository(), //
|
||||
applicationComponent.fileUtil(), //
|
||||
applicationComponent.contentResolverUtil(), //
|
||||
Companion.applicationContext)
|
||||
applicationComponent.cloudContentRepository(), //
|
||||
applicationComponent.fileUtil(), //
|
||||
applicationComponent.contentResolverUtil(), //
|
||||
Companion.applicationContext
|
||||
)
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(name: ComponentName) {
|
||||
@ -124,11 +127,11 @@ class CryptomatorApp : MultiDexApplication(), HasComponent<ApplicationComponent>
|
||||
|
||||
private fun initializeInjector() {
|
||||
applicationComponent = DaggerApplicationComponent.builder() //
|
||||
.applicationModule(ApplicationModule(this)) //
|
||||
.threadModule(ThreadModule()) //
|
||||
.repositoryModule(RepositoryModule()) //
|
||||
.cryptorsModule(CryptorsModule(appCryptors)) //
|
||||
.build()
|
||||
.applicationModule(ApplicationModule(this)) //
|
||||
.threadModule(ThreadModule()) //
|
||||
.repositoryModule(RepositoryModule()) //
|
||||
.cryptorsModule(CryptorsModule(appCryptors)) //
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun cleanupCache() {
|
||||
|
@ -15,7 +15,7 @@ class MissingCryptorExceptionHandler : ExceptionHandler() {
|
||||
public override fun doHandle(view: View, e: Throwable) {
|
||||
view.showMessage(R.string.error_vault_has_been_locked)
|
||||
Intents.vaultListIntent() //
|
||||
.preventGoingBackInHistory() //
|
||||
.startActivity(view)
|
||||
.preventGoingBackInHistory() //
|
||||
.startActivity(view)
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,7 @@ public interface UnlockVaultIntent {
|
||||
VaultAction vaultAction();
|
||||
|
||||
enum VaultAction {
|
||||
UNLOCK,
|
||||
UNLOCK_FOR_BIOMETRIC_AUTH,
|
||||
ENCRYPT_PASSWORD,
|
||||
CHANGE_PASSWORD
|
||||
UNLOCK, UNLOCK_FOR_BIOMETRIC_AUTH, ENCRYPT_PASSWORD, CHANGE_PASSWORD
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ object Logfiles {
|
||||
* Maximum size of all logfiles
|
||||
*/
|
||||
private const val MAX_LOGS_SIZE = (1 shl 20 // 1 MiB
|
||||
.toLong().toInt()).toLong()
|
||||
.toLong().toInt()).toLong()
|
||||
|
||||
/**
|
||||
* When this size is reached a logfile is rotated
|
||||
|
@ -8,14 +8,14 @@ import timber.log.Timber
|
||||
class ReleaseLogger(context: Context) : Timber.Tree() {
|
||||
|
||||
private val priorityNames = charArrayOf( //
|
||||
'?', //
|
||||
'?', //
|
||||
'V', //
|
||||
'D', //
|
||||
'I', //
|
||||
'W', //
|
||||
'E', //
|
||||
'A' //
|
||||
'?', //
|
||||
'?', //
|
||||
'V', //
|
||||
'D', //
|
||||
'I', //
|
||||
'W', //
|
||||
'E', //
|
||||
'A' //
|
||||
)
|
||||
private val log: LogRotator
|
||||
|
||||
@ -26,10 +26,10 @@ class ReleaseLogger(context: Context) : Timber.Tree() {
|
||||
override fun log(priority: Int, tag: String?, message: String, throwable: Throwable?) {
|
||||
val line = StringBuilder()
|
||||
line //
|
||||
.append(priorityNames[validPriority(priority)]).append('\t') //
|
||||
.append(FormattedTime.now()).append('\t') //
|
||||
.append(tag ?: "App").append('\t') //
|
||||
.append(message)
|
||||
.append(priorityNames[validPriority(priority)]).append('\t') //
|
||||
.append(FormattedTime.now()).append('\t') //
|
||||
.append(tag ?: "App").append('\t') //
|
||||
.append(message)
|
||||
if (throwable != null) {
|
||||
line.append("\nErrorCode: ").append(GeneratedErrorCode.of(throwable))
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package org.cryptomator.presentation.model
|
||||
import java.io.Serializable
|
||||
|
||||
data class AutoUploadFilesStore(
|
||||
val uris: Set<String>
|
||||
val uris: Set<String>
|
||||
) : Serializable {
|
||||
|
||||
companion object {
|
||||
|
@ -6,38 +6,52 @@ import org.cryptomator.presentation.R
|
||||
enum class CloudTypeModel(builder: Builder) {
|
||||
|
||||
CRYPTO(Builder("CRYPTO", R.string.cloud_names_crypto)), //
|
||||
DROPBOX(Builder("DROPBOX", R.string.cloud_names_dropbox) //
|
||||
DROPBOX(
|
||||
Builder("DROPBOX", R.string.cloud_names_dropbox) //
|
||||
.withCloudImageResource(R.drawable.dropbox) //
|
||||
.withVaultImageResource(R.drawable.dropbox_vault) //
|
||||
.withVaultSelectedImageResource(R.drawable.dropbox_vault_selected)), //
|
||||
GOOGLE_DRIVE(Builder("GOOGLE_DRIVE", R.string.cloud_names_google_drive) //
|
||||
.withVaultSelectedImageResource(R.drawable.dropbox_vault_selected)
|
||||
), //
|
||||
GOOGLE_DRIVE(
|
||||
Builder("GOOGLE_DRIVE", R.string.cloud_names_google_drive) //
|
||||
.withCloudImageResource(R.drawable.google_drive) //
|
||||
.withVaultImageResource(R.drawable.google_drive_vault) //
|
||||
.withVaultSelectedImageResource(R.drawable.google_drive_vault_selected)), //
|
||||
ONEDRIVE(Builder("ONEDRIVE", R.string.cloud_names_onedrive) //
|
||||
.withVaultSelectedImageResource(R.drawable.google_drive_vault_selected)
|
||||
), //
|
||||
ONEDRIVE(
|
||||
Builder("ONEDRIVE", R.string.cloud_names_onedrive) //
|
||||
.withCloudImageResource(R.drawable.onedrive) //
|
||||
.withVaultImageResource(R.drawable.onedrive_vault) //
|
||||
.withVaultSelectedImageResource(R.drawable.onedrive_vault_selected)), //
|
||||
PCLOUD(Builder("PCLOUD", R.string.cloud_names_pcloud) //
|
||||
.withVaultSelectedImageResource(R.drawable.onedrive_vault_selected)
|
||||
), //
|
||||
PCLOUD(
|
||||
Builder("PCLOUD", R.string.cloud_names_pcloud) //
|
||||
.withCloudImageResource(R.drawable.pcloud) //
|
||||
.withVaultImageResource(R.drawable.pcloud_vault) //
|
||||
.withVaultSelectedImageResource(R.drawable.pcloud_vault_selected) //
|
||||
.withMultiInstances()), //
|
||||
WEBDAV(Builder("WEBDAV", R.string.cloud_names_webdav) //
|
||||
.withMultiInstances()
|
||||
), //
|
||||
WEBDAV(
|
||||
Builder("WEBDAV", R.string.cloud_names_webdav) //
|
||||
.withCloudImageResource(R.drawable.webdav) //
|
||||
.withVaultImageResource(R.drawable.webdav_vault) //
|
||||
.withVaultSelectedImageResource(R.drawable.webdav_vault_selected) //
|
||||
.withMultiInstances()), //
|
||||
S3(Builder("S3", R.string.cloud_names_s3) //
|
||||
.withMultiInstances()
|
||||
), //
|
||||
S3(
|
||||
Builder("S3", R.string.cloud_names_s3) //
|
||||
.withCloudImageResource(R.drawable.s3) //
|
||||
.withVaultImageResource(R.drawable.s3_vault) //
|
||||
.withVaultSelectedImageResource(R.drawable.s3_vault_selected) //
|
||||
.withMultiInstances()), //
|
||||
LOCAL(Builder("LOCAL", R.string.cloud_names_local_storage) //
|
||||
.withMultiInstances()
|
||||
), //
|
||||
LOCAL(
|
||||
Builder("LOCAL", R.string.cloud_names_local_storage) //
|
||||
.withCloudImageResource(R.drawable.local_fs) //
|
||||
.withVaultImageResource(R.drawable.local_fs_vault) //
|
||||
.withVaultSelectedImageResource(R.drawable.local_fs_vault_selected) //
|
||||
.withMultiInstances());
|
||||
.withMultiInstances()
|
||||
);
|
||||
|
||||
val cloudName: String = builder.cloudName
|
||||
val displayNameResource: Int = builder.displayNameResource
|
||||
|
@ -8,6 +8,6 @@ import kotlinx.android.parcel.Parcelize
|
||||
@Parcelize
|
||||
@SuppressLint("ParcelCreator")
|
||||
data class ImagePreviewFile(
|
||||
val cloudFileModel: CloudFileModel,
|
||||
var uri: Uri?
|
||||
val cloudFileModel: CloudFileModel,
|
||||
var uri: Uri?
|
||||
) : Parcelable
|
||||
|
@ -3,6 +3,6 @@ package org.cryptomator.presentation.model
|
||||
import java.io.Serializable
|
||||
|
||||
data class ImagePreviewFilesStore(
|
||||
val cloudFileModels: ArrayList<CloudFileModel>,
|
||||
var index: Int
|
||||
val cloudFileModels: ArrayList<CloudFileModel>,
|
||||
var index: Int
|
||||
) : Serializable
|
||||
|
@ -31,21 +31,29 @@ class ProgressStateModelMapper @Inject internal constructor(private val fileUtil
|
||||
|
||||
fun toModel(state: UploadState): ProgressStateModel {
|
||||
return if (state.isUpload) {
|
||||
FileProgressStateModel(state.file(), FileIcon.fileIconFor(state.file().name, fileUtil), FileProgressStateModel.UPLOAD, ProgressStateModel.image(R.drawable.ic_file_upload),
|
||||
ProgressStateModel.text(R.string.dialog_progress_upload_file))
|
||||
FileProgressStateModel(
|
||||
state.file(), FileIcon.fileIconFor(state.file().name, fileUtil), FileProgressStateModel.UPLOAD, ProgressStateModel.image(R.drawable.ic_file_upload),
|
||||
ProgressStateModel.text(R.string.dialog_progress_upload_file)
|
||||
)
|
||||
} else {
|
||||
FileProgressStateModel(state.file(), FileIcon.fileIconFor(state.file().name, fileUtil), FileProgressStateModel.ENCRYPTION, ProgressStateModel.image(R.drawable.ic_lock_closed),
|
||||
ProgressStateModel.text(R.string.dialog_progress_encryption))
|
||||
FileProgressStateModel(
|
||||
state.file(), FileIcon.fileIconFor(state.file().name, fileUtil), FileProgressStateModel.ENCRYPTION, ProgressStateModel.image(R.drawable.ic_lock_closed),
|
||||
ProgressStateModel.text(R.string.dialog_progress_encryption)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun toModel(state: DownloadState): ProgressStateModel {
|
||||
return if (state.isDownload) {
|
||||
FileProgressStateModel(state.file(), FileIcon.fileIconFor(state.file().name, fileUtil), FileProgressStateModel.DOWNLOAD, ProgressStateModel.image(R.drawable.ic_file_download),
|
||||
ProgressStateModel.text(R.string.dialog_progress_download_file))
|
||||
FileProgressStateModel(
|
||||
state.file(), FileIcon.fileIconFor(state.file().name, fileUtil), FileProgressStateModel.DOWNLOAD, ProgressStateModel.image(R.drawable.ic_file_download),
|
||||
ProgressStateModel.text(R.string.dialog_progress_download_file)
|
||||
)
|
||||
} else {
|
||||
FileProgressStateModel(state.file(), FileIcon.fileIconFor(state.file().name, fileUtil), FileProgressStateModel.DECRYPTION, ProgressStateModel.image(R.drawable.ic_lock_open),
|
||||
ProgressStateModel.text(R.string.dialog_progress_decryption))
|
||||
FileProgressStateModel(
|
||||
state.file(), FileIcon.fileIconFor(state.file().name, fileUtil), FileProgressStateModel.DECRYPTION, ProgressStateModel.image(R.drawable.ic_lock_open),
|
||||
ProgressStateModel.text(R.string.dialog_progress_decryption)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,13 +26,14 @@ import javax.inject.Inject
|
||||
|
||||
@PerView
|
||||
class AutoUploadChooseVaultPresenter @Inject constructor( //
|
||||
private val getVaultListUseCase: GetVaultListUseCase, //
|
||||
private val getRootFolderUseCase: GetRootFolderUseCase, //
|
||||
private val getDecryptedCloudForVaultUseCase: GetDecryptedCloudForVaultUseCase, //
|
||||
private val cloudFolderModelMapper: CloudFolderModelMapper, //
|
||||
private val sharedPreferencesHandler: SharedPreferencesHandler, //
|
||||
private val authenticationExceptionHandler: AuthenticationExceptionHandler, //
|
||||
exceptionMappings: ExceptionHandlers) : Presenter<AutoUploadChooseVaultView>(exceptionMappings) {
|
||||
private val getVaultListUseCase: GetVaultListUseCase, //
|
||||
private val getRootFolderUseCase: GetRootFolderUseCase, //
|
||||
private val getDecryptedCloudForVaultUseCase: GetDecryptedCloudForVaultUseCase, //
|
||||
private val cloudFolderModelMapper: CloudFolderModelMapper, //
|
||||
private val sharedPreferencesHandler: SharedPreferencesHandler, //
|
||||
private val authenticationExceptionHandler: AuthenticationExceptionHandler, //
|
||||
exceptionMappings: ExceptionHandlers
|
||||
) : Presenter<AutoUploadChooseVaultView>(exceptionMappings) {
|
||||
|
||||
private var selectedVault: VaultModel? = null
|
||||
private var location: CloudFolderModel? = null
|
||||
@ -79,8 +80,9 @@ class AutoUploadChooseVaultPresenter @Inject constructor( //
|
||||
} else {
|
||||
if (!isPaused) {
|
||||
requestActivityResult( //
|
||||
ActivityResultCallbacks.vaultUnlockedAutoUpload(), //
|
||||
Intents.unlockVaultIntent().withVaultModel(VaultModel(authenticatedVault)).withVaultAction(UnlockVaultIntent.VaultAction.UNLOCK))
|
||||
ActivityResultCallbacks.vaultUnlockedAutoUpload(), //
|
||||
Intents.unlockVaultIntent().withVaultModel(VaultModel(authenticatedVault)).withVaultAction(UnlockVaultIntent.VaultAction.UNLOCK)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -95,24 +97,25 @@ class AutoUploadChooseVaultPresenter @Inject constructor( //
|
||||
}
|
||||
|
||||
|
||||
|
||||
private fun decryptedCloudFor(vault: Vault) {
|
||||
getDecryptedCloudForVaultUseCase //
|
||||
.withVault(vault) //
|
||||
.run(object : DefaultResultHandler<Cloud>() {
|
||||
override fun onSuccess(cloud: Cloud) {
|
||||
rootFolderFor(cloud)
|
||||
}
|
||||
.withVault(vault) //
|
||||
.run(object : DefaultResultHandler<Cloud>() {
|
||||
override fun onSuccess(cloud: Cloud) {
|
||||
rootFolderFor(cloud)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
if (!authenticationExceptionHandler.handleAuthenticationException( //
|
||||
this@AutoUploadChooseVaultPresenter, //
|
||||
e, //
|
||||
ActivityResultCallbacks.decryptedCloudForAfterAuthInAutoPhotoUpload(vault))) {
|
||||
super.onError(e)
|
||||
}
|
||||
override fun onError(e: Throwable) {
|
||||
if (!authenticationExceptionHandler.handleAuthenticationException( //
|
||||
this@AutoUploadChooseVaultPresenter, //
|
||||
e, //
|
||||
ActivityResultCallbacks.decryptedCloudForAfterAuthInAutoPhotoUpload(vault)
|
||||
)
|
||||
) {
|
||||
super.onError(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Callback
|
||||
@ -123,33 +126,35 @@ class AutoUploadChooseVaultPresenter @Inject constructor( //
|
||||
|
||||
private fun rootFolderFor(cloud: Cloud) {
|
||||
getRootFolderUseCase //
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<CloudFolder>() {
|
||||
override fun onSuccess(folder: CloudFolder) {
|
||||
when (authenticationState) {
|
||||
AuthenticationState.CHOOSE_LOCATION -> {
|
||||
location = cloudFolderModelMapper.toModel(folder)
|
||||
selectedVault?.let { navigateToVaultContent(it, location) }
|
||||
}
|
||||
AuthenticationState.INIT_ROOT -> location = cloudFolderModelMapper.toModel(folder)
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<CloudFolder>() {
|
||||
override fun onSuccess(folder: CloudFolder) {
|
||||
when (authenticationState) {
|
||||
AuthenticationState.CHOOSE_LOCATION -> {
|
||||
location = cloudFolderModelMapper.toModel(folder)
|
||||
selectedVault?.let { navigateToVaultContent(it, location) }
|
||||
}
|
||||
AuthenticationState.INIT_ROOT -> location = cloudFolderModelMapper.toModel(folder)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun navigateToVaultContent(vaultModel: VaultModel, decryptedRoot: CloudFolderModel?) {
|
||||
requestActivityResult( //
|
||||
ActivityResultCallbacks.onAutoUploadChooseLocation(vaultModel), //
|
||||
Intents.browseFilesIntent() //
|
||||
.withFolder(decryptedRoot) //
|
||||
.withTitle(vaultModel.name) //
|
||||
.withChooseCloudNodeSettings( //
|
||||
ChooseCloudNodeSettings.chooseCloudNodeSettings() //
|
||||
.withExtraTitle(context().getString(R.string.screen_file_browser_share_destination_title)) //
|
||||
.withExtraToolbarIcon(R.drawable.ic_clear) //
|
||||
.withButtonText(context().getString(R.string.screen_file_browser_share_button_text)) //
|
||||
.selectingFolders() //
|
||||
.build()))
|
||||
ActivityResultCallbacks.onAutoUploadChooseLocation(vaultModel), //
|
||||
Intents.browseFilesIntent() //
|
||||
.withFolder(decryptedRoot) //
|
||||
.withTitle(vaultModel.name) //
|
||||
.withChooseCloudNodeSettings( //
|
||||
ChooseCloudNodeSettings.chooseCloudNodeSettings() //
|
||||
.withExtraTitle(context().getString(R.string.screen_file_browser_share_destination_title)) //
|
||||
.withExtraToolbarIcon(R.drawable.ic_clear) //
|
||||
.withButtonText(context().getString(R.string.screen_file_browser_share_button_text)) //
|
||||
.selectingFolders() //
|
||||
.build()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Callback
|
||||
|
@ -22,11 +22,12 @@ import timber.log.Timber
|
||||
|
||||
@PerView
|
||||
class BiometricAuthSettingsPresenter @Inject constructor( //
|
||||
private val getVaultListUseCase: GetVaultListUseCase, //
|
||||
private val saveVaultUseCase: SaveVaultUseCase, //
|
||||
private val lockVaultUseCase: LockVaultUseCase, //
|
||||
exceptionMappings: ExceptionHandlers, //
|
||||
private val sharedPreferencesHandler: SharedPreferencesHandler) : Presenter<BiometricAuthSettingsView>(exceptionMappings) {
|
||||
private val getVaultListUseCase: GetVaultListUseCase, //
|
||||
private val saveVaultUseCase: SaveVaultUseCase, //
|
||||
private val lockVaultUseCase: LockVaultUseCase, //
|
||||
exceptionMappings: ExceptionHandlers, //
|
||||
private val sharedPreferencesHandler: SharedPreferencesHandler
|
||||
) : Presenter<BiometricAuthSettingsView>(exceptionMappings) {
|
||||
|
||||
fun loadVaultList() {
|
||||
updateVaultListView()
|
||||
@ -55,19 +56,21 @@ class BiometricAuthSettingsPresenter @Inject constructor( //
|
||||
Timber.tag("BiomtricAuthSettngsPres").i("Checking entered vault password")
|
||||
if (vaultModel.isLocked) {
|
||||
requestActivityResult( //
|
||||
ActivityResultCallbacks.vaultUnlockedBiometricAuthPres(vaultModel), //
|
||||
Intents.unlockVaultIntent().withVaultModel(vaultModel).withVaultAction(UnlockVaultIntent.VaultAction.UNLOCK_FOR_BIOMETRIC_AUTH))
|
||||
ActivityResultCallbacks.vaultUnlockedBiometricAuthPres(vaultModel), //
|
||||
Intents.unlockVaultIntent().withVaultModel(vaultModel).withVaultAction(UnlockVaultIntent.VaultAction.UNLOCK_FOR_BIOMETRIC_AUTH)
|
||||
)
|
||||
} else {
|
||||
lockVaultUseCase
|
||||
.withVault(vaultModel.toVault())
|
||||
.run(object : DefaultResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
super.onSuccess(vault)
|
||||
requestActivityResult( //
|
||||
ActivityResultCallbacks.vaultUnlockedBiometricAuthPres(vaultModel), //
|
||||
Intents.unlockVaultIntent().withVaultModel(vaultModel).withVaultAction(UnlockVaultIntent.VaultAction.UNLOCK_FOR_BIOMETRIC_AUTH))
|
||||
}
|
||||
})
|
||||
.withVault(vaultModel.toVault())
|
||||
.run(object : DefaultResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
super.onSuccess(vault)
|
||||
requestActivityResult( //
|
||||
ActivityResultCallbacks.vaultUnlockedBiometricAuthPres(vaultModel), //
|
||||
Intents.unlockVaultIntent().withVaultModel(vaultModel).withVaultAction(UnlockVaultIntent.VaultAction.UNLOCK_FOR_BIOMETRIC_AUTH)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,8 +81,9 @@ class BiometricAuthSettingsPresenter @Inject constructor( //
|
||||
val vault = Vault.aCopyOf(vaultModel.toVault()).withCloud(cloud).withSavedPassword(password).build()
|
||||
when {
|
||||
result.isResultOk -> requestActivityResult( //
|
||||
ActivityResultCallbacks.encryptVaultPassword(vaultModel), //
|
||||
Intents.unlockVaultIntent().withVaultModel(VaultModel(vault)).withVaultAction(UnlockVaultIntent.VaultAction.ENCRYPT_PASSWORD))
|
||||
ActivityResultCallbacks.encryptVaultPassword(vaultModel), //
|
||||
Intents.unlockVaultIntent().withVaultModel(VaultModel(vault)).withVaultAction(UnlockVaultIntent.VaultAction.ENCRYPT_PASSWORD)
|
||||
)
|
||||
else -> TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
@ -96,12 +100,12 @@ class BiometricAuthSettingsPresenter @Inject constructor( //
|
||||
|
||||
private fun saveVault(vault: Vault?) {
|
||||
saveVaultUseCase //
|
||||
.withVault(vault) //
|
||||
.run(object : ProgressCompletingResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
Timber.tag("BiomtricAuthSettngsPres").i("Saved updated vault successfully")
|
||||
}
|
||||
})
|
||||
.withVault(vault) //
|
||||
.run(object : ProgressCompletingResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
Timber.tag("BiomtricAuthSettngsPres").i("Saved updated vault successfully")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun switchedGeneralBiometricAuthSettings(isChecked: Boolean) {
|
||||
@ -124,9 +128,9 @@ class BiometricAuthSettingsPresenter @Inject constructor( //
|
||||
|
||||
private fun removePasswordAndSave(vault: Vault) {
|
||||
val vaultWithRemovedPassword = Vault //
|
||||
.aCopyOf(vault) //
|
||||
.withSavedPassword(null) //
|
||||
.build()
|
||||
.aCopyOf(vault) //
|
||||
.withSavedPassword(null) //
|
||||
.build()
|
||||
saveVault(vaultWithRemovedPassword)
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -20,11 +20,12 @@ import javax.inject.Inject
|
||||
|
||||
@PerView
|
||||
class ChooseCloudServicePresenter @Inject constructor( //
|
||||
private val getCloudsUseCase: GetCloudsUseCase, //
|
||||
private val cloudModelMapper: CloudModelMapper, //
|
||||
private val addExistingVaultWorkflow: AddExistingVaultWorkflow, //
|
||||
private val createNewVaultWorkflow: CreateNewVaultWorkflow, //
|
||||
exceptionMappings: ExceptionHandlers) : Presenter<ChooseCloudServiceView>(exceptionMappings) {
|
||||
private val getCloudsUseCase: GetCloudsUseCase, //
|
||||
private val cloudModelMapper: CloudModelMapper, //
|
||||
private val addExistingVaultWorkflow: AddExistingVaultWorkflow, //
|
||||
private val createNewVaultWorkflow: CreateNewVaultWorkflow, //
|
||||
exceptionMappings: ExceptionHandlers
|
||||
) : Presenter<ChooseCloudServiceView>(exceptionMappings) {
|
||||
|
||||
override fun workflows(): Iterable<Workflow<*>> {
|
||||
return listOf(addExistingVaultWorkflow, createNewVaultWorkflow)
|
||||
@ -55,11 +56,12 @@ class ChooseCloudServicePresenter @Inject constructor( //
|
||||
|
||||
private fun startCloudConnectionListActivity(cloudTypeModel: CloudTypeModel) {
|
||||
requestActivityResult( //
|
||||
ActivityResultCallbacks.cloudConnectionListFinished(), //
|
||||
Intents.cloudConnectionListIntent() //
|
||||
.withCloudType(cloudTypeModel) //
|
||||
.withDialogTitle(context().getString(R.string.screen_cloud_connections_title)) //
|
||||
.withFinishOnCloudItemClick(true))
|
||||
ActivityResultCallbacks.cloudConnectionListFinished(), //
|
||||
Intents.cloudConnectionListIntent() //
|
||||
.withCloudType(cloudTypeModel) //
|
||||
.withDialogTitle(context().getString(R.string.screen_cloud_connections_title)) //
|
||||
.withFinishOnCloudItemClick(true)
|
||||
)
|
||||
}
|
||||
|
||||
@Callback
|
||||
@ -70,15 +72,15 @@ class ChooseCloudServicePresenter @Inject constructor( //
|
||||
|
||||
private fun handleSingleInstanceClouds(cloudTypeModel: CloudTypeModel) {
|
||||
getCloudsUseCase //
|
||||
.withCloudType(CloudTypeModel.valueOf(cloudTypeModel)) //
|
||||
.run(object : DefaultResultHandler<List<Cloud>>() {
|
||||
override fun onSuccess(clouds: List<Cloud>) {
|
||||
if (clouds.size > 1) {
|
||||
throw FatalBackendException("More then one cloud")
|
||||
}
|
||||
onCloudSelected(clouds[0])
|
||||
.withCloudType(CloudTypeModel.valueOf(cloudTypeModel)) //
|
||||
.run(object : DefaultResultHandler<List<Cloud>>() {
|
||||
override fun onSuccess(clouds: List<Cloud>) {
|
||||
if (clouds.size > 1) {
|
||||
throw FatalBackendException("More then one cloud")
|
||||
}
|
||||
})
|
||||
onCloudSelected(clouds[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun onCloudSelected(cloud: Cloud) {
|
||||
|
@ -42,14 +42,15 @@ import timber.log.Timber
|
||||
|
||||
@PerView
|
||||
class CloudConnectionListPresenter @Inject constructor( //
|
||||
private val getCloudsUseCase: GetCloudsUseCase, //
|
||||
private val getUsernameUseCase: GetUsernameUseCase, //
|
||||
private val removeCloudUseCase: RemoveCloudUseCase, //
|
||||
private val addOrChangeCloudConnectionUseCase: AddOrChangeCloudConnectionUseCase, //
|
||||
private val getVaultListUseCase: GetVaultListUseCase, //
|
||||
private val deleteVaultUseCase: DeleteVaultUseCase, //
|
||||
private val cloudModelMapper: CloudModelMapper, //
|
||||
exceptionMappings: ExceptionHandlers) : Presenter<CloudConnectionListView>(exceptionMappings) {
|
||||
private val getCloudsUseCase: GetCloudsUseCase, //
|
||||
private val getUsernameUseCase: GetUsernameUseCase, //
|
||||
private val removeCloudUseCase: RemoveCloudUseCase, //
|
||||
private val addOrChangeCloudConnectionUseCase: AddOrChangeCloudConnectionUseCase, //
|
||||
private val getVaultListUseCase: GetVaultListUseCase, //
|
||||
private val deleteVaultUseCase: DeleteVaultUseCase, //
|
||||
private val cloudModelMapper: CloudModelMapper, //
|
||||
exceptionMappings: ExceptionHandlers
|
||||
) : Presenter<CloudConnectionListView>(exceptionMappings) {
|
||||
|
||||
private val selectedCloudType = AtomicReference<CloudTypeModel>()
|
||||
private var defaultLocalStorageCloud: LocalStorageCloud? = null
|
||||
@ -59,22 +60,22 @@ class CloudConnectionListPresenter @Inject constructor( //
|
||||
|
||||
fun loadCloudList() {
|
||||
getCloudsUseCase //
|
||||
.withCloudType(CloudTypeModel.valueOf(selectedCloudType.get())) //
|
||||
.run(object : DefaultResultHandler<List<Cloud>>() {
|
||||
override fun onSuccess(clouds: List<Cloud>) {
|
||||
val cloudModels: MutableList<CloudModel> = ArrayList()
|
||||
clouds.forEach { cloud ->
|
||||
if (CloudTypeModel.LOCAL == selectedCloudType.get()) {
|
||||
if ((cloud as LocalStorageCloud).rootUri() == null) {
|
||||
defaultLocalStorageCloud = cloud
|
||||
return@forEach
|
||||
}
|
||||
.withCloudType(CloudTypeModel.valueOf(selectedCloudType.get())) //
|
||||
.run(object : DefaultResultHandler<List<Cloud>>() {
|
||||
override fun onSuccess(clouds: List<Cloud>) {
|
||||
val cloudModels: MutableList<CloudModel> = ArrayList()
|
||||
clouds.forEach { cloud ->
|
||||
if (CloudTypeModel.LOCAL == selectedCloudType.get()) {
|
||||
if ((cloud as LocalStorageCloud).rootUri() == null) {
|
||||
defaultLocalStorageCloud = cloud
|
||||
return@forEach
|
||||
}
|
||||
cloudModels.add(cloudModelMapper.toModel(cloud))
|
||||
}
|
||||
view?.showCloudModels(cloudModels)
|
||||
cloudModels.add(cloudModelMapper.toModel(cloud))
|
||||
}
|
||||
})
|
||||
view?.showCloudModels(cloudModels)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun onDeleteCloudClicked(cloudModel: CloudModel) {
|
||||
@ -120,32 +121,39 @@ class CloudConnectionListPresenter @Inject constructor( //
|
||||
|
||||
private fun deleteCloud(cloud: Cloud) {
|
||||
removeCloudUseCase //
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onSuccess(ignore: Void?) {
|
||||
loadCloudList()
|
||||
}
|
||||
})
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onSuccess(ignore: Void?) {
|
||||
loadCloudList()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun onAddConnectionClicked() {
|
||||
when (selectedCloudType.get()) {
|
||||
CloudTypeModel.WEBDAV -> requestActivityResult(ActivityResultCallbacks.addChangeMultiCloud(), //
|
||||
Intents.webDavAddOrChangeIntent())
|
||||
CloudTypeModel.WEBDAV -> requestActivityResult(
|
||||
ActivityResultCallbacks.addChangeMultiCloud(), //
|
||||
Intents.webDavAddOrChangeIntent()
|
||||
)
|
||||
CloudTypeModel.PCLOUD -> {
|
||||
val authIntent: Intent = AuthorizationActivity.createIntent(
|
||||
this.context(),
|
||||
AuthorizationRequest.create()
|
||||
.setType(AuthorizationRequest.Type.TOKEN)
|
||||
.setClientId(BuildConfig.PCLOUD_CLIENT_ID)
|
||||
.setForceAccessApproval(true)
|
||||
.addPermission("manageshares")
|
||||
.build())
|
||||
requestActivityResult(ActivityResultCallbacks.pCloudAuthenticationFinished(), //
|
||||
authIntent)
|
||||
this.context(),
|
||||
AuthorizationRequest.create()
|
||||
.setType(AuthorizationRequest.Type.TOKEN)
|
||||
.setClientId(BuildConfig.PCLOUD_CLIENT_ID)
|
||||
.setForceAccessApproval(true)
|
||||
.addPermission("manageshares")
|
||||
.build()
|
||||
)
|
||||
requestActivityResult(
|
||||
ActivityResultCallbacks.pCloudAuthenticationFinished(), //
|
||||
authIntent
|
||||
)
|
||||
}
|
||||
CloudTypeModel.S3 -> requestActivityResult(ActivityResultCallbacks.addChangeMultiCloud(), //
|
||||
Intents.s3AddOrChangeIntent())
|
||||
CloudTypeModel.S3 -> requestActivityResult(
|
||||
ActivityResultCallbacks.addChangeMultiCloud(), //
|
||||
Intents.s3AddOrChangeIntent()
|
||||
)
|
||||
CloudTypeModel.LOCAL -> openDocumentTree()
|
||||
}
|
||||
}
|
||||
@ -154,15 +162,17 @@ class CloudConnectionListPresenter @Inject constructor( //
|
||||
private fun openDocumentTree() {
|
||||
try {
|
||||
requestActivityResult( //
|
||||
ActivityResultCallbacks.pickedLocalStorageLocation(), //
|
||||
Intent(Intent.ACTION_OPEN_DOCUMENT_TREE))
|
||||
ActivityResultCallbacks.pickedLocalStorageLocation(), //
|
||||
Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
)
|
||||
} catch (exception: ActivityNotFoundException) {
|
||||
Toast //
|
||||
.makeText( //
|
||||
activity().applicationContext, //
|
||||
context().getText(R.string.screen_cloud_local_error_no_content_provider), //
|
||||
Toast.LENGTH_SHORT) //
|
||||
.show()
|
||||
.makeText( //
|
||||
activity().applicationContext, //
|
||||
context().getText(R.string.screen_cloud_local_error_no_content_provider), //
|
||||
Toast.LENGTH_SHORT
|
||||
) //
|
||||
.show()
|
||||
Timber.tag("CloudConnListPresenter").e(exception, "No ContentProvider on system")
|
||||
}
|
||||
}
|
||||
@ -170,14 +180,18 @@ class CloudConnectionListPresenter @Inject constructor( //
|
||||
fun onChangeCloudClicked(cloudModel: CloudModel) {
|
||||
when {
|
||||
cloudModel.cloudType() == CloudTypeModel.WEBDAV -> {
|
||||
requestActivityResult(ActivityResultCallbacks.addChangeMultiCloud(), //
|
||||
Intents.webDavAddOrChangeIntent() //
|
||||
.withWebDavCloud(cloudModel as WebDavCloudModel))
|
||||
requestActivityResult(
|
||||
ActivityResultCallbacks.addChangeMultiCloud(), //
|
||||
Intents.webDavAddOrChangeIntent() //
|
||||
.withWebDavCloud(cloudModel as WebDavCloudModel)
|
||||
)
|
||||
}
|
||||
cloudModel.cloudType() == CloudTypeModel.S3 -> {
|
||||
requestActivityResult(ActivityResultCallbacks.addChangeMultiCloud(), //
|
||||
Intents.s3AddOrChangeIntent() //
|
||||
.withS3Cloud(cloudModel as S3CloudModel))
|
||||
requestActivityResult(
|
||||
ActivityResultCallbacks.addChangeMultiCloud(), //
|
||||
Intents.s3AddOrChangeIntent() //
|
||||
.withS3Cloud(cloudModel as S3CloudModel)
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
throw IllegalStateException("Change cloud with type " + cloudModel.cloudType() + " is not supported")
|
||||
@ -202,19 +216,19 @@ class CloudConnectionListPresenter @Inject constructor( //
|
||||
when (result) {
|
||||
AuthorizationResult.ACCESS_GRANTED -> {
|
||||
val accessToken: String = CredentialCryptor //
|
||||
.getInstance(this.context()) //
|
||||
.encrypt(authData.token)
|
||||
.getInstance(this.context()) //
|
||||
.encrypt(authData.token)
|
||||
val pCloudSkeleton: PCloud = PCloud.aPCloud() //
|
||||
.withAccessToken(accessToken)
|
||||
.withUrl(authData.apiHost)
|
||||
.build();
|
||||
.withAccessToken(accessToken)
|
||||
.withUrl(authData.apiHost)
|
||||
.build();
|
||||
getUsernameUseCase //
|
||||
.withCloud(pCloudSkeleton) //
|
||||
.run(object : DefaultResultHandler<String>() {
|
||||
override fun onSuccess(username: String?) {
|
||||
prepareForSavingPCloud(PCloud.aCopyOf(pCloudSkeleton).withUsername(username).build())
|
||||
}
|
||||
})
|
||||
.withCloud(pCloudSkeleton) //
|
||||
.run(object : DefaultResultHandler<String>() {
|
||||
override fun onSuccess(username: String?) {
|
||||
prepareForSavingPCloud(PCloud.aCopyOf(pCloudSkeleton).withUsername(username).build())
|
||||
}
|
||||
})
|
||||
}
|
||||
AuthorizationResult.ACCESS_DENIED -> {
|
||||
Timber.tag("CloudConnListPresenter").e("Account access denied")
|
||||
@ -233,30 +247,32 @@ class CloudConnectionListPresenter @Inject constructor( //
|
||||
|
||||
fun prepareForSavingPCloud(cloud: PCloud) {
|
||||
getCloudsUseCase //
|
||||
.withCloudType(CloudTypeModel.valueOf(selectedCloudType.get())) //
|
||||
.run(object : DefaultResultHandler<List<Cloud>>() {
|
||||
override fun onSuccess(clouds: List<Cloud>) {
|
||||
clouds.firstOrNull {
|
||||
(it as PCloud).username() == cloud.username()
|
||||
}?.let {
|
||||
it as PCloud
|
||||
saveCloud(PCloud.aCopyOf(it) //
|
||||
.withUrl(cloud.url())
|
||||
.withAccessToken(cloud.accessToken())
|
||||
.build())
|
||||
} ?: saveCloud(cloud)
|
||||
}
|
||||
})
|
||||
.withCloudType(CloudTypeModel.valueOf(selectedCloudType.get())) //
|
||||
.run(object : DefaultResultHandler<List<Cloud>>() {
|
||||
override fun onSuccess(clouds: List<Cloud>) {
|
||||
clouds.firstOrNull {
|
||||
(it as PCloud).username() == cloud.username()
|
||||
}?.let {
|
||||
it as PCloud
|
||||
saveCloud(
|
||||
PCloud.aCopyOf(it) //
|
||||
.withUrl(cloud.url())
|
||||
.withAccessToken(cloud.accessToken())
|
||||
.build()
|
||||
)
|
||||
} ?: saveCloud(cloud)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun saveCloud(cloud: PCloud) {
|
||||
addOrChangeCloudConnectionUseCase //
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onSuccess(void: Void?) {
|
||||
loadCloudList()
|
||||
}
|
||||
})
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onSuccess(void: Void?) {
|
||||
loadCloudList()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Callback
|
||||
@ -264,34 +280,38 @@ class CloudConnectionListPresenter @Inject constructor( //
|
||||
fun pickedLocalStorageLocation(result: ActivityResult) {
|
||||
val rootTreeUriOfLocalStorage = result.intent().data
|
||||
persistUriPermission(rootTreeUriOfLocalStorage)
|
||||
addOrChangeCloudConnectionUseCase.withCloud(LocalStorageCloud.aLocalStorage() //
|
||||
addOrChangeCloudConnectionUseCase.withCloud(
|
||||
LocalStorageCloud.aLocalStorage() //
|
||||
.withRootUri(rootTreeUriOfLocalStorage.toString()) //
|
||||
.build()) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onSuccess(void: Void?) {
|
||||
loadCloudList()
|
||||
}
|
||||
})
|
||||
.build()
|
||||
) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onSuccess(void: Void?) {
|
||||
loadCloudList()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
private fun persistUriPermission(rootTreeUriOfLocalStorage: Uri?) {
|
||||
rootTreeUriOfLocalStorage?.let {
|
||||
context() //
|
||||
.contentResolver //
|
||||
.takePersistableUriPermission( //
|
||||
it, //
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
.contentResolver //
|
||||
.takePersistableUriPermission( //
|
||||
it, //
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
private fun releaseUriPermission(uri: String) {
|
||||
context() //
|
||||
.contentResolver //
|
||||
.releasePersistableUriPermission( //
|
||||
Uri.parse(uri), //
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
.contentResolver //
|
||||
.releasePersistableUriPermission( //
|
||||
Uri.parse(uri), //
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
)
|
||||
}
|
||||
|
||||
fun onCloudConnectionClicked(cloudModel: CloudModel) {
|
||||
|
@ -29,18 +29,20 @@ import javax.inject.Inject
|
||||
|
||||
@PerView
|
||||
class CloudSettingsPresenter @Inject constructor( //
|
||||
private val getAllCloudsUseCase: GetAllCloudsUseCase, //
|
||||
private val getCloudsUseCase: GetCloudsUseCase, //
|
||||
private val logoutCloudUsecase: LogoutCloudUseCase, //
|
||||
private val cloudModelMapper: CloudModelMapper, //
|
||||
exceptionMappings: ExceptionHandlers) : Presenter<CloudSettingsView>(exceptionMappings) {
|
||||
private val getAllCloudsUseCase: GetAllCloudsUseCase, //
|
||||
private val getCloudsUseCase: GetCloudsUseCase, //
|
||||
private val logoutCloudUsecase: LogoutCloudUseCase, //
|
||||
private val cloudModelMapper: CloudModelMapper, //
|
||||
exceptionMappings: ExceptionHandlers
|
||||
) : Presenter<CloudSettingsView>(exceptionMappings) {
|
||||
|
||||
private val nonSingleLoginClouds: Set<CloudTypeModel> = EnumSet.of( //
|
||||
CloudTypeModel.CRYPTO, //
|
||||
CloudTypeModel.LOCAL, //
|
||||
CloudTypeModel.PCLOUD, //
|
||||
CloudTypeModel.S3, //
|
||||
CloudTypeModel.WEBDAV)
|
||||
CloudTypeModel.CRYPTO, //
|
||||
CloudTypeModel.LOCAL, //
|
||||
CloudTypeModel.PCLOUD, //
|
||||
CloudTypeModel.S3, //
|
||||
CloudTypeModel.WEBDAV
|
||||
)
|
||||
|
||||
fun loadClouds() {
|
||||
getAllCloudsUseCase.run(CloudsSubscriber())
|
||||
@ -52,12 +54,12 @@ class CloudSettingsPresenter @Inject constructor( //
|
||||
} else {
|
||||
if (isLoggedIn(cloudModel)) {
|
||||
logoutCloudUsecase //
|
||||
.withCloud(cloudModel.toCloud()) //
|
||||
.run(object : DefaultResultHandler<Cloud>() {
|
||||
override fun onSuccess(cloud: Cloud) {
|
||||
loadClouds()
|
||||
}
|
||||
})
|
||||
.withCloud(cloudModel.toCloud()) //
|
||||
.run(object : DefaultResultHandler<Cloud>() {
|
||||
override fun onSuccess(cloud: Cloud) {
|
||||
loadClouds()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
loginCloud(cloudModel)
|
||||
}
|
||||
@ -66,15 +68,15 @@ class CloudSettingsPresenter @Inject constructor( //
|
||||
|
||||
private fun loginCloud(cloudModel: CloudModel) {
|
||||
getCloudsUseCase //
|
||||
.withCloudType(CloudTypeModel.valueOf(cloudModel.cloudType())) //
|
||||
.run(object : DefaultResultHandler<List<Cloud>>() {
|
||||
override fun onSuccess(clouds: List<Cloud>) {
|
||||
if (clouds.size > 1) {
|
||||
throw FatalBackendException("More then one cloud")
|
||||
}
|
||||
startAuthentication(clouds[0])
|
||||
.withCloudType(CloudTypeModel.valueOf(cloudModel.cloudType())) //
|
||||
.run(object : DefaultResultHandler<List<Cloud>>() {
|
||||
override fun onSuccess(clouds: List<Cloud>) {
|
||||
if (clouds.size > 1) {
|
||||
throw FatalBackendException("More then one cloud")
|
||||
}
|
||||
})
|
||||
startAuthentication(clouds[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun isLoggedIn(cloudModel: CloudModel): Boolean {
|
||||
@ -83,11 +85,12 @@ class CloudSettingsPresenter @Inject constructor( //
|
||||
|
||||
private fun startConnectionListActivity(cloudTypeModel: CloudTypeModel) {
|
||||
requestActivityResult( //
|
||||
ActivityResultCallbacks.webDavConnectionListFinisheds(), //
|
||||
Intents.cloudConnectionListIntent() //
|
||||
.withCloudType(cloudTypeModel) //
|
||||
.withDialogTitle(effectiveTitle(cloudTypeModel)) //
|
||||
.withFinishOnCloudItemClick(false))
|
||||
ActivityResultCallbacks.webDavConnectionListFinisheds(), //
|
||||
Intents.cloudConnectionListIntent() //
|
||||
.withCloudType(cloudTypeModel) //
|
||||
.withDialogTitle(effectiveTitle(cloudTypeModel)) //
|
||||
.withFinishOnCloudItemClick(false)
|
||||
)
|
||||
}
|
||||
|
||||
private fun effectiveTitle(cloudTypeModel: CloudTypeModel): String {
|
||||
@ -108,9 +111,10 @@ class CloudSettingsPresenter @Inject constructor( //
|
||||
|
||||
private fun startAuthentication(cloud: Cloud) {
|
||||
requestActivityResult( //
|
||||
ActivityResultCallbacks.onCloudAuthenticated(), //
|
||||
Intents.authenticateCloudIntent() //
|
||||
.withCloud(cloudModelMapper.toModel(cloud)))
|
||||
ActivityResultCallbacks.onCloudAuthenticated(), //
|
||||
Intents.authenticateCloudIntent() //
|
||||
.withCloud(cloudModelMapper.toModel(cloud))
|
||||
)
|
||||
}
|
||||
|
||||
@Callback
|
||||
@ -122,15 +126,15 @@ class CloudSettingsPresenter @Inject constructor( //
|
||||
|
||||
override fun onSuccess(clouds: List<Cloud>) {
|
||||
val cloudModel = cloudModelMapper.toModels(clouds) //
|
||||
.filter { isSingleLoginCloud(it) } //
|
||||
.filter { cloud -> !(BuildConfig.FLAVOR == "fdroid" && cloud.cloudType() == CloudTypeModel.GOOGLE_DRIVE) } //
|
||||
.toMutableList() //
|
||||
.also {
|
||||
it.add(aPCloud())
|
||||
it.add(aWebdavCloud())
|
||||
it.add(aS3Cloud())
|
||||
it.add(aLocalCloud())
|
||||
}
|
||||
.filter { isSingleLoginCloud(it) } //
|
||||
.filter { cloud -> !(BuildConfig.FLAVOR == "fdroid" && cloud.cloudType() == CloudTypeModel.GOOGLE_DRIVE) } //
|
||||
.toMutableList() //
|
||||
.also {
|
||||
it.add(aPCloud())
|
||||
it.add(aWebdavCloud())
|
||||
it.add(aS3Cloud())
|
||||
it.add(aLocalCloud())
|
||||
}
|
||||
view?.render(cloudModel)
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,9 @@ import javax.inject.Inject
|
||||
|
||||
@PerView
|
||||
class CreateVaultPresenter @Inject constructor( //
|
||||
private val createNewVaultWorkflow: CreateNewVaultWorkflow, //
|
||||
exceptionMappings: ExceptionHandlers) : Presenter<CreateVaultView>(exceptionMappings) {
|
||||
private val createNewVaultWorkflow: CreateNewVaultWorkflow, //
|
||||
exceptionMappings: ExceptionHandlers
|
||||
) : Presenter<CreateVaultView>(exceptionMappings) {
|
||||
|
||||
override fun workflows(): Iterable<Workflow<*>> {
|
||||
return setOf(createNewVaultWorkflow)
|
||||
|
@ -42,15 +42,16 @@ import timber.log.Timber
|
||||
|
||||
@PerView
|
||||
class ImagePreviewPresenter @Inject constructor( //
|
||||
exceptionMappings: ExceptionHandlers, //
|
||||
private val shareFileHelper: ShareFileHelper, //
|
||||
private val contentResolverUtil: ContentResolverUtil, //
|
||||
private val copyDataUseCase: CopyDataUseCase, //
|
||||
private val downloadFilesUseCase: DownloadFilesUseCase, //
|
||||
private val deleteNodesUseCase: DeleteNodesUseCase, //
|
||||
private val downloadFileUtil: DownloadFileUtil, //
|
||||
private val fileUtil: FileUtil, //
|
||||
private val cloudFileModelMapper: CloudFileModelMapper) : Presenter<ImagePreviewView>(exceptionMappings) {
|
||||
exceptionMappings: ExceptionHandlers, //
|
||||
private val shareFileHelper: ShareFileHelper, //
|
||||
private val contentResolverUtil: ContentResolverUtil, //
|
||||
private val copyDataUseCase: CopyDataUseCase, //
|
||||
private val downloadFilesUseCase: DownloadFilesUseCase, //
|
||||
private val deleteNodesUseCase: DeleteNodesUseCase, //
|
||||
private val downloadFileUtil: DownloadFileUtil, //
|
||||
private val fileUtil: FileUtil, //
|
||||
private val cloudFileModelMapper: CloudFileModelMapper
|
||||
) : Presenter<ImagePreviewView>(exceptionMappings) {
|
||||
|
||||
private var isSystemUiVisible = true
|
||||
|
||||
@ -66,8 +67,10 @@ class ImagePreviewPresenter @Inject constructor( //
|
||||
}
|
||||
|
||||
private fun copyFileToDownloadDirectory(uri: Uri) {
|
||||
requestPermissions(PermissionsResultCallbacks.copyFileToDownloadDirectory(uri.toString()), //
|
||||
R.string.permission_message_export_file, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
requestPermissions(
|
||||
PermissionsResultCallbacks.copyFileToDownloadDirectory(uri.toString()), //
|
||||
R.string.permission_message_export_file, Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
)
|
||||
}
|
||||
|
||||
@Callback
|
||||
@ -95,13 +98,13 @@ class ImagePreviewPresenter @Inject constructor( //
|
||||
throw FatalBackendException("Input- or OutputStream is null")
|
||||
}
|
||||
copyDataUseCase //
|
||||
.withSource(source) //
|
||||
.andTarget(target) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onFinished() {
|
||||
view?.showMessage(R.string.screen_file_browser_msg_file_exported)
|
||||
}
|
||||
})
|
||||
.withSource(source) //
|
||||
.andTarget(target) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onFinished() {
|
||||
view?.showMessage(R.string.screen_file_browser_msg_file_exported)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun copyFileToUserSelectedLocation(uri: Uri) {
|
||||
@ -114,17 +117,21 @@ class ImagePreviewPresenter @Inject constructor( //
|
||||
|
||||
@Callback
|
||||
fun copyFileToUserSelectedLocation(result: ActivityResult, sourceUri: String?) {
|
||||
requestPermissions(PermissionsResultCallbacks.copyFileToUserSelectedLocation(result.intent()?.dataString, sourceUri), //
|
||||
R.string.permission_message_export_file, //
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
requestPermissions(
|
||||
PermissionsResultCallbacks.copyFileToUserSelectedLocation(result.intent()?.dataString, sourceUri), //
|
||||
R.string.permission_message_export_file, //
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
)
|
||||
}
|
||||
|
||||
@Callback
|
||||
fun copyFileToUserSelectedLocation(result: PermissionsResult, targetUri: String?, sourceUri: String?) {
|
||||
if (result.granted()) {
|
||||
try {
|
||||
copyFile(contentResolverUtil.openInputStream(Uri.parse(sourceUri)), //
|
||||
contentResolverUtil.openOutputStream(Uri.parse(targetUri)))
|
||||
copyFile(
|
||||
contentResolverUtil.openInputStream(Uri.parse(sourceUri)), //
|
||||
contentResolverUtil.openOutputStream(Uri.parse(targetUri))
|
||||
)
|
||||
} catch (e: FileNotFoundException) {
|
||||
showError(e)
|
||||
}
|
||||
@ -142,18 +149,18 @@ class ImagePreviewPresenter @Inject constructor( //
|
||||
fun onDeleteImageConfirmed(imagePreviewFile: ImagePreviewFile, index: Int) {
|
||||
view?.showProgress(ProgressModel.GENERIC)
|
||||
deleteNodesUseCase
|
||||
.withCloudNodes(listOf(imagePreviewFile.cloudFileModel.toCloudNode()))
|
||||
.run(object : ProgressCompletingResultHandler<List<CloudNode?>?>() {
|
||||
override fun onFinished() {
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
view?.onImageDeleted(index)
|
||||
}
|
||||
.withCloudNodes(listOf(imagePreviewFile.cloudFileModel.toCloudNode()))
|
||||
.run(object : ProgressCompletingResultHandler<List<CloudNode?>?>() {
|
||||
override fun onFinished() {
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
view?.onImageDeleted(index)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
Timber.tag("ImagePreviewPresenter").e(e, "Failed to delete preview image")
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
}
|
||||
})
|
||||
override fun onError(e: Throwable) {
|
||||
Timber.tag("ImagePreviewPresenter").e(e, "Failed to delete preview image")
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun onImagePreviewClicked() {
|
||||
@ -167,24 +174,24 @@ class ImagePreviewPresenter @Inject constructor( //
|
||||
|
||||
fun onMissingImagePreviewFile(imagePreviewFile: ImagePreviewFile) {
|
||||
downloadFilesUseCase //
|
||||
.withDownloadFiles(downloadFileUtil.createDownloadFilesFor(this, listOf(imagePreviewFile.cloudFileModel))) //
|
||||
.run(object : DefaultProgressAwareResultHandler<List<CloudFile>, DownloadState>() {
|
||||
override fun onSuccess(result: List<CloudFile>) {
|
||||
cloudFileModelMapper.toModel(result[0])
|
||||
imagePreviewFile.uri = fileUtil.contentUriFor(cloudFileModelMapper.toModel(result[0]))
|
||||
view?.showImagePreview(imagePreviewFile)
|
||||
view?.hideProgressBar(imagePreviewFile)
|
||||
}
|
||||
.withDownloadFiles(downloadFileUtil.createDownloadFilesFor(this, listOf(imagePreviewFile.cloudFileModel))) //
|
||||
.run(object : DefaultProgressAwareResultHandler<List<CloudFile>, DownloadState>() {
|
||||
override fun onSuccess(result: List<CloudFile>) {
|
||||
cloudFileModelMapper.toModel(result[0])
|
||||
imagePreviewFile.uri = fileUtil.contentUriFor(cloudFileModelMapper.toModel(result[0]))
|
||||
view?.showImagePreview(imagePreviewFile)
|
||||
view?.hideProgressBar(imagePreviewFile)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
if (ExceptionUtil.contains(e, IOException::class.java, ExceptionUtil.thatContainsMessage("Stream Closed"))) {
|
||||
// ignore error
|
||||
Timber.tag("ImagePreviewPresenter").d("User swiped to quickly and close the stream before finishing the download.")
|
||||
} else {
|
||||
super.onError(e)
|
||||
}
|
||||
override fun onError(e: Throwable) {
|
||||
if (ExceptionUtil.contains(e, IOException::class.java, ExceptionUtil.thatContainsMessage("Stream Closed"))) {
|
||||
// ignore error
|
||||
Timber.tag("ImagePreviewPresenter").d("User swiped to quickly and close the stream before finishing the download.")
|
||||
} else {
|
||||
super.onError(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun getImagePreviewFileStore(path: String): ImagePreviewFilesStore {
|
||||
|
@ -11,24 +11,25 @@ import javax.inject.Inject
|
||||
import timber.log.Timber
|
||||
|
||||
class LicenseCheckPresenter @Inject internal constructor(
|
||||
exceptionHandlers: ExceptionHandlers, //
|
||||
private val doLicenseCheckUsecase: DoLicenseCheckUseCase, //
|
||||
private val sharedPreferencesHandler: SharedPreferencesHandler) : Presenter<UpdateLicenseView>(exceptionHandlers) {
|
||||
exceptionHandlers: ExceptionHandlers, //
|
||||
private val doLicenseCheckUsecase: DoLicenseCheckUseCase, //
|
||||
private val sharedPreferencesHandler: SharedPreferencesHandler
|
||||
) : Presenter<UpdateLicenseView>(exceptionHandlers) {
|
||||
|
||||
fun validate(data: Uri?) {
|
||||
data?.let {
|
||||
val license = it.fragment ?: it.lastPathSegment ?: ""
|
||||
view?.showOrUpdateLicenseDialog(license)
|
||||
doLicenseCheckUsecase
|
||||
.withLicense(license)
|
||||
.run(CheckLicenseStatusSubscriber())
|
||||
.withLicense(license)
|
||||
.run(CheckLicenseStatusSubscriber())
|
||||
}
|
||||
}
|
||||
|
||||
fun validateDialogAware(license: String?) {
|
||||
doLicenseCheckUsecase
|
||||
.withLicense(license)
|
||||
.run(CheckLicenseStatusSubscriber())
|
||||
.withLicense(license)
|
||||
.run(CheckLicenseStatusSubscriber())
|
||||
}
|
||||
|
||||
private inner class CheckLicenseStatusSubscriber : NoOpResultHandler<LicenseCheck>() {
|
||||
|
@ -76,23 +76,23 @@ abstract class Presenter<V : View> protected constructor(private val exceptionMa
|
||||
|
||||
fun finishWithResult(resultName: String, result: Serializable?) {
|
||||
activeWorkflow()?.dispatch(result)
|
||||
?: run {
|
||||
val data = Intent()
|
||||
when (result) {
|
||||
null -> {
|
||||
activity().setResult(Activity.RESULT_CANCELED)
|
||||
}
|
||||
is Throwable -> {
|
||||
data.putExtra(resultName, result)
|
||||
activity().setResult(Activity.RESULT_CANCELED, data)
|
||||
}
|
||||
else -> {
|
||||
data.putExtra(resultName, result)
|
||||
activity().setResult(Activity.RESULT_OK, data)
|
||||
}
|
||||
?: run {
|
||||
val data = Intent()
|
||||
when (result) {
|
||||
null -> {
|
||||
activity().setResult(Activity.RESULT_CANCELED)
|
||||
}
|
||||
is Throwable -> {
|
||||
data.putExtra(resultName, result)
|
||||
activity().setResult(Activity.RESULT_CANCELED, data)
|
||||
}
|
||||
else -> {
|
||||
data.putExtra(resultName, result)
|
||||
activity().setResult(Activity.RESULT_OK, data)
|
||||
}
|
||||
finish()
|
||||
}
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
private fun activeWorkflow(): Workflow<*>? {
|
||||
|
@ -16,9 +16,10 @@ import javax.inject.Inject
|
||||
|
||||
@PerView
|
||||
class S3AddOrChangePresenter @Inject internal constructor( //
|
||||
private val addOrChangeCloudConnectionUseCase: AddOrChangeCloudConnectionUseCase, //
|
||||
private val connectToS3UseCase: ConnectToS3UseCase, //
|
||||
exceptionMappings: ExceptionHandlers) : Presenter<S3AddOrChangeView>(exceptionMappings) {
|
||||
private val addOrChangeCloudConnectionUseCase: AddOrChangeCloudConnectionUseCase, //
|
||||
private val connectToS3UseCase: ConnectToS3UseCase, //
|
||||
exceptionMappings: ExceptionHandlers
|
||||
) : Presenter<S3AddOrChangeView>(exceptionMappings) {
|
||||
|
||||
fun checkUserInput(accessKey: String, secretKey: String, bucket: String, endpoint: String?, region: String?, cloudId: Long?, displayName: String) {
|
||||
var statusMessage: String? = null
|
||||
@ -48,19 +49,19 @@ class S3AddOrChangePresenter @Inject internal constructor( //
|
||||
|
||||
private fun encrypt(text: String): String {
|
||||
return CredentialCryptor //
|
||||
.getInstance(context()) //
|
||||
.encrypt(text)
|
||||
.getInstance(context()) //
|
||||
.encrypt(text)
|
||||
}
|
||||
|
||||
private fun mapToCloud(accessKey: String, secretKey: String, bucket: String, endpoint: String?, region: String?, cloudId: Long?, displayName: String): S3Cloud {
|
||||
var builder = S3Cloud //
|
||||
.aS3Cloud() //
|
||||
.withAccessKey(accessKey) //
|
||||
.withSecretKey(secretKey) //
|
||||
.withS3Bucket(bucket) //
|
||||
.withS3Endpoint(endpoint) //
|
||||
.withS3Region(region) //
|
||||
.withDisplayName(displayName)
|
||||
.aS3Cloud() //
|
||||
.withAccessKey(accessKey) //
|
||||
.withSecretKey(secretKey) //
|
||||
.withS3Bucket(bucket) //
|
||||
.withS3Endpoint(endpoint) //
|
||||
.withS3Region(region) //
|
||||
.withDisplayName(displayName)
|
||||
|
||||
cloudId?.let { builder = builder.withId(cloudId) }
|
||||
|
||||
@ -74,17 +75,17 @@ class S3AddOrChangePresenter @Inject internal constructor( //
|
||||
private fun authenticate(cloud: S3Cloud) {
|
||||
view?.showProgress(ProgressModel(ProgressStateModel.AUTHENTICATION))
|
||||
connectToS3UseCase //
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onSuccess(void: Void?) {
|
||||
onCloudAuthenticated(cloud)
|
||||
}
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onSuccess(void: Void?) {
|
||||
onCloudAuthenticated(cloud)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
super.onError(e)
|
||||
}
|
||||
})
|
||||
override fun onError(e: Throwable) {
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
super.onError(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun onCloudAuthenticated(cloud: Cloud) {
|
||||
@ -94,8 +95,8 @@ class S3AddOrChangePresenter @Inject internal constructor( //
|
||||
|
||||
private fun save(cloud: Cloud) {
|
||||
addOrChangeCloudConnectionUseCase //
|
||||
.withCloud(cloud) //
|
||||
.run(DefaultResultHandler())
|
||||
.withCloud(cloud) //
|
||||
.run(DefaultResultHandler())
|
||||
}
|
||||
|
||||
init {
|
||||
|
@ -10,8 +10,9 @@ import javax.inject.Inject
|
||||
|
||||
@PerView
|
||||
class SetPasswordPresenter @Inject constructor( //
|
||||
private val createNewVaultWorkflow: CreateNewVaultWorkflow, //
|
||||
exceptionMappings: ExceptionHandlers) : Presenter<SetPasswordView>(exceptionMappings) {
|
||||
private val createNewVaultWorkflow: CreateNewVaultWorkflow, //
|
||||
exceptionMappings: ExceptionHandlers
|
||||
) : Presenter<SetPasswordView>(exceptionMappings) {
|
||||
|
||||
override fun workflows(): Iterable<Workflow<*>> {
|
||||
return setOf(createNewVaultWorkflow)
|
||||
|
@ -39,12 +39,13 @@ import timber.log.Timber
|
||||
|
||||
@PerView
|
||||
class SettingsPresenter @Inject internal constructor(
|
||||
private val updateCheckUseCase: DoUpdateCheckUseCase, //
|
||||
private val updateUseCase: DoUpdateUseCase, //
|
||||
private val networkConnectionCheck: NetworkConnectionCheck, //
|
||||
exceptionMappings: ExceptionHandlers, //
|
||||
private val fileUtil: FileUtil, //
|
||||
private val sharedPreferencesHandler: SharedPreferencesHandler) : Presenter<SettingsView>(exceptionMappings) {
|
||||
private val updateCheckUseCase: DoUpdateCheckUseCase, //
|
||||
private val updateUseCase: DoUpdateUseCase, //
|
||||
private val networkConnectionCheck: NetworkConnectionCheck, //
|
||||
exceptionMappings: ExceptionHandlers, //
|
||||
private val fileUtil: FileUtil, //
|
||||
private val sharedPreferencesHandler: SharedPreferencesHandler
|
||||
) : Presenter<SettingsView>(exceptionMappings) {
|
||||
|
||||
fun onSendErrorReportClicked() {
|
||||
view?.showProgress(ProgressModel.GENERIC)
|
||||
@ -58,11 +59,11 @@ class SettingsPresenter @Inject internal constructor(
|
||||
|
||||
private fun sendErrorReport(attachment: File) {
|
||||
EmailBuilder.anEmail() //
|
||||
.to("support@cryptomator.org") //
|
||||
.withSubject(context().getString(R.string.error_report_subject)) //
|
||||
.withBody(errorReportEmailBody()) //
|
||||
.attach(attachment) //
|
||||
.send(activity())
|
||||
.to("support@cryptomator.org") //
|
||||
.withSubject(context().getString(R.string.error_report_subject)) //
|
||||
.withBody(errorReportEmailBody()) //
|
||||
.attach(attachment) //
|
||||
.send(activity())
|
||||
}
|
||||
|
||||
private fun errorReportEmailBody(): String {
|
||||
@ -76,20 +77,22 @@ class SettingsPresenter @Inject internal constructor(
|
||||
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') //
|
||||
.append(context().getString(R.string.error_report_summary_description)).append("\n\n") //
|
||||
.append("### ").append(context().getString(R.string.error_report_section_device)).append("\n") //
|
||||
.append("Cryptomator v").append(BuildConfig.VERSION_NAME).append(" (").append(BuildConfig.VERSION_CODE).append(") ").append(variant).append("\n") //
|
||||
.append("Android ").append(Build.VERSION.RELEASE).append(" / API").append(Build.VERSION.SDK_INT).append("\n") //
|
||||
.append("Device ").append(Build.MODEL) //
|
||||
.toString()
|
||||
.append("### ").append(context().getString(R.string.error_report_section_summary)).append('\n') //
|
||||
.append(context().getString(R.string.error_report_summary_description)).append("\n\n") //
|
||||
.append("### ").append(context().getString(R.string.error_report_section_device)).append("\n") //
|
||||
.append("Cryptomator v").append(BuildConfig.VERSION_NAME).append(" (").append(BuildConfig.VERSION_CODE).append(") ").append(variant).append("\n") //
|
||||
.append("Android ").append(Build.VERSION.RELEASE).append(" / API").append(Build.VERSION.SDK_INT).append("\n") //
|
||||
.append("Device ").append(Build.MODEL) //
|
||||
.toString()
|
||||
}
|
||||
|
||||
fun grantLocalStoragePermissionForAutoUpload() {
|
||||
requestPermissions(PermissionsResultCallbacks.onLocalStoragePermissionGranted(), //
|
||||
R.string.permission_snackbar_auth_auto_upload, //
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE, //
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
requestPermissions(
|
||||
PermissionsResultCallbacks.onLocalStoragePermissionGranted(), //
|
||||
R.string.permission_snackbar_auth_auto_upload, //
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE, //
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
)
|
||||
}
|
||||
|
||||
@Callback
|
||||
@ -106,23 +109,23 @@ class SettingsPresenter @Inject internal constructor(
|
||||
fun onCheckUpdateClicked() {
|
||||
if (networkConnectionCheck.isPresent) {
|
||||
updateCheckUseCase //
|
||||
.withVersion(BuildConfig.VERSION_NAME)
|
||||
.run(object : NoOpResultHandler<Optional<UpdateCheck?>?>() {
|
||||
override fun onSuccess(result: Optional<UpdateCheck?>?) {
|
||||
if (result?.isPresent == true) {
|
||||
result.get()?.let { updateStatusRetrieved(it, context()) }
|
||||
} else {
|
||||
Timber.tag("SettingsPresenter").i("UpdateCheck finished, latest version")
|
||||
Toast.makeText(context(), getString(R.string.notification_update_check_finished_latest), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
sharedPreferencesHandler.updateExecuted()
|
||||
view?.refreshUpdateTimeView()
|
||||
.withVersion(BuildConfig.VERSION_NAME)
|
||||
.run(object : NoOpResultHandler<Optional<UpdateCheck?>?>() {
|
||||
override fun onSuccess(result: Optional<UpdateCheck?>?) {
|
||||
if (result?.isPresent == true) {
|
||||
result.get()?.let { updateStatusRetrieved(it, context()) }
|
||||
} else {
|
||||
Timber.tag("SettingsPresenter").i("UpdateCheck finished, latest version")
|
||||
Toast.makeText(context(), getString(R.string.notification_update_check_finished_latest), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
sharedPreferencesHandler.updateExecuted()
|
||||
view?.refreshUpdateTimeView()
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
showError(e)
|
||||
}
|
||||
})
|
||||
override fun onError(e: Throwable) {
|
||||
showError(e)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Toast.makeText(context(), R.string.error_update_no_internet, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
@ -145,21 +148,21 @@ class SettingsPresenter @Inject internal constructor(
|
||||
val uri = fileUtil.contentUriForNewTempFile("cryptomator.apk")
|
||||
val file = fileUtil.tempFile("cryptomator.apk")
|
||||
updateUseCase //
|
||||
.withFile(file) //
|
||||
.run(object : NoOpResultHandler<Void?>() {
|
||||
override fun onError(e: Throwable) {
|
||||
showError(e)
|
||||
}
|
||||
.withFile(file) //
|
||||
.run(object : NoOpResultHandler<Void?>() {
|
||||
override fun onError(e: Throwable) {
|
||||
showError(e)
|
||||
}
|
||||
|
||||
override fun onSuccess(result: Void?) {
|
||||
super.onSuccess(result)
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.setDataAndType(uri, "application/vnd.android.package-archive")
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
context().startActivity(intent)
|
||||
}
|
||||
})
|
||||
override fun onSuccess(result: Void?) {
|
||||
super.onSuccess(result)
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.setDataAndType(uri, "application/vnd.android.package-archive")
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
context().startActivity(intent)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private inner class CreateErrorReportArchiveTask : AsyncTask<Void?, IOException?, File?>() {
|
||||
|
@ -32,17 +32,18 @@ import timber.log.Timber
|
||||
|
||||
@PerView
|
||||
class SharedFilesPresenter @Inject constructor( //
|
||||
private val getVaultListUseCase: GetVaultListUseCase, //
|
||||
private val getRootFolderUseCase: GetRootFolderUseCase, //
|
||||
private val getDecryptedCloudForVaultUseCase: GetDecryptedCloudForVaultUseCase, //
|
||||
private val uploadFilesUseCase: UploadFilesUseCase, //
|
||||
private val getCloudListUseCase: GetCloudListUseCase, //
|
||||
private val contentResolverUtil: ContentResolverUtil, //
|
||||
private val fileCacheUtils: FileCacheUtils, //
|
||||
private val authenticationExceptionHandler: AuthenticationExceptionHandler, //
|
||||
private val cloudFolderModelMapper: CloudFolderModelMapper, //
|
||||
private val progressModelMapper: ProgressModelMapper, //
|
||||
exceptionMappings: ExceptionHandlers) : Presenter<SharedFilesView>(exceptionMappings) {
|
||||
private val getVaultListUseCase: GetVaultListUseCase, //
|
||||
private val getRootFolderUseCase: GetRootFolderUseCase, //
|
||||
private val getDecryptedCloudForVaultUseCase: GetDecryptedCloudForVaultUseCase, //
|
||||
private val uploadFilesUseCase: UploadFilesUseCase, //
|
||||
private val getCloudListUseCase: GetCloudListUseCase, //
|
||||
private val contentResolverUtil: ContentResolverUtil, //
|
||||
private val fileCacheUtils: FileCacheUtils, //
|
||||
private val authenticationExceptionHandler: AuthenticationExceptionHandler, //
|
||||
private val cloudFolderModelMapper: CloudFolderModelMapper, //
|
||||
private val progressModelMapper: ProgressModelMapper, //
|
||||
exceptionMappings: ExceptionHandlers
|
||||
) : Presenter<SharedFilesView>(exceptionMappings) {
|
||||
|
||||
private val filesForUpload: MutableSet<UploadFile> = HashSet()
|
||||
private val existingFilesForUpload: MutableSet<UploadFile> = HashSet()
|
||||
@ -65,8 +66,8 @@ class SharedFilesPresenter @Inject constructor( //
|
||||
} else {
|
||||
Timber.tag("SharedFile").i("Received 1 file")
|
||||
contentResolverUtil.fileName(uri)
|
||||
?.let { filesForUpload.add(createUploadFile(it, uri)) }
|
||||
?: Timber.tag("SharedFile").i("The file doesn't have a path in the URI")
|
||||
?.let { filesForUpload.add(createUploadFile(it, uri)) }
|
||||
?: Timber.tag("SharedFile").i("The file doesn't have a path in the URI")
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,8 +75,8 @@ class SharedFilesPresenter @Inject constructor( //
|
||||
Timber.tag("SharedFile").i("Received %d files", uris.size)
|
||||
uris.forEach { uri ->
|
||||
contentResolverUtil.fileName(uri)
|
||||
?.let { filesForUpload.add(createUploadFile(it, uri)) }
|
||||
?: Timber.tag("SharedFile").i("The file doesn't have a path in the URI")
|
||||
?.let { filesForUpload.add(createUploadFile(it, uri)) }
|
||||
?: Timber.tag("SharedFile").i("The file doesn't have a path in the URI")
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,8 +129,9 @@ class SharedFilesPresenter @Inject constructor( //
|
||||
} else {
|
||||
if (!isPaused) {
|
||||
requestActivityResult( //
|
||||
ActivityResultCallbacks.vaultUnlockedSharedFiles(), //
|
||||
Intents.unlockVaultIntent().withVaultModel(VaultModel(authenticatedVault)).withVaultAction(UnlockVaultIntent.VaultAction.UNLOCK))
|
||||
ActivityResultCallbacks.vaultUnlockedSharedFiles(), //
|
||||
Intents.unlockVaultIntent().withVaultModel(VaultModel(authenticatedVault)).withVaultAction(UnlockVaultIntent.VaultAction.UNLOCK)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -146,18 +148,18 @@ class SharedFilesPresenter @Inject constructor( //
|
||||
|
||||
private fun decryptedCloudFor(vault: Vault) {
|
||||
getDecryptedCloudForVaultUseCase //
|
||||
.withVault(vault) //
|
||||
.run(object : DefaultResultHandler<Cloud>() {
|
||||
override fun onSuccess(cloud: Cloud) {
|
||||
rootFolderFor(cloud)
|
||||
}
|
||||
.withVault(vault) //
|
||||
.run(object : DefaultResultHandler<Cloud>() {
|
||||
override fun onSuccess(cloud: Cloud) {
|
||||
rootFolderFor(cloud)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
if (!authenticationExceptionHandler.handleAuthenticationException(this@SharedFilesPresenter, e, ActivityResultCallbacks.decryptedCloudForAfterAuth(vault))) {
|
||||
super.onError(e)
|
||||
}
|
||||
override fun onError(e: Throwable) {
|
||||
if (!authenticationExceptionHandler.handleAuthenticationException(this@SharedFilesPresenter, e, ActivityResultCallbacks.decryptedCloudForAfterAuth(vault))) {
|
||||
super.onError(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Callback
|
||||
@ -168,18 +170,18 @@ class SharedFilesPresenter @Inject constructor( //
|
||||
|
||||
private fun rootFolderFor(cloud: Cloud) {
|
||||
getRootFolderUseCase //
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<CloudFolder>() {
|
||||
override fun onSuccess(folder: CloudFolder) {
|
||||
when (authenticationState) {
|
||||
AuthenticationState.CHOOSE_LOCATION -> navigateToVaultContent((folder.cloud as CryptoCloud).vault, folder)
|
||||
AuthenticationState.INIT_ROOT -> {
|
||||
location = cloudFolderModelMapper.toModel(folder)
|
||||
checkForUsedFileNames(folder)
|
||||
}
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<CloudFolder>() {
|
||||
override fun onSuccess(folder: CloudFolder) {
|
||||
when (authenticationState) {
|
||||
AuthenticationState.CHOOSE_LOCATION -> navigateToVaultContent((folder.cloud as CryptoCloud).vault, folder)
|
||||
AuthenticationState.INIT_ROOT -> {
|
||||
location = cloudFolderModelMapper.toModel(folder)
|
||||
checkForUsedFileNames(folder)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun navigateToVaultContent(vault: Vault, folder: CloudFolder) {
|
||||
@ -192,9 +194,11 @@ class SharedFilesPresenter @Inject constructor( //
|
||||
this.location = location
|
||||
}
|
||||
|
||||
private fun uploadFiles(nonReplacing: Set<UploadFile>, //
|
||||
replacing: Set<UploadFile>, //
|
||||
folder: CloudFolder) {
|
||||
private fun uploadFiles(
|
||||
nonReplacing: Set<UploadFile>, //
|
||||
replacing: Set<UploadFile>, //
|
||||
folder: CloudFolder
|
||||
) {
|
||||
if (nonReplacing.size + replacing.size == 0) {
|
||||
view?.finish()
|
||||
}
|
||||
@ -207,17 +211,17 @@ class SharedFilesPresenter @Inject constructor( //
|
||||
|
||||
private fun uploadFiles(folder: CloudFolder, files: List<UploadFile>) {
|
||||
uploadFilesUseCase //
|
||||
.withParent(folder) //
|
||||
.andFiles(files) //
|
||||
.run(object : DefaultProgressAwareResultHandler<List<CloudFile>, UploadState>() {
|
||||
override fun onProgress(progress: Progress<UploadState>) {
|
||||
view?.showProgress(progressModelMapper.toModel(progress))
|
||||
}
|
||||
.withParent(folder) //
|
||||
.andFiles(files) //
|
||||
.run(object : DefaultProgressAwareResultHandler<List<CloudFile>, UploadState>() {
|
||||
override fun onProgress(progress: Progress<UploadState>) {
|
||||
view?.showProgress(progressModelMapper.toModel(progress))
|
||||
}
|
||||
|
||||
override fun onFinished() {
|
||||
onFileUploadCompleted()
|
||||
}
|
||||
})
|
||||
override fun onFinished() {
|
||||
onFileUploadCompleted()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun onFileUploadCompleted() {
|
||||
@ -248,12 +252,12 @@ class SharedFilesPresenter @Inject constructor( //
|
||||
private fun checkForUsedFileNames(folder: CloudFolder) {
|
||||
view?.showProgress(ProgressModel.GENERIC)
|
||||
getCloudListUseCase //
|
||||
.withFolder(folder) //
|
||||
.run(object : DefaultResultHandler<List<CloudNode>>() {
|
||||
override fun onSuccess(currentCloudNodes: List<CloudNode>) {
|
||||
checkForExistingFilesOrUploadFiles(folder, currentCloudNodes)
|
||||
}
|
||||
})
|
||||
.withFolder(folder) //
|
||||
.run(object : DefaultResultHandler<List<CloudNode>>() {
|
||||
override fun onSuccess(currentCloudNodes: List<CloudNode>) {
|
||||
checkForExistingFilesOrUploadFiles(folder, currentCloudNodes)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun hasUsedFileNamesAtLocation(currentCloudNodes: List<CloudNode>): Boolean {
|
||||
@ -264,9 +268,10 @@ class SharedFilesPresenter @Inject constructor( //
|
||||
if (cloudNode is CloudFile) {
|
||||
filesForUpload.remove(uploadFileWithName.get())
|
||||
existingFilesForUpload.add( //
|
||||
UploadFile.aCopyOf(uploadFileWithName.get()) //
|
||||
.thatIsReplacing(true) //
|
||||
.build())
|
||||
UploadFile.aCopyOf(uploadFileWithName.get()) //
|
||||
.thatIsReplacing(true) //
|
||||
.build()
|
||||
)
|
||||
} else {
|
||||
// remove file when name is used by a folder
|
||||
filesForUpload.remove(uploadFileWithName.get())
|
||||
@ -278,9 +283,9 @@ class SharedFilesPresenter @Inject constructor( //
|
||||
|
||||
private fun fileForUploadWithName(name: String): Optional<UploadFile> {
|
||||
return filesForUpload
|
||||
.firstOrNull { it.fileName == name }
|
||||
?.let { Optional.of(it) }
|
||||
?: Optional.empty()
|
||||
.firstOrNull { it.fileName == name }
|
||||
?.let { Optional.of(it) }
|
||||
?: Optional.empty()
|
||||
}
|
||||
|
||||
private fun checkForExistingFilesOrUploadFiles(folder: CloudFolder, currentCloudNodes: List<CloudNode>) {
|
||||
@ -297,7 +302,7 @@ class SharedFilesPresenter @Inject constructor( //
|
||||
|
||||
private fun prepareSavingFiles() {
|
||||
location?.let { checkForUsedFileNames(it.toCloudNode()) }
|
||||
?: authenticate(selectedVault, AuthenticationState.INIT_ROOT)
|
||||
?: authenticate(selectedVault, AuthenticationState.INIT_ROOT)
|
||||
}
|
||||
|
||||
fun onSaveButtonPressed(filesForUpload: List<SharedFileModel>) {
|
||||
@ -310,9 +315,11 @@ class SharedFilesPresenter @Inject constructor( //
|
||||
view?.showMessage(R.string.error_names_contains_invalid_characters)
|
||||
}
|
||||
else -> {
|
||||
requestPermissions(PermissionsResultCallbacks.saveFilesPermissionCallback(), //
|
||||
R.string.permission_message_share_file, //
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
requestPermissions(
|
||||
PermissionsResultCallbacks.saveFilesPermissionCallback(), //
|
||||
R.string.permission_message_share_file, //
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -335,17 +342,19 @@ class SharedFilesPresenter @Inject constructor( //
|
||||
|
||||
private fun navigateToVaultContent(vaultModel: VaultModel, decryptedRoot: CloudFolderModel) {
|
||||
requestActivityResult( //
|
||||
ActivityResultCallbacks.onChooseLocation(vaultModel), //
|
||||
Intents.browseFilesIntent() //
|
||||
.withFolder(decryptedRoot) //
|
||||
.withTitle(vaultModel.name) //
|
||||
.withChooseCloudNodeSettings( //
|
||||
ChooseCloudNodeSettings.chooseCloudNodeSettings() //
|
||||
.withExtraTitle(context().getString(R.string.screen_file_browser_share_destination_title)) //
|
||||
.withExtraToolbarIcon(R.drawable.ic_clear) //
|
||||
.withButtonText(context().getString(R.string.screen_file_browser_share_button_text)) //
|
||||
.selectingFolders() //
|
||||
.build()))
|
||||
ActivityResultCallbacks.onChooseLocation(vaultModel), //
|
||||
Intents.browseFilesIntent() //
|
||||
.withFolder(decryptedRoot) //
|
||||
.withTitle(vaultModel.name) //
|
||||
.withChooseCloudNodeSettings( //
|
||||
ChooseCloudNodeSettings.chooseCloudNodeSettings() //
|
||||
.withExtraTitle(context().getString(R.string.screen_file_browser_share_destination_title)) //
|
||||
.withExtraToolbarIcon(R.drawable.ic_clear) //
|
||||
.withButtonText(context().getString(R.string.screen_file_browser_share_button_text)) //
|
||||
.selectingFolders() //
|
||||
.build()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Callback
|
||||
@ -396,18 +405,19 @@ class SharedFilesPresenter @Inject constructor( //
|
||||
|
||||
private fun createUploadFile(fileName: String, uri: Uri): UploadFile {
|
||||
return UploadFile.anUploadFile() //
|
||||
.withFileName(fileName) //
|
||||
.withDataSource(UriBasedDataSource.from(uri)) //
|
||||
.thatIsReplacing(false) //
|
||||
.build()
|
||||
.withFileName(fileName) //
|
||||
.withDataSource(UriBasedDataSource.from(uri)) //
|
||||
.thatIsReplacing(false) //
|
||||
.build()
|
||||
}
|
||||
|
||||
init {
|
||||
unsubscribeOnDestroy( //
|
||||
getRootFolderUseCase, //
|
||||
getVaultListUseCase, //
|
||||
getDecryptedCloudForVaultUseCase, //
|
||||
uploadFilesUseCase, //
|
||||
getCloudListUseCase)
|
||||
getRootFolderUseCase, //
|
||||
getVaultListUseCase, //
|
||||
getDecryptedCloudForVaultUseCase, //
|
||||
uploadFilesUseCase, //
|
||||
getCloudListUseCase
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -21,11 +21,12 @@ import javax.inject.Inject
|
||||
|
||||
@PerView
|
||||
class TextEditorPresenter @Inject constructor( //
|
||||
private val fileCacheUtils: FileCacheUtils, //
|
||||
private val fileUtil: FileUtil, //
|
||||
private val contentResolverUtil: ContentResolverUtil, //
|
||||
private val uploadFilesUseCase: UploadFilesUseCase, //
|
||||
exceptionMappings: ExceptionHandlers) : Presenter<TextEditorView>(exceptionMappings) {
|
||||
private val fileCacheUtils: FileCacheUtils, //
|
||||
private val fileUtil: FileUtil, //
|
||||
private val contentResolverUtil: ContentResolverUtil, //
|
||||
private val uploadFilesUseCase: UploadFilesUseCase, //
|
||||
exceptionMappings: ExceptionHandlers
|
||||
) : Presenter<TextEditorView>(exceptionMappings) {
|
||||
|
||||
private val textFile = AtomicReference<CloudFileModel>()
|
||||
|
||||
@ -64,34 +65,36 @@ class TextEditorPresenter @Inject constructor( //
|
||||
view?.let {
|
||||
it.showProgress(ProgressModel.GENERIC)
|
||||
val uri = fileCacheUtils.tmpFile() //
|
||||
.withContent(it.textFileContent) //
|
||||
.create()
|
||||
.withContent(it.textFileContent) //
|
||||
.create()
|
||||
uploadFile(textFile.get().name, UriBasedDataSource.from(uri))
|
||||
}
|
||||
}
|
||||
|
||||
private fun uploadFile(fileName: String, dataSource: DataSource) {
|
||||
uploadFilesUseCase //
|
||||
.withParent(textFile.get().parent.toCloudNode()) //
|
||||
.andFiles(listOf( //
|
||||
UploadFile.anUploadFile() //
|
||||
.withFileName(fileName) //
|
||||
.withDataSource(dataSource) //
|
||||
.thatIsReplacing(true) //
|
||||
.build() //
|
||||
)) //
|
||||
.run(object : DefaultProgressAwareResultHandler<List<CloudFile?>, UploadState>() {
|
||||
override fun onFinished() {
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
view?.finish()
|
||||
view?.showMessage(R.string.screen_text_editor_save_success)
|
||||
}
|
||||
.withParent(textFile.get().parent.toCloudNode()) //
|
||||
.andFiles(
|
||||
listOf( //
|
||||
UploadFile.anUploadFile() //
|
||||
.withFileName(fileName) //
|
||||
.withDataSource(dataSource) //
|
||||
.thatIsReplacing(true) //
|
||||
.build() //
|
||||
)
|
||||
) //
|
||||
.run(object : DefaultProgressAwareResultHandler<List<CloudFile?>, UploadState>() {
|
||||
override fun onFinished() {
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
view?.finish()
|
||||
view?.showMessage(R.string.screen_text_editor_save_success)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
showError(e)
|
||||
}
|
||||
})
|
||||
override fun onError(e: Throwable) {
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
showError(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun loadFileContent() {
|
||||
|
@ -40,17 +40,18 @@ import timber.log.Timber
|
||||
|
||||
@PerView
|
||||
class UnlockVaultPresenter @Inject constructor(
|
||||
private val changePasswordUseCase: ChangePasswordUseCase,
|
||||
private val deleteVaultUseCase: DeleteVaultUseCase,
|
||||
private val getUnverifiedVaultConfigUseCase: GetUnverifiedVaultConfigUseCase,
|
||||
private val lockVaultUseCase: LockVaultUseCase,
|
||||
private val unlockVaultUsingMasterkeyUseCase: UnlockVaultUsingMasterkeyUseCase,
|
||||
private val prepareUnlockUseCase: PrepareUnlockUseCase,
|
||||
private val removeStoredVaultPasswordsUseCase: RemoveStoredVaultPasswordsUseCase,
|
||||
private val saveVaultUseCase: SaveVaultUseCase,
|
||||
private val authenticationExceptionHandler: AuthenticationExceptionHandler,
|
||||
private val sharedPreferencesHandler: SharedPreferencesHandler,
|
||||
exceptionMappings: ExceptionHandlers) : Presenter<UnlockVaultView>(exceptionMappings) {
|
||||
private val changePasswordUseCase: ChangePasswordUseCase,
|
||||
private val deleteVaultUseCase: DeleteVaultUseCase,
|
||||
private val getUnverifiedVaultConfigUseCase: GetUnverifiedVaultConfigUseCase,
|
||||
private val lockVaultUseCase: LockVaultUseCase,
|
||||
private val unlockVaultUsingMasterkeyUseCase: UnlockVaultUsingMasterkeyUseCase,
|
||||
private val prepareUnlockUseCase: PrepareUnlockUseCase,
|
||||
private val removeStoredVaultPasswordsUseCase: RemoveStoredVaultPasswordsUseCase,
|
||||
private val saveVaultUseCase: SaveVaultUseCase,
|
||||
private val authenticationExceptionHandler: AuthenticationExceptionHandler,
|
||||
private val sharedPreferencesHandler: SharedPreferencesHandler,
|
||||
exceptionMappings: ExceptionHandlers
|
||||
) : Presenter<UnlockVaultView>(exceptionMappings) {
|
||||
|
||||
private var startedUsingPrepareUnlock = false
|
||||
private var retryUnlockHandler: Handler? = null
|
||||
@ -77,27 +78,27 @@ class UnlockVaultPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
getUnverifiedVaultConfigUseCase
|
||||
.withVault(intent.vaultModel().toVault())
|
||||
.run(object : DefaultResultHandler<Optional<UnverifiedVaultConfig>>() {
|
||||
override fun onSuccess(unverifiedVaultConfig: Optional<UnverifiedVaultConfig>) {
|
||||
if (unverifiedVaultConfig.isAbsent || unverifiedVaultConfig.get().keyId.scheme == CryptoConstants.MASTERKEY_SCHEME) {
|
||||
when (intent.vaultAction()) {
|
||||
UnlockVaultIntent.VaultAction.UNLOCK, UnlockVaultIntent.VaultAction.UNLOCK_FOR_BIOMETRIC_AUTH -> {
|
||||
startedUsingPrepareUnlock = sharedPreferencesHandler.backgroundUnlockPreparation()
|
||||
pendingUnlockFor(intent.vaultModel().toVault())?.unverifiedVaultConfig = unverifiedVaultConfig.orElse(null)
|
||||
unlockVault(intent.vaultModel())
|
||||
}
|
||||
UnlockVaultIntent.VaultAction.CHANGE_PASSWORD -> view?.showChangePasswordDialog(intent.vaultModel(), unverifiedVaultConfig.orElse(null))
|
||||
else -> TODO("Not yet implemented")
|
||||
.withVault(intent.vaultModel().toVault())
|
||||
.run(object : DefaultResultHandler<Optional<UnverifiedVaultConfig>>() {
|
||||
override fun onSuccess(unverifiedVaultConfig: Optional<UnverifiedVaultConfig>) {
|
||||
if (unverifiedVaultConfig.isAbsent || unverifiedVaultConfig.get().keyId.scheme == CryptoConstants.MASTERKEY_SCHEME) {
|
||||
when (intent.vaultAction()) {
|
||||
UnlockVaultIntent.VaultAction.UNLOCK, UnlockVaultIntent.VaultAction.UNLOCK_FOR_BIOMETRIC_AUTH -> {
|
||||
startedUsingPrepareUnlock = sharedPreferencesHandler.backgroundUnlockPreparation()
|
||||
pendingUnlockFor(intent.vaultModel().toVault())?.unverifiedVaultConfig = unverifiedVaultConfig.orElse(null)
|
||||
unlockVault(intent.vaultModel())
|
||||
}
|
||||
UnlockVaultIntent.VaultAction.CHANGE_PASSWORD -> view?.showChangePasswordDialog(intent.vaultModel(), unverifiedVaultConfig.orElse(null))
|
||||
else -> TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
super.onError(e)
|
||||
finishWithResult(null)
|
||||
}
|
||||
})
|
||||
override fun onError(e: Throwable) {
|
||||
super.onError(e)
|
||||
finishWithResult(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun unlockVault(vaultModel: VaultModel) {
|
||||
@ -134,8 +135,8 @@ class UnlockVaultPresenter @Inject constructor(
|
||||
|
||||
private fun canUseBiometricOn(vault: VaultModel): Boolean {
|
||||
return vault.password != null && BiometricManager //
|
||||
.from(context()) //
|
||||
.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_SUCCESS
|
||||
.from(context()) //
|
||||
.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_SUCCESS
|
||||
}
|
||||
|
||||
fun onUnlockCanceled() {
|
||||
@ -146,31 +147,31 @@ class UnlockVaultPresenter @Inject constructor(
|
||||
|
||||
fun startPrepareUnlockUseCase(vault: Vault) {
|
||||
prepareUnlockUseCase //
|
||||
.withVault(vault) //
|
||||
.andUnverifiedVaultConfig(Optional.ofNullable(pendingUnlockFor(intent.vaultModel().toVault())?.unverifiedVaultConfig))
|
||||
.run(object : DefaultResultHandler<UnlockToken>() {
|
||||
override fun onSuccess(unlockToken: UnlockToken) {
|
||||
if (!startedUsingPrepareUnlock && vault.password != null) {
|
||||
doUnlock(unlockToken, vault.password, pendingUnlockFor(intent.vaultModel().toVault())?.unverifiedVaultConfig)
|
||||
} else {
|
||||
unlockTokenObtained(unlockToken)
|
||||
}
|
||||
.withVault(vault) //
|
||||
.andUnverifiedVaultConfig(Optional.ofNullable(pendingUnlockFor(intent.vaultModel().toVault())?.unverifiedVaultConfig))
|
||||
.run(object : DefaultResultHandler<UnlockToken>() {
|
||||
override fun onSuccess(unlockToken: UnlockToken) {
|
||||
if (!startedUsingPrepareUnlock && vault.password != null) {
|
||||
doUnlock(unlockToken, vault.password, pendingUnlockFor(intent.vaultModel().toVault())?.unverifiedVaultConfig)
|
||||
} else {
|
||||
unlockTokenObtained(unlockToken)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
if (e is AuthenticationException) {
|
||||
view?.cancelBasicAuthIfRunning()
|
||||
}
|
||||
if (!authenticationExceptionHandler.handleAuthenticationException(this@UnlockVaultPresenter, e, ActivityResultCallbacks.authenticatedAfterUnlock(vault))) {
|
||||
super.onError(e)
|
||||
if (e is NetworkConnectionException) {
|
||||
running = true
|
||||
retryUnlockHandler = Handler()
|
||||
restartUnlockUseCase(vault)
|
||||
}
|
||||
override fun onError(e: Throwable) {
|
||||
if (e is AuthenticationException) {
|
||||
view?.cancelBasicAuthIfRunning()
|
||||
}
|
||||
if (!authenticationExceptionHandler.handleAuthenticationException(this@UnlockVaultPresenter, e, ActivityResultCallbacks.authenticatedAfterUnlock(vault))) {
|
||||
super.onError(e)
|
||||
if (e is NetworkConnectionException) {
|
||||
running = true
|
||||
retryUnlockHandler = Handler()
|
||||
restartUnlockUseCase(vault)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Callback(dispatchResultOkOnly = false)
|
||||
@ -197,22 +198,22 @@ class UnlockVaultPresenter @Inject constructor(
|
||||
retryUnlockHandler?.postDelayed({
|
||||
if (running) {
|
||||
prepareUnlockUseCase //
|
||||
.withVault(vault) //
|
||||
.run(object : DefaultResultHandler<UnlockToken>() {
|
||||
override fun onSuccess(unlockToken: UnlockToken) {
|
||||
if (!startedUsingPrepareUnlock && vault.password != null) {
|
||||
doUnlock(unlockToken, vault.password, pendingUnlockFor(intent.vaultModel().toVault())?.unverifiedVaultConfig)
|
||||
} else {
|
||||
unlockTokenObtained(unlockToken)
|
||||
}
|
||||
.withVault(vault) //
|
||||
.run(object : DefaultResultHandler<UnlockToken>() {
|
||||
override fun onSuccess(unlockToken: UnlockToken) {
|
||||
if (!startedUsingPrepareUnlock && vault.password != null) {
|
||||
doUnlock(unlockToken, vault.password, pendingUnlockFor(intent.vaultModel().toVault())?.unverifiedVaultConfig)
|
||||
} else {
|
||||
unlockTokenObtained(unlockToken)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
if (e is NetworkConnectionException) {
|
||||
restartUnlockUseCase(vault)
|
||||
}
|
||||
override fun onError(e: Throwable) {
|
||||
if (e is NetworkConnectionException) {
|
||||
restartUnlockUseCase(vault)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
@ -228,28 +229,28 @@ class UnlockVaultPresenter @Inject constructor(
|
||||
|
||||
private fun doUnlock(token: UnlockToken, password: String, unverifiedVaultConfig: UnverifiedVaultConfig?) {
|
||||
unlockVaultUsingMasterkeyUseCase //
|
||||
.withVaultOrUnlockToken(VaultOrUnlockToken.from(token)) //
|
||||
.andUnverifiedVaultConfig(Optional.ofNullable(unverifiedVaultConfig)) //
|
||||
.andPassword(password) //
|
||||
.run(object : DefaultResultHandler<Cloud>() {
|
||||
override fun onSuccess(cloud: Cloud) {
|
||||
when (intent.vaultAction()) {
|
||||
UnlockVaultIntent.VaultAction.ENCRYPT_PASSWORD, UnlockVaultIntent.VaultAction.UNLOCK_FOR_BIOMETRIC_AUTH -> {
|
||||
handleUnlockVaultSuccess(token.vault, cloud, password)
|
||||
}
|
||||
UnlockVaultIntent.VaultAction.UNLOCK -> finishWithResult(cloud)
|
||||
else -> TODO("Not yet implemented")
|
||||
.withVaultOrUnlockToken(VaultOrUnlockToken.from(token)) //
|
||||
.andUnverifiedVaultConfig(Optional.ofNullable(unverifiedVaultConfig)) //
|
||||
.andPassword(password) //
|
||||
.run(object : DefaultResultHandler<Cloud>() {
|
||||
override fun onSuccess(cloud: Cloud) {
|
||||
when (intent.vaultAction()) {
|
||||
UnlockVaultIntent.VaultAction.ENCRYPT_PASSWORD, UnlockVaultIntent.VaultAction.UNLOCK_FOR_BIOMETRIC_AUTH -> {
|
||||
handleUnlockVaultSuccess(token.vault, cloud, password)
|
||||
}
|
||||
UnlockVaultIntent.VaultAction.UNLOCK -> finishWithResult(cloud)
|
||||
else -> TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
super.onError(e)
|
||||
// finish in case of biometric auth, otherwise show error in dialog
|
||||
if(view?.isShowingDialog(EnterPasswordDialog::class) == false) {
|
||||
finishWithResult(null)
|
||||
}
|
||||
override fun onError(e: Throwable) {
|
||||
super.onError(e)
|
||||
// finish in case of biometric auth, otherwise show error in dialog
|
||||
if (view?.isShowingDialog(EnterPasswordDialog::class) == false) {
|
||||
finishWithResult(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun handleUnlockVaultSuccess(vault: Vault, cloud: Cloud, password: String) {
|
||||
@ -295,12 +296,12 @@ class UnlockVaultPresenter @Inject constructor(
|
||||
}
|
||||
UnlockVaultIntent.VaultAction.CHANGE_PASSWORD -> {
|
||||
saveVaultUseCase //
|
||||
.withVault(vaultModel.toVault()) //
|
||||
.run(object : DefaultResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
finishWithResult(vaultModel)
|
||||
}
|
||||
})
|
||||
.withVault(vaultModel.toVault()) //
|
||||
.run(object : DefaultResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
finishWithResult(vaultModel)
|
||||
}
|
||||
})
|
||||
}
|
||||
else -> TODO("Not yet implemented")
|
||||
}
|
||||
@ -309,31 +310,36 @@ class UnlockVaultPresenter @Inject constructor(
|
||||
fun onChangePasswordClick(vaultModel: VaultModel, unverifiedVaultConfig: UnverifiedVaultConfig?, oldPassword: String, newPassword: String) {
|
||||
view?.showProgress(ProgressModel(ProgressStateModel.CHANGING_PASSWORD))
|
||||
changePasswordUseCase.withVault(vaultModel.toVault()) //
|
||||
.andUnverifiedVaultConfig(Optional.ofNullable(unverifiedVaultConfig)) //
|
||||
.andOldPassword(oldPassword) //
|
||||
.andNewPassword(newPassword) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onSuccess(void: Void?) {
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
view?.showMessage(R.string.screen_vault_list_change_password_successful)
|
||||
if (canUseBiometricOn(vaultModel)) {
|
||||
view?.getEncryptedPasswordWithBiometricAuthentication(VaultModel( //
|
||||
Vault.aCopyOf(vaultModel.toVault()) //
|
||||
.withSavedPassword(newPassword) //
|
||||
.build()))
|
||||
} else {
|
||||
finishWithResult(vaultModel)
|
||||
}
|
||||
.andUnverifiedVaultConfig(Optional.ofNullable(unverifiedVaultConfig)) //
|
||||
.andOldPassword(oldPassword) //
|
||||
.andNewPassword(newPassword) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onSuccess(void: Void?) {
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
view?.showMessage(R.string.screen_vault_list_change_password_successful)
|
||||
if (canUseBiometricOn(vaultModel)) {
|
||||
view?.getEncryptedPasswordWithBiometricAuthentication(
|
||||
VaultModel( //
|
||||
Vault.aCopyOf(vaultModel.toVault()) //
|
||||
.withSavedPassword(newPassword) //
|
||||
.build()
|
||||
)
|
||||
)
|
||||
} else {
|
||||
finishWithResult(vaultModel)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
if (!authenticationExceptionHandler.handleAuthenticationException( //
|
||||
this@UnlockVaultPresenter, e, //
|
||||
ActivityResultCallbacks.changePasswordAfterAuthentication(vaultModel.toVault(), unverifiedVaultConfig, oldPassword, newPassword))) {
|
||||
showError(e)
|
||||
}
|
||||
override fun onError(e: Throwable) {
|
||||
if (!authenticationExceptionHandler.handleAuthenticationException( //
|
||||
this@UnlockVaultPresenter, e, //
|
||||
ActivityResultCallbacks.changePasswordAfterAuthentication(vaultModel.toVault(), unverifiedVaultConfig, oldPassword, newPassword)
|
||||
)
|
||||
) {
|
||||
showError(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Callback
|
||||
@ -346,22 +352,22 @@ class UnlockVaultPresenter @Inject constructor(
|
||||
fun saveVaultAfterChangePasswordButFailedBiometricAuth(vault: Vault) {
|
||||
Timber.tag("UnlockVaultPresenter").e("Save vault without password because biometric auth failed after changing vault password")
|
||||
saveVaultUseCase //
|
||||
.withVault(vault) //
|
||||
.run(object : DefaultResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
finishWithResult(vault)
|
||||
}
|
||||
})
|
||||
.withVault(vault) //
|
||||
.run(object : DefaultResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
finishWithResult(vault)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun onDeleteMissingVaultClicked(vault: Vault) {
|
||||
deleteVaultUseCase //
|
||||
.withVault(vault) //
|
||||
.run(object : DefaultResultHandler<Long>() {
|
||||
override fun onSuccess(vaultId: Long) {
|
||||
finishWithResult(null)
|
||||
}
|
||||
})
|
||||
.withVault(vault) //
|
||||
.run(object : DefaultResultHandler<Long>() {
|
||||
override fun onSuccess(vaultId: Long) {
|
||||
finishWithResult(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun onCancelMissingVaultClicked(vault: Vault) {
|
||||
@ -410,14 +416,15 @@ class UnlockVaultPresenter @Inject constructor(
|
||||
|
||||
init {
|
||||
unsubscribeOnDestroy( //
|
||||
changePasswordUseCase, //
|
||||
deleteVaultUseCase, //
|
||||
getUnverifiedVaultConfigUseCase, //
|
||||
lockVaultUseCase, //
|
||||
unlockVaultUsingMasterkeyUseCase, //
|
||||
prepareUnlockUseCase, //
|
||||
removeStoredVaultPasswordsUseCase, //
|
||||
saveVaultUseCase)
|
||||
changePasswordUseCase, //
|
||||
deleteVaultUseCase, //
|
||||
getUnverifiedVaultConfigUseCase, //
|
||||
lockVaultUseCase, //
|
||||
unlockVaultUsingMasterkeyUseCase, //
|
||||
prepareUnlockUseCase, //
|
||||
removeStoredVaultPasswordsUseCase, //
|
||||
saveVaultUseCase
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -61,25 +61,26 @@ import timber.log.Timber
|
||||
|
||||
@PerView
|
||||
class VaultListPresenter @Inject constructor( //
|
||||
private val getVaultListUseCase: GetVaultListUseCase, //
|
||||
private val deleteVaultUseCase: DeleteVaultUseCase, //
|
||||
private val renameVaultUseCase: RenameVaultUseCase, //
|
||||
private val lockVaultUseCase: LockVaultUseCase, //
|
||||
private val getDecryptedCloudForVaultUseCase: GetDecryptedCloudForVaultUseCase, //
|
||||
private val getRootFolderUseCase: GetRootFolderUseCase, //
|
||||
private val addExistingVaultWorkflow: AddExistingVaultWorkflow, //
|
||||
private val createNewVaultWorkflow: CreateNewVaultWorkflow, //
|
||||
private val saveVaultUseCase: SaveVaultUseCase, //
|
||||
private val moveVaultPositionUseCase: MoveVaultPositionUseCase, //
|
||||
private val licenseCheckUseCase: DoLicenseCheckUseCase, //
|
||||
private val updateCheckUseCase: DoUpdateCheckUseCase, //
|
||||
private val updateUseCase: DoUpdateUseCase, //
|
||||
private val networkConnectionCheck: NetworkConnectionCheck, //
|
||||
private val fileUtil: FileUtil, //
|
||||
private val authenticationExceptionHandler: AuthenticationExceptionHandler, //
|
||||
private val cloudFolderModelMapper: CloudFolderModelMapper, //
|
||||
private val sharedPreferencesHandler: SharedPreferencesHandler, //
|
||||
exceptionMappings: ExceptionHandlers) : Presenter<VaultListView>(exceptionMappings) {
|
||||
private val getVaultListUseCase: GetVaultListUseCase, //
|
||||
private val deleteVaultUseCase: DeleteVaultUseCase, //
|
||||
private val renameVaultUseCase: RenameVaultUseCase, //
|
||||
private val lockVaultUseCase: LockVaultUseCase, //
|
||||
private val getDecryptedCloudForVaultUseCase: GetDecryptedCloudForVaultUseCase, //
|
||||
private val getRootFolderUseCase: GetRootFolderUseCase, //
|
||||
private val addExistingVaultWorkflow: AddExistingVaultWorkflow, //
|
||||
private val createNewVaultWorkflow: CreateNewVaultWorkflow, //
|
||||
private val saveVaultUseCase: SaveVaultUseCase, //
|
||||
private val moveVaultPositionUseCase: MoveVaultPositionUseCase, //
|
||||
private val licenseCheckUseCase: DoLicenseCheckUseCase, //
|
||||
private val updateCheckUseCase: DoUpdateCheckUseCase, //
|
||||
private val updateUseCase: DoUpdateUseCase, //
|
||||
private val networkConnectionCheck: NetworkConnectionCheck, //
|
||||
private val fileUtil: FileUtil, //
|
||||
private val authenticationExceptionHandler: AuthenticationExceptionHandler, //
|
||||
private val cloudFolderModelMapper: CloudFolderModelMapper, //
|
||||
private val sharedPreferencesHandler: SharedPreferencesHandler, //
|
||||
exceptionMappings: ExceptionHandlers
|
||||
) : Presenter<VaultListView>(exceptionMappings) {
|
||||
|
||||
private var vaultAction: VaultAction? = null
|
||||
|
||||
@ -107,56 +108,56 @@ class VaultListPresenter @Inject constructor( //
|
||||
private fun checkLicense() {
|
||||
if (BuildConfig.FLAVOR == "apkstore" || BuildConfig.FLAVOR == "fdroid") {
|
||||
licenseCheckUseCase //
|
||||
.withLicense("") //
|
||||
.run(object : NoOpResultHandler<LicenseCheck>() {
|
||||
override fun onSuccess(licenseCheck: LicenseCheck) {
|
||||
if (BuildConfig.FLAVOR == "apkstore" && sharedPreferencesHandler.doUpdate()) {
|
||||
checkForAppUpdates()
|
||||
}
|
||||
.withLicense("") //
|
||||
.run(object : NoOpResultHandler<LicenseCheck>() {
|
||||
override fun onSuccess(licenseCheck: LicenseCheck) {
|
||||
if (BuildConfig.FLAVOR == "apkstore" && sharedPreferencesHandler.doUpdate()) {
|
||||
checkForAppUpdates()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
var license: String? = ""
|
||||
if (e is LicenseNotValidException) {
|
||||
license = e.license
|
||||
}
|
||||
val intent = Intent(context(), LicenseCheckActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
intent.data = Uri.parse(String.format("app://cryptomator/%s", license))
|
||||
|
||||
try {
|
||||
context().startActivity(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Toast.makeText(context(), "Please contact the support.", Toast.LENGTH_LONG).show()
|
||||
finish()
|
||||
}
|
||||
override fun onError(e: Throwable) {
|
||||
var license: String? = ""
|
||||
if (e is LicenseNotValidException) {
|
||||
license = e.license
|
||||
}
|
||||
})
|
||||
val intent = Intent(context(), LicenseCheckActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
intent.data = Uri.parse(String.format("app://cryptomator/%s", license))
|
||||
|
||||
try {
|
||||
context().startActivity(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Toast.makeText(context(), "Please contact the support.", Toast.LENGTH_LONG).show()
|
||||
finish()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkForAppUpdates() {
|
||||
if (networkConnectionCheck.isPresent) {
|
||||
updateCheckUseCase //
|
||||
.withVersion(BuildConfig.VERSION_NAME) //
|
||||
.run(object : NoOpResultHandler<Optional<UpdateCheck>>() {
|
||||
override fun onSuccess(updateCheck: Optional<UpdateCheck>) {
|
||||
if (updateCheck.isPresent) {
|
||||
updateStatusRetrieved(updateCheck.get(), context())
|
||||
} else {
|
||||
Timber.tag("VaultListPresenter").i("UpdateCheck finished, latest version")
|
||||
}
|
||||
sharedPreferencesHandler.updateExecuted()
|
||||
.withVersion(BuildConfig.VERSION_NAME) //
|
||||
.run(object : NoOpResultHandler<Optional<UpdateCheck>>() {
|
||||
override fun onSuccess(updateCheck: Optional<UpdateCheck>) {
|
||||
if (updateCheck.isPresent) {
|
||||
updateStatusRetrieved(updateCheck.get(), context())
|
||||
} else {
|
||||
Timber.tag("VaultListPresenter").i("UpdateCheck finished, latest version")
|
||||
}
|
||||
sharedPreferencesHandler.updateExecuted()
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
if (e is SSLHandshakePreAndroid5UpdateCheckException) {
|
||||
Timber.tag("SettingsPresenter").e(e, "Update check failed due to Android pre 5 and SSL Handshake not accepted")
|
||||
} else {
|
||||
showError(e)
|
||||
}
|
||||
override fun onError(e: Throwable) {
|
||||
if (e is SSLHandshakePreAndroid5UpdateCheckException) {
|
||||
Timber.tag("SettingsPresenter").e(e, "Update check failed due to Android pre 5 and SSL Handshake not accepted")
|
||||
} else {
|
||||
showError(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Timber.tag("VaultListPresenter").i("Update check not started due to no internal connection")
|
||||
}
|
||||
@ -193,32 +194,34 @@ class VaultListPresenter @Inject constructor( //
|
||||
|
||||
fun deleteVault(vaultModel: VaultModel) {
|
||||
deleteVaultUseCase //
|
||||
.withVault(vaultModel.toVault()) //
|
||||
.run(object : DefaultResultHandler<Long>() {
|
||||
override fun onSuccess(vaultId: Long) {
|
||||
view?.deleteVaultFromAdapter(vaultId)
|
||||
}
|
||||
})
|
||||
.withVault(vaultModel.toVault()) //
|
||||
.run(object : DefaultResultHandler<Long>() {
|
||||
override fun onSuccess(vaultId: Long) {
|
||||
view?.deleteVaultFromAdapter(vaultId)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun renameVault(vaultModel: VaultModel, newVaultName: String?) {
|
||||
renameVaultUseCase //
|
||||
.withVault(vaultModel.toVault()) //
|
||||
.andNewVaultName(newVaultName) //
|
||||
.run(object : DefaultResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
view?.renameVault(VaultModel(vault))
|
||||
view?.closeDialog()
|
||||
}
|
||||
.withVault(vaultModel.toVault()) //
|
||||
.andNewVaultName(newVaultName) //
|
||||
.run(object : DefaultResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
view?.renameVault(VaultModel(vault))
|
||||
view?.closeDialog()
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
if (!authenticationExceptionHandler.handleAuthenticationException( //
|
||||
this@VaultListPresenter, e, //
|
||||
ActivityResultCallbacks.renameVaultAfterAuthentication(vaultModel.toVault(), newVaultName))) {
|
||||
showError(e)
|
||||
}
|
||||
override fun onError(e: Throwable) {
|
||||
if (!authenticationExceptionHandler.handleAuthenticationException( //
|
||||
this@VaultListPresenter, e, //
|
||||
ActivityResultCallbacks.renameVaultAfterAuthentication(vaultModel.toVault(), newVaultName)
|
||||
)
|
||||
) {
|
||||
showError(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Callback
|
||||
@ -230,32 +233,32 @@ class VaultListPresenter @Inject constructor( //
|
||||
|
||||
private fun browseFilesOf(vault: VaultModel) {
|
||||
getDecryptedCloudForVaultUseCase //
|
||||
.withVault(vault.toVault()) //
|
||||
.run(object : DefaultResultHandler<Cloud>() {
|
||||
override fun onSuccess(cloud: Cloud) {
|
||||
getRootFolderAndNavigateInto(cloud)
|
||||
}
|
||||
})
|
||||
.withVault(vault.toVault()) //
|
||||
.run(object : DefaultResultHandler<Cloud>() {
|
||||
override fun onSuccess(cloud: Cloud) {
|
||||
getRootFolderAndNavigateInto(cloud)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun getRootFolderAndNavigateInto(cloud: Cloud) {
|
||||
getRootFolderUseCase //
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<CloudFolder>() {
|
||||
override fun onSuccess(folder: CloudFolder) {
|
||||
navigateToVaultContent((folder.cloud as CryptoCloud).vault, folder)
|
||||
}
|
||||
})
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<CloudFolder>() {
|
||||
override fun onSuccess(folder: CloudFolder) {
|
||||
navigateToVaultContent((folder.cloud as CryptoCloud).vault, folder)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun lockVault(vaultModel: VaultModel) {
|
||||
lockVaultUseCase //
|
||||
.withVault(vaultModel.toVault()) //
|
||||
.run(object : DefaultResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
view?.addOrUpdateVault(VaultModel(vault))
|
||||
}
|
||||
})
|
||||
.withVault(vaultModel.toVault()) //
|
||||
.run(object : DefaultResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
view?.addOrUpdateVault(VaultModel(vault))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private val vaultList: Unit
|
||||
@ -297,12 +300,12 @@ class VaultListPresenter @Inject constructor( //
|
||||
onVaultWithoutCloudClickedAndLocked(vault)
|
||||
} else {
|
||||
lockVaultUseCase //
|
||||
.withVault(vault.toVault()) //
|
||||
.run(object : DefaultResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
onVaultWithoutCloudClickedAndLocked(VaultModel(vault))
|
||||
}
|
||||
})
|
||||
.withVault(vault.toVault()) //
|
||||
.run(object : DefaultResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
onVaultWithoutCloudClickedAndLocked(VaultModel(vault))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -310,11 +313,12 @@ class VaultListPresenter @Inject constructor( //
|
||||
private fun onVaultWithoutCloudClickedAndLocked(vault: VaultModel) {
|
||||
if (isWebdavOrLocal(vault.cloudType)) {
|
||||
requestActivityResult( //
|
||||
ActivityResultCallbacks.cloudConnectionForVaultSelected(vault), //
|
||||
Intents.cloudConnectionListIntent() //
|
||||
.withCloudType(vault.cloudType) //
|
||||
.withDialogTitle(context().getString(R.string.screen_cloud_connections_title)) //
|
||||
.withFinishOnCloudItemClick(true))
|
||||
ActivityResultCallbacks.cloudConnectionForVaultSelected(vault), //
|
||||
Intents.cloudConnectionListIntent() //
|
||||
.withCloudType(vault.cloudType) //
|
||||
.withDialogTitle(context().getString(R.string.screen_cloud_connections_title)) //
|
||||
.withFinishOnCloudItemClick(true)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -326,16 +330,16 @@ class VaultListPresenter @Inject constructor( //
|
||||
fun cloudConnectionForVaultSelected(result: ActivityResult, vaultModel: VaultModel) {
|
||||
val cloud = result.intent().getSerializableExtra(CloudConnectionListPresenter.SELECTED_CLOUD) as Cloud
|
||||
val vault = Vault.aCopyOf(vaultModel.toVault()) //
|
||||
.withCloud(cloud) //
|
||||
.build()
|
||||
.withCloud(cloud) //
|
||||
.build()
|
||||
saveVaultUseCase //
|
||||
.withVault(vault) //
|
||||
.run(object : DefaultResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
view?.addOrUpdateVault(VaultModel(vault))
|
||||
onCloudOfVaultAuthenticated(vault)
|
||||
}
|
||||
})
|
||||
.withVault(vault) //
|
||||
.run(object : DefaultResultHandler<Vault>() {
|
||||
override fun onSuccess(vault: Vault) {
|
||||
view?.addOrUpdateVault(VaultModel(vault))
|
||||
onCloudOfVaultAuthenticated(vault)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun onCloudOfVaultAuthenticated(authenticatedVault: Vault) {
|
||||
@ -352,8 +356,9 @@ class VaultListPresenter @Inject constructor( //
|
||||
if (authenticatedVault.isLocked) {
|
||||
if (!isPaused) {
|
||||
requestActivityResult( //
|
||||
ActivityResultCallbacks.vaultUnlockedVaultList(), //
|
||||
Intents.unlockVaultIntent().withVaultModel(authenticatedVault).withVaultAction(UnlockVaultIntent.VaultAction.UNLOCK))
|
||||
ActivityResultCallbacks.vaultUnlockedVaultList(), //
|
||||
Intents.unlockVaultIntent().withVaultModel(authenticatedVault).withVaultAction(UnlockVaultIntent.VaultAction.UNLOCK)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
browseFilesOf(authenticatedVault)
|
||||
@ -371,18 +376,18 @@ class VaultListPresenter @Inject constructor( //
|
||||
|
||||
private fun navigateToVaultContent(cloud: Cloud) {
|
||||
getRootFolderUseCase //
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<CloudFolder>() {
|
||||
override fun onSuccess(folder: CloudFolder) {
|
||||
val vault = (folder.cloud as CryptoCloud).vault
|
||||
view?.addOrUpdateVault(VaultModel(vault))
|
||||
navigateToVaultContent(vault, folder)
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
if (checkToStartAutoImageUpload(vault)) {
|
||||
context().startService(AutoUploadService.startAutoUploadIntent(context(), folder.cloud))
|
||||
}
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<CloudFolder>() {
|
||||
override fun onSuccess(folder: CloudFolder) {
|
||||
val vault = (folder.cloud as CryptoCloud).vault
|
||||
view?.addOrUpdateVault(VaultModel(vault))
|
||||
navigateToVaultContent(vault, folder)
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
if (checkToStartAutoImageUpload(vault)) {
|
||||
context().startService(AutoUploadService.startAutoUploadIntent(context(), folder.cloud))
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun checkToStartAutoImageUpload(vault: Vault): Boolean {
|
||||
@ -407,10 +412,10 @@ class VaultListPresenter @Inject constructor( //
|
||||
|
||||
fun onChangePasswordClicked(vaultModel: VaultModel) {
|
||||
Intents
|
||||
.unlockVaultIntent()
|
||||
.withVaultModel(vaultModel)
|
||||
.withVaultAction(UnlockVaultIntent.VaultAction.CHANGE_PASSWORD)
|
||||
.startActivity(this)
|
||||
.unlockVaultIntent()
|
||||
.withVaultModel(vaultModel)
|
||||
.withVaultAction(UnlockVaultIntent.VaultAction.CHANGE_PASSWORD)
|
||||
.startActivity(this)
|
||||
}
|
||||
|
||||
fun onVaultSettingsClicked(vaultModel: VaultModel) {
|
||||
@ -446,17 +451,17 @@ class VaultListPresenter @Inject constructor( //
|
||||
|
||||
fun onVaultMoved(fromPosition: Int, toPosition: Int) {
|
||||
moveVaultPositionUseCase
|
||||
.withFromPosition(fromPosition) //
|
||||
.andToPosition(toPosition) //
|
||||
.run(object : DefaultResultHandler<List<Vault>>() {
|
||||
override fun onSuccess(vaults: List<Vault>) {
|
||||
view?.vaultMoved(vaults.mapTo(ArrayList()) { VaultModel(it) })
|
||||
}
|
||||
.withFromPosition(fromPosition) //
|
||||
.andToPosition(toPosition) //
|
||||
.run(object : DefaultResultHandler<List<Vault>>() {
|
||||
override fun onSuccess(vaults: List<Vault>) {
|
||||
view?.vaultMoved(vaults.mapTo(ArrayList()) { VaultModel(it) })
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
Timber.tag("VaultListPresenter").e(e, "Failed to execute MoveVaultUseCase")
|
||||
}
|
||||
})
|
||||
override fun onError(e: Throwable) {
|
||||
Timber.tag("VaultListPresenter").e(e, "Failed to execute MoveVaultUseCase")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private enum class VaultAction {
|
||||
@ -468,33 +473,34 @@ class VaultListPresenter @Inject constructor( //
|
||||
val uri = fileUtil.contentUriForNewTempFile("cryptomator.apk")
|
||||
val file = fileUtil.tempFile("cryptomator.apk")
|
||||
updateUseCase //
|
||||
.withFile(file) //
|
||||
.run(object : NoOpResultHandler<Void?>() {
|
||||
override fun onError(e: Throwable) {
|
||||
showError(e)
|
||||
}
|
||||
.withFile(file) //
|
||||
.run(object : NoOpResultHandler<Void?>() {
|
||||
override fun onError(e: Throwable) {
|
||||
showError(e)
|
||||
}
|
||||
|
||||
override fun onSuccess(aVoid: Void?) {
|
||||
super.onSuccess(aVoid)
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.setDataAndType(uri, "application/vnd.android.package-archive")
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
context().startActivity(intent)
|
||||
}
|
||||
})
|
||||
override fun onSuccess(aVoid: Void?) {
|
||||
super.onSuccess(aVoid)
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.setDataAndType(uri, "application/vnd.android.package-archive")
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
context().startActivity(intent)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
init {
|
||||
unsubscribeOnDestroy( //
|
||||
deleteVaultUseCase, //
|
||||
renameVaultUseCase, //
|
||||
lockVaultUseCase, //
|
||||
getVaultListUseCase, //
|
||||
saveVaultUseCase, //
|
||||
moveVaultPositionUseCase, //
|
||||
licenseCheckUseCase, //
|
||||
updateCheckUseCase, //
|
||||
updateUseCase)
|
||||
deleteVaultUseCase, //
|
||||
renameVaultUseCase, //
|
||||
lockVaultUseCase, //
|
||||
getVaultListUseCase, //
|
||||
saveVaultUseCase, //
|
||||
moveVaultPositionUseCase, //
|
||||
licenseCheckUseCase, //
|
||||
updateCheckUseCase, //
|
||||
updateUseCase
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -21,10 +21,11 @@ import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
|
||||
@PerView
|
||||
class WebDavAddOrChangePresenter @Inject internal constructor( //
|
||||
private val addOrChangeCloudConnectionUseCase: AddOrChangeCloudConnectionUseCase, //
|
||||
private val connectToWebDavUseCase: ConnectToWebDavUseCase, //
|
||||
private val authenticationExceptionHandler: AuthenticationExceptionHandler, //
|
||||
exceptionMappings: ExceptionHandlers) : Presenter<WebDavAddOrChangeView>(exceptionMappings) {
|
||||
private val addOrChangeCloudConnectionUseCase: AddOrChangeCloudConnectionUseCase, //
|
||||
private val connectToWebDavUseCase: ConnectToWebDavUseCase, //
|
||||
private val authenticationExceptionHandler: AuthenticationExceptionHandler, //
|
||||
exceptionMappings: ExceptionHandlers
|
||||
) : Presenter<WebDavAddOrChangeView>(exceptionMappings) {
|
||||
|
||||
fun checkUserInput(urlPort: String, username: String, password: String, cloudId: Long?, certificate: String?) {
|
||||
var statusMessage: String? = null
|
||||
@ -55,8 +56,8 @@ class WebDavAddOrChangePresenter @Inject internal constructor( //
|
||||
|
||||
private fun encryptPassword(password: String): String {
|
||||
return CredentialCryptor //
|
||||
.getInstance(context()) //
|
||||
.encrypt(password)
|
||||
.getInstance(context()) //
|
||||
.encrypt(password)
|
||||
}
|
||||
|
||||
private fun isValid(urlPort: String): Boolean {
|
||||
@ -65,10 +66,10 @@ class WebDavAddOrChangePresenter @Inject internal constructor( //
|
||||
|
||||
private fun mapToCloud(username: String, password: String, hostPort: String, id: Long?, certificate: String?): WebDavCloud {
|
||||
var builder = WebDavCloud //
|
||||
.aWebDavCloudCloud() //
|
||||
.withUrl(hostPort) //
|
||||
.withUsername(username) //
|
||||
.withPassword(password)
|
||||
.aWebDavCloudCloud() //
|
||||
.withUrl(hostPort) //
|
||||
.withUsername(username) //
|
||||
.withPassword(password)
|
||||
|
||||
if (id != null) {
|
||||
builder = builder.withId(id)
|
||||
@ -88,19 +89,19 @@ class WebDavAddOrChangePresenter @Inject internal constructor( //
|
||||
private fun authenticate(cloud: WebDavCloud) {
|
||||
view?.showProgress(ProgressModel(ProgressStateModel.AUTHENTICATION))
|
||||
connectToWebDavUseCase //
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onSuccess(void: Void?) {
|
||||
onCloudAuthenticated(cloud)
|
||||
}
|
||||
.withCloud(cloud) //
|
||||
.run(object : DefaultResultHandler<Void?>() {
|
||||
override fun onSuccess(void: Void?) {
|
||||
onCloudAuthenticated(cloud)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
if (!authenticationExceptionHandler.handleAuthenticationException(this@WebDavAddOrChangePresenter, e, ActivityResultCallbacks.handledAuthenticationWebDavCloud())) {
|
||||
super.onError(e)
|
||||
}
|
||||
override fun onError(e: Throwable) {
|
||||
view?.showProgress(ProgressModel.COMPLETED)
|
||||
if (!authenticationExceptionHandler.handleAuthenticationException(this@WebDavAddOrChangePresenter, e, ActivityResultCallbacks.handledAuthenticationWebDavCloud())) {
|
||||
super.onError(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Callback
|
||||
@ -117,8 +118,8 @@ class WebDavAddOrChangePresenter @Inject internal constructor( //
|
||||
|
||||
private fun save(cloud: Cloud) {
|
||||
addOrChangeCloudConnectionUseCase //
|
||||
.withCloud(cloud) //
|
||||
.run(DefaultResultHandler())
|
||||
.withCloud(cloud) //
|
||||
.run(DefaultResultHandler())
|
||||
}
|
||||
|
||||
init {
|
||||
|
@ -29,26 +29,27 @@ class AutoUploadNotification(private val context: Context, private val amountOfP
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
val notificationChannel = NotificationChannel( //
|
||||
NOTIFICATION_CHANNEL_ID, //
|
||||
NOTIFICATION_CHANNEL_NAME, //
|
||||
IMPORTANCE_LOW)
|
||||
NOTIFICATION_CHANNEL_ID, //
|
||||
NOTIFICATION_CHANNEL_NAME, //
|
||||
IMPORTANCE_LOW
|
||||
)
|
||||
notificationManager?.createNotificationChannel(notificationChannel)
|
||||
}
|
||||
|
||||
this.builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) //
|
||||
.setContentTitle(context.getString(R.string.notification_auto_upload_title)) //
|
||||
.setSmallIcon(R.drawable.background_splash_cryptomator) //
|
||||
.setColor(getColor(R.color.colorPrimary)) //
|
||||
.addAction(cancelNowAction())
|
||||
.setGroup(NOTIFICATION_GROUP_KEY)
|
||||
.setOngoing(true)
|
||||
.setContentTitle(context.getString(R.string.notification_auto_upload_title)) //
|
||||
.setSmallIcon(R.drawable.background_splash_cryptomator) //
|
||||
.setColor(getColor(R.color.colorPrimary)) //
|
||||
.addAction(cancelNowAction())
|
||||
.setGroup(NOTIFICATION_GROUP_KEY)
|
||||
.setOngoing(true)
|
||||
}
|
||||
|
||||
private fun cancelNowAction(): NotificationCompat.Action {
|
||||
return NotificationCompat.Action.Builder( //
|
||||
R.drawable.ic_lock, //
|
||||
getString(R.string.notification_cancel_auto_upload), //
|
||||
cancelNowIntent() //
|
||||
R.drawable.ic_lock, //
|
||||
getString(R.string.notification_cancel_auto_upload), //
|
||||
cancelNowIntent() //
|
||||
).build()
|
||||
}
|
||||
|
||||
@ -67,11 +68,14 @@ class AutoUploadNotification(private val context: Context, private val amountOfP
|
||||
fun update(progress: Int) {
|
||||
builder.setContentIntent(startTheActivity())
|
||||
builder //
|
||||
.setContentText( //
|
||||
String.format(context.getString(R.string.notification_auto_upload_message), //
|
||||
alreadyUploadedPictures + 1, //
|
||||
amountOfPictures)) //
|
||||
.setProgress(100, progress, false)
|
||||
.setContentText( //
|
||||
String.format(
|
||||
context.getString(R.string.notification_auto_upload_message), //
|
||||
alreadyUploadedPictures + 1, //
|
||||
amountOfPictures
|
||||
)
|
||||
) //
|
||||
.setProgress(100, progress, false)
|
||||
show()
|
||||
}
|
||||
|
||||
@ -95,24 +99,24 @@ class AutoUploadNotification(private val context: Context, private val amountOfP
|
||||
private fun showErrorWithMessage(message: String) {
|
||||
builder.setContentIntent(startTheActivity())
|
||||
builder //
|
||||
.setContentTitle(context.getString(R.string.notification_auto_upload_failed_title))
|
||||
.setContentText(message) //
|
||||
.setProgress(0, 0, false)
|
||||
.setAutoCancel(true)
|
||||
.setOngoing(false)
|
||||
.mActions.clear()
|
||||
.setContentTitle(context.getString(R.string.notification_auto_upload_failed_title))
|
||||
.setContentText(message) //
|
||||
.setProgress(0, 0, false)
|
||||
.setAutoCancel(true)
|
||||
.setOngoing(false)
|
||||
.mActions.clear()
|
||||
show()
|
||||
}
|
||||
|
||||
fun showUploadFinished(size: Int) {
|
||||
builder.setContentIntent(startTheActivity())
|
||||
builder //
|
||||
.setContentTitle(context.getString(R.string.notification_auto_upload_finished_title))
|
||||
.setContentText(format(context.getString(R.string.notification_auto_upload_finished_message), size)) //
|
||||
.setProgress(0, 0, false)
|
||||
.setAutoCancel(true)
|
||||
.setOngoing(false)
|
||||
.mActions.clear()
|
||||
.setContentTitle(context.getString(R.string.notification_auto_upload_finished_title))
|
||||
.setContentText(format(context.getString(R.string.notification_auto_upload_finished_message), size)) //
|
||||
.setProgress(0, 0, false)
|
||||
.setAutoCancel(true)
|
||||
.setOngoing(false)
|
||||
.mActions.clear()
|
||||
show()
|
||||
}
|
||||
|
||||
|
@ -26,27 +26,28 @@ class OpenWritableFileNotification(private val context: Context, private val uri
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
val notificationChannel = NotificationChannel( //
|
||||
NOTIFICATION_CHANNEL_ID, //
|
||||
NOTIFICATION_CHANNEL_NAME, //
|
||||
IMPORTANCE_LOW)
|
||||
NOTIFICATION_CHANNEL_ID, //
|
||||
NOTIFICATION_CHANNEL_NAME, //
|
||||
IMPORTANCE_LOW
|
||||
)
|
||||
notificationManager?.createNotificationChannel(notificationChannel)
|
||||
}
|
||||
|
||||
this.builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) //
|
||||
.setContentTitle(context.getString(R.string.notification_open_writable_file_title)) //
|
||||
.setContentText(context.getString(R.string.notification_open_writable_file_message)) //
|
||||
.setSmallIcon(R.drawable.background_splash_cryptomator) //
|
||||
.setColor(getColor(R.color.colorPrimary)) //
|
||||
.setGroup(NOTIFICATION_GROUP_KEY)
|
||||
.setOngoing(true)
|
||||
.addAction(cancelNowAction())
|
||||
.setContentTitle(context.getString(R.string.notification_open_writable_file_title)) //
|
||||
.setContentText(context.getString(R.string.notification_open_writable_file_message)) //
|
||||
.setSmallIcon(R.drawable.background_splash_cryptomator) //
|
||||
.setColor(getColor(R.color.colorPrimary)) //
|
||||
.setGroup(NOTIFICATION_GROUP_KEY)
|
||||
.setOngoing(true)
|
||||
.addAction(cancelNowAction())
|
||||
}
|
||||
|
||||
private fun cancelNowAction(): NotificationCompat.Action {
|
||||
return NotificationCompat.Action.Builder( //
|
||||
R.drawable.ic_lock, //
|
||||
ResourceHelper.getString(R.string.notification_cancel_open_writable_file), //
|
||||
cancelNowIntent() //
|
||||
R.drawable.ic_lock, //
|
||||
ResourceHelper.getString(R.string.notification_cancel_open_writable_file), //
|
||||
cancelNowIntent() //
|
||||
).build()
|
||||
}
|
||||
|
||||
|
@ -75,12 +75,16 @@ class PhotoContentJob : JobService() {
|
||||
private fun getContentResolvers(ids: Set<String>): Array<Cursor?> {
|
||||
val selection = buildSelection(ids)
|
||||
|
||||
var resolvers = arrayOf(contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, PROJECTION_IMAGES, selection, null, null),
|
||||
contentResolver.query(MediaStore.Images.Media.INTERNAL_CONTENT_URI, PROJECTION_IMAGES, selection, null, null))
|
||||
var resolvers = arrayOf(
|
||||
contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, PROJECTION_IMAGES, selection, null, null),
|
||||
contentResolver.query(MediaStore.Images.Media.INTERNAL_CONTENT_URI, PROJECTION_IMAGES, selection, null, null)
|
||||
)
|
||||
|
||||
if (SharedPreferencesHandler(applicationContext).autoPhotoUploadIncludingVideos()) {
|
||||
resolvers += arrayOf(contentResolver.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, PROJECTION_VIDEOS, selection, null, null),
|
||||
contentResolver.query(MediaStore.Video.Media.INTERNAL_CONTENT_URI, PROJECTION_VIDEOS, selection, null, null))
|
||||
resolvers += arrayOf(
|
||||
contentResolver.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, PROJECTION_VIDEOS, selection, null, null),
|
||||
contentResolver.query(MediaStore.Video.Media.INTERNAL_CONTENT_URI, PROJECTION_VIDEOS, selection, null, null)
|
||||
)
|
||||
}
|
||||
|
||||
return resolvers
|
||||
@ -88,14 +92,14 @@ class PhotoContentJob : JobService() {
|
||||
|
||||
private fun getIds(params: JobParameters): Set<String>? {
|
||||
return params.triggeredContentUris
|
||||
?.map { it.pathSegments }
|
||||
?.filter {
|
||||
it != null && (it.size == MediaStore.Images.Media.EXTERNAL_CONTENT_URI.pathSegments.size + 1
|
||||
|| it.size == MediaStore.Video.Media.EXTERNAL_CONTENT_URI.pathSegments.size + 1
|
||||
|| it.size == MediaStore.Images.Media.INTERNAL_CONTENT_URI.pathSegments.size + 1
|
||||
|| it.size == MediaStore.Video.Media.INTERNAL_CONTENT_URI.pathSegments.size + 1)
|
||||
}
|
||||
?.mapTo(HashSet()) { it[it.size - 1] }
|
||||
?.map { it.pathSegments }
|
||||
?.filter {
|
||||
it != null && (it.size == MediaStore.Images.Media.EXTERNAL_CONTENT_URI.pathSegments.size + 1
|
||||
|| it.size == MediaStore.Video.Media.EXTERNAL_CONTENT_URI.pathSegments.size + 1
|
||||
|| it.size == MediaStore.Images.Media.INTERNAL_CONTENT_URI.pathSegments.size + 1
|
||||
|| it.size == MediaStore.Video.Media.INTERNAL_CONTENT_URI.pathSegments.size + 1)
|
||||
}
|
||||
?.mapTo(HashSet()) { it[it.size - 1] }
|
||||
}
|
||||
|
||||
private fun buildSelection(ids: Set<String>): String {
|
||||
|
@ -15,8 +15,8 @@ import javax.inject.Inject
|
||||
|
||||
@Activity(layout = R.layout.activity_empty)
|
||||
class AuthenticateCloudActivity : BaseActivity(),
|
||||
AuthenticateCloudView,
|
||||
AssignSslCertificateDialog.Callback {
|
||||
AuthenticateCloudView,
|
||||
AssignSslCertificateDialog.Callback {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: AuthenticateCloudPresenter
|
||||
|
@ -14,8 +14,8 @@ import kotlinx.android.synthetic.main.toolbar_layout.toolbar
|
||||
|
||||
@Activity
|
||||
class AutoUploadChooseVaultActivity : BaseActivity(), //
|
||||
AutoUploadChooseVaultView, //
|
||||
NotEnoughVaultsDialog.Callback {
|
||||
AutoUploadChooseVaultView, //
|
||||
NotEnoughVaultsDialog.Callback {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: AutoUploadChooseVaultPresenter
|
||||
@ -42,9 +42,9 @@ class AutoUploadChooseVaultActivity : BaseActivity(), //
|
||||
|
||||
override fun displayDialogUnableToUploadFiles() {
|
||||
NotEnoughVaultsDialog //
|
||||
.withContext(this) //
|
||||
.andTitle(getString(R.string.dialog_unable_to_auto_upload_files_title)) //
|
||||
.show()
|
||||
.withContext(this) //
|
||||
.andTitle(getString(R.string.dialog_unable_to_auto_upload_files_title)) //
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onNotEnoughVaultsOkClicked() {
|
||||
|
@ -162,9 +162,9 @@ abstract class BaseActivity : AppCompatActivity(), View, ActivityCompat.OnReques
|
||||
|
||||
private fun initializeDagger(): ActivityComponent {
|
||||
val activityComponent = DaggerActivityComponent.builder()
|
||||
.applicationComponent(applicationComponent)
|
||||
.activityModule(ActivityModule(this))
|
||||
.build()
|
||||
.applicationComponent(applicationComponent)
|
||||
.activityModule(ActivityModule(this))
|
||||
.build()
|
||||
Activities.inject(activityComponent, this)
|
||||
return activityComponent
|
||||
}
|
||||
@ -316,7 +316,7 @@ abstract class BaseActivity : AppCompatActivity(), View, ActivityCompat.OnReques
|
||||
|
||||
internal open fun snackbarView(): android.view.View {
|
||||
return activity().findViewById(R.id.locationsRecyclerView) as android.view.View?
|
||||
?: return activity().findViewById(R.id.coordinatorLayout)
|
||||
?: return activity().findViewById(R.id.coordinatorLayout)
|
||||
}
|
||||
|
||||
internal fun getCurrentFragment(fragmentContainer: Int): Fragment? = supportFragmentManager.findFragmentById(fragmentContainer)
|
||||
@ -374,10 +374,11 @@ abstract class BaseActivity : AppCompatActivity(), View, ActivityCompat.OnReques
|
||||
}
|
||||
|
||||
internal enum class FragmentAnimation constructor(
|
||||
val enter: Int,
|
||||
val exit: Int,
|
||||
val popEnter: Int,
|
||||
val popExit: Int) {
|
||||
val enter: Int,
|
||||
val exit: Int,
|
||||
val popEnter: Int,
|
||||
val popExit: Int
|
||||
) {
|
||||
|
||||
NAVIGATE_IN_TO_FOLDER(R.animator.enter_from_right, R.animator.exit_to_left, R.animator.enter_from_left, R.animator.exit_to_right), //
|
||||
NAVIGATE_OUT_OF_FOLDER(R.animator.enter_from_left, R.animator.exit_to_right, R.animator.enter_from_right, R.animator.exit_to_left)
|
||||
|
@ -14,8 +14,8 @@ import kotlinx.android.synthetic.main.toolbar_layout.toolbar
|
||||
|
||||
@Activity
|
||||
class BiometricAuthSettingsActivity : BaseActivity(), //
|
||||
BiometricAuthSettingsView, //
|
||||
EnrollSystemBiometricDialog.Callback {
|
||||
BiometricAuthSettingsView, //
|
||||
EnrollSystemBiometricDialog.Callback {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: BiometricAuthSettingsPresenter
|
||||
@ -29,8 +29,8 @@ class BiometricAuthSettingsActivity : BaseActivity(), //
|
||||
|
||||
override fun showSetupBiometricAuthDialog() {
|
||||
val biometricAuthenticationAvailable = BiometricManager //
|
||||
.from(context()) //
|
||||
.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG)
|
||||
.from(context()) //
|
||||
.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG)
|
||||
if (biometricAuthenticationAvailable == BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) {
|
||||
showDialog(EnrollSystemBiometricDialog.newInstance())
|
||||
}
|
||||
|
@ -51,17 +51,17 @@ import kotlinx.android.synthetic.main.toolbar_layout.toolbar
|
||||
|
||||
@Activity
|
||||
class BrowseFilesActivity : BaseActivity(), //
|
||||
BrowseFilesView, //
|
||||
BrowseFilesCallback, //
|
||||
ReplaceDialog.Callback, //
|
||||
FileNameDialog.Callback, //
|
||||
ConfirmDeleteCloudNodeDialog.Callback, //
|
||||
UploadCloudFileDialog.Callback,
|
||||
ExportCloudFilesDialog.Callback,
|
||||
SymLinkDialog.CallBack,
|
||||
NoDirFileDialog.CallBack,
|
||||
SearchView.OnQueryTextListener,
|
||||
SearchView.OnCloseListener {
|
||||
BrowseFilesView, //
|
||||
BrowseFilesCallback, //
|
||||
ReplaceDialog.Callback, //
|
||||
FileNameDialog.Callback, //
|
||||
ConfirmDeleteCloudNodeDialog.Callback, //
|
||||
UploadCloudFileDialog.Callback,
|
||||
ExportCloudFilesDialog.Callback,
|
||||
SymLinkDialog.CallBack,
|
||||
NoDirFileDialog.CallBack,
|
||||
SearchView.OnQueryTextListener,
|
||||
SearchView.OnCloseListener {
|
||||
|
||||
@Inject
|
||||
lateinit var browseFilesPresenter: BrowseFilesPresenter
|
||||
@ -97,8 +97,10 @@ class BrowseFilesActivity : BaseActivity(), //
|
||||
get() = browseFilesFragment().folder
|
||||
|
||||
override fun createFragment(): Fragment =
|
||||
BrowseFilesFragment.newInstance(browseFilesIntent.folder(),
|
||||
browseFilesIntent.chooseCloudNodeSettings())
|
||||
BrowseFilesFragment.newInstance(
|
||||
browseFilesIntent.folder(),
|
||||
browseFilesIntent.chooseCloudNodeSettings()
|
||||
)
|
||||
|
||||
override fun onBackPressed() {
|
||||
browseFilesPresenter.onBackPressed()
|
||||
@ -121,7 +123,7 @@ class BrowseFilesActivity : BaseActivity(), //
|
||||
private fun isNavigationMode(navigationMode: ChooseCloudNodeSettings.NavigationMode): Boolean = this.navigationMode == navigationMode
|
||||
|
||||
private fun hasCloudNodeSettings(): Boolean =
|
||||
browseFilesIntent.chooseCloudNodeSettings() != null
|
||||
browseFilesIntent.chooseCloudNodeSettings() != null
|
||||
|
||||
override fun getCustomMenuResource(): Int {
|
||||
return when {
|
||||
@ -160,14 +162,17 @@ class BrowseFilesActivity : BaseActivity(), //
|
||||
true
|
||||
}
|
||||
R.id.action_move_items -> {
|
||||
browseFilesPresenter.onMoveNodesClicked(folder, //
|
||||
browseFilesFragment().selectedCloudNodes as ArrayList<CloudNodeModel<*>>)
|
||||
browseFilesPresenter.onMoveNodesClicked(
|
||||
folder, //
|
||||
browseFilesFragment().selectedCloudNodes as ArrayList<CloudNodeModel<*>>
|
||||
)
|
||||
true
|
||||
}
|
||||
R.id.action_export_items -> {
|
||||
browseFilesPresenter.onExportNodesClicked( //
|
||||
browseFilesFragment().selectedCloudNodes as ArrayList<CloudNodeModel<*>>, //
|
||||
BrowseFilesPresenter.EXPORT_TRIGGERED_BY_USER)
|
||||
browseFilesFragment().selectedCloudNodes as ArrayList<CloudNodeModel<*>>, //
|
||||
BrowseFilesPresenter.EXPORT_TRIGGERED_BY_USER
|
||||
)
|
||||
true
|
||||
}
|
||||
R.id.action_share_items -> {
|
||||
@ -398,14 +403,18 @@ class BrowseFilesActivity : BaseActivity(), //
|
||||
}
|
||||
|
||||
override fun navigateTo(folder: CloudFolderModel) {
|
||||
replaceFragment(BrowseFilesFragment.newInstance(folder,
|
||||
browseFilesIntent.chooseCloudNodeSettings()),
|
||||
FragmentAnimation.NAVIGATE_IN_TO_FOLDER)
|
||||
replaceFragment(
|
||||
BrowseFilesFragment.newInstance(
|
||||
folder,
|
||||
browseFilesIntent.chooseCloudNodeSettings()
|
||||
),
|
||||
FragmentAnimation.NAVIGATE_IN_TO_FOLDER
|
||||
)
|
||||
}
|
||||
|
||||
override fun showAddContentDialog() {
|
||||
VaultContentActionBottomSheet.newInstance(browseFilesFragment().folder)
|
||||
.show(supportFragmentManager, "AddContentDialog")
|
||||
.show(supportFragmentManager, "AddContentDialog")
|
||||
}
|
||||
|
||||
override fun updateTitle(folder: CloudFolderModel) {
|
||||
@ -484,10 +493,14 @@ class BrowseFilesActivity : BaseActivity(), //
|
||||
}
|
||||
|
||||
private fun createBackStackFor(sourceParent: CloudFolderModel) {
|
||||
replaceFragment(BrowseFilesFragment.newInstance(sourceParent,
|
||||
browseFilesIntent.chooseCloudNodeSettings()),
|
||||
FragmentAnimation.NAVIGATE_OUT_OF_FOLDER,
|
||||
false)
|
||||
replaceFragment(
|
||||
BrowseFilesFragment.newInstance(
|
||||
sourceParent,
|
||||
browseFilesIntent.chooseCloudNodeSettings()
|
||||
),
|
||||
FragmentAnimation.NAVIGATE_OUT_OF_FOLDER,
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
override fun onRenameCloudNodeClicked(cloudNodeModel: CloudNodeModel<*>, newCloudNodeName: String) {
|
||||
|
@ -18,9 +18,9 @@ import kotlinx.android.synthetic.main.toolbar_layout.toolbar
|
||||
|
||||
@Activity
|
||||
class CloudConnectionListActivity : BaseActivity(),
|
||||
CloudConnectionListView,
|
||||
CloudConnectionSettingsBottomSheet.Callback,
|
||||
DeleteCloudConnectionWithVaultsDialog.Callback {
|
||||
CloudConnectionListView,
|
||||
CloudConnectionSettingsBottomSheet.Callback,
|
||||
DeleteCloudConnectionWithVaultsDialog.Callback {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: CloudConnectionListPresenter
|
||||
@ -55,7 +55,7 @@ class CloudConnectionListActivity : BaseActivity(),
|
||||
|
||||
override fun showNodeSettings(cloudModel: CloudModel) {
|
||||
val cloudNodeSettingDialog = //
|
||||
CloudConnectionSettingsBottomSheet.newInstance(cloudModel)
|
||||
CloudConnectionSettingsBottomSheet.newInstance(cloudModel)
|
||||
cloudNodeSettingDialog.show(supportFragmentManager, "CloudNodeSettings")
|
||||
}
|
||||
|
||||
|
@ -24,14 +24,16 @@ class EmptyDirIdFileInfoActivity : BaseActivity(), EmptyDirFileView {
|
||||
}
|
||||
|
||||
private fun setupToolbar() {
|
||||
toolbar.title = getString(R.string.screen_empty_dir_file_info_title,
|
||||
emptyDirIdFileInfoIntent.dirName())
|
||||
toolbar.title = getString(
|
||||
R.string.screen_empty_dir_file_info_title,
|
||||
emptyDirIdFileInfoIntent.dirName()
|
||||
)
|
||||
setSupportActionBar(toolbar)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
(supportFragmentManager.findFragmentByTag("EmptyDirIdFileInfoFragment") as EmptyDirIdFileInfoFragment)
|
||||
.setDirFilePath(emptyDirIdFileInfoIntent.dirFilePath())
|
||||
.setDirFilePath(emptyDirIdFileInfoIntent.dirFilePath())
|
||||
}
|
||||
}
|
||||
|
@ -180,10 +180,10 @@ class ImagePreviewActivity : BaseActivity(), ImagePreviewView, ConfirmDeleteClou
|
||||
|
||||
private fun fragmentFor(imagePreviewFile: ImagePreviewFile): Optional<ImagePreviewFragment> {
|
||||
return supportFragmentManager.fragments
|
||||
.map { it as ImagePreviewFragment }
|
||||
.firstOrNull { it.imagePreviewFile() == imagePreviewFile }
|
||||
?.let { Optional.of(it) }
|
||||
?: Optional.empty()
|
||||
.map { it as ImagePreviewFragment }
|
||||
.firstOrNull { it.imagePreviewFile() == imagePreviewFile }
|
||||
?.let { Optional.of(it) }
|
||||
?: Optional.empty()
|
||||
}
|
||||
|
||||
override fun hideProgressBar(imagePreviewFile: ImagePreviewFile) {
|
||||
|
@ -63,7 +63,7 @@ class LicenseCheckActivity : BaseActivity(), UpdateLicenseDialog.Callback, Licen
|
||||
|
||||
override fun licenseConfirmationClicked() {
|
||||
vaultListIntent() //
|
||||
.preventGoingBackInHistory() //
|
||||
.startActivity(this) //
|
||||
.preventGoingBackInHistory() //
|
||||
.startActivity(this) //
|
||||
}
|
||||
}
|
||||
|
@ -19,12 +19,12 @@ import kotlinx.android.synthetic.main.toolbar_layout.toolbar
|
||||
|
||||
@Activity(layout = R.layout.activity_settings)
|
||||
class SettingsActivity : BaseActivity(),
|
||||
SettingsView,
|
||||
DebugModeDisclaimerDialog.Callback,
|
||||
DisableAppWhenObscuredDisclaimerDialog.Callback,
|
||||
DisableSecureScreenDisclaimerDialog.Callback,
|
||||
UpdateAppAvailableDialog.Callback, //
|
||||
UpdateAppDialog.Callback {
|
||||
SettingsView,
|
||||
DebugModeDisclaimerDialog.Callback,
|
||||
DisableAppWhenObscuredDisclaimerDialog.Callback,
|
||||
DisableSecureScreenDisclaimerDialog.Callback,
|
||||
UpdateAppAvailableDialog.Callback, //
|
||||
UpdateAppDialog.Callback {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: SettingsPresenter
|
||||
|
@ -26,10 +26,10 @@ import timber.log.Timber
|
||||
|
||||
@Activity
|
||||
class SharedFilesActivity : BaseActivity(), //
|
||||
SharedFilesView, //
|
||||
ReplaceDialog.Callback, //
|
||||
NotEnoughVaultsDialog.Callback, //
|
||||
UploadCloudFileDialog.Callback {
|
||||
SharedFilesView, //
|
||||
ReplaceDialog.Callback, //
|
||||
NotEnoughVaultsDialog.Callback, //
|
||||
UploadCloudFileDialog.Callback {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: SharedFilesPresenter
|
||||
@ -92,8 +92,8 @@ class SharedFilesActivity : BaseActivity(), //
|
||||
val uriList = ArrayList<Uri>(clipData.itemCount)
|
||||
(0 until clipData.itemCount).forEach { i ->
|
||||
clipData.getItemAt(i).uri
|
||||
?.let { uriList.add(it) }
|
||||
?: Timber.tag("Sharing").i("Item %d without uri", i)
|
||||
?.let { uriList.add(it) }
|
||||
?: Timber.tag("Sharing").i("Item %d without uri", i)
|
||||
}
|
||||
return uriList
|
||||
}
|
||||
@ -173,10 +173,10 @@ class SharedFilesActivity : BaseActivity(), //
|
||||
|
||||
override fun onNotEnoughVaultsCreateVaultClicked() {
|
||||
packageManager.getLaunchIntentForPackage(packageName)
|
||||
?.let {
|
||||
it.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
startActivity(it)
|
||||
}
|
||||
?.let {
|
||||
it.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
startActivity(it)
|
||||
}
|
||||
finish()
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,9 @@ import kotlinx.android.synthetic.main.toolbar_layout.toolbar
|
||||
|
||||
@Activity
|
||||
class TextEditorActivity : BaseActivity(),
|
||||
TextEditorView,
|
||||
UnsavedChangesDialog.Callback,
|
||||
SearchView.OnQueryTextListener {
|
||||
TextEditorView,
|
||||
UnsavedChangesDialog.Callback,
|
||||
SearchView.OnQueryTextListener {
|
||||
|
||||
@Inject
|
||||
lateinit var textEditorPresenter: TextEditorPresenter
|
||||
@ -45,18 +45,18 @@ class TextEditorActivity : BaseActivity(),
|
||||
super.onCreateOptionsMenu(menu)
|
||||
|
||||
menu.findItem(R.id.action_search)
|
||||
.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
|
||||
override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
|
||||
menu.findItem(R.id.action_search_previous).isVisible = true
|
||||
menu.findItem(R.id.action_search_next).isVisible = true
|
||||
return true
|
||||
}
|
||||
.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
|
||||
override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
|
||||
menu.findItem(R.id.action_search_previous).isVisible = true
|
||||
menu.findItem(R.id.action_search_next).isVisible = true
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
|
||||
invalidateOptionsMenu()
|
||||
return true
|
||||
}
|
||||
})
|
||||
override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
|
||||
invalidateOptionsMenu()
|
||||
return true
|
||||
}
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -21,10 +21,10 @@ import javax.inject.Inject
|
||||
|
||||
@Activity(layout = R.layout.activity_unlock_vault)
|
||||
class UnlockVaultActivity : BaseActivity(), //
|
||||
UnlockVaultView, //
|
||||
BiometricAuthentication.Callback,
|
||||
ChangePasswordDialog.Callback,
|
||||
VaultNotFoundDialog.Callback {
|
||||
UnlockVaultView, //
|
||||
BiometricAuthentication.Callback,
|
||||
ChangePasswordDialog.Callback,
|
||||
VaultNotFoundDialog.Callback {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: UnlockVaultPresenter
|
||||
@ -84,7 +84,7 @@ class UnlockVaultActivity : BaseActivity(), //
|
||||
|
||||
override fun onBiometricAuthenticationFailed(vault: VaultModel) {
|
||||
val vaultWithoutPassword = Vault.aCopyOf(vault.toVault()).withSavedPassword(null).build()
|
||||
when(unlockVaultIntent.vaultAction()) {
|
||||
when (unlockVaultIntent.vaultAction()) {
|
||||
UnlockVaultIntent.VaultAction.CHANGE_PASSWORD -> presenter.saveVaultAfterChangePasswordButFailedBiometricAuth(vaultWithoutPassword)
|
||||
else -> {
|
||||
if (!presenter.startedUsingPrepareUnlock()) {
|
||||
@ -100,7 +100,7 @@ class UnlockVaultActivity : BaseActivity(), //
|
||||
}
|
||||
|
||||
private fun unlockVaultFragment(): UnlockVaultFragment = //
|
||||
getCurrentFragment(R.id.fragmentContainer) as UnlockVaultFragment
|
||||
getCurrentFragment(R.id.fragmentContainer) as UnlockVaultFragment
|
||||
|
||||
override fun showChangePasswordDialog(vaultModel: VaultModel, unverifiedVaultConfig: UnverifiedVaultConfig?) {
|
||||
showDialog(ChangePasswordDialog.newInstance(vaultModel, unverifiedVaultConfig))
|
||||
|
@ -35,12 +35,12 @@ import kotlinx.android.synthetic.main.toolbar_layout.toolbar
|
||||
|
||||
@Activity(layout = R.layout.activity_layout_obscure_aware)
|
||||
class VaultListActivity : BaseActivity(), //
|
||||
VaultListView, //
|
||||
VaultListCallback, //
|
||||
AskForLockScreenDialog.Callback, //
|
||||
UpdateAppAvailableDialog.Callback, //
|
||||
UpdateAppDialog.Callback, //
|
||||
BetaConfirmationDialog.Callback {
|
||||
VaultListView, //
|
||||
VaultListCallback, //
|
||||
AskForLockScreenDialog.Callback, //
|
||||
UpdateAppAvailableDialog.Callback, //
|
||||
UpdateAppDialog.Callback, //
|
||||
BetaConfirmationDialog.Callback {
|
||||
|
||||
@Inject
|
||||
lateinit var vaultListPresenter: VaultListPresenter
|
||||
@ -122,7 +122,7 @@ class VaultListActivity : BaseActivity(), //
|
||||
|
||||
override fun showVaultSettingsDialog(vaultModel: VaultModel) {
|
||||
val vaultSettingDialog = //
|
||||
SettingsVaultBottomSheet.newInstance(vaultModel)
|
||||
SettingsVaultBottomSheet.newInstance(vaultModel)
|
||||
vaultSettingDialog.show(supportFragmentManager, "VaultSettings")
|
||||
}
|
||||
|
||||
@ -164,7 +164,7 @@ class VaultListActivity : BaseActivity(), //
|
||||
|
||||
override fun onDeleteVaultClick(vaultModel: VaultModel) {
|
||||
VaultDeleteConfirmationDialog.newInstance(vaultModel) //
|
||||
.show(supportFragmentManager, "VaultDeleteConfirmationDialog")
|
||||
.show(supportFragmentManager, "VaultDeleteConfirmationDialog")
|
||||
}
|
||||
|
||||
override fun onRenameVaultClick(vaultModel: VaultModel) {
|
||||
@ -192,7 +192,7 @@ class VaultListActivity : BaseActivity(), //
|
||||
}
|
||||
|
||||
private fun vaultListFragment(): VaultListFragment = //
|
||||
getCurrentFragment(R.id.fragmentContainer) as VaultListFragment
|
||||
getCurrentFragment(R.id.fragmentContainer) as VaultListFragment
|
||||
|
||||
override fun onUpdateAppDialogLoaded() {
|
||||
showProgress(ProgressModel.GENERIC)
|
||||
|
@ -17,8 +17,8 @@ import kotlinx.android.synthetic.main.toolbar_layout.toolbar
|
||||
|
||||
@Activity
|
||||
class WebDavAddOrChangeActivity : BaseActivity(),
|
||||
WebDavAddOrChangeView,
|
||||
WebDavAskForHttpDialog.Callback {
|
||||
WebDavAddOrChangeView,
|
||||
WebDavAskForHttpDialog.Callback {
|
||||
|
||||
@Inject
|
||||
lateinit var webDavAddOrChangePresenter: WebDavAddOrChangePresenter
|
||||
|
@ -45,10 +45,12 @@ import kotlinx.android.synthetic.main.view_cloud_folder_content.view.cloudFolder
|
||||
import kotlinx.android.synthetic.main.view_cloud_folder_content.view.cloudFolderText
|
||||
|
||||
class BrowseFilesAdapter @Inject
|
||||
constructor(private val dateHelper: DateHelper, //
|
||||
private val fileSizeHelper: FileSizeHelper, //
|
||||
private val fileUtil: FileUtil, //
|
||||
private val sharedPreferencesHandler: SharedPreferencesHandler) : RecyclerViewBaseAdapter<CloudNodeModel<*>, BrowseFilesAdapter.ItemClickListener, VaultContentViewHolder>(CloudNodeModelNameAZComparator()), FastScrollRecyclerView.SectionedAdapter {
|
||||
constructor(
|
||||
private val dateHelper: DateHelper, //
|
||||
private val fileSizeHelper: FileSizeHelper, //
|
||||
private val fileUtil: FileUtil, //
|
||||
private val sharedPreferencesHandler: SharedPreferencesHandler
|
||||
) : RecyclerViewBaseAdapter<CloudNodeModel<*>, BrowseFilesAdapter.ItemClickListener, VaultContentViewHolder>(CloudNodeModelNameAZComparator()), FastScrollRecyclerView.SectionedAdapter {
|
||||
|
||||
private var chooseCloudNodeSettings: ChooseCloudNodeSettings? = null
|
||||
private var navigationMode: ChooseCloudNodeSettings.NavigationMode? = null
|
||||
|
@ -7,4 +7,5 @@ import org.cryptomator.presentation.ui.dialog.CloudNodeRenameDialog
|
||||
import org.cryptomator.presentation.ui.dialog.CreateFolderDialog
|
||||
import org.cryptomator.presentation.ui.dialog.FileTypeNotSupportedDialog
|
||||
|
||||
interface BrowseFilesCallback : CreateFolderDialog.Callback, VaultContentActionBottomSheet.Callback, FileSettingsBottomSheet.Callback, FolderSettingsBottomSheet.Callback, CloudNodeRenameDialog.Callback, FileTypeNotSupportedDialog.Callback
|
||||
interface BrowseFilesCallback : CreateFolderDialog.Callback, VaultContentActionBottomSheet.Callback, FileSettingsBottomSheet.Callback, FolderSettingsBottomSheet.Callback, CloudNodeRenameDialog.Callback,
|
||||
FileTypeNotSupportedDialog.Callback
|
||||
|
@ -7,6 +7,6 @@ import org.cryptomator.presentation.ui.dialog.VaultRenameDialog
|
||||
|
||||
// FIXME delete this file and add this interfaces to VaultListView.kt
|
||||
interface VaultListCallback : AddVaultBottomSheet.Callback, //
|
||||
SettingsVaultBottomSheet.Callback, //
|
||||
VaultDeleteConfirmationDialog.Callback, //
|
||||
VaultRenameDialog.Callback
|
||||
SettingsVaultBottomSheet.Callback, //
|
||||
VaultDeleteConfirmationDialog.Callback, //
|
||||
VaultRenameDialog.Callback
|
||||
|
@ -14,8 +14,8 @@ class AppIsObscuredInfoDialog : BaseDialog<Activity>() {
|
||||
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
builder //
|
||||
.setTitle(R.string.dialog_app_is_obscured_info_title) //
|
||||
.setNeutralButton(R.string.dialog_app_is_obscured_info_neutral_button) { dialog: DialogInterface, _: Int -> dialog.dismiss() }
|
||||
.setTitle(R.string.dialog_app_is_obscured_info_title) //
|
||||
.setNeutralButton(R.string.dialog_app_is_obscured_info_neutral_button) { dialog: DialogInterface, _: Int -> dialog.dismiss() }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,8 @@ class AskForLockScreenDialog : BaseDialog<AskForLockScreenDialog.Callback>() {
|
||||
|
||||
override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
builder //
|
||||
.setTitle(R.string.dialog_no_screen_lock_title) //
|
||||
.setNeutralButton(getString(R.string.dialog_unable_to_share_positive_button)) { _: DialogInterface, _: Int -> callback?.onAskForLockScreenFinished(cb_select_screen_lock.isChecked) }
|
||||
.setTitle(R.string.dialog_no_screen_lock_title) //
|
||||
.setNeutralButton(getString(R.string.dialog_unable_to_share_positive_button)) { _: DialogInterface, _: Int -> callback?.onAskForLockScreenFinished(cb_select_screen_lock.isChecked) }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
@ -29,14 +29,14 @@ class AssignSslCertificateDialog : BaseDialog<AssignSslCertificateDialog.Callbac
|
||||
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
builder //
|
||||
.setTitle(requireContext().getString(R.string.dialog_accept_ssl_certificate_title))
|
||||
.setPositiveButton(requireActivity().getString(R.string.dialog_unable_to_share_positive_button)) { _: DialogInterface, _: Int ->
|
||||
val cloud = requireArguments().getSerializable(WEBDAV_CLOUD) as WebDavCloud
|
||||
callback?.onAcceptCertificateClicked(cloud, certificate)
|
||||
} //
|
||||
.setNegativeButton(requireContext().getString(R.string.dialog_button_cancel)) { _: DialogInterface, _: Int ->
|
||||
callback?.onAcceptCertificateDenied()
|
||||
}
|
||||
.setTitle(requireContext().getString(R.string.dialog_accept_ssl_certificate_title))
|
||||
.setPositiveButton(requireActivity().getString(R.string.dialog_unable_to_share_positive_button)) { _: DialogInterface, _: Int ->
|
||||
val cloud = requireArguments().getSerializable(WEBDAV_CLOUD) as WebDavCloud
|
||||
callback?.onAcceptCertificateClicked(cloud, certificate)
|
||||
} //
|
||||
.setNegativeButton(requireContext().getString(R.string.dialog_button_cancel)) { _: DialogInterface, _: Int ->
|
||||
callback?.onAcceptCertificateDenied()
|
||||
}
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,8 @@ class BetaConfirmationDialog : BaseDialog<BetaConfirmationDialog.Callback>() {
|
||||
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
builder //
|
||||
.setTitle(R.string.dialog_beta_confirmation_title) //
|
||||
.setNeutralButton(getString(R.string.dialog_unable_to_share_positive_button)) { _: DialogInterface, _: Int -> callback?.onAskForBetaConfirmationFinished() }
|
||||
.setTitle(R.string.dialog_beta_confirmation_title) //
|
||||
.setNeutralButton(getString(R.string.dialog_unable_to_share_positive_button)) { _: DialogInterface, _: Int -> callback?.onAskForBetaConfirmationFinished() }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,8 @@ class BiometricAuthKeyInvalidatedDialog : BaseDialog<BiometricAuthKeyInvalidated
|
||||
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
builder //
|
||||
.setTitle(R.string.dialog_biometric_auth_key_invalidated_title) //
|
||||
.setNegativeButton(getString(R.string.dialog_biometric_auth_key_invalidated_neutral_button)) { _: DialogInterface, _: Int -> }
|
||||
.setTitle(R.string.dialog_biometric_auth_key_invalidated_title) //
|
||||
.setNegativeButton(getString(R.string.dialog_biometric_auth_key_invalidated_neutral_button)) { _: DialogInterface, _: Int -> }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
@ -35,13 +35,18 @@ class ChangePasswordDialog : BaseProgressErrorDialog<ChangePasswordDialog.Callba
|
||||
changePasswordButton?.setOnClickListener {
|
||||
val vaultModel = requireArguments().getSerializable(VAULT_ARG) as VaultModel
|
||||
val unverifiedVaultConfig = requireArguments().getSerializable(VAULT_CONFIG_ARG) as UnverifiedVaultConfig?
|
||||
if (valid(et_old_password.text.toString(), //
|
||||
et_new_password.text.toString(), //
|
||||
et_new_retype_password.text.toString())) {
|
||||
callback?.onChangePasswordClick(vaultModel, //
|
||||
unverifiedVaultConfig, //
|
||||
et_old_password.text.toString(), //
|
||||
et_new_password.text.toString())
|
||||
if (valid(
|
||||
et_old_password.text.toString(), //
|
||||
et_new_password.text.toString(), //
|
||||
et_new_retype_password.text.toString()
|
||||
)
|
||||
) {
|
||||
callback?.onChangePasswordClick(
|
||||
vaultModel, //
|
||||
unverifiedVaultConfig, //
|
||||
et_old_password.text.toString(), //
|
||||
et_new_password.text.toString()
|
||||
)
|
||||
onWaitForResponse(et_old_password)
|
||||
} else {
|
||||
hideKeyboard(et_old_password)
|
||||
@ -58,10 +63,12 @@ class ChangePasswordDialog : BaseProgressErrorDialog<ChangePasswordDialog.Callba
|
||||
registerOnEditorDoneActionAndPerformButtonClick(et_new_retype_password) { changePasswordButton }
|
||||
|
||||
PasswordStrengthUtil() //
|
||||
.startUpdatingPasswordStrengthMeter(et_new_password, //
|
||||
progressBarPwStrengthIndicator, //
|
||||
textViewPwStrengthIndicator, //
|
||||
changePasswordButton)
|
||||
.startUpdatingPasswordStrengthMeter(
|
||||
et_new_password, //
|
||||
progressBarPwStrengthIndicator, //
|
||||
textViewPwStrengthIndicator, //
|
||||
changePasswordButton
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,10 +93,10 @@ class ChangePasswordDialog : BaseProgressErrorDialog<ChangePasswordDialog.Callba
|
||||
override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
val vaultModel = requireArguments().getSerializable(VAULT_ARG) as VaultModel
|
||||
return builder //
|
||||
.setTitle(vaultModel.name) //
|
||||
.setPositiveButton(getString(R.string.dialog_change_password)) { _: DialogInterface, _: Int -> } //
|
||||
.setNegativeButton(getString(R.string.dialog_button_cancel)) { _: DialogInterface?, _: Int -> } //
|
||||
.create()
|
||||
.setTitle(vaultModel.name) //
|
||||
.setPositiveButton(getString(R.string.dialog_change_password)) { _: DialogInterface, _: Int -> } //
|
||||
.setNegativeButton(getString(R.string.dialog_button_cancel)) { _: DialogInterface?, _: Int -> } //
|
||||
.create()
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
|
@ -50,10 +50,10 @@ class CloudNodeRenameDialog : BaseProgressErrorDialog<CloudNodeRenameDialog.Call
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
val cloudNodeModel = requireArguments().getSerializable(CLOUD_NODE_ARG) as CloudNodeModel<*>
|
||||
return builder
|
||||
.setTitle(getTitle(cloudNodeModel))
|
||||
.setPositiveButton(requireActivity().getString(R.string.dialog_rename_node_positive_button)) { _: DialogInterface, _: Int -> }
|
||||
.setNegativeButton(requireActivity().getString(R.string.dialog_button_cancel)) { _: DialogInterface, _: Int -> }
|
||||
.create()
|
||||
.setTitle(getTitle(cloudNodeModel))
|
||||
.setPositiveButton(requireActivity().getString(R.string.dialog_rename_node_positive_button)) { _: DialogInterface, _: Int -> }
|
||||
.setNegativeButton(requireActivity().getString(R.string.dialog_button_cancel)) { _: DialogInterface, _: Int -> }
|
||||
.create()
|
||||
}
|
||||
|
||||
private fun getTitle(cloudNodeModel: CloudNodeModel<*>): String {
|
||||
|
@ -27,10 +27,10 @@ class ConfirmDeleteCloudNodeDialog : BaseDialog<ConfirmDeleteCloudNodeDialog.Cal
|
||||
title = nodes[0].name
|
||||
}
|
||||
return builder //
|
||||
.setTitle(title) //
|
||||
.setPositiveButton(getString(R.string.dialog_confirm_delete_positive_button)) { _: DialogInterface, _: Int -> callback?.onDeleteCloudNodeConfirmed(nodes) } //
|
||||
.setNegativeButton(getString(R.string.dialog_confirm_delete_negative_button)) { _: DialogInterface, _: Int -> } //
|
||||
.create()
|
||||
.setTitle(title) //
|
||||
.setPositiveButton(getString(R.string.dialog_confirm_delete_positive_button)) { _: DialogInterface, _: Int -> callback?.onDeleteCloudNodeConfirmed(nodes) } //
|
||||
.setNegativeButton(getString(R.string.dialog_confirm_delete_negative_button)) { _: DialogInterface, _: Int -> } //
|
||||
.create()
|
||||
}
|
||||
|
||||
private fun getMessage(cloudNodeModel: CloudNodeModel<*>): String {
|
||||
|
@ -44,9 +44,9 @@ class CreateFolderDialog : BaseProgressErrorDialog<CreateFolderDialog.Callback>(
|
||||
|
||||
override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
return builder.setTitle(requireContext().getString(R.string.dialog_create_folder_title))
|
||||
.setPositiveButton(requireContext().getString(R.string.dialog_create_folder_positive_button)) { _: DialogInterface, _: Int -> }
|
||||
.setNegativeButton(requireContext().getString(R.string.dialog_button_cancel)) { _: DialogInterface, _: Int -> }
|
||||
.create()
|
||||
.setPositiveButton(requireContext().getString(R.string.dialog_create_folder_positive_button)) { _: DialogInterface, _: Int -> }
|
||||
.setNegativeButton(requireContext().getString(R.string.dialog_button_cancel)) { _: DialogInterface, _: Int -> }
|
||||
.create()
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
|
@ -17,9 +17,9 @@ class DebugModeDisclaimerDialog : BaseDialog<DebugModeDisclaimerDialog.Callback>
|
||||
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
builder //
|
||||
.setTitle(R.string.dialog_debug_mode_disclaimer_title) //
|
||||
.setPositiveButton(getString(R.string.dialog_debug_mode_positive_button)) { _: DialogInterface, _: Int -> callback?.onDisclaimerAccepted() } //
|
||||
.setNegativeButton(getString(R.string.dialog_debug_mode_negative_button)) { _: DialogInterface, _: Int -> callback?.onDisclaimerRejected() }
|
||||
.setTitle(R.string.dialog_debug_mode_disclaimer_title) //
|
||||
.setPositiveButton(getString(R.string.dialog_debug_mode_positive_button)) { _: DialogInterface, _: Int -> callback?.onDisclaimerAccepted() } //
|
||||
.setNegativeButton(getString(R.string.dialog_debug_mode_negative_button)) { _: DialogInterface, _: Int -> callback?.onDisclaimerRejected() }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
@ -20,11 +20,11 @@ class DeleteCloudConnectionWithVaultsDialog : BaseDialog<DeleteCloudConnectionWi
|
||||
override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
val cloudModel = requireArguments().getSerializable(ARG_CLOUD) as CloudModel
|
||||
builder.setTitle(cloudModel.name()) //
|
||||
.setPositiveButton(getString(R.string.dialog_delete_cloud_connection_with_vaults_positive_button)) { _: DialogInterface, _: Int ->
|
||||
val vaultsOfCloud = requireArguments().getSerializable(ARG_VAULTS) as ArrayList<Vault>
|
||||
callback?.onDeleteCloudConnectionAndVaults(cloudModel, vaultsOfCloud)
|
||||
dismiss()
|
||||
}.setNegativeButton(getString(R.string.dialog_delete_cloud_connection_with_vaults_negative_button)) { _: DialogInterface, _: Int -> }
|
||||
.setPositiveButton(getString(R.string.dialog_delete_cloud_connection_with_vaults_positive_button)) { _: DialogInterface, _: Int ->
|
||||
val vaultsOfCloud = requireArguments().getSerializable(ARG_VAULTS) as ArrayList<Vault>
|
||||
callback?.onDeleteCloudConnectionAndVaults(cloudModel, vaultsOfCloud)
|
||||
dismiss()
|
||||
}.setNegativeButton(getString(R.string.dialog_delete_cloud_connection_with_vaults_negative_button)) { _: DialogInterface, _: Int -> }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,9 @@ class DisableAppWhenObscuredDisclaimerDialog : BaseDialog<DisableAppWhenObscured
|
||||
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
builder //
|
||||
.setTitle(R.string.dialog_disable_app_obscured_disclaimer_title) //
|
||||
.setPositiveButton(getString(R.string.dialog_disable_app_obscured_positive_button)) { _: DialogInterface, _: Int -> callback?.onDisableAppObscuredDisclaimerAccepted() } //
|
||||
.setNegativeButton(getString(R.string.dialog_disable_app_obscured_negative_button)) { _: DialogInterface, _: Int -> callback?.onDisableAppObscuredDisclaimerRejected() }
|
||||
.setTitle(R.string.dialog_disable_app_obscured_disclaimer_title) //
|
||||
.setPositiveButton(getString(R.string.dialog_disable_app_obscured_positive_button)) { _: DialogInterface, _: Int -> callback?.onDisableAppObscuredDisclaimerAccepted() } //
|
||||
.setNegativeButton(getString(R.string.dialog_disable_app_obscured_negative_button)) { _: DialogInterface, _: Int -> callback?.onDisableAppObscuredDisclaimerRejected() }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,9 @@ class DisableSecureScreenDisclaimerDialog : BaseDialog<DisableSecureScreenDiscla
|
||||
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
builder //
|
||||
.setTitle(R.string.dialog_disable_app_obscured_disclaimer_title) //
|
||||
.setPositiveButton(getString(R.string.dialog_disable_app_obscured_positive_button)) { _: DialogInterface, _: Int -> callback?.onDisableSecureScreenDisclaimerAccepted() } //
|
||||
.setNegativeButton(getString(R.string.dialog_disable_app_obscured_negative_button)) { _: DialogInterface, _: Int -> callback?.onDisableSecureScreenDisclaimerRejected() }
|
||||
.setTitle(R.string.dialog_disable_app_obscured_disclaimer_title) //
|
||||
.setPositiveButton(getString(R.string.dialog_disable_app_obscured_positive_button)) { _: DialogInterface, _: Int -> callback?.onDisableSecureScreenDisclaimerAccepted() } //
|
||||
.setNegativeButton(getString(R.string.dialog_disable_app_obscured_negative_button)) { _: DialogInterface, _: Int -> callback?.onDisableSecureScreenDisclaimerRejected() }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
@ -21,11 +21,13 @@ class EnrollSystemBiometricDialog : BaseDialog<EnrollSystemBiometricDialog.Callb
|
||||
|
||||
override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
builder //
|
||||
.setTitle(getString(R.string.dialog_no_biometric_auth_set_up_title)) //
|
||||
.setPositiveButton(getString(R.string.dialog_unable_to_share_positive_button) //
|
||||
) { _: DialogInterface, _: Int -> callback?.onSetupBiometricAuthInSystemClicked() }
|
||||
.setNegativeButton(getString(R.string.dialog_button_cancel) //
|
||||
) { _: DialogInterface?, _: Int -> callback?.onCancelSetupBiometricAuthInSystemClicked() }
|
||||
.setTitle(getString(R.string.dialog_no_biometric_auth_set_up_title)) //
|
||||
.setPositiveButton(
|
||||
getString(R.string.dialog_unable_to_share_positive_button) //
|
||||
) { _: DialogInterface, _: Int -> callback?.onSetupBiometricAuthInSystemClicked() }
|
||||
.setNegativeButton(
|
||||
getString(R.string.dialog_button_cancel) //
|
||||
) { _: DialogInterface?, _: Int -> callback?.onCancelSetupBiometricAuthInSystemClicked() }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
@ -51,12 +51,12 @@ class EnterPasswordDialog : BaseProgressErrorDialog<EnterPasswordDialog.Callback
|
||||
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
return builder //
|
||||
.setTitle(vaultModel().name) //
|
||||
.setPositiveButton(getString(R.string.dialog_enter_password_positive_button)) { _: DialogInterface, _: Int -> }
|
||||
.setNegativeButton(getString(R.string.dialog_button_cancel)) { _: DialogInterface, _: Int ->
|
||||
callback?.onUnlockCanceled()
|
||||
callback?.closeDialog()
|
||||
}.create()
|
||||
.setTitle(vaultModel().name) //
|
||||
.setPositiveButton(getString(R.string.dialog_enter_password_positive_button)) { _: DialogInterface, _: Int -> }
|
||||
.setNegativeButton(getString(R.string.dialog_button_cancel)) { _: DialogInterface, _: Int ->
|
||||
callback?.onUnlockCanceled()
|
||||
callback?.closeDialog()
|
||||
}.create()
|
||||
}
|
||||
|
||||
fun vaultModel(): VaultModel {
|
||||
|
@ -19,8 +19,8 @@ class ExistingFileDialog : BaseDialog<ExistingFileDialog.Callback>() {
|
||||
override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
val fileUri = requireArguments().getParcelable<Uri>(FILE_URI_ARG)
|
||||
builder.setTitle(getString(R.string.dialog_existing_file_title)) //
|
||||
.setPositiveButton(getString(R.string.dialog_existing_file_positive_button)) { _: DialogInterface?, _: Int -> fileUri?.let { callback?.onReplaceClick(it) } } //
|
||||
.setNegativeButton(getString(R.string.dialog_button_cancel)) { _: DialogInterface?, _: Int -> }
|
||||
.setPositiveButton(getString(R.string.dialog_existing_file_positive_button)) { _: DialogInterface?, _: Int -> fileUri?.let { callback?.onReplaceClick(it) } } //
|
||||
.setNegativeButton(getString(R.string.dialog_button_cancel)) { _: DialogInterface?, _: Int -> }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
@ -32,15 +32,17 @@ class ExportCloudFilesDialog : BaseProgressErrorDialog<ExportCloudFilesDialog.Ca
|
||||
|
||||
override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
return builder //
|
||||
.setTitle(effectiveTitle(1)) //
|
||||
.setNeutralButton(getString(R.string.dialog_export_file_cancel_button)) { _: DialogInterface, _: Int -> callback?.onExportCancelled() } //
|
||||
.create()
|
||||
.setTitle(effectiveTitle(1)) //
|
||||
.setNeutralButton(getString(R.string.dialog_export_file_cancel_button)) { _: DialogInterface, _: Int -> callback?.onExportCancelled() } //
|
||||
.create()
|
||||
}
|
||||
|
||||
private fun effectiveTitle(seenFiles: Int): String {
|
||||
return String.format(getString(R.string.dialog_export_file_title), //
|
||||
seenFiles, //
|
||||
requireArguments().getInt(ARG_NUMBER_OF_FILES))
|
||||
return String.format(
|
||||
getString(R.string.dialog_export_file_title), //
|
||||
seenFiles, //
|
||||
requireArguments().getInt(ARG_NUMBER_OF_FILES)
|
||||
)
|
||||
}
|
||||
|
||||
override fun setupView() {}
|
||||
|
@ -46,9 +46,9 @@ class FileNameDialog : BaseProgressErrorDialog<FileNameDialog.Callback>() {
|
||||
|
||||
override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
return builder.setTitle(R.string.dialog_file_name_title) //
|
||||
.setPositiveButton(R.string.dialog_file_name_create) { _: DialogInterface, _: Int -> } //
|
||||
.setNegativeButton(R.string.dialog_file_name_cancel) { _: DialogInterface, _: Int -> } //
|
||||
.create()
|
||||
.setPositiveButton(R.string.dialog_file_name_create) { _: DialogInterface, _: Int -> } //
|
||||
.setNegativeButton(R.string.dialog_file_name_cancel) { _: DialogInterface, _: Int -> } //
|
||||
.create()
|
||||
}
|
||||
|
||||
private fun effectiveNewFileName(newFileName: String): String {
|
||||
|
@ -18,8 +18,8 @@ class FileTypeNotSupportedDialog : BaseDialog<FileTypeNotSupportedDialog.Callbac
|
||||
override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
val cloudFileModel = requireArguments().getSerializable(CLOUD_FILE_ARG) as CloudFileModel
|
||||
builder.setTitle(String.format(getString(R.string.dialog_filetype_not_supported_title), cloudFileModel.name))
|
||||
.setPositiveButton(getString(R.string.dialog_filetype_not_supported_positive_button)) { _: DialogInterface, _: Int -> callback?.onExportFileAfterAppChooserClicked(cloudFileModel) } //
|
||||
.setNegativeButton(getString(R.string.dialog_button_cancel)) { _: DialogInterface, _: Int -> }
|
||||
.setPositiveButton(getString(R.string.dialog_filetype_not_supported_positive_button)) { _: DialogInterface, _: Int -> callback?.onExportFileAfterAppChooserClicked(cloudFileModel) } //
|
||||
.setNegativeButton(getString(R.string.dialog_button_cancel)) { _: DialogInterface, _: Int -> }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,8 @@ class LicenseConfirmationDialog : BaseDialog<LicenseConfirmationDialog.Callback>
|
||||
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
builder //
|
||||
.setTitle(getString(R.string.dialog_license_confirmation_title)) //
|
||||
.setNeutralButton(getText(R.string.dialog_license_confirmation_ok_btn)) { _: DialogInterface, _: Int -> callback?.licenseConfirmationClicked() }
|
||||
.setTitle(getString(R.string.dialog_license_confirmation_title)) //
|
||||
.setNeutralButton(getText(R.string.dialog_license_confirmation_ok_btn)) { _: DialogInterface, _: Int -> callback?.licenseConfirmationClicked() }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
@ -18,11 +18,11 @@ class NoDirFileDialog : BaseDialog<NoDirFileDialog.CallBack>() {
|
||||
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
builder //
|
||||
.setTitle(R.string.dialog_no_dir_file_title) //
|
||||
.setNeutralButton(R.string.dialog_no_dir_file_back_button) { dialog: DialogInterface, _: Int ->
|
||||
callback?.navigateFolderBackBecauseNoDirFile()
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setTitle(R.string.dialog_no_dir_file_title) //
|
||||
.setNeutralButton(R.string.dialog_no_dir_file_back_button) { dialog: DialogInterface, _: Int ->
|
||||
callback?.navigateFolderBackBecauseNoDirFile()
|
||||
dialog.dismiss()
|
||||
}
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
@ -24,13 +24,13 @@ class NotEnoughVaultsDialog private constructor(private val context: Context) {
|
||||
|
||||
fun show() {
|
||||
AlertDialog.Builder(context) //
|
||||
.setCancelable(false) //
|
||||
.setTitle(title) //
|
||||
.setMessage(ResourceHelper.getString(R.string.dialog_unable_to_share_message)) //
|
||||
.setPositiveButton(ResourceHelper.getString(R.string.dialog_unable_to_share_positive_button)) { _: DialogInterface, _: Int -> callback.onNotEnoughVaultsOkClicked() } //
|
||||
.setNegativeButton(ResourceHelper.getString(R.string.dialog_unable_to_share_negative_button)) { _: DialogInterface, _: Int -> callback.onNotEnoughVaultsCreateVaultClicked() } //
|
||||
.create() //
|
||||
.show()
|
||||
.setCancelable(false) //
|
||||
.setTitle(title) //
|
||||
.setMessage(ResourceHelper.getString(R.string.dialog_unable_to_share_message)) //
|
||||
.setPositiveButton(ResourceHelper.getString(R.string.dialog_unable_to_share_positive_button)) { _: DialogInterface, _: Int -> callback.onNotEnoughVaultsOkClicked() } //
|
||||
.setNegativeButton(ResourceHelper.getString(R.string.dialog_unable_to_share_negative_button)) { _: DialogInterface, _: Int -> callback.onNotEnoughVaultsCreateVaultClicked() } //
|
||||
.create() //
|
||||
.show()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -20,11 +20,11 @@ class ReplaceDialog private constructor(private val context: Context) {
|
||||
fun show(existingFiles: List<String>, uploadingFilesCount: Int) {
|
||||
val existingFilesCount = existingFiles.size
|
||||
val alertDialogBuilder = AlertDialog.Builder(context) //
|
||||
.setTitle(effectiveReplaceDialogTitle(existingFilesCount)) //
|
||||
.setMessage(effectiveReplaceDialogMessage(existingFiles, uploadingFilesCount))
|
||||
.setPositiveButton(effectiveReplaceDialogPositiveButton(existingFilesCount, uploadingFilesCount)) { _: DialogInterface, _: Int -> callback.onReplacePositiveClicked() } //
|
||||
.setNeutralButton(effectiveReplaceDialogNeutralButton()) { _: DialogInterface, _: Int -> callback.onReplaceCanceled() } //
|
||||
.setOnCancelListener { callback.onReplaceCanceled() }
|
||||
.setTitle(effectiveReplaceDialogTitle(existingFilesCount)) //
|
||||
.setMessage(effectiveReplaceDialogMessage(existingFiles, uploadingFilesCount))
|
||||
.setPositiveButton(effectiveReplaceDialogPositiveButton(existingFilesCount, uploadingFilesCount)) { _: DialogInterface, _: Int -> callback.onReplacePositiveClicked() } //
|
||||
.setNeutralButton(effectiveReplaceDialogNeutralButton()) { _: DialogInterface, _: Int -> callback.onReplaceCanceled() } //
|
||||
.setOnCancelListener { callback.onReplaceCanceled() }
|
||||
if (uploadingFilesCount > 1 && existingFilesCount != uploadingFilesCount) {
|
||||
alertDialogBuilder.setNegativeButton(effectiveReplaceDialogNegativeButton()) { _: DialogInterface, _: Int -> callback.onReplaceNegativeClicked() }
|
||||
}
|
||||
|
@ -18,11 +18,11 @@ class SymLinkDialog : BaseDialog<SymLinkDialog.CallBack?>() {
|
||||
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
builder //
|
||||
.setTitle(R.string.dialog_sym_link_title) //
|
||||
.setNeutralButton(R.string.dialog_sym_link_back_button) { dialog: DialogInterface, _: Int ->
|
||||
callback?.navigateFolderBackBecauseSymlink()
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setTitle(R.string.dialog_sym_link_title) //
|
||||
.setNeutralButton(R.string.dialog_sym_link_back_button) { dialog: DialogInterface, _: Int ->
|
||||
callback?.navigateFolderBackBecauseSymlink()
|
||||
dialog.dismiss()
|
||||
}
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
@ -17,12 +17,12 @@ class UnsavedChangesDialog private constructor(private val context: Context) {
|
||||
|
||||
fun show() {
|
||||
AlertDialog.Builder(context) //
|
||||
.setCancelable(false) //
|
||||
.setTitle(R.string.dialog_unsaved_changes_title) //
|
||||
.setMessage(R.string.dialog_unsaved_changes_message) //
|
||||
.setPositiveButton(R.string.dialog_unsaved_changes_save) { _: DialogInterface?, _: Int -> callback.onSaveChangesClicked() } //
|
||||
.setNegativeButton(R.string.dialog_unsaved_changes_discard) { _: DialogInterface?, _: Int -> callback.onDiscardChangesClicked() } //
|
||||
.create().show()
|
||||
.setCancelable(false) //
|
||||
.setTitle(R.string.dialog_unsaved_changes_title) //
|
||||
.setMessage(R.string.dialog_unsaved_changes_message) //
|
||||
.setPositiveButton(R.string.dialog_unsaved_changes_save) { _: DialogInterface?, _: Int -> callback.onSaveChangesClicked() } //
|
||||
.setNegativeButton(R.string.dialog_unsaved_changes_discard) { _: DialogInterface?, _: Int -> callback.onDiscardChangesClicked() } //
|
||||
.create().show()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -22,12 +22,12 @@ class UpdateAppAvailableDialog : BaseProgressErrorDialog<UpdateAppAvailableDialo
|
||||
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
return builder //
|
||||
.setTitle(getString(R.string.dialog_update_available_title)) //
|
||||
.setPositiveButton(getString(R.string.dialog_update_available_update)) { _: DialogInterface, _: Int -> callback?.installUpdate() } //
|
||||
.setNeutralButton(getString(R.string.dialog_update_available_download_site)) { _: DialogInterface, _: Int -> callback?.showUpdateWebsite() }
|
||||
.setNegativeButton(getText(R.string.dialog_update_available_cancel)) { _: DialogInterface, _: Int -> callback?.cancelUpdateClicked() } //
|
||||
.setCancelable(false) //
|
||||
.create()
|
||||
.setTitle(getString(R.string.dialog_update_available_title)) //
|
||||
.setPositiveButton(getString(R.string.dialog_update_available_update)) { _: DialogInterface, _: Int -> callback?.installUpdate() } //
|
||||
.setNeutralButton(getString(R.string.dialog_update_available_download_site)) { _: DialogInterface, _: Int -> callback?.showUpdateWebsite() }
|
||||
.setNegativeButton(getText(R.string.dialog_update_available_cancel)) { _: DialogInterface, _: Int -> callback?.cancelUpdateClicked() } //
|
||||
.setCancelable(false) //
|
||||
.create()
|
||||
}
|
||||
|
||||
public override fun setupView() {
|
||||
|
@ -21,9 +21,9 @@ class UpdateAppDialog : BaseProgressErrorDialog<UpdateAppDialog.Callback>() {
|
||||
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
return builder //
|
||||
.setTitle(getString(R.string.dialog_download_update_title)) //
|
||||
.setCancelable(false) //
|
||||
.create()
|
||||
.setTitle(getString(R.string.dialog_download_update_title)) //
|
||||
.setCancelable(false) //
|
||||
.create()
|
||||
}
|
||||
|
||||
public override fun setupView() {
|
||||
|
@ -39,10 +39,10 @@ class UpdateLicenseDialog : BaseProgressErrorDialog<UpdateLicenseDialog.Callback
|
||||
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
return builder //
|
||||
.setTitle(getString(R.string.dialog_enter_license_title)) //
|
||||
.setPositiveButton(getText(R.string.dialog_enter_license_ok_button)) { _: DialogInterface, _: Int -> } //
|
||||
.setNegativeButton(getText(R.string.dialog_enter_license_decline_button)) { _: DialogInterface, _: Int -> callback?.onCheckLicenseCanceled() } //
|
||||
.create()
|
||||
.setTitle(getString(R.string.dialog_enter_license_title)) //
|
||||
.setPositiveButton(getText(R.string.dialog_enter_license_ok_button)) { _: DialogInterface, _: Int -> } //
|
||||
.setNegativeButton(getText(R.string.dialog_enter_license_decline_button)) { _: DialogInterface, _: Int -> callback?.onCheckLicenseCanceled() } //
|
||||
.create()
|
||||
}
|
||||
|
||||
public override fun setupView() {
|
||||
|
@ -41,9 +41,9 @@ class UploadCloudFileDialog : BaseProgressErrorDialog<UploadCloudFileDialog.Call
|
||||
|
||||
override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
return builder //
|
||||
.setTitle(effectiveTitle()) //
|
||||
.setNeutralButton(getString(R.string.dialog_upload_file_cancel_button)) { _: DialogInterface?, _: Int -> } //
|
||||
.create()
|
||||
.setTitle(effectiveTitle()) //
|
||||
.setNeutralButton(getString(R.string.dialog_upload_file_cancel_button)) { _: DialogInterface?, _: Int -> } //
|
||||
.create()
|
||||
}
|
||||
|
||||
private fun effectiveTitle(): String {
|
||||
|
@ -19,8 +19,8 @@ class VaultDeleteConfirmationDialog : BaseDialog<VaultDeleteConfirmationDialog.C
|
||||
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
|
||||
val vaultModel = requireArguments().getSerializable(VAULT_ARG) as VaultModel
|
||||
builder.setTitle(vaultModel.name) //
|
||||
.setPositiveButton(getString(R.string.dialog_delete_vault_positive_button_text)) { _: DialogInterface, _: Int -> callback?.onDeleteConfirmedClick(vaultModel) } //
|
||||
.setNegativeButton(getString(R.string.dialog_button_cancel)) { _: DialogInterface, _: Int -> }
|
||||
.setPositiveButton(getString(R.string.dialog_delete_vault_positive_button_text)) { _: DialogInterface, _: Int -> callback?.onDeleteConfirmedClick(vaultModel) } //
|
||||
.setNegativeButton(getString(R.string.dialog_button_cancel)) { _: DialogInterface, _: Int -> }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user