Commit 46b4ce28 by Aleksandr

open details screen after creating job

parent c39a2157
......@@ -130,7 +130,7 @@ class RenderUseCase @Inject constructor(
)
SendJobWorker.create(context)
emit(FlowResult.Success(null))
emit(FlowResult.Success(job.id))
}
}
......@@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import com.isidroid.c23.ui._component.BackCloseComponent
import com.isidroid.c23.ui.navigation.routeJobDetails
import com.isidroid.c23.ui.navigation.routeMap
import com.isidroid.c23.ui.navigation.routeSelectContent
import com.isidroid.c23.ui.screen.render_preview.RenderContract
......@@ -32,6 +33,7 @@ fun RenderScreenDestination(navController: NavController) {
RenderContract.Effect.Navigation.ToMap -> navController.navigate(routeMap())
RenderContract.Effect.Navigation.ToSelectContent -> navController.navigateSingleTopTo(routeSelectContent())
is RenderContract.Effect.Navigation.ToDetails -> navController.navigateSingleTopTo(routeJobDetails(effect.jobId))
}
}
)
......
......@@ -28,6 +28,8 @@ class JobDetailsContract {
val lng: Double? = null,
val routeConfirmationVisible: Boolean = false,
val requestLocationPermission: Boolean = false,
val distance: String? = null
val distance: String? = null,
val renderProgress: Pair<Int, Int>? = null,
val uploadProgress: Pair<Int, Int>? = null,
) : ViewState
}
\ No newline at end of file
......@@ -19,7 +19,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onEach
......@@ -36,7 +35,7 @@ class JobDetailsViewModel @Inject constructor(
private val _spotResultStateFlow = MutableStateFlow<List<MapMarker>>(emptyList())
val spotResultStateFlow = _spotResultStateFlow.asStateFlow()
private lateinit var jobId: String
private lateinit var _jobId: String
init {
viewModelScope.launch { create(savedStateHandle) }
......@@ -61,7 +60,7 @@ class JobDetailsViewModel @Inject constructor(
savedStateHandle.getStateFlow<String?>(Argument.ID, null)
.filterNotNull()
.onEach {
jobId = it
_jobId = it
loadDetails()
}
.singleOrNull()
......@@ -69,12 +68,18 @@ class JobDetailsViewModel @Inject constructor(
private suspend fun listenSendJobEvents() {
sendJobEventCollectorFlow.eventsFlow
.filterIsInstance<JobSenderResult.Statuses>()
.collect { st -> updateStatuses(st) }
.collect { st ->
when (st) {
is JobSenderResult.Error -> {}
is JobSenderResult.RenderProgress -> onRenderProgress(st.jobId, st.position, st.total)
is JobSenderResult.Statuses -> updateStatuses(st)
is JobSenderResult.UploadProgress -> onUploadProgress(st.jobId, st.position, st.total)
}
}
}
private suspend fun loadDetails() {
useCase.loadDetails(jobId)
useCase.loadDetails(_jobId)
.flowOn(Dispatchers.IO)
.catchTimber {
when (it) {
......@@ -116,4 +121,14 @@ class JobDetailsViewModel @Inject constructor(
val updated = useCase.updateStatuses(viewState.value.printJob, info = statuses) ?: return
setState { copy(printJob = updated) }
}
private fun onRenderProgress(jobId: String, position: Int, total: Int) {
if (jobId != _jobId) return
setState { copy(renderProgress = Pair(position, total), uploadProgress = null) }
}
private fun onUploadProgress(jobId: String, position: Int, total: Int) {
if (jobId != _jobId) return
setState { copy(uploadProgress = Pair(position, total), renderProgress = null) }
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@ package com.isidroid.c23.ui.screen.details.component
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
......@@ -10,21 +11,27 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.LinearProgressIndicator
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
......@@ -38,6 +45,7 @@ import com.isidroid.ui.maps.model.MapMarker
import com.isidroid.utils.asCost
import com.isidroid.utils.spaceInCenter
import kotlinx.coroutines.flow.StateFlow
import timber.log.Timber
import java.text.DateFormat
@OptIn(ExperimentalMaterial3Api::class)
......@@ -67,6 +75,9 @@ fun DetailsV2(
) {
PrintInfoComponent(printJob)
ProgressComponentState(state)
HorizontalDivider(Modifier.padding(vertical = 16.dp))
SpotInfoComponent(
lat = state.value.lat,
......@@ -84,6 +95,65 @@ fun DetailsV2(
}
@Composable
private fun ProgressComponentState(
state: State<JobDetailsContract.State>,
modifier: Modifier = Modifier
) {
val renderProgress = state.value.renderProgress
val uploadProgress = state.value.uploadProgress
val index = renderProgress?.first ?: uploadProgress?.first ?: return
val total = renderProgress?.second ?: uploadProgress?.second ?: return
ProgressComponent(index, total, isRender = renderProgress != null, modifier)
}
@Composable
private fun ProgressComponent(
index: Int,
total: Int,
isRender: Boolean,
modifier: Modifier = Modifier
) {
val progress = index.toFloat() / total.toFloat()
val title = if (isRender) R.string.progress_rendering else R.string.progress_uploading
Timber.i("===> progress=$index/$total, progress=$progress")
Column(
modifier = modifier
.fillMaxWidth()
.padding(bottom = 16.dp),
horizontalAlignment = Alignment.End
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 16.dp, bottom = 2.dp)
) {
Text(
text = stringResource(id = title),
modifier = Modifier.weight(1f),
style = MaterialTheme.typography.labelLarge
)
Text(
text = "$index/$total",
style = MaterialTheme.typography.labelLarge,
fontWeight = FontWeight.Medium
)
}
LinearProgressIndicator(
progress = progress,
modifier = Modifier.fillMaxWidth()
)
}
}
@Composable
private fun PrintInfoComponent(printJob: PrintJobListItem) {
val textStrings = listOfNotNull(
"PIN code: ${printJob.accessCode.spaceInCenter()}",
......
......@@ -34,11 +34,11 @@ class RenderContract {
}
sealed interface Effect : ViewSideEffect {
data object PrintJobCreated: Effect
sealed interface Navigation : Effect {
data object ToSelectContent: Navigation
data object ToMap : Navigation
data object ToBack : Navigation
data class ToDetails(val jobId: String): Navigation
}
}
......
......@@ -80,7 +80,6 @@ fun RenderPreviewScreen(
effectFlow?.collect { effect ->
when (effect) {
is RenderContract.Effect.Navigation -> onNavigationRequested(effect)
RenderContract.Effect.PrintJobCreated -> Toast.makeText(context, R.string.print_job_sending, Toast.LENGTH_SHORT).show()
}
}
}
......
......@@ -186,7 +186,7 @@ class RenderViewModel @Inject constructor(
.collect { res ->
when (res) {
FlowResult.Loading -> setState { copy(disablePrintButton = true) }
is FlowResult.Success -> onPrintJobCreated()
is FlowResult.Success -> onPrintJobCreated(res.result)
}
}
}
......@@ -234,8 +234,7 @@ class RenderViewModel @Inject constructor(
_renderResults.clear()
}
private fun onPrintJobCreated(){
setEffect { RenderContract.Effect.PrintJobCreated }
setEffect { RenderContract.Effect.Navigation.ToSelectContent }
private fun onPrintJobCreated(jobId: String) {
setEffect { RenderContract.Effect.Navigation.ToDetails(jobId) }
}
}
\ No newline at end of file
......@@ -44,4 +44,6 @@
<string name="print_job_status_sending">Sending</string>
<string name="pin_code">Pin code</string>
<string name="price">Price</string>
<string name="progress_rendering">Rendering progress</string>
<string name="progress_uploading">Uploading progress</string>
</resources>
\ No newline at end of file
......@@ -16,8 +16,8 @@ class SendJobEventCollectorFlow @Inject constructor() {
private suspend fun emit(result: JobSenderResult) = _eventsFlow.emit(result)
.also { Timber.i("call: $result") }
suspend fun renderProgress(index: Int, total: Int) = emit(JobSenderResult.RenderProgress(index, total))
suspend fun updateProgress(index: Int, total: Int) = emit(JobSenderResult.UploadProgress(index, total))
suspend fun renderProgress(jobId: String, index: Int, total: Int) = emit(JobSenderResult.RenderProgress(jobId, index, total))
suspend fun uploadProgress(jobId: String, index: Int, total: Int) = emit(JobSenderResult.UploadProgress(jobId, index, total))
suspend fun jobError(jobId: String, t: Throwable) = emit(JobSenderResult.Error(jobId, t))
suspend fun updateStatus(@JobStatus status: Int, vararg jobIds: String?) = emit(JobSenderResult.Statuses(status = status, jobIds = jobIds.toSet()))
......
......@@ -3,8 +3,8 @@ package com.isidroid.job_sender.domain.dto
import com.isidroid.job.constant.JobStatus
sealed interface JobSenderResult {
data class RenderProgress(val position: Int, val total: Int) : JobSenderResult
data class UploadProgress(val position: Int, val total: Int) : JobSenderResult
data class RenderProgress(val jobId: String, val position: Int, val total: Int) : JobSenderResult
data class UploadProgress(val jobId: String, val position: Int, val total: Int) : JobSenderResult
data class Error(val jobId: String, val t: Throwable) : JobSenderResult
data class Statuses(@JobStatus val status: Int, val jobIds: Collection<String?>): JobSenderResult
data class Statuses(@JobStatus val status: Int, val jobIds: Collection<String?>) : JobSenderResult
}
\ No newline at end of file
......@@ -93,13 +93,14 @@ internal suspend fun createRenderItems(
jobIdleList: Collection<PrintJob>
): Collection<PrintJobSender> {
val richSpots = spotRepository.findLocalRichSpots(ids = jobIdleList.map { it.spotId })
var index = 0
val total = jobIdleList.size
val result = jobIdleList.mapNotNull { printJob ->
val jobTotal = printJob.sourceFiles.orEmpty().size
var jobIndex = 0
printJob.sourceFiles?.mapNotNull { source ->
createSingleRender(context, renderRepository, richSpots, printJob, source)
.also { eventCollector.renderProgress(++index, total) }
.also { eventCollector.renderProgress(printJob.id, ++jobIndex, jobTotal) }
}
}.flatten()
......
......@@ -59,7 +59,7 @@ internal class JobSendRepositoryImpl(
val sendJobResults = items.groupBy { it.printJobId }.mapValues { it.value.size }.toMutableMap()
for ((index, item) in items.withIndex()) {
eventCollector.updateProgress(index, total)
eventCollector.uploadProgress(item.printJobId, index, total)
try {
updateStatus(item, SendJobStatus.SENDING)
......@@ -82,8 +82,6 @@ internal class JobSendRepositoryImpl(
}
}
eventCollector.updateProgress(total, total)
// update jobs
val successJobIds = sendJobResults.filter { it.value == 0 }.keys
printJobRepository.updateJobStatus(status = JobStatus.RENDER_UPLOAD, *successJobIds.toTypedArray())
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment