diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/NewHlsVideoScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/NewHlsVideoScreen.kt
index 28d30bb5c..316aeaf62 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/NewHlsVideoScreen.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/video/hls/NewHlsVideoScreen.kt
@@ -67,7 +67,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -508,27 +510,50 @@ private fun ProgressBody(
HorizontalDivider(modifier = Modifier.padding(vertical = 12.dp))
- val uploadingFraction =
- (state as? HlsPublishState.Uploading)?.let { up ->
- if (up.total == 0) 0f else up.done.toFloat() / up.total
+ // Persist the last-observed upload count across transitions so the Uploading row
+ // doesn't flicker back to "0 of 0" whenever state flips to Transcoding (between
+ // renditions) or Publishing (after the last upload). The counter should read
+ // monotonically: 1 of N → 2 of N → … → N of N as uploads actually complete.
+ var lastDone by remember { mutableIntStateOf(0) }
+ var lastTotal by remember { mutableIntStateOf(0) }
+ LaunchedEffect(state) {
+ if (state is HlsPublishState.Uploading) {
+ lastDone = state.done
+ lastTotal = state.total
}
+ }
+
+ val uploadingFraction =
+ if (lastTotal > 0) lastDone.toFloat() / lastTotal else null
val uploadingLabel =
- when (state) {
- is HlsPublishState.Uploading -> {
- if (state.currentLabel.isNotBlank()) {
- stringResource(
- R.string.hls_state_uploading_with_label_format,
- state.currentLabel,
- state.done,
- state.total,
- )
- } else {
- stringResource(R.string.hls_state_uploading_format, state.done, state.total)
- }
+ when {
+ // Currently in flight: present-tense, file label in the line.
+ state is HlsPublishState.Uploading && state.currentLabel.isNotBlank() -> {
+ stringResource(
+ R.string.hls_state_uploading_with_label_format,
+ state.currentLabel,
+ state.done,
+ state.total,
+ )
}
+ // Currently in flight, no file label (unreachable in practice — orchestrator
+ // always sets a label — but kept for completeness).
+ state is HlsPublishState.Uploading -> {
+ stringResource(R.string.hls_state_uploading_format, state.done, state.total)
+ }
+
+ // Between uploads or after all uploads finish: past-tense, monotonic count.
+ // The last uploaded file's index sticks on screen while the transcoder
+ // works on the next rendition, and lands on "Uploaded N of N" when the row
+ // flips to its checkmark/done state.
+ lastTotal > 0 -> {
+ stringResource(R.string.hls_state_uploaded_format, lastDone, lastTotal)
+ }
+
+ // Nothing has started uploading yet (very beginning of publish flow).
else -> {
- stringResource(R.string.hls_state_uploading_format, 0, 0)
+ stringResource(R.string.hls_state_uploading_idle)
}
}
PhaseRow(
diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml
index 8f26c16bf..07ecc77b2 100644
--- a/amethyst/src/main/res/values/strings.xml
+++ b/amethyst/src/main/res/values/strings.xml
@@ -2106,8 +2106,10 @@
Publish HD video
Publishing “%1$s”…
Transcoding %1$s
+ Upload
Uploading %1$d of %2$d
Uploading %1$s (%2$d of %3$d)
+ Uploaded %1$d of %2$d
Publishing event…
Video published
Your HD video is live on Nostr.