Большая реструктуризация проекта

This commit is contained in:
2026-05-11 19:33:32 +03:00
parent ad985679ee
commit 3928ac5409
132 changed files with 574 additions and 450 deletions

View File

@@ -9,6 +9,10 @@ java {
}
}
kotlin {
jvmToolchain(17)
}
dependencies {
implementation(libs.kotlinx.coroutines.core)
testImplementation(libs.junit)

View File

@@ -1,11 +0,0 @@
package com.github.nullptroma.wallenc.domain.usecases
import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo
import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager
import kotlinx.coroutines.flow.StateFlow
import java.util.UUID
class GetOpenedStoragesUseCase(private val unlockManager: IUnlockManager) {
val openedStorages: StateFlow<Map<UUID, IStorageInfo>>
get() = unlockManager.openedStorages
}

View File

@@ -1,74 +0,0 @@
package com.github.nullptroma.wallenc.domain.usecases
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
import com.github.nullptroma.wallenc.domain.encrypt.Encryptor
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo
import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager
import com.github.nullptroma.wallenc.domain.tasks.TaskProgress
import kotlinx.coroutines.flow.first
class ManageStoragesEncryptionUseCase(
private val unlockManager: IUnlockManager,
) {
sealed interface CanEncryptResult {
data object Allowed : CanEncryptResult
data object UnsupportedStorageType : CanEncryptResult
data object AlreadyEncrypted : CanEncryptResult
data object StorageIsNotEmpty : CanEncryptResult
data object StorageStateUnknown : CanEncryptResult
}
suspend fun canEncrypt(storage: IStorageInfo): CanEncryptResult {
if (storage !is IStorage) return CanEncryptResult.UnsupportedStorageType
if (storage.metaInfo.value.encInfo != null) return CanEncryptResult.AlreadyEncrypted
val isEmpty = storage.isEmpty.first()
return when (isEmpty) {
true -> CanEncryptResult.Allowed
false -> CanEncryptResult.StorageIsNotEmpty
null -> CanEncryptResult.StorageStateUnknown
}
}
suspend fun enableEncryption(storage: IStorageInfo, key: EncryptKey, encryptPath: Boolean) {
when (val result = canEncrypt(storage)) {
CanEncryptResult.Allowed -> (storage as IStorage).setEncInfo(
Encryptor.generateEncryptionInfo(key, encryptPath)
)
CanEncryptResult.AlreadyEncrypted -> throw IllegalStateException("Storage is already encrypted")
CanEncryptResult.StorageIsNotEmpty -> throw IllegalStateException("Storage is not empty")
CanEncryptResult.StorageStateUnknown -> throw IllegalStateException("Storage state is unknown")
CanEncryptResult.UnsupportedStorageType -> throw IllegalStateException("Unsupported storage type")
}
}
suspend fun openStorage(storage: IStorageInfo, key: EncryptKey, rememberPassword: Boolean): IStorageInfo {
if (storage is IStorage) return unlockManager.open(storage, key, rememberPassword)
throw IllegalStateException("Unsupported storage type")
}
suspend fun closeStorage(storage: IStorageInfo) {
if (storage is IStorage) {
unlockManager.close(storage)
}
}
suspend fun clearAndDisableEncryption(
storage: IStorageInfo,
onClearProgress: suspend (TaskProgress) -> Unit = {},
) {
if (storage !is IStorage) return
storage.clearAllContent(onClearProgress)
storage.setEncInfo(null)
unlockManager.close(storage)
}
suspend fun changePassword(storage: IStorageInfo, newKey: EncryptKey, encryptPath: Boolean) {
if (storage !is IStorage) return
if (storage.metaInfo.value.encInfo == null) {
throw IllegalStateException("Storage is not encrypted")
}
storage.setEncInfo(Encryptor.generateEncryptionInfo(newKey, encryptPath))
}
}

View File

@@ -1,34 +0,0 @@
package com.github.nullptroma.wallenc.domain.usecases
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
import com.github.nullptroma.wallenc.domain.interfaces.IVault
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import java.util.UUID
@OptIn(ExperimentalCoroutinesApi::class)
class ManageVaultUseCase(private val manager: IVaultsManager) {
/** Найти vault по идентификатору в текущем состоянии. */
fun find(vaultUuid: UUID): IVault? =
manager.vaults.value.firstOrNull { it.uuid == vaultUuid }
/** Реактивно отдаёт сам vault, либо null если он отсутствует. */
fun observe(vaultUuid: UUID): Flow<IVault?> =
manager.vaults.map { list -> list.firstOrNull { it.uuid == vaultUuid } }
/** Реактивно отдаёт storages указанного vault'а; пустой список, если vault не найден. */
fun storagesOf(vaultUuid: UUID): Flow<List<IStorage>> =
observe(vaultUuid).flatMapLatest { vault -> vault?.storages ?: flowOf(emptyList()) }
/** Создать новое хранилище в указанном vault'е. */
suspend fun createStorage(vaultUuid: UUID): IStorage {
val vault = find(vaultUuid)
?: throw IllegalStateException("Vault $vaultUuid is not registered")
return vault.createStorage()
}
}

View File

@@ -1,43 +0,0 @@
package com.github.nullptroma.wallenc.domain.usecases
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo
import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager
import com.github.nullptroma.wallenc.domain.interfaces.IVault
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
import java.util.UUID
class RemoveStorageUseCase(
private val vaultsManager: IVaultsManager,
private val unlockManager: IUnlockManager,
private val manageStoragesEncryptionUseCase: ManageStoragesEncryptionUseCase,
) {
suspend fun remove(storage: IStorageInfo) {
if (storage !is IStorage) return
if (!storage.isVirtualStorage) {
unlockManager.close(storage)
findOwningVault(storage.uuid)?.remove(storage)
return
}
val parent = findParentStorage(storage) ?: return
manageStoragesEncryptionUseCase.clearAndDisableEncryption(parent)
}
private fun findOwningVault(storageUuid: UUID): IVault? =
vaultsManager.vaults.value.firstOrNull { v ->
v.storages.value.any { it.uuid == storageUuid }
}
private fun findParentStorage(storage: IStorage): IStorage? {
val opened = unlockManager.openedStorages.value
val parentUuid = opened.entries.firstOrNull { it.value.uuid == storage.uuid }?.key
?: return null
val realParent = vaultsManager.vaults.value
.flatMap { it.storages.value }
.firstOrNull { it.uuid == parentUuid }
return realParent ?: opened[parentUuid]
}
}

View File

@@ -1,12 +0,0 @@
package com.github.nullptroma.wallenc.domain.usecases
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo
class RenameStorageUseCase {
suspend fun rename(storage: IStorageInfo, newName: String) {
when (storage) {
is IStorage -> storage.rename(newName)
}
}
}

View File

@@ -1,26 +0,0 @@
package com.github.nullptroma.wallenc.domain.usecases
import com.github.nullptroma.wallenc.domain.interfaces.IDirectory
import com.github.nullptroma.wallenc.domain.interfaces.IFile
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo
class StorageFileManagementUseCase {
private var _storage: IStorage? = null
fun setStorage(storage: IStorageInfo) {
when (storage) {
is IStorage -> _storage = storage
}
}
suspend fun getAllFiles(): List<IFile> {
val storage = _storage ?: return listOf()
return storage.accessor.getAllFiles()
}
suspend fun getAllDirs(): List<IDirectory> {
val storage = _storage ?: return listOf()
return storage.accessor.getAllDirs()
}
}