Использования менеджера Tasks
This commit is contained in:
@@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
|||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import java.util.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
@@ -92,8 +93,12 @@ class LocalVaultViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun printStorageInfoToLog(storage: IStorageInfo) {
|
fun printStorageInfoToLog(storage: IStorageInfo) {
|
||||||
|
taskOrchestrator.enqueue(
|
||||||
|
title = "Dump storage to log",
|
||||||
|
dispatcher = Dispatchers.IO,
|
||||||
|
work = { ctx ->
|
||||||
storageFileManagementUseCase.setStorage(storage)
|
storageFileManagementUseCase.setStorage(storage)
|
||||||
viewModelScope.launch {
|
ctx.log(TaskLogLevel.Info, "Enumerating files and directories…")
|
||||||
val files: List<IFile>
|
val files: List<IFile>
|
||||||
val dirs: List<IDirectory>
|
val dirs: List<IDirectory>
|
||||||
val time = measureTimeMillis {
|
val time = measureTimeMillis {
|
||||||
@@ -108,7 +113,12 @@ class LocalVaultViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
logger.debug("Time", "Time: $time ms")
|
logger.debug("Time", "Time: $time ms")
|
||||||
logger.debug("Storage", storage.toPrintable())
|
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() {
|
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) {
|
fun enableEncryption(storage: IStorageInfo, password: String, encryptPath: Boolean) {
|
||||||
val id = storage.uuid
|
val id = storage.uuid
|
||||||
if (runningStorages.contains(id))
|
synchronized(storageOpMutex) {
|
||||||
return
|
if (runningStorages.contains(id)) return
|
||||||
tasksCount++
|
|
||||||
runningStorages.add(id)
|
runningStorages.add(id)
|
||||||
|
tasksCount++
|
||||||
|
}
|
||||||
val key = EncryptKey(password)
|
val key = EncryptKey(password)
|
||||||
viewModelScope.launch {
|
taskOrchestrator.enqueue(
|
||||||
|
title = "Enable encryption",
|
||||||
|
dispatcher = Dispatchers.IO,
|
||||||
|
work = { ctx ->
|
||||||
try {
|
try {
|
||||||
|
ctx.log(TaskLogLevel.Info, "Checking storage…")
|
||||||
when (manageStoragesEncryptionUseCase.canEncrypt(storage)) {
|
when (manageStoragesEncryptionUseCase.canEncrypt(storage)) {
|
||||||
ManageStoragesEncryptionUseCase.CanEncryptResult.Allowed -> {
|
ManageStoragesEncryptionUseCase.CanEncryptResult.Allowed -> {
|
||||||
|
ctx.log(TaskLogLevel.Info, "Encrypting…")
|
||||||
manageStoragesEncryptionUseCase.enableEncryption(storage, key, encryptPath)
|
manageStoragesEncryptionUseCase.enableEncryption(storage, key, encryptPath)
|
||||||
manageStoragesEncryptionUseCase.openStorage(storage, key, true)
|
manageStoragesEncryptionUseCase.openStorage(storage, key, true)
|
||||||
|
ctx.log(TaskLogLevel.Info, "Encryption enabled")
|
||||||
_messages.emit("Encryption enabled")
|
_messages.emit("Encryption enabled")
|
||||||
}
|
}
|
||||||
ManageStoragesEncryptionUseCase.CanEncryptResult.AlreadyEncrypted -> {
|
ManageStoragesEncryptionUseCase.CanEncryptResult.AlreadyEncrypted -> {
|
||||||
|
ctx.log(TaskLogLevel.Info, "Storage is already encrypted")
|
||||||
_messages.emit("Storage is already encrypted")
|
_messages.emit("Storage is already encrypted")
|
||||||
}
|
}
|
||||||
ManageStoragesEncryptionUseCase.CanEncryptResult.StorageIsNotEmpty -> {
|
ManageStoragesEncryptionUseCase.CanEncryptResult.StorageIsNotEmpty -> {
|
||||||
|
ctx.log(TaskLogLevel.Info, "Storage is not empty")
|
||||||
_messages.emit("Storage is not empty")
|
_messages.emit("Storage is not empty")
|
||||||
}
|
}
|
||||||
ManageStoragesEncryptionUseCase.CanEncryptResult.StorageStateUnknown -> {
|
ManageStoragesEncryptionUseCase.CanEncryptResult.StorageStateUnknown -> {
|
||||||
|
ctx.log(TaskLogLevel.Info, "Cannot determine whether storage is empty")
|
||||||
_messages.emit("Cannot determine whether storage is empty")
|
_messages.emit("Cannot determine whether storage is empty")
|
||||||
}
|
}
|
||||||
ManageStoragesEncryptionUseCase.CanEncryptResult.UnsupportedStorageType -> {
|
ManageStoragesEncryptionUseCase.CanEncryptResult.UnsupportedStorageType -> {
|
||||||
|
ctx.log(TaskLogLevel.Info, "Unsupported storage type")
|
||||||
_messages.emit("Unsupported storage type")
|
_messages.emit("Unsupported storage type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
ctx.log(TaskLogLevel.Error, e.message ?: "Failed to enable encryption")
|
||||||
_messages.emit(e.message ?: "Failed to enable encryption")
|
_messages.emit(e.message ?: "Failed to enable encryption")
|
||||||
}
|
} finally {
|
||||||
finally {
|
synchronized(storageOpMutex) {
|
||||||
runningStorages.remove(id)
|
runningStorages.remove(id)
|
||||||
tasksCount--
|
tasksCount--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openEncryptedStorage(storage: IStorageInfo, password: String, rememberPassword: Boolean) {
|
fun openEncryptedStorage(storage: IStorageInfo, password: String, rememberPassword: Boolean) {
|
||||||
val id = storage.uuid
|
val id = storage.uuid
|
||||||
|
synchronized(storageOpMutex) {
|
||||||
if (runningStorages.contains(id)) return
|
if (runningStorages.contains(id)) return
|
||||||
tasksCount++
|
|
||||||
runningStorages.add(id)
|
runningStorages.add(id)
|
||||||
|
tasksCount++
|
||||||
|
}
|
||||||
val key = EncryptKey(password)
|
val key = EncryptKey(password)
|
||||||
viewModelScope.launch {
|
taskOrchestrator.enqueue(
|
||||||
|
title = "Open encrypted storage",
|
||||||
|
dispatcher = Dispatchers.IO,
|
||||||
|
work = { ctx ->
|
||||||
try {
|
try {
|
||||||
|
ctx.log(TaskLogLevel.Info, "Opening storage…")
|
||||||
manageStoragesEncryptionUseCase.openStorage(storage, key, rememberPassword)
|
manageStoragesEncryptionUseCase.openStorage(storage, key, rememberPassword)
|
||||||
|
ctx.log(TaskLogLevel.Info, "Storage opened")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
ctx.log(TaskLogLevel.Error, e.message ?: "Failed to open encrypted storage")
|
||||||
_messages.emit(e.message ?: "Failed to open encrypted storage")
|
_messages.emit(e.message ?: "Failed to open encrypted storage")
|
||||||
} finally {
|
} finally {
|
||||||
|
synchronized(storageOpMutex) {
|
||||||
runningStorages.remove(id)
|
runningStorages.remove(id)
|
||||||
tasksCount--
|
tasksCount--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun closeEncryptedStorage(storage: IStorageInfo) {
|
fun closeEncryptedStorage(storage: IStorageInfo) {
|
||||||
viewModelScope.launch {
|
taskOrchestrator.enqueue(
|
||||||
|
title = "Close encrypted storage",
|
||||||
|
dispatcher = Dispatchers.IO,
|
||||||
|
work = { ctx ->
|
||||||
try {
|
try {
|
||||||
|
ctx.log(TaskLogLevel.Info, "Closing storage…")
|
||||||
manageStoragesEncryptionUseCase.closeStorage(storage)
|
manageStoragesEncryptionUseCase.closeStorage(storage)
|
||||||
|
ctx.log(TaskLogLevel.Info, "Storage closed")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
ctx.log(TaskLogLevel.Error, e.message ?: "Failed to close encrypted storage")
|
||||||
_messages.emit(e.message ?: "Failed to close encrypted storage")
|
_messages.emit(e.message ?: "Failed to close encrypted storage")
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun disableEncryption(storage: IStorageInfo) {
|
fun disableEncryption(storage: IStorageInfo) {
|
||||||
@@ -211,9 +255,19 @@ class LocalVaultViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun rename(storage: IStorageInfo, newName: String) {
|
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)
|
renameStorageUseCase.rename(storage, newName)
|
||||||
|
ctx.log(TaskLogLevel.Info, "Renamed")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
ctx.log(TaskLogLevel.Error, e.message ?: "Rename failed")
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun remove(storage: IStorageInfo) {
|
fun remove(storage: IStorageInfo) {
|
||||||
|
|||||||
@@ -4,18 +4,22 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import com.github.nullptroma.wallenc.domain.auth.RemoteYandexSignInLauncher
|
import com.github.nullptroma.wallenc.domain.auth.RemoteYandexSignInLauncher
|
||||||
import com.github.nullptroma.wallenc.domain.interfaces.IYandexVault
|
import com.github.nullptroma.wallenc.domain.interfaces.IYandexVault
|
||||||
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
|
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 com.github.nullptroma.wallenc.presentation.ViewModelBase
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.withContext
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class RemoteVaultsViewModel @Inject constructor(
|
class RemoteVaultsViewModel @Inject constructor(
|
||||||
private val vaultsManager: IVaultsManager,
|
private val vaultsManager: IVaultsManager,
|
||||||
val yandexSignIn: RemoteYandexSignInLauncher,
|
val yandexSignIn: RemoteYandexSignInLauncher,
|
||||||
|
private val taskOrchestrator: ITaskOrchestrator,
|
||||||
) : ViewModelBase<RemoteVaultsScreenState>(RemoteVaultsScreenState()) {
|
) : ViewModelBase<RemoteVaultsScreenState>(RemoteVaultsScreenState()) {
|
||||||
|
|
||||||
val uiState = combine(
|
val uiState = combine(
|
||||||
@@ -50,15 +54,25 @@ class RemoteVaultsViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onYandexAuthSuccess(accessToken: String) {
|
fun onYandexAuthSuccess(accessToken: String) {
|
||||||
viewModelScope.launch {
|
|
||||||
setBusy(true)
|
setBusy(true)
|
||||||
|
taskOrchestrator.enqueue(
|
||||||
|
title = "Add Yandex vault",
|
||||||
|
dispatcher = Dispatchers.IO,
|
||||||
|
work = { ctx ->
|
||||||
try {
|
try {
|
||||||
|
ctx.log(TaskLogLevel.Info, "Adding vault…")
|
||||||
vaultsManager.addYandexVault(accessToken)
|
vaultsManager.addYandexVault(accessToken)
|
||||||
|
ctx.log(TaskLogLevel.Info, "Vault added")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
ctx.log(TaskLogLevel.Error, e.message ?: "Failed to add vault")
|
||||||
} finally {
|
} finally {
|
||||||
|
withContext(Dispatchers.Main.immediate) {
|
||||||
setBusy(false)
|
setBusy(false)
|
||||||
setAddChoiceVisible(false)
|
setAddChoiceVisible(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestDeleteVault(item: RemoteVaultListItem) {
|
fun requestDeleteVault(item: RemoteVaultListItem) {
|
||||||
@@ -71,14 +85,25 @@ class RemoteVaultsViewModel @Inject constructor(
|
|||||||
|
|
||||||
fun confirmDeleteVault() {
|
fun confirmDeleteVault() {
|
||||||
val pending = state.value.vaultPendingDelete ?: return
|
val pending = state.value.vaultPendingDelete ?: return
|
||||||
viewModelScope.launch {
|
val uuid = pending.uuid
|
||||||
setBusy(true)
|
setBusy(true)
|
||||||
|
taskOrchestrator.enqueue(
|
||||||
|
title = "Remove remote vault",
|
||||||
|
dispatcher = Dispatchers.IO,
|
||||||
|
work = { ctx ->
|
||||||
try {
|
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 {
|
} finally {
|
||||||
|
withContext(Dispatchers.Main.immediate) {
|
||||||
setBusy(false)
|
setBusy(false)
|
||||||
dismissDeleteVault()
|
dismissDeleteVault()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user