feat: show upload progress for attachments and tweaks
Signed-off-by: Infi <wingit@geist.ga>
This commit is contained in:
parent
75c7ec95a4
commit
21c2556eb1
|
|
@ -1,15 +1,27 @@
|
||||||
package chat.revolt.components.screens.chat
|
package chat.revolt.components.screens.chat
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.horizontalScroll
|
import androidx.compose.foundation.horizontalScroll
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.ProgressIndicatorDefaults
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.surfaceColorAtElevation
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
@ -23,44 +35,57 @@ import java.io.File
|
||||||
fun AttachmentManager(
|
fun AttachmentManager(
|
||||||
attachments: List<FileArgs>,
|
attachments: List<FileArgs>,
|
||||||
uploading: Boolean,
|
uploading: Boolean,
|
||||||
|
uploadProgress: Float = 0f,
|
||||||
onRemove: (FileArgs) -> Unit,
|
onRemove: (FileArgs) -> Unit,
|
||||||
) {
|
) {
|
||||||
Row(
|
val animatedProgress by animateFloatAsState(
|
||||||
|
targetValue = uploadProgress,
|
||||||
|
animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec,
|
||||||
|
label = "Upload progress"
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp))
|
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp))
|
||||||
.horizontalScroll(rememberScrollState())
|
|
||||||
.padding(horizontal = 8.dp, vertical = 4.dp)
|
|
||||||
) {
|
) {
|
||||||
AnimatedVisibility(uploading) {
|
Row(
|
||||||
CircularProgressIndicator(
|
modifier = Modifier
|
||||||
modifier = Modifier.padding(4.dp),
|
.horizontalScroll(rememberScrollState())
|
||||||
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.7f)
|
.padding(horizontal = 8.dp, vertical = 4.dp)
|
||||||
)
|
) {
|
||||||
|
|
||||||
|
attachments.forEach { attachment ->
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(4.dp)
|
||||||
|
.clip(MaterialTheme.shapes.small)
|
||||||
|
.clickable {
|
||||||
|
onRemove(attachment)
|
||||||
|
}
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colorScheme.background,
|
||||||
|
shape = MaterialTheme.shapes.small
|
||||||
|
)
|
||||||
|
.padding(8.dp)
|
||||||
|
) {
|
||||||
|
Text(attachment.filename, maxLines = 1)
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
Icon(
|
||||||
|
Icons.Default.Close,
|
||||||
|
contentDescription = stringResource(R.string.remove_attachment_alt)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attachments.forEach { attachment ->
|
AnimatedVisibility(visible = uploading) {
|
||||||
Row(
|
LinearProgressIndicator(
|
||||||
|
progress = animatedProgress,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(4.dp)
|
.fillMaxWidth()
|
||||||
.clip(MaterialTheme.shapes.small)
|
)
|
||||||
.clickable {
|
|
||||||
onRemove(attachment)
|
|
||||||
}
|
|
||||||
.background(
|
|
||||||
color = MaterialTheme.colorScheme.background,
|
|
||||||
shape = MaterialTheme.shapes.small
|
|
||||||
)
|
|
||||||
.padding(8.dp)
|
|
||||||
) {
|
|
||||||
Text(attachment.filename, maxLines = 1)
|
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
|
||||||
Icon(
|
|
||||||
Icons.Default.Close,
|
|
||||||
contentDescription = stringResource(R.string.remove_attachment_alt)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -385,7 +385,8 @@ fun ChannelScreen(
|
||||||
AttachmentManager(
|
AttachmentManager(
|
||||||
attachments = viewModel.pendingAttachments,
|
attachments = viewModel.pendingAttachments,
|
||||||
uploading = viewModel.isSendingMessage,
|
uploading = viewModel.isSendingMessage,
|
||||||
onRemove = { viewModel.pendingAttachments.remove(it) }
|
uploadProgress = viewModel.pendingUploadProgress,
|
||||||
|
onRemove = { viewModel.pendingAttachments.remove(it) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,11 @@ package chat.revolt.screens.chat.views.channel
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
import androidx.compose.runtime.mutableStateListOf
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
import androidx.compose.runtime.toMutableStateList
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import chat.revolt.api.RevoltAPI
|
import chat.revolt.api.RevoltAPI
|
||||||
|
|
@ -55,9 +56,11 @@ class ChannelScreenViewModel : ViewModel() {
|
||||||
var pendingReplies = mutableStateListOf<SendMessageReply>()
|
var pendingReplies = mutableStateListOf<SendMessageReply>()
|
||||||
var pendingAttachments = mutableStateListOf<FileArgs>()
|
var pendingAttachments = mutableStateListOf<FileArgs>()
|
||||||
|
|
||||||
|
var pendingUploadProgress by mutableFloatStateOf(0f)
|
||||||
|
|
||||||
private fun popAttachmentBatch() {
|
private fun popAttachmentBatch() {
|
||||||
pendingAttachments =
|
pendingAttachments =
|
||||||
pendingAttachments.drop(MAX_ATTACHMENTS_PER_MESSAGE) as SnapshotStateList<FileArgs>
|
pendingAttachments.drop(MAX_ATTACHMENTS_PER_MESSAGE).toMutableStateList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setRenderableMessages(messages: List<Message>) {
|
private fun setRenderableMessages(messages: List<Message>) {
|
||||||
|
|
@ -142,14 +145,20 @@ class ChannelScreenViewModel : ViewModel() {
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val attachmentIds = arrayListOf<String>()
|
val attachmentIds = arrayListOf<String>()
|
||||||
|
val takenAttachments = pendingAttachments.take(MAX_ATTACHMENTS_PER_MESSAGE)
|
||||||
|
val totalTaken = takenAttachments.size
|
||||||
|
|
||||||
pendingAttachments.take(MAX_ATTACHMENTS_PER_MESSAGE).forEach {
|
takenAttachments.forEachIndexed { index, it ->
|
||||||
try {
|
try {
|
||||||
val id = uploadToAutumn(
|
val id = uploadToAutumn(
|
||||||
it.file,
|
it.file,
|
||||||
it.filename,
|
it.filename,
|
||||||
"attachments",
|
"attachments",
|
||||||
ContentType.parse(it.contentType)
|
ContentType.parse(it.contentType),
|
||||||
|
onProgress = { current, total ->
|
||||||
|
pendingUploadProgress =
|
||||||
|
((current.toFloat() / total.toFloat()) / totalTaken.toFloat()) + (index.toFloat() / totalTaken.toFloat())
|
||||||
|
}
|
||||||
)
|
)
|
||||||
Log.d("ChannelScreen", "Uploaded attachment with id $id")
|
Log.d("ChannelScreen", "Uploaded attachment with id $id")
|
||||||
attachmentIds.add(id)
|
attachmentIds.add(id)
|
||||||
|
|
@ -168,6 +177,8 @@ class ChannelScreenViewModel : ViewModel() {
|
||||||
|
|
||||||
pendingMessageContent = ""
|
pendingMessageContent = ""
|
||||||
hasNoMoreMessages = false
|
hasNoMoreMessages = false
|
||||||
|
isSendingMessage = false
|
||||||
|
pendingUploadProgress = 0f
|
||||||
popAttachmentBatch()
|
popAttachmentBatch()
|
||||||
clearInReplyTo()
|
clearInReplyTo()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue