Большой рефакторинг
Из domain выкинуты типы vault, теперь он ничего не знает о Yandex. Объявления провайдеров вынесены в vault-api, а реализации в data
This commit is contained in:
@@ -1,17 +0,0 @@
|
||||
package com.github.nullptroma.wallenc.domain.auth
|
||||
|
||||
/**
|
||||
* Результат входа через Яндекс (без зависимости от Yandex SDK).
|
||||
*/
|
||||
sealed interface RemoteYandexAuthResult {
|
||||
data class Success(val accessToken: String) : RemoteYandexAuthResult
|
||||
data class Failure(val message: String) : RemoteYandexAuthResult
|
||||
data object Cancelled : RemoteYandexAuthResult
|
||||
}
|
||||
|
||||
/**
|
||||
* Запуск OAuth Яндекса. Реализация только в модуле app (Yandex Auth SDK).
|
||||
*/
|
||||
fun interface RemoteYandexSignInLauncher {
|
||||
fun launch(onResult: (RemoteYandexAuthResult) -> Unit)
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.github.nullptroma.wallenc.domain.enums
|
||||
|
||||
enum class VaultType {
|
||||
LOCAL,
|
||||
DECRYPTED,
|
||||
YANDEX
|
||||
}
|
||||
@@ -3,10 +3,18 @@ package com.github.nullptroma.wallenc.domain.interfaces
|
||||
import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/**
|
||||
* Контракт vault'а: коллекция [IStorage] с реактивным состоянием.
|
||||
*
|
||||
* domain не различает локальные/удалённые/Yandex/etc. — это общий порт.
|
||||
*/
|
||||
interface IVault : IVaultInfo {
|
||||
override val storages: StateFlow<List<IStorage>?>
|
||||
val storages: StateFlow<List<IStorage>>
|
||||
val isAvailable: StateFlow<Boolean>
|
||||
val totalSpace: StateFlow<Int?>
|
||||
val availableSpace: StateFlow<Int?>
|
||||
|
||||
suspend fun createStorage(): IStorage
|
||||
suspend fun createStorage(enc: StorageEncryptionInfo): IStorage
|
||||
suspend fun remove(storage: IStorage)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package com.github.nullptroma.wallenc.domain.interfaces
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.enums.VaultType
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.util.UUID
|
||||
|
||||
sealed interface IVaultInfo {
|
||||
val type: VaultType
|
||||
/**
|
||||
* Минимальная идентификация vault'а.
|
||||
*
|
||||
* Намеренно «голая»: domain ничего не знает о брендах, локальности или статусе —
|
||||
* вся категоризация лежит во внешнем кольце (`:vault-api: VaultDescriptor`).
|
||||
*/
|
||||
interface IVaultInfo {
|
||||
val uuid: UUID
|
||||
val storages: StateFlow<List<IStorageInfo>?>
|
||||
val isAvailable: StateFlow<Boolean>
|
||||
val totalSpace: StateFlow<Int?>
|
||||
val availableSpace: StateFlow<Int?>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package com.github.nullptroma.wallenc.domain.interfaces
|
||||
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* Единая точка доступа ко всем vault'ам приложения.
|
||||
*
|
||||
* domain не различает категории vault'ов — потребители (presentation) фильтруют
|
||||
* [vaults] через `:vault-api` (`VaultDescriptor`/`DescribedVault`).
|
||||
*/
|
||||
interface IVaultsManager {
|
||||
val localVault: IVault
|
||||
val unlockManager: IUnlockManager
|
||||
val remoteVaults: StateFlow<List<IVault>>
|
||||
val vaults: StateFlow<List<IVault>>
|
||||
val allStorages: StateFlow<List<IStorage>>
|
||||
val allVaults: StateFlow<List<IVault>>
|
||||
suspend fun addYandexVault(accessToken: String)
|
||||
|
||||
suspend fun removeRemoteVault(vaultUuid: UUID)
|
||||
}
|
||||
val unlockManager: IUnlockManager
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package com.github.nullptroma.wallenc.domain.interfaces
|
||||
|
||||
/**
|
||||
* Удалённый vault Яндекс с привязанным аккаунтом (почта для UI).
|
||||
*/
|
||||
interface IYandexVault : IVault {
|
||||
val accountEmail: String
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.github.nullptroma.wallenc.domain.usecases
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
class ManageLocalVaultUseCase(private val manager: IVaultsManager) {
|
||||
val localStorages: StateFlow<List<IStorageInfo>?>
|
||||
get() = manager.localVault.storages
|
||||
|
||||
suspend fun createStorage() {
|
||||
manager.localVault.createStorage()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@ 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,
|
||||
@@ -12,12 +14,11 @@ class RemoveStorageUseCase(
|
||||
) {
|
||||
|
||||
suspend fun remove(storage: IStorageInfo) {
|
||||
|
||||
if (storage !is IStorage) return
|
||||
|
||||
if (!storage.isVirtualStorage) {
|
||||
unlockManager.close(storage)
|
||||
vaultsManager.localVault.remove(storage)
|
||||
findOwningVault(storage.uuid)?.remove(storage)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -25,13 +26,18 @@ class RemoveStorageUseCase(
|
||||
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 locals = vaultsManager.localVault.storages.value.orEmpty()
|
||||
return locals.firstOrNull { it.uuid == parentUuid }
|
||||
?: opened[parentUuid]
|
||||
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]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user