Использования менеджера Tasks

This commit is contained in:
2026-04-27 00:54:37 +03:00
parent 404ff201c4
commit 2b1be58a8e
2 changed files with 169 additions and 90 deletions

View File

@@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
import java.util.UUID
import javax.inject.Inject
import kotlin.system.measureTimeMillis
@@ -92,8 +93,12 @@ class LocalVaultViewModel @Inject constructor(
}
fun printStorageInfoToLog(storage: IStorageInfo) {
taskOrchestrator.enqueue(
title = "Dump storage to log",
dispatcher = Dispatchers.IO,
work = { ctx ->
storageFileManagementUseCase.setStorage(storage)
viewModelScope.launch {
ctx.log(TaskLogLevel.Info, "Enumerating files and directories…")
val files: List<IFile>
val dirs: List<IDirectory>
val time = measureTimeMillis {
@@ -108,7 +113,12 @@ class LocalVaultViewModel @Inject constructor(
}
logger.debug("Time", "Time: $time ms")
logger.debug("Storage", storage.toPrintable())
}
ctx.log(
TaskLogLevel.Info,
"Done: ${files.size} files, ${dirs.size} dirs in ${time}ms (see app log for lines)",
)
},
)
}
fun createStorage() {
@@ -123,71 +133,105 @@ class LocalVaultViewModel @Inject constructor(
)
}
private val runningStorages = mutableSetOf<java.util.UUID>()
private val storageOpMutex = Any()
private val runningStorages = mutableSetOf<UUID>()
fun enableEncryption(storage: IStorageInfo, password: String, encryptPath: Boolean) {
val id = storage.uuid
if (runningStorages.contains(id))
return
tasksCount++
synchronized(storageOpMutex) {
if (runningStorages.contains(id)) return
runningStorages.add(id)
tasksCount++
}
val key = EncryptKey(password)
viewModelScope.launch {
taskOrchestrator.enqueue(
title = "Enable encryption",
dispatcher = Dispatchers.IO,
work = { ctx ->
try {
ctx.log(TaskLogLevel.Info, "Checking storage…")
when (manageStoragesEncryptionUseCase.canEncrypt(storage)) {
ManageStoragesEncryptionUseCase.CanEncryptResult.Allowed -> {
ctx.log(TaskLogLevel.Info, "Encrypting…")
manageStoragesEncryptionUseCase.enableEncryption(storage, key, encryptPath)
manageStoragesEncryptionUseCase.openStorage(storage, key, true)
ctx.log(TaskLogLevel.Info, "Encryption enabled")
_messages.emit("Encryption enabled")
}
ManageStoragesEncryptionUseCase.CanEncryptResult.AlreadyEncrypted -> {
ctx.log(TaskLogLevel.Info, "Storage is already encrypted")
_messages.emit("Storage is already encrypted")
}
ManageStoragesEncryptionUseCase.CanEncryptResult.StorageIsNotEmpty -> {
ctx.log(TaskLogLevel.Info, "Storage is not empty")
_messages.emit("Storage is not empty")
}
ManageStoragesEncryptionUseCase.CanEncryptResult.StorageStateUnknown -> {
ctx.log(TaskLogLevel.Info, "Cannot determine whether storage is empty")
_messages.emit("Cannot determine whether storage is empty")
}
ManageStoragesEncryptionUseCase.CanEncryptResult.UnsupportedStorageType -> {
ctx.log(TaskLogLevel.Info, "Unsupported storage type")
_messages.emit("Unsupported storage type")
}
}
} catch (e: Exception) {
ctx.log(TaskLogLevel.Error, e.message ?: "Failed to enable encryption")
_messages.emit(e.message ?: "Failed to enable encryption")
}
finally {
} finally {
synchronized(storageOpMutex) {
runningStorages.remove(id)
tasksCount--
}
}
},
)
}
fun openEncryptedStorage(storage: IStorageInfo, password: String, rememberPassword: Boolean) {
val id = storage.uuid
synchronized(storageOpMutex) {
if (runningStorages.contains(id)) return
tasksCount++
runningStorages.add(id)
tasksCount++
}
val key = EncryptKey(password)
viewModelScope.launch {
taskOrchestrator.enqueue(
title = "Open encrypted storage",
dispatcher = Dispatchers.IO,
work = { ctx ->
try {
ctx.log(TaskLogLevel.Info, "Opening storage…")
manageStoragesEncryptionUseCase.openStorage(storage, key, rememberPassword)
ctx.log(TaskLogLevel.Info, "Storage opened")
} catch (e: Exception) {
ctx.log(TaskLogLevel.Error, e.message ?: "Failed to open encrypted storage")
_messages.emit(e.message ?: "Failed to open encrypted storage")
} finally {
synchronized(storageOpMutex) {
runningStorages.remove(id)
tasksCount--
}
}
},
)
}
fun closeEncryptedStorage(storage: IStorageInfo) {
viewModelScope.launch {
taskOrchestrator.enqueue(
title = "Close encrypted storage",
dispatcher = Dispatchers.IO,
work = { ctx ->
try {
ctx.log(TaskLogLevel.Info, "Closing storage…")
manageStoragesEncryptionUseCase.closeStorage(storage)
ctx.log(TaskLogLevel.Info, "Storage closed")
} catch (e: Exception) {
ctx.log(TaskLogLevel.Error, e.message ?: "Failed to close encrypted storage")
_messages.emit(e.message ?: "Failed to close encrypted storage")
}
}
},
)
}
fun disableEncryption(storage: IStorageInfo) {
@@ -211,9 +255,19 @@ class LocalVaultViewModel @Inject constructor(
}
fun rename(storage: IStorageInfo, newName: String) {
viewModelScope.launch {
taskOrchestrator.enqueue(
title = "Rename storage",
dispatcher = Dispatchers.IO,
work = { ctx ->
try {
ctx.log(TaskLogLevel.Info, "Renaming…")
renameStorageUseCase.rename(storage, newName)
ctx.log(TaskLogLevel.Info, "Renamed")
} catch (e: Exception) {
ctx.log(TaskLogLevel.Error, e.message ?: "Rename failed")
}
},
)
}
fun remove(storage: IStorageInfo) {

View File

@@ -4,18 +4,22 @@ import androidx.lifecycle.viewModelScope
import com.github.nullptroma.wallenc.domain.auth.RemoteYandexSignInLauncher
import com.github.nullptroma.wallenc.domain.interfaces.IYandexVault
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
import com.github.nullptroma.wallenc.domain.tasks.ITaskOrchestrator
import com.github.nullptroma.wallenc.domain.tasks.TaskLogLevel
import com.github.nullptroma.wallenc.presentation.ViewModelBase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
@HiltViewModel
class RemoteVaultsViewModel @Inject constructor(
private val vaultsManager: IVaultsManager,
val yandexSignIn: RemoteYandexSignInLauncher,
private val taskOrchestrator: ITaskOrchestrator,
) : ViewModelBase<RemoteVaultsScreenState>(RemoteVaultsScreenState()) {
val uiState = combine(
@@ -50,15 +54,25 @@ class RemoteVaultsViewModel @Inject constructor(
}
fun onYandexAuthSuccess(accessToken: String) {
viewModelScope.launch {
setBusy(true)
taskOrchestrator.enqueue(
title = "Add Yandex vault",
dispatcher = Dispatchers.IO,
work = { ctx ->
try {
ctx.log(TaskLogLevel.Info, "Adding vault…")
vaultsManager.addYandexVault(accessToken)
ctx.log(TaskLogLevel.Info, "Vault added")
} catch (e: Exception) {
ctx.log(TaskLogLevel.Error, e.message ?: "Failed to add vault")
} finally {
withContext(Dispatchers.Main.immediate) {
setBusy(false)
setAddChoiceVisible(false)
}
}
},
)
}
fun requestDeleteVault(item: RemoteVaultListItem) {
@@ -71,14 +85,25 @@ class RemoteVaultsViewModel @Inject constructor(
fun confirmDeleteVault() {
val pending = state.value.vaultPendingDelete ?: return
viewModelScope.launch {
val uuid = pending.uuid
setBusy(true)
taskOrchestrator.enqueue(
title = "Remove remote vault",
dispatcher = Dispatchers.IO,
work = { ctx ->
try {
vaultsManager.removeRemoteVault(pending.uuid)
ctx.log(TaskLogLevel.Info, "Removing remote vault")
vaultsManager.removeRemoteVault(uuid)
ctx.log(TaskLogLevel.Info, "Remote vault removed")
} catch (e: Exception) {
ctx.log(TaskLogLevel.Error, e.message ?: "Failed to remove vault")
} finally {
withContext(Dispatchers.Main.immediate) {
setBusy(false)
dismissDeleteVault()
}
}
},
)
}
}