Новый конвейер задач и уведомлений

This commit is contained in:
2026-04-21 01:52:31 +03:00
parent 52353ea4a0
commit 75162e2d64
12 changed files with 474 additions and 195 deletions

View File

@@ -18,6 +18,7 @@ import com.github.nullptroma.wallenc.domain.usecases.StorageFileManagementUseCas
import com.github.nullptroma.wallenc.presentation.ViewModelBase
import com.github.nullptroma.wallenc.presentation.extensions.toPrintable
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.combine
@@ -113,7 +114,7 @@ class LocalVaultViewModel @Inject constructor(
fun createStorage() {
taskOrchestrator.enqueue(
title = "Create storage",
requiresForeground = false,
dispatcher = Dispatchers.IO,
work = { ctx ->
ctx.log(TaskLogLevel.Info, "Creating storage…")
manageLocalVaultUseCase.createStorage()
@@ -192,7 +193,7 @@ class LocalVaultViewModel @Inject constructor(
fun disableEncryption(storage: IStorageInfo) {
taskOrchestrator.enqueue(
title = "Disable encryption",
requiresForeground = true,
dispatcher = Dispatchers.IO,
work = { ctx ->
try {
ctx.log(TaskLogLevel.Info, "Disabling encryption…")
@@ -218,7 +219,7 @@ class LocalVaultViewModel @Inject constructor(
fun remove(storage: IStorageInfo) {
taskOrchestrator.enqueue(
title = "Remove storage",
requiresForeground = true,
dispatcher = Dispatchers.IO,
work = { ctx ->
try {
ctx.log(TaskLogLevel.Info, "Removing storage…")

View File

@@ -2,7 +2,6 @@ package com.github.nullptroma.wallenc.presentation.screens.main.screens.tasks
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
@@ -43,7 +42,7 @@ fun TaskPipelineScreen(
val pipeline by viewModel.orchestrator.pipelineState.collectAsStateWithLifecycle()
val logs by viewModel.orchestrator.logLines.collectAsStateWithLifecycle()
val hasAnyTask = pipeline.tasks.isNotEmpty()
val currentTask = pipeline.tasks.firstOrNull { it.id == pipeline.currentTaskId }
val runningTaskIds = pipeline.runningTaskIds
var showTestDialog by remember { mutableStateOf(false) }
var testDurationSec by remember { mutableFloatStateOf(10f) }
@@ -67,32 +66,12 @@ fun TaskPipelineScreen(
Text(stringResource(R.string.task_pipeline_run_test))
}
Text(
stringResource(R.string.task_pipeline_current_task),
style = MaterialTheme.typography.titleMedium,
)
if (currentTask == null) {
Text(
stringResource(R.string.task_pipeline_no_current_task),
style = MaterialTheme.typography.bodyMedium,
)
} else {
TaskRow(task = currentTask, isCurrent = true)
}
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Button(
onClick = { viewModel.orchestrator.cancelCurrent() },
enabled = currentTask != null,
) {
Text(stringResource(R.string.task_pipeline_cancel_current))
}
Button(
onClick = { viewModel.orchestrator.cancelAll() },
enabled = hasAnyTask,
) {
Text(stringResource(R.string.task_pipeline_cancel_all))
}
Button(
onClick = { viewModel.orchestrator.cancelAll() },
enabled = hasAnyTask,
modifier = Modifier.fillMaxWidth(),
) {
Text(stringResource(R.string.task_pipeline_cancel_all))
}
Text(
stringResource(R.string.task_pipeline_jobs),
@@ -103,7 +82,7 @@ fun TaskPipelineScreen(
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
items(pipeline.tasks, key = { it.id.uuid }) { task ->
TaskRow(task = task, isCurrent = task.id == pipeline.currentTaskId)
TaskRow(task = task, isRunning = task.id in runningTaskIds)
}
}
Text(
@@ -171,11 +150,11 @@ fun TaskPipelineScreen(
}
@Composable
private fun TaskRow(task: PipelineTask, isCurrent: Boolean) {
private fun TaskRow(task: PipelineTask, isRunning: Boolean) {
Column(Modifier.fillMaxWidth()) {
Text(
task.title,
style = if (isCurrent) MaterialTheme.typography.titleSmall
style = if (isRunning) MaterialTheme.typography.titleSmall
else MaterialTheme.typography.bodyMedium,
)
val stateLabel = when (val s = task.state) {

View File

@@ -5,6 +5,7 @@ import com.github.nullptroma.wallenc.domain.tasks.ITaskOrchestrator
import com.github.nullptroma.wallenc.domain.tasks.PipelineWork
import com.github.nullptroma.wallenc.domain.tasks.TaskLogLevel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import javax.inject.Inject
@@ -17,7 +18,7 @@ class TaskPipelineViewModel @Inject constructor(
val safeDurationSec = durationSec.coerceIn(0, 60)
orchestrator.enqueue(
title = "Test task (${safeDurationSec}s)",
requiresForeground = true,
dispatcher = Dispatchers.Default,
work = { ctx ->
val steps = if (safeDurationSec == 0) 1 else safeDurationSec * 10
ctx.log(TaskLogLevel.Info, "Test task started for ${safeDurationSec}s")

View File

@@ -18,12 +18,9 @@
<string name="task_pipeline_title">Task pipeline</string>
<string name="task_pipeline_jobs">Jobs</string>
<string name="task_pipeline_log">Log</string>
<string name="task_pipeline_cancel_current">Cancel current</string>
<string name="task_pipeline_cancel_all">Cancel all</string>
<string name="task_pipeline_open">Open task pipeline</string>
<string name="task_pipeline_run_test">Run test task</string>
<string name="task_pipeline_current_task">Current task</string>
<string name="task_pipeline_no_current_task">No running task</string>
<string name="task_pipeline_test_dialog_title">Test task setup</string>
<string name="task_pipeline_test_dialog_duration">Duration: %1$d s</string>
<string name="task_pipeline_test_dialog_start">Start</string>