From dc7cef7fb5882761992859ad7f02fc085dc923db Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Sun, 31 Jan 2021 16:45:02 +0100 Subject: [PATCH 01/11] #168 implement UI for sorting vault list. Backend still WIP --- .../presenter/VaultListPresenter.kt | 11 +++++++ .../ui/activity/VaultListActivity.kt | 4 +++ .../ui/activity/view/VaultListView.kt | 2 +- .../presentation/ui/adapter/VaultsAdapter.kt | 10 ++++-- .../ui/adapter/VaultsMoveListener.kt | 32 +++++++++++++++++++ .../ui/fragment/VaultListFragment.kt | 29 ++++++++++++++++- 6 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 presentation/src/main/java/org/cryptomator/presentation/ui/adapter/VaultsMoveListener.kt diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt index 74a3d225..47c67091 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt @@ -603,6 +603,17 @@ class VaultListPresenter @Inject constructor( // view?.showDialog(AppIsObscuredInfoDialog.newInstance()) } + fun onVaultMoved(fromPosition: Int, toPosition: Int) { + // FIXME insert position int into the db and update here + + getVaultListUseCase.run(object : DefaultResultHandler>() { + override fun onSuccess(vaults: List) { + val vaultModels = vaults.mapTo(ArrayList()) { VaultModel(it) } + view?.vaultMoved(fromPosition, toPosition, vaultModels) + } + }) + } + fun onBiometricAuthenticationSucceeded(vaultModel: VaultModel) { if (changedVaultPassword) { changedVaultPassword = false diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/VaultListActivity.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/VaultListActivity.kt index 8d8e4642..e7643f43 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/VaultListActivity.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/VaultListActivity.kt @@ -150,6 +150,10 @@ class VaultListActivity : BaseActivity(), // return biometricAuthentication?.stoppedBiometricAuthDuringCloudAuthentication() == true } + override fun vaultMoved(fromPosition: Int, toPosition: Int, vaultModelCollection: List) { + vaultListFragment().vaultMoved(fromPosition, toPosition, vaultModelCollection) + } + override fun showVaultSettingsDialog(vaultModel: VaultModel) { val vaultSettingDialog = // SettingsVaultBottomSheet.newInstance(vaultModel) diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/view/VaultListView.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/view/VaultListView.kt index 300ea4da..1682c7a2 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/view/VaultListView.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/view/VaultListView.kt @@ -23,5 +23,5 @@ interface VaultListView : View { fun isVaultLocked(vaultModel: VaultModel): Boolean fun cancelBasicAuthIfRunning() fun stoppedBiometricAuthDuringCloudAuthentication(): Boolean - + fun vaultMoved(fromPosition: Int, toPosition: Int, vaultModelCollection: List) } diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/adapter/VaultsAdapter.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/adapter/VaultsAdapter.kt index 322e4f54..779a1ea4 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/adapter/VaultsAdapter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/adapter/VaultsAdapter.kt @@ -8,14 +8,16 @@ import org.cryptomator.presentation.ui.adapter.VaultsAdapter.VaultViewHolder import javax.inject.Inject class VaultsAdapter @Inject -internal constructor() : RecyclerViewBaseAdapter() { +internal constructor() : RecyclerViewBaseAdapter(), VaultsMoveListener.Listener { - interface OnItemClickListener { + interface OnItemInteractionListener { fun onVaultClicked(vaultModel: VaultModel) fun onVaultSettingsClicked(vaultModel: VaultModel) fun onVaultLockClicked(vaultModel: VaultModel) + + fun onVaultMoved(fromPosition: Int, toPosition: Int) } override fun getItemLayout(viewType: Int): Int { @@ -65,4 +67,8 @@ internal constructor() : RecyclerViewBaseAdapter?) { + if (fromPosition < toPosition) { + for (i in fromPosition until toPosition) { + Collections.swap(vaultModelCollection, i, i + 1) + } + } else { + for (i in fromPosition downTo toPosition + 1) { + Collections.swap(vaultModelCollection, i, i - 1) + } + } + + vaultsAdapter.notifyItemMoved(fromPosition, toPosition) + } + fun rootView(): View = coordinatorLayout } From 00174fdf5ac94b7dec3a0353fc13a6663102935d Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Sun, 31 Jan 2021 22:54:49 +0100 Subject: [PATCH 02/11] #168 implement backend for sorting vault list. --- data/build.gradle | 2 +- .../cryptomator/data/db/DatabaseUpgrades.java | 6 +- .../org/cryptomator/data/db/Upgrade3To4.kt | 66 +++++++++++++++++++ .../data/db/entities/VaultEntity.java | 16 ++++- .../data/db/mappers/VaultEntityMapper.java | 2 + .../java/org/cryptomator/domain/Vault.java | 18 ++++- .../domain/usecases/vault/MoveVault.java | 28 ++++++++ .../domain/usecases/vault/MoveVaultHelper.kt | 45 +++++++++++++ .../presentation/model/VaultModel.kt | 2 + .../presenter/VaultListPresenter.kt | 27 ++++++-- .../ui/activity/VaultListActivity.kt | 8 ++- .../ui/activity/view/VaultListView.kt | 4 +- .../presentation/ui/adapter/VaultsAdapter.kt | 17 ++++- .../ui/adapter/VaultsMoveListener.kt | 25 +++++++ .../ui/fragment/VaultListFragment.kt | 20 +++--- 15 files changed, 258 insertions(+), 28 deletions(-) create mode 100644 data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt create mode 100644 domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVault.java create mode 100644 domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt diff --git a/data/build.gradle b/data/build.gradle index d9b3ca1c..7740b19c 100644 --- a/data/build.gradle +++ b/data/build.gradle @@ -74,7 +74,7 @@ android { } greendao { - schemaVersion 3 + schemaVersion 4 } configurations.all { diff --git a/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrades.java b/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrades.java index f188e34f..60458e36 100644 --- a/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrades.java +++ b/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrades.java @@ -21,12 +21,14 @@ class DatabaseUpgrades { public DatabaseUpgrades( // Upgrade0To1 upgrade0To1, // Upgrade1To2 upgrade1To2, // - Upgrade2To3 upgrade2To3) { + Upgrade2To3 upgrade2To3, // + Upgrade3To4 upgrade3To4) { availableUpgrades = defineUpgrades( // upgrade0To1, // upgrade1To2, // - upgrade2To3); + upgrade2To3, // + upgrade3To4); } private Map> defineUpgrades(DatabaseUpgrade... upgrades) { diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt new file mode 100644 index 00000000..5ecb6cb2 --- /dev/null +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt @@ -0,0 +1,66 @@ +package org.cryptomator.data.db + +import org.cryptomator.data.db.Sql.SqlCreateTableBuilder.ForeignKeyBehaviour +import org.cryptomator.data.db.entities.CloudEntityDao +import org.cryptomator.data.db.entities.VaultEntityDao +import org.greenrobot.greendao.database.Database +import org.greenrobot.greendao.internal.DaoConfig +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +internal class Upgrade3To4 @Inject constructor() : DatabaseUpgrade(3, 4) { + + override fun internalApplyTo(db: Database, origin: Int) { + db.beginTransaction() + try { + upgradeDatabaseScheme(db) + updateVaultPositions(db) + db.setTransactionSuccessful() + } finally { + db.endTransaction() + } + } + + private fun upgradeDatabaseScheme(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) + + Sql.insertInto("VAULT_ENTITY") // + .select("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "CLOUD_ENTITY.TYPE") // + .columns("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "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) + + Sql.dropTable("VAULT_ENTITY_OLD").executeOn(db) + } + + private fun updateVaultPositions(db: Database) { + CloudEntityDao(DaoConfig(db, VaultEntityDao::class.java)) // + .loadAll() // + .map { + Sql.update("CLOUD_ENTITY") // + .where("_id", Sql.eq(it.id)) // + .set("POSITION", Sql.toInteger(it.id)) // + .executeOn(db) + } + } +} diff --git a/data/src/main/java/org/cryptomator/data/db/entities/VaultEntity.java b/data/src/main/java/org/cryptomator/data/db/entities/VaultEntity.java index 75baf600..9201131d 100644 --- a/data/src/main/java/org/cryptomator/data/db/entities/VaultEntity.java +++ b/data/src/main/java/org/cryptomator/data/db/entities/VaultEntity.java @@ -28,6 +28,8 @@ public class VaultEntity extends DatabaseEntity { private String password; + private Integer position; + /** * Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}. * Entity must attached to an entity context. @@ -152,6 +154,14 @@ public class VaultEntity extends DatabaseEntity { this.password = password; } + public Integer getPosition() { + return this.position; + } + + public void setPosition(Integer position) { + this.position = position; + } + /** called by internal mechanisms, do not call yourself. */ @Generated(hash = 674742652) public void __setDaoSession(DaoSession daoSession) { @@ -159,14 +169,16 @@ public class VaultEntity extends DatabaseEntity { myDao = daoSession != null ? daoSession.getVaultEntityDao() : null; } - @Generated(hash = 1196809909) - public VaultEntity(Long id, Long folderCloudId, String folderPath, String folderName, @NotNull String cloudType, String password) { + @Generated(hash = 825602374) + public VaultEntity(Long id, Long folderCloudId, String folderPath, String folderName, @NotNull String cloudType, String password, + Integer position) { this.id = id; this.folderCloudId = folderCloudId; this.folderPath = folderPath; this.folderName = folderName; this.cloudType = cloudType; this.password = password; + this.position = position; } @Generated(hash = 691253864) diff --git a/data/src/main/java/org/cryptomator/data/db/mappers/VaultEntityMapper.java b/data/src/main/java/org/cryptomator/data/db/mappers/VaultEntityMapper.java index 645ab322..aabbfff1 100644 --- a/data/src/main/java/org/cryptomator/data/db/mappers/VaultEntityMapper.java +++ b/data/src/main/java/org/cryptomator/data/db/mappers/VaultEntityMapper.java @@ -30,6 +30,7 @@ public class VaultEntityMapper extends EntityMapper { .withCloud(cloudFrom(entity)) // .withCloudType(CloudType.valueOf(entity.getCloudType())) // .withSavedPassword(entity.getPassword()) // + .withPosition(entity.getPosition()) // .build(); } @@ -51,6 +52,7 @@ public class VaultEntityMapper extends EntityMapper { } entity.setCloudType(domainObject.getCloudType().name()); entity.setPassword(domainObject.getPassword()); + entity.setPosition(domainObject.getPosition()); return entity; } } diff --git a/domain/src/main/java/org/cryptomator/domain/Vault.java b/domain/src/main/java/org/cryptomator/domain/Vault.java index 6bcd3669..1290f40b 100644 --- a/domain/src/main/java/org/cryptomator/domain/Vault.java +++ b/domain/src/main/java/org/cryptomator/domain/Vault.java @@ -19,7 +19,8 @@ public class Vault implements Serializable { .withPath(vault.getPath()) // .withUnlocked(vault.isUnlocked()) // .withSavedPassword(vault.getPassword()) // - .withVersion(vault.getVersion()); + .withVersion(vault.getVersion()) + .withPosition(vault.getPosition()); } private final Long id; @@ -30,6 +31,7 @@ public class Vault implements Serializable { private final boolean unlocked; private final String password; private final int version; + private final int position; private Vault(Builder builder) { this.id = builder.id; @@ -40,6 +42,7 @@ public class Vault implements Serializable { this.cloudType = builder.cloudType; this.password = builder.password; this.version = builder.version; + this.position = builder.position; } public Long getId() { @@ -74,6 +77,10 @@ public class Vault implements Serializable { return version; } + public int getPosition() { + return position; + } + public static class Builder { private Long id = NOT_SET; @@ -84,6 +91,7 @@ public class Vault implements Serializable { private boolean unlocked; private String password; private int version = -1; + private int position = -1; private Builder() { } @@ -154,6 +162,11 @@ public class Vault implements Serializable { return this; } + public Builder withPosition(int position) { + this.position = position; + return this; + } + public Vault build() { validate(); return new Vault(this); @@ -172,6 +185,9 @@ public class Vault implements Serializable { if (cloudType == null) { throw new IllegalStateException("cloudtype must be set"); } + if (position == -1) { + throw new IllegalStateException("position must be set"); + } } } diff --git a/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVault.java b/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVault.java new file mode 100644 index 00000000..10bce6a5 --- /dev/null +++ b/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVault.java @@ -0,0 +1,28 @@ +package org.cryptomator.domain.usecases.vault; + +import org.cryptomator.domain.Vault; +import org.cryptomator.domain.exception.BackendException; +import org.cryptomator.domain.repository.VaultRepository; +import org.cryptomator.generator.Parameter; +import org.cryptomator.generator.UseCase; + +import java.util.List; + +@UseCase +class MoveVault { + + private final VaultRepository vaultRepository; + private final int from; + private final int to; + + public MoveVault(VaultRepository vaultRepository, @Parameter Integer from, @Parameter Integer to) { + this.vaultRepository = vaultRepository; + this.from = from; + this.to = to; + } + + public List execute() throws BackendException { + List vaults = MoveVaultHelper.Companion.updateVaultPosition(from, to, vaultRepository); + return MoveVaultHelper.Companion.updateVaultsInDatabase(vaults, vaultRepository); + } +} diff --git a/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt b/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt new file mode 100644 index 00000000..7bd498c6 --- /dev/null +++ b/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt @@ -0,0 +1,45 @@ +package org.cryptomator.domain.usecases.vault; + +import org.cryptomator.domain.Vault +import org.cryptomator.domain.repository.VaultRepository +import java.util.* + +class MoveVaultHelper { + + companion object { + fun updateVaultPosition(from: Int, to: Int, vaultRepository: VaultRepository): List { + val vaults = vaultRepository.vaults() + + vaults.sortWith(VaultComparator()) + + if (from < to) { + for (i in from until to) { + Collections.swap(vaults, i, i + 1) + } + } else { + for (i in from downTo to + 1) { + Collections.swap(vaults, i, i - 1) + } + } + + for (i in 0 until vaults.size) { + vaults[i] = Vault.aCopyOf(vaults[i]).withPosition(i + 1).build() + } + + vaults.forEach { vault -> vaultRepository.store(vault) } + + return vaults + } + + fun updateVaultsInDatabase(vaults: List, vaultRepository: VaultRepository): List { + vaults.forEach { vault -> vaultRepository.store(vault) } + return vaultRepository.vaults() + } + } + + internal class VaultComparator : Comparator { + override fun compare(o1: Vault, o2: Vault): Int { + return o1.position - o2.position + } + } +} diff --git a/presentation/src/main/java/org/cryptomator/presentation/model/VaultModel.kt b/presentation/src/main/java/org/cryptomator/presentation/model/VaultModel.kt index 762d4a95..f15f1c50 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/model/VaultModel.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/model/VaultModel.kt @@ -13,6 +13,8 @@ class VaultModel(private val vault: Vault) : Serializable { get() = vault.path val isLocked: Boolean get() = !vault.isUnlocked + val position: Int + get() = vault.position fun toVault(): Vault { return vault diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt index 47c67091..09557a25 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt @@ -53,6 +53,7 @@ class VaultListPresenter @Inject constructor( // private val addExistingVaultWorkflow: AddExistingVaultWorkflow, // private val createNewVaultWorkflow: CreateNewVaultWorkflow, // private val saveVaultUseCase: SaveVaultUseCase, // + private val moveVaultUseCase: MoveVaultUseCase, // private val changePasswordUseCase: ChangePasswordUseCase, // private val removeStoredVaultPasswordsUseCase: RemoveStoredVaultPasswordsUseCase, // private val licenseCheckUseCase: DoLicenseCheckUseCase, // @@ -603,17 +604,33 @@ class VaultListPresenter @Inject constructor( // view?.showDialog(AppIsObscuredInfoDialog.newInstance()) } - fun onVaultMoved(fromPosition: Int, toPosition: Int) { - // FIXME insert position int into the db and update here - + fun onRowMoved(fromPosition: Int, toPosition: Int) { getVaultListUseCase.run(object : DefaultResultHandler>() { override fun onSuccess(vaults: List) { - val vaultModels = vaults.mapTo(ArrayList()) { VaultModel(it) } - view?.vaultMoved(fromPosition, toPosition, vaultModels) + view?.rowMoved(fromPosition, toPosition) + } + + override fun onError(e: Throwable) { + Timber.tag("VaultListPresenter").e(e, "Failed to query vault list while row moving") } }) } + fun onVaultMoved(fromPosition: Int, toPosition: Int) { + moveVaultUseCase + .withFrom(fromPosition) // + .andTo(toPosition) // + .run(object : DefaultResultHandler>() { + override fun onSuccess(vaults: List) { + view?.vaultMoved(vaults.mapTo(ArrayList()) { VaultModel(it) }) + } + + override fun onError(e: Throwable) { + Timber.tag("VaultListPresenter").e(e, "Failed to execute MoveVaultUseCase") + } + }) + } + fun onBiometricAuthenticationSucceeded(vaultModel: VaultModel) { if (changedVaultPassword) { changedVaultPassword = false diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/VaultListActivity.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/VaultListActivity.kt index e7643f43..73778681 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/VaultListActivity.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/VaultListActivity.kt @@ -150,8 +150,12 @@ class VaultListActivity : BaseActivity(), // return biometricAuthentication?.stoppedBiometricAuthDuringCloudAuthentication() == true } - override fun vaultMoved(fromPosition: Int, toPosition: Int, vaultModelCollection: List) { - vaultListFragment().vaultMoved(fromPosition, toPosition, vaultModelCollection) + override fun vaultMoved(vaults: List) { + vaultListFragment().vaultMoved(vaults) + } + + override fun rowMoved(fromPosition: Int, toPosition: Int) { + vaultListFragment().rowMoved(fromPosition, toPosition) } override fun showVaultSettingsDialog(vaultModel: VaultModel) { diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/view/VaultListView.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/view/VaultListView.kt index 1682c7a2..d5d25fb7 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/view/VaultListView.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/view/VaultListView.kt @@ -23,5 +23,7 @@ interface VaultListView : View { fun isVaultLocked(vaultModel: VaultModel): Boolean fun cancelBasicAuthIfRunning() fun stoppedBiometricAuthDuringCloudAuthentication(): Boolean - fun vaultMoved(fromPosition: Int, toPosition: Int, vaultModelCollection: List) + fun vaultMoved(vaults: List) + fun rowMoved(fromPosition: Int, toPosition: Int) + } diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/adapter/VaultsAdapter.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/adapter/VaultsAdapter.kt index 779a1ea4..5d00e96d 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/adapter/VaultsAdapter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/adapter/VaultsAdapter.kt @@ -8,8 +8,7 @@ import org.cryptomator.presentation.ui.adapter.VaultsAdapter.VaultViewHolder import javax.inject.Inject class VaultsAdapter @Inject -internal constructor() : RecyclerViewBaseAdapter(), VaultsMoveListener.Listener { - +internal constructor() : RecyclerViewBaseAdapter(VaultModelComparator()), VaultsMoveListener.Listener { interface OnItemInteractionListener { fun onVaultClicked(vaultModel: VaultModel) @@ -17,6 +16,8 @@ internal constructor() : RecyclerViewBaseAdapter { + override fun compare(o1: VaultModel, o2: VaultModel): Int { + return o1.position - o2.position + } + } } diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/adapter/VaultsMoveListener.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/adapter/VaultsMoveListener.kt index 4723be1a..6c0ee760 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/adapter/VaultsMoveListener.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/adapter/VaultsMoveListener.kt @@ -5,6 +5,9 @@ import androidx.recyclerview.widget.RecyclerView class VaultsMoveListener(val adapter: VaultsAdapter) : ItemTouchHelper.Callback() { + var dragFrom = -1 + var dragTo = -1 + override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN return makeMovementFlags(dragFlags, 0) @@ -19,14 +22,36 @@ class VaultsMoveListener(val adapter: VaultsAdapter) : ItemTouchHelper.Callback( } override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { + val fromPosition = viewHolder.adapterPosition + val toPosition = target.adapterPosition + + if (dragFrom == -1) { + dragFrom = fromPosition; + } + + dragTo = toPosition; + adapter.onRowMoved(viewHolder.adapterPosition, target.adapterPosition) return true } + + override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) { + super.clearView(recyclerView, viewHolder) + + if (dragFrom != -1 && dragTo != -1 && dragFrom != dragTo) { + adapter.onVaultMoved(dragFrom, dragTo) + } + + dragTo = -1 + dragFrom = -1 + } + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { } interface Listener { fun onRowMoved(fromPosition: Int, toPosition: Int) + fun onVaultMoved(fromPosition: Int, toPosition: Int) } } diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/VaultListFragment.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/VaultListFragment.kt index 617b2bac..9069acbc 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/VaultListFragment.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/fragment/VaultListFragment.kt @@ -13,7 +13,6 @@ import org.cryptomator.presentation.model.VaultModel import org.cryptomator.presentation.presenter.VaultListPresenter import org.cryptomator.presentation.ui.adapter.VaultsAdapter import org.cryptomator.presentation.ui.adapter.VaultsMoveListener -import java.util.* import javax.inject.Inject @Fragment(R.layout.fragment_vault_list) @@ -40,6 +39,10 @@ class VaultListFragment : BaseFragment() { vaultListPresenter.onVaultLockClicked(vaultModel) } + override fun onRowMoved(fromPosition: Int, toPosition: Int) { + vaultListPresenter.onRowMoved(fromPosition, toPosition) + } + override fun onVaultMoved(fromPosition: Int, toPosition: Int) { vaultListPresenter.onVaultMoved(fromPosition, toPosition) } @@ -96,17 +99,12 @@ class VaultListFragment : BaseFragment() { vaultsAdapter.addOrUpdateVault(vaultModel) } - fun vaultMoved(fromPosition: Int, toPosition: Int, vaultModelCollection: List?) { - if (fromPosition < toPosition) { - for (i in fromPosition until toPosition) { - Collections.swap(vaultModelCollection, i, i + 1) - } - } else { - for (i in fromPosition downTo toPosition + 1) { - Collections.swap(vaultModelCollection, i, i - 1) - } - } + fun vaultMoved(vaults: List) { + vaultsAdapter.clear() + vaultsAdapter.addAll(vaults) + } + fun rowMoved(fromPosition: Int, toPosition: Int) { vaultsAdapter.notifyItemMoved(fromPosition, toPosition) } From 52e88b865def5c9ddafde5dcf46de37716c4dae8 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Sun, 31 Jan 2021 23:12:43 +0100 Subject: [PATCH 03/11] Fix tests -.- --- .../presentation/presenter/VaultListPresenterTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/presentation/src/test/java/org/cryptomator/presentation/presenter/VaultListPresenterTest.java b/presentation/src/test/java/org/cryptomator/presentation/presenter/VaultListPresenterTest.java index ef80a487..2f1e9248 100644 --- a/presentation/src/test/java/org/cryptomator/presentation/presenter/VaultListPresenterTest.java +++ b/presentation/src/test/java/org/cryptomator/presentation/presenter/VaultListPresenterTest.java @@ -17,6 +17,7 @@ import org.cryptomator.domain.usecases.vault.ChangePasswordUseCase; import org.cryptomator.domain.usecases.vault.DeleteVaultUseCase; import org.cryptomator.domain.usecases.vault.GetVaultListUseCase; import org.cryptomator.domain.usecases.vault.LockVaultUseCase; +import org.cryptomator.domain.usecases.vault.MoveVaultUseCase; import org.cryptomator.domain.usecases.vault.PrepareUnlockUseCase; import org.cryptomator.domain.usecases.vault.RemoveStoredVaultPasswordsUseCase; import org.cryptomator.domain.usecases.vault.RenameVaultUseCase; @@ -56,6 +57,7 @@ public class VaultListPresenterTest { private static final Vault AN_UNLOCKED_VAULT = Vault.aVault() // .withId(1L) // + .withPosition(1) // .withName("Top Secret") // .withPath("/top secret") // .withCloudType(CloudType.DROPBOX) // @@ -63,6 +65,7 @@ public class VaultListPresenterTest { private static final Vault ANOTHER_VAULT_WITH_CLOUD = Vault.aVault() // .withId(2L) // + .withPosition(2) // .withName("Trip to the moon") // .withPath("/trip to the moon") // .withCloudType(CloudType.ONEDRIVE) // @@ -70,6 +73,7 @@ public class VaultListPresenterTest { private static final Vault A_VAULT_WITH_NEW_NAME = Vault.aVault() // .withId(3L) // + .withPosition(3) // .withName(A_NEW_VAULT_NAME) // .withPath("/trip to the moon") // .withCloudType(CloudType.GOOGLE_DRIVE) // @@ -120,6 +124,8 @@ public class VaultListPresenterTest { private SaveVaultUseCase saveVaultUseCase = Mockito.mock(SaveVaultUseCase.class); + private MoveVaultUseCase moveVaultUseCase = Mockito.mock(MoveVaultUseCase.class); + private ChangePasswordUseCase changePasswordUseCase = Mockito.mock(ChangePasswordUseCase.class); private RemoveStoredVaultPasswordsUseCase removeStoredVaultPasswordsUseCase = Mockito.mock(RemoveStoredVaultPasswordsUseCase.class); @@ -157,6 +163,7 @@ public class VaultListPresenterTest { addExistingVaultWorkflow, // createNewVaultWorkflow, // saveVaultUseCase, // + moveVaultUseCase, // changePasswordUseCase, // removeStoredVaultPasswordsUseCase, // doLicenceCheckUsecase, // From 36f7b800024a5c89f98195778758dbb65090e3f5 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Sun, 31 Jan 2021 23:20:47 +0100 Subject: [PATCH 04/11] Preserve vault passwords as well while updating the database schema --- data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt index 5ecb6cb2..8c011b7e 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt @@ -14,7 +14,7 @@ internal class Upgrade3To4 @Inject constructor() : DatabaseUpgrade(3, 4) { override fun internalApplyTo(db: Database, origin: Int) { db.beginTransaction() try { - upgradeDatabaseScheme(db) + upgradeDatabaseSchema(db) updateVaultPositions(db) db.setTransactionSuccessful() } finally { @@ -22,7 +22,7 @@ internal class Upgrade3To4 @Inject constructor() : DatabaseUpgrade(3, 4) { } } - private fun upgradeDatabaseScheme(db: Database) { + private fun upgradeDatabaseSchema(db: Database) { Sql.alterTable("VAULT_ENTITY").renameTo("VAULT_ENTITY_OLD").executeOn(db) Sql.createTable("VAULT_ENTITY") // .id() // @@ -36,8 +36,8 @@ internal class Upgrade3To4 @Inject constructor() : DatabaseUpgrade(3, 4) { .executeOn(db) Sql.insertInto("VAULT_ENTITY") // - .select("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "CLOUD_ENTITY.TYPE") // - .columns("_id", "FOLDER_CLOUD_ID", "FOLDER_PATH", "FOLDER_NAME", "CLOUD_TYPE") // + .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) From a6b327f26458940caf76f52771a3f21307b4d805 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Mon, 1 Feb 2021 00:12:16 +0100 Subject: [PATCH 05/11] Remove dead code --- .../presentation/presenter/VaultListPresenter.kt | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt index 09557a25..50930743 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt @@ -605,15 +605,7 @@ class VaultListPresenter @Inject constructor( // } fun onRowMoved(fromPosition: Int, toPosition: Int) { - getVaultListUseCase.run(object : DefaultResultHandler>() { - override fun onSuccess(vaults: List) { - view?.rowMoved(fromPosition, toPosition) - } - - override fun onError(e: Throwable) { - Timber.tag("VaultListPresenter").e(e, "Failed to query vault list while row moving") - } - }) + view?.rowMoved(fromPosition, toPosition) } fun onVaultMoved(fromPosition: Int, toPosition: Int) { From 657e2877ba793336358f31c2503403ac74170ab0 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Mon, 1 Feb 2021 00:37:31 +0100 Subject: [PATCH 06/11] #168 final clean-up --- .../java/org/cryptomator/data/db/Upgrade3To4.kt | 8 ++++---- .../domain/usecases/vault/MoveVaultHelper.kt | 10 ++++------ .../{MoveVault.java => MoveVaultPosition.java} | 14 +++++++------- .../presentation/presenter/VaultListPresenter.kt | 9 +++++---- .../presentation/ui/activity/VaultListActivity.kt | 8 ++++---- .../presentation/ui/activity/view/VaultListView.kt | 2 +- .../presenter/VaultListPresenterTest.java | 6 +++--- 7 files changed, 28 insertions(+), 29 deletions(-) rename domain/src/main/java/org/cryptomator/domain/usecases/vault/{MoveVault.java => MoveVaultPosition.java} (65%) diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt index 8c011b7e..e31364e2 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt @@ -14,15 +14,15 @@ internal class Upgrade3To4 @Inject constructor() : DatabaseUpgrade(3, 4) { override fun internalApplyTo(db: Database, origin: Int) { db.beginTransaction() try { - upgradeDatabaseSchema(db) - updateVaultPositions(db) + addPositionToVaultSchema(db) + initVaultPositionUsingCurrentSortOrder(db) db.setTransactionSuccessful() } finally { db.endTransaction() } } - private fun upgradeDatabaseSchema(db: Database) { + private fun addPositionToVaultSchema(db: Database) { Sql.alterTable("VAULT_ENTITY").renameTo("VAULT_ENTITY_OLD").executeOn(db) Sql.createTable("VAULT_ENTITY") // .id() // @@ -53,7 +53,7 @@ internal class Upgrade3To4 @Inject constructor() : DatabaseUpgrade(3, 4) { Sql.dropTable("VAULT_ENTITY_OLD").executeOn(db) } - private fun updateVaultPositions(db: Database) { + private fun initVaultPositionUsingCurrentSortOrder(db: Database) { CloudEntityDao(DaoConfig(db, VaultEntityDao::class.java)) // .loadAll() // .map { diff --git a/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt b/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt index 7bd498c6..b405550d 100644 --- a/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt +++ b/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt @@ -7,17 +7,17 @@ import java.util.* class MoveVaultHelper { companion object { - fun updateVaultPosition(from: Int, to: Int, vaultRepository: VaultRepository): List { + fun updateVaultPosition(fromPosition: Int, toPosition: Int, vaultRepository: VaultRepository): List { val vaults = vaultRepository.vaults() vaults.sortWith(VaultComparator()) - if (from < to) { - for (i in from until to) { + if (fromPosition < toPosition) { + for (i in fromPosition until toPosition) { Collections.swap(vaults, i, i + 1) } } else { - for (i in from downTo to + 1) { + for (i in fromPosition downTo toPosition + 1) { Collections.swap(vaults, i, i - 1) } } @@ -26,8 +26,6 @@ class MoveVaultHelper { vaults[i] = Vault.aCopyOf(vaults[i]).withPosition(i + 1).build() } - vaults.forEach { vault -> vaultRepository.store(vault) } - return vaults } diff --git a/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVault.java b/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultPosition.java similarity index 65% rename from domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVault.java rename to domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultPosition.java index 10bce6a5..fd7c43d3 100644 --- a/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVault.java +++ b/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultPosition.java @@ -9,20 +9,20 @@ import org.cryptomator.generator.UseCase; import java.util.List; @UseCase -class MoveVault { +class MoveVaultPosition { private final VaultRepository vaultRepository; - private final int from; - private final int to; + private final int fromPosition; + private final int toPosition; - public MoveVault(VaultRepository vaultRepository, @Parameter Integer from, @Parameter Integer to) { + public MoveVaultPosition(VaultRepository vaultRepository, @Parameter Integer fromPosition, @Parameter Integer toPosition) { this.vaultRepository = vaultRepository; - this.from = from; - this.to = to; + this.fromPosition = fromPosition; + this.toPosition = toPosition; } public List execute() throws BackendException { - List vaults = MoveVaultHelper.Companion.updateVaultPosition(from, to, vaultRepository); + List vaults = MoveVaultHelper.Companion.updateVaultPosition(fromPosition, toPosition, vaultRepository); return MoveVaultHelper.Companion.updateVaultsInDatabase(vaults, vaultRepository); } } diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt index 50930743..d4e1867b 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt @@ -53,7 +53,7 @@ class VaultListPresenter @Inject constructor( // private val addExistingVaultWorkflow: AddExistingVaultWorkflow, // private val createNewVaultWorkflow: CreateNewVaultWorkflow, // private val saveVaultUseCase: SaveVaultUseCase, // - private val moveVaultUseCase: MoveVaultUseCase, // + private val moveVaultPositionUseCase: MoveVaultPositionUseCase, // private val changePasswordUseCase: ChangePasswordUseCase, // private val removeStoredVaultPasswordsUseCase: RemoveStoredVaultPasswordsUseCase, // private val licenseCheckUseCase: DoLicenseCheckUseCase, // @@ -609,9 +609,9 @@ class VaultListPresenter @Inject constructor( // } fun onVaultMoved(fromPosition: Int, toPosition: Int) { - moveVaultUseCase - .withFrom(fromPosition) // - .andTo(toPosition) // + moveVaultPositionUseCase + .withFromPosition(fromPosition) // + .andToPosition(toPosition) // .run(object : DefaultResultHandler>() { override fun onSuccess(vaults: List) { view?.vaultMoved(vaults.mapTo(ArrayList()) { VaultModel(it) }) @@ -710,6 +710,7 @@ class VaultListPresenter @Inject constructor( // lockVaultUseCase, // getVaultListUseCase, // saveVaultUseCase, // + moveVaultPositionUseCase, // removeStoredVaultPasswordsUseCase, // unlockVaultUseCase, // prepareUnlockUseCase, // diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/VaultListActivity.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/VaultListActivity.kt index 73778681..b3784a71 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/VaultListActivity.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/VaultListActivity.kt @@ -150,14 +150,14 @@ class VaultListActivity : BaseActivity(), // return biometricAuthentication?.stoppedBiometricAuthDuringCloudAuthentication() == true } - override fun vaultMoved(vaults: List) { - vaultListFragment().vaultMoved(vaults) - } - override fun rowMoved(fromPosition: Int, toPosition: Int) { vaultListFragment().rowMoved(fromPosition, toPosition) } + override fun vaultMoved(vaults: List) { + vaultListFragment().vaultMoved(vaults) + } + override fun showVaultSettingsDialog(vaultModel: VaultModel) { val vaultSettingDialog = // SettingsVaultBottomSheet.newInstance(vaultModel) diff --git a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/view/VaultListView.kt b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/view/VaultListView.kt index d5d25fb7..4551f245 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/ui/activity/view/VaultListView.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/ui/activity/view/VaultListView.kt @@ -23,7 +23,7 @@ interface VaultListView : View { fun isVaultLocked(vaultModel: VaultModel): Boolean fun cancelBasicAuthIfRunning() fun stoppedBiometricAuthDuringCloudAuthentication(): Boolean - fun vaultMoved(vaults: List) fun rowMoved(fromPosition: Int, toPosition: Int) + fun vaultMoved(vaults: List) } diff --git a/presentation/src/test/java/org/cryptomator/presentation/presenter/VaultListPresenterTest.java b/presentation/src/test/java/org/cryptomator/presentation/presenter/VaultListPresenterTest.java index 2f1e9248..30e66dc2 100644 --- a/presentation/src/test/java/org/cryptomator/presentation/presenter/VaultListPresenterTest.java +++ b/presentation/src/test/java/org/cryptomator/presentation/presenter/VaultListPresenterTest.java @@ -17,7 +17,7 @@ import org.cryptomator.domain.usecases.vault.ChangePasswordUseCase; import org.cryptomator.domain.usecases.vault.DeleteVaultUseCase; import org.cryptomator.domain.usecases.vault.GetVaultListUseCase; import org.cryptomator.domain.usecases.vault.LockVaultUseCase; -import org.cryptomator.domain.usecases.vault.MoveVaultUseCase; +import org.cryptomator.domain.usecases.vault.MoveVaultPositionUseCase; import org.cryptomator.domain.usecases.vault.PrepareUnlockUseCase; import org.cryptomator.domain.usecases.vault.RemoveStoredVaultPasswordsUseCase; import org.cryptomator.domain.usecases.vault.RenameVaultUseCase; @@ -124,7 +124,7 @@ public class VaultListPresenterTest { private SaveVaultUseCase saveVaultUseCase = Mockito.mock(SaveVaultUseCase.class); - private MoveVaultUseCase moveVaultUseCase = Mockito.mock(MoveVaultUseCase.class); + private MoveVaultPositionUseCase moveVaultPositionUseCase = Mockito.mock(MoveVaultPositionUseCase.class); private ChangePasswordUseCase changePasswordUseCase = Mockito.mock(ChangePasswordUseCase.class); @@ -163,7 +163,7 @@ public class VaultListPresenterTest { addExistingVaultWorkflow, // createNewVaultWorkflow, // saveVaultUseCase, // - moveVaultUseCase, // + moveVaultPositionUseCase, // changePasswordUseCase, // removeStoredVaultPasswordsUseCase, // doLicenceCheckUsecase, // From 2ef3824b793109ae2c0a3bafffb18c070b4e871e Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Mon, 1 Feb 2021 22:15:10 +0100 Subject: [PATCH 07/11] Fix tablename in upgrade script --- data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt index e31364e2..a6e67481 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt @@ -57,7 +57,7 @@ internal class Upgrade3To4 @Inject constructor() : DatabaseUpgrade(3, 4) { CloudEntityDao(DaoConfig(db, VaultEntityDao::class.java)) // .loadAll() // .map { - Sql.update("CLOUD_ENTITY") // + Sql.update("VAULT_ENTITY") // .where("_id", Sql.eq(it.id)) // .set("POSITION", Sql.toInteger(it.id)) // .executeOn(db) From 9b63b7c525768ff1f571f025f6ca1a756561db79 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Thu, 4 Feb 2021 23:34:48 +0100 Subject: [PATCH 08/11] #168 set vault position while creating, adding and deleting vaults --- .../domain/usecases/vault/CreateVault.java | 7 ++-- .../domain/usecases/vault/DeleteVault.java | 9 ++++- .../domain/usecases/vault/MoveVaultHelper.kt | 13 +++++++ .../workflow/AddExistingVaultWorkflow.java | 35 ++++++++++++------- 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/domain/src/main/java/org/cryptomator/domain/usecases/vault/CreateVault.java b/domain/src/main/java/org/cryptomator/domain/usecases/vault/CreateVault.java index 9b73b5f2..ee61b6a9 100644 --- a/domain/src/main/java/org/cryptomator/domain/usecases/vault/CreateVault.java +++ b/domain/src/main/java/org/cryptomator/domain/usecases/vault/CreateVault.java @@ -35,7 +35,10 @@ class CreateVault { CloudFolder vaultFolder = cloudContentRepository.folder(folder, vaultName); vaultFolder = cloudContentRepository.create(vaultFolder); cloudRepository.create(vaultFolder, password); - return vaultRepository.store(aVault().thatIsNew().withNamePathAndCloudFrom(vaultFolder).build()); + return vaultRepository.store(aVault() // + .thatIsNew() // + .withNamePathAndCloudFrom(vaultFolder) // + .withPosition(vaultRepository.vaults().size() + 1) // + .build()); } - } diff --git a/domain/src/main/java/org/cryptomator/domain/usecases/vault/DeleteVault.java b/domain/src/main/java/org/cryptomator/domain/usecases/vault/DeleteVault.java index 7ff6cb17..7a807060 100644 --- a/domain/src/main/java/org/cryptomator/domain/usecases/vault/DeleteVault.java +++ b/domain/src/main/java/org/cryptomator/domain/usecases/vault/DeleteVault.java @@ -6,6 +6,8 @@ import org.cryptomator.domain.repository.VaultRepository; import org.cryptomator.generator.Parameter; import org.cryptomator.generator.UseCase; +import java.util.List; + @UseCase class DeleteVault { @@ -18,7 +20,12 @@ class DeleteVault { } public Long execute() throws BackendException { - return vaultRepository.delete(vault); + Long vaultId = vaultRepository.delete(vault); + + List reorderVaults = MoveVaultHelper.Companion.reorderVaults(vaultRepository); + MoveVaultHelper.Companion.updateVaultsInDatabase(reorderVaults, vaultRepository); + + return vaultId; } } diff --git a/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt b/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt index b405550d..40985b64 100644 --- a/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt +++ b/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt @@ -29,6 +29,19 @@ class MoveVaultHelper { return vaults } + private fun reorderVaults(vaults: MutableList) : List { + for (i in 0 until vaults.size) { + vaults[i] = Vault.aCopyOf(vaults[i]).withPosition(i + 1).build() + } + return vaults; + } + + fun reorderVaults(vaultRepository: VaultRepository) : List { + val vaults = vaultRepository.vaults() + vaults.sortWith(VaultComparator()) + return reorderVaults(vaults) + } + fun updateVaultsInDatabase(vaults: List, vaultRepository: VaultRepository): List { vaults.forEach { vault -> vaultRepository.store(vault) } return vaultRepository.vaults() diff --git a/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java b/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java index 1ec41190..937e07ae 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java +++ b/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java @@ -7,6 +7,7 @@ import org.cryptomator.domain.CloudFolder; import org.cryptomator.domain.Vault; import org.cryptomator.domain.di.PerView; import org.cryptomator.domain.usecases.cloud.GetRootFolderUseCase; +import org.cryptomator.domain.usecases.vault.GetVaultListUseCase; import org.cryptomator.domain.usecases.vault.SaveVaultUseCase; import org.cryptomator.generator.Callback; import org.cryptomator.presentation.R; @@ -18,6 +19,7 @@ import org.cryptomator.presentation.model.mappers.CloudModelMapper; import org.cryptomator.presentation.presenter.VaultListPresenter; import java.io.Serializable; +import java.util.List; import javax.inject.Inject; @@ -30,6 +32,7 @@ import static org.cryptomator.presentation.intent.Intents.chooseCloudServiceInte public class AddExistingVaultWorkflow extends Workflow { private final SaveVaultUseCase saveVaultUseCase; + private final GetVaultListUseCase getVaultListUseCase; private final GetRootFolderUseCase getRootFolderUseCase; private final CloudModelMapper cloudModelMapper; private final AuthenticationExceptionHandler authenticationExceptionHandler; @@ -38,13 +41,15 @@ public class AddExistingVaultWorkflow extends Workflow() { - @Override - public void onSuccess(Vault vault) { - ((VaultListPresenter) presenter()).onAddOrCreateVaultCompleted(vault); - } - }); + getVaultListUseCase.run(presenter().new ProgressCompletingResultHandler>() { + @Override + public void onSuccess(List vaults) { + saveVaultUseCase// + .withVault(aVault() // + .withNamePathAndCloudFrom(state().masterkeyFile.getParent()) // + .withPosition(vaults.size() + 1) // + .thatIsNew() // + .build()) // + .run(presenter().new ProgressCompletingResultHandler() { + @Override + public void onSuccess(Vault vault) { + ((VaultListPresenter) presenter()).onAddOrCreateVaultCompleted(vault); + } + }); + } + }); } public static class State implements Serializable { From 22c53f5abe3bae4245fec9e94c59722880d5187d Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Wed, 10 Feb 2021 19:15:44 +0100 Subject: [PATCH 09/11] #168 start position indices by 0 and test position helper --- .../org/cryptomator/data/db/Upgrade3To4.kt | 2 +- .../domain/usecases/vault/CreateVault.java | 2 +- .../domain/usecases/vault/MoveVaultHelper.kt | 9 +- .../usecases/vault/MoveVaultHelperTest.kt | 100 ++++++++++++++++++ .../workflow/AddExistingVaultWorkflow.java | 2 +- 5 files changed, 105 insertions(+), 10 deletions(-) create mode 100644 domain/src/test/java/org/cryptomator/domain/usecases/vault/MoveVaultHelperTest.kt diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt index a6e67481..8be61f62 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt @@ -59,7 +59,7 @@ internal class Upgrade3To4 @Inject constructor() : DatabaseUpgrade(3, 4) { .map { Sql.update("VAULT_ENTITY") // .where("_id", Sql.eq(it.id)) // - .set("POSITION", Sql.toInteger(it.id)) // + .set("POSITION", Sql.toInteger(it.id - 1)) // .executeOn(db) } } diff --git a/domain/src/main/java/org/cryptomator/domain/usecases/vault/CreateVault.java b/domain/src/main/java/org/cryptomator/domain/usecases/vault/CreateVault.java index ee61b6a9..6df1bcde 100644 --- a/domain/src/main/java/org/cryptomator/domain/usecases/vault/CreateVault.java +++ b/domain/src/main/java/org/cryptomator/domain/usecases/vault/CreateVault.java @@ -38,7 +38,7 @@ class CreateVault { return vaultRepository.store(aVault() // .thatIsNew() // .withNamePathAndCloudFrom(vaultFolder) // - .withPosition(vaultRepository.vaults().size() + 1) // + .withPosition(vaultRepository.vaults().size()) // .build()); } } diff --git a/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt b/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt index 40985b64..e42c5bbf 100644 --- a/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt +++ b/domain/src/main/java/org/cryptomator/domain/usecases/vault/MoveVaultHelper.kt @@ -21,17 +21,12 @@ class MoveVaultHelper { Collections.swap(vaults, i, i - 1) } } - - for (i in 0 until vaults.size) { - vaults[i] = Vault.aCopyOf(vaults[i]).withPosition(i + 1).build() - } - - return vaults + return reorderVaults(vaults) } private fun reorderVaults(vaults: MutableList) : List { for (i in 0 until vaults.size) { - vaults[i] = Vault.aCopyOf(vaults[i]).withPosition(i + 1).build() + vaults[i] = Vault.aCopyOf(vaults[i]).withPosition(i).build() } return vaults; } diff --git a/domain/src/test/java/org/cryptomator/domain/usecases/vault/MoveVaultHelperTest.kt b/domain/src/test/java/org/cryptomator/domain/usecases/vault/MoveVaultHelperTest.kt new file mode 100644 index 00000000..0a9fb96c --- /dev/null +++ b/domain/src/test/java/org/cryptomator/domain/usecases/vault/MoveVaultHelperTest.kt @@ -0,0 +1,100 @@ +package org.cryptomator.domain.usecases.vault + +import org.cryptomator.domain.CloudType +import org.cryptomator.domain.Vault +import org.cryptomator.domain.repository.VaultRepository +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mockito + + +class MoveVaultHelperTest { + + private lateinit var orderedVaults: ArrayList + private lateinit var unorderedVaults: ArrayList + + private lateinit var vaultRepository: VaultRepository + private lateinit var cloudType: CloudType + + @Test + fun reorderVaults() { + Mockito.`when`(vaultRepository.vaults()).thenReturn(unorderedVaults) + assertEquals(orderedVaults, MoveVaultHelper.Companion.reorderVaults(vaultRepository), "Failed to reorderVaults") + } + + @Test + fun movePositionUp() { + Mockito.`when`(vaultRepository.vaults()).thenReturn(orderedVaults) + + val resultList = ArrayList() + resultList.add(Vault.aVault().withId(2).withPath("").withCloudType(cloudType).withName("foo 5").withPosition(0).build()) + resultList.add(Vault.aVault().withId(3).withPath("").withCloudType(cloudType).withName("foo 10").withPosition(1).build()) + resultList.add(Vault.aVault().withId(24).withPath("").withCloudType(cloudType).withName("foo 1").withPosition(2).build()) + resultList.add(Vault.aVault().withId(4).withPath("").withCloudType(cloudType).withName("foo 15").withPosition(3).build()) + + assertEquals(resultList, MoveVaultHelper.Companion.updateVaultPosition(0, 2, vaultRepository), "Failed to movePositionUp") + } + + @Test + fun movePositionDown() { + Mockito.`when`(vaultRepository.vaults()).thenReturn(orderedVaults) + + val resultList2 = ArrayList() + resultList2.add(Vault.aVault().withId(3).withPath("").withCloudType(cloudType).withName("foo 10").withPosition(0).build()) + resultList2.add(Vault.aVault().withId(24).withPath("").withCloudType(cloudType).withName("foo 1").withPosition(1).build()) + resultList2.add(Vault.aVault().withId(2).withPath("").withCloudType(cloudType).withName("foo 5").withPosition(2).build()) + resultList2.add(Vault.aVault().withId(4).withPath("").withCloudType(cloudType).withName("foo 15").withPosition(3).build()) + + assertEquals(resultList2, MoveVaultHelper.Companion.updateVaultPosition(2, 0, vaultRepository), "Failed to movePositionDown") + } + + @Test + fun movePositionToSelf() { + Mockito.`when`(vaultRepository.vaults()).thenReturn(orderedVaults) + + val resultList2 = ArrayList() + resultList2.add(Vault.aVault().withId(24).withPath("").withCloudType(cloudType).withName("foo 1").withPosition(0).build()) + resultList2.add(Vault.aVault().withId(2).withPath("").withCloudType(cloudType).withName("foo 5").withPosition(1).build()) + resultList2.add(Vault.aVault().withId(3).withPath("").withCloudType(cloudType).withName("foo 10").withPosition(2).build()) + resultList2.add(Vault.aVault().withId(4).withPath("").withCloudType(cloudType).withName("foo 15").withPosition(3).build()) + + assertEquals(resultList2, MoveVaultHelper.Companion.updateVaultPosition(1, 1, vaultRepository), "Failed to movePositionToSelf") + } + + @Test + fun movePositionOutOfBounds() { + Mockito.`when`(vaultRepository.vaults()).thenReturn(orderedVaults) + Assertions.assertThrows(IndexOutOfBoundsException::class.java) { MoveVaultHelper.Companion.updateVaultPosition(1, 4, vaultRepository) } + } + + @Test + fun verifyStoreInVaultRepo() { + Mockito.`when`(vaultRepository.vaults()).thenReturn(orderedVaults) + val result = MoveVaultHelper.Companion.updateVaultsInDatabase(orderedVaults, vaultRepository) + assertEquals(orderedVaults, result, "Failed to verifyStoreInVaultRepo") + + orderedVaults.forEach { + Mockito.verify(vaultRepository).store(Mockito.eq(it)) + } + } + + @BeforeEach + fun setup() { + vaultRepository = Mockito.mock(VaultRepository::class.java) + cloudType = Mockito.mock(CloudType::class.java) + + unorderedVaults = ArrayList() + unorderedVaults.add(Vault.aVault().withId(24).withPath("").withCloudType(cloudType).withName("foo 1").withPosition(1).build()) + unorderedVaults.add(Vault.aVault().withId(3).withPath("").withCloudType(cloudType).withName("foo 10").withPosition(10).build()) + unorderedVaults.add(Vault.aVault().withId(2).withPath("").withCloudType(cloudType).withName("foo 5").withPosition(5).build()) + unorderedVaults.add(Vault.aVault().withId(4).withPath("").withCloudType(cloudType).withName("foo 15").withPosition(15).build()) + + orderedVaults = ArrayList() + orderedVaults.add(Vault.aVault().withId(24).withPath("").withCloudType(cloudType).withName("foo 1").withPosition(0).build()) + orderedVaults.add(Vault.aVault().withId(2).withPath("").withCloudType(cloudType).withName("foo 5").withPosition(1).build()) + orderedVaults.add(Vault.aVault().withId(3).withPath("").withCloudType(cloudType).withName("foo 10").withPosition(2).build()) + orderedVaults.add(Vault.aVault().withId(4).withPath("").withCloudType(cloudType).withName("foo 15").withPosition(3).build()) + } +} diff --git a/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java b/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java index 937e07ae..a0bb9fe5 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java +++ b/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java @@ -128,7 +128,7 @@ public class AddExistingVaultWorkflow extends Workflow() { From 6f7caf902877169043462f67206ed3b3945c9c9f Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Wed, 10 Feb 2021 19:32:33 +0100 Subject: [PATCH 10/11] Fix test which fails only using gradlew -.- --- .../cryptomator/domain/usecases/vault/MoveVaultHelperTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/test/java/org/cryptomator/domain/usecases/vault/MoveVaultHelperTest.kt b/domain/src/test/java/org/cryptomator/domain/usecases/vault/MoveVaultHelperTest.kt index 0a9fb96c..fe5630f0 100644 --- a/domain/src/test/java/org/cryptomator/domain/usecases/vault/MoveVaultHelperTest.kt +++ b/domain/src/test/java/org/cryptomator/domain/usecases/vault/MoveVaultHelperTest.kt @@ -83,7 +83,7 @@ class MoveVaultHelperTest { @BeforeEach fun setup() { vaultRepository = Mockito.mock(VaultRepository::class.java) - cloudType = Mockito.mock(CloudType::class.java) + cloudType = CloudType.LOCAL unorderedVaults = ArrayList() unorderedVaults.add(Vault.aVault().withId(24).withPath("").withCloudType(cloudType).withName("foo 1").withPosition(1).build()) From 93ae29e1a2dac787442c8af47c120b686319014f Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Wed, 10 Feb 2021 19:39:46 +0100 Subject: [PATCH 11/11] Final clean-up [ci skip] --- .../java/org/cryptomator/domain/Vault.java | 2 +- .../usecases/vault/MoveVaultHelperTest.kt | 24 +++++++++---------- .../workflow/AddExistingVaultWorkflow.java | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/domain/src/main/java/org/cryptomator/domain/Vault.java b/domain/src/main/java/org/cryptomator/domain/Vault.java index 1290f40b..7a1be5e2 100644 --- a/domain/src/main/java/org/cryptomator/domain/Vault.java +++ b/domain/src/main/java/org/cryptomator/domain/Vault.java @@ -19,7 +19,7 @@ public class Vault implements Serializable { .withPath(vault.getPath()) // .withUnlocked(vault.isUnlocked()) // .withSavedPassword(vault.getPassword()) // - .withVersion(vault.getVersion()) + .withVersion(vault.getVersion()) // .withPosition(vault.getPosition()); } diff --git a/domain/src/test/java/org/cryptomator/domain/usecases/vault/MoveVaultHelperTest.kt b/domain/src/test/java/org/cryptomator/domain/usecases/vault/MoveVaultHelperTest.kt index fe5630f0..36fd6a4a 100644 --- a/domain/src/test/java/org/cryptomator/domain/usecases/vault/MoveVaultHelperTest.kt +++ b/domain/src/test/java/org/cryptomator/domain/usecases/vault/MoveVaultHelperTest.kt @@ -41,26 +41,26 @@ class MoveVaultHelperTest { fun movePositionDown() { Mockito.`when`(vaultRepository.vaults()).thenReturn(orderedVaults) - val resultList2 = ArrayList() - resultList2.add(Vault.aVault().withId(3).withPath("").withCloudType(cloudType).withName("foo 10").withPosition(0).build()) - resultList2.add(Vault.aVault().withId(24).withPath("").withCloudType(cloudType).withName("foo 1").withPosition(1).build()) - resultList2.add(Vault.aVault().withId(2).withPath("").withCloudType(cloudType).withName("foo 5").withPosition(2).build()) - resultList2.add(Vault.aVault().withId(4).withPath("").withCloudType(cloudType).withName("foo 15").withPosition(3).build()) + val resultList = ArrayList() + resultList.add(Vault.aVault().withId(3).withPath("").withCloudType(cloudType).withName("foo 10").withPosition(0).build()) + resultList.add(Vault.aVault().withId(24).withPath("").withCloudType(cloudType).withName("foo 1").withPosition(1).build()) + resultList.add(Vault.aVault().withId(2).withPath("").withCloudType(cloudType).withName("foo 5").withPosition(2).build()) + resultList.add(Vault.aVault().withId(4).withPath("").withCloudType(cloudType).withName("foo 15").withPosition(3).build()) - assertEquals(resultList2, MoveVaultHelper.Companion.updateVaultPosition(2, 0, vaultRepository), "Failed to movePositionDown") + assertEquals(resultList, MoveVaultHelper.Companion.updateVaultPosition(2, 0, vaultRepository), "Failed to movePositionDown") } @Test fun movePositionToSelf() { Mockito.`when`(vaultRepository.vaults()).thenReturn(orderedVaults) - val resultList2 = ArrayList() - resultList2.add(Vault.aVault().withId(24).withPath("").withCloudType(cloudType).withName("foo 1").withPosition(0).build()) - resultList2.add(Vault.aVault().withId(2).withPath("").withCloudType(cloudType).withName("foo 5").withPosition(1).build()) - resultList2.add(Vault.aVault().withId(3).withPath("").withCloudType(cloudType).withName("foo 10").withPosition(2).build()) - resultList2.add(Vault.aVault().withId(4).withPath("").withCloudType(cloudType).withName("foo 15").withPosition(3).build()) + val resultList = ArrayList() + resultList.add(Vault.aVault().withId(24).withPath("").withCloudType(cloudType).withName("foo 1").withPosition(0).build()) + resultList.add(Vault.aVault().withId(2).withPath("").withCloudType(cloudType).withName("foo 5").withPosition(1).build()) + resultList.add(Vault.aVault().withId(3).withPath("").withCloudType(cloudType).withName("foo 10").withPosition(2).build()) + resultList.add(Vault.aVault().withId(4).withPath("").withCloudType(cloudType).withName("foo 15").withPosition(3).build()) - assertEquals(resultList2, MoveVaultHelper.Companion.updateVaultPosition(1, 1, vaultRepository), "Failed to movePositionToSelf") + assertEquals(resultList, MoveVaultHelper.Companion.updateVaultPosition(1, 1, vaultRepository), "Failed to movePositionToSelf") } @Test diff --git a/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java b/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java index a0bb9fe5..6548e311 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java +++ b/presentation/src/main/java/org/cryptomator/presentation/workflow/AddExistingVaultWorkflow.java @@ -41,7 +41,7 @@ public class AddExistingVaultWorkflow extends Workflow