diff --git a/android/app/src/main/java/com/fabledsword/minstrel/admin/ui/AdminRequestsScreen.kt b/android/app/src/main/java/com/fabledsword/minstrel/admin/ui/AdminRequestsScreen.kt index 013a3cb9..39fa8942 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/admin/ui/AdminRequestsScreen.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/admin/ui/AdminRequestsScreen.kt @@ -81,6 +81,7 @@ fun AdminRequestsScreen( ) is AdminRequestsUiState.Success -> RequestList( rows = s.rows, + usernames = s.usernames, onApprove = viewModel::approve, onReject = viewModel::reject, ) @@ -92,12 +93,20 @@ fun AdminRequestsScreen( @Composable private fun RequestList( rows: List, + usernames: Map, onApprove: (String) -> Unit, onReject: (String) -> Unit, ) { LazyColumn(modifier = Modifier.fillMaxSize()) { items(items = rows, key = { it.id }) { req -> - AdminRequestRow(req = req, onApprove = { onApprove(req.id) }, onReject = { onReject(req.id) }) + AdminRequestRow( + req = req, + requester = usernames[req.userId] + ?: req.userId.takeIf { it.isNotEmpty() }?.take(8) + ?: "unknown", + onApprove = { onApprove(req.id) }, + onReject = { onReject(req.id) }, + ) HorizontalDivider() } } @@ -106,6 +115,7 @@ private fun RequestList( @Composable private fun AdminRequestRow( req: RequestRef, + requester: String, onApprove: () -> Unit, onReject: () -> Unit, ) { @@ -122,6 +132,13 @@ private fun AdminRequestRow( maxLines = 1, overflow = TextOverflow.Ellipsis, ) + Text( + text = "Requested by $requester", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) { AssistChip( onClick = {}, diff --git a/android/app/src/main/java/com/fabledsword/minstrel/admin/ui/AdminRequestsViewModel.kt b/android/app/src/main/java/com/fabledsword/minstrel/admin/ui/AdminRequestsViewModel.kt index 657722a1..3e3ba216 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/admin/ui/AdminRequestsViewModel.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/admin/ui/AdminRequestsViewModel.kt @@ -3,10 +3,13 @@ package com.fabledsword.minstrel.admin.ui import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.fabledsword.minstrel.admin.data.AdminRequestsRepository +import com.fabledsword.minstrel.admin.data.AdminUsersRepository import com.fabledsword.minstrel.events.EventsStream import com.fabledsword.minstrel.models.RequestRef import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Job +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -19,13 +22,17 @@ private val RELEVANT_EVENT_KINDS = setOf("request.status_changed") sealed interface AdminRequestsUiState { data object Loading : AdminRequestsUiState data object Empty : AdminRequestsUiState - data class Success(val rows: List) : AdminRequestsUiState + data class Success( + val rows: List, + val usernames: Map, + ) : AdminRequestsUiState data class Error(val message: String) : AdminRequestsUiState } @HiltViewModel class AdminRequestsViewModel @Inject constructor( private val repository: AdminRequestsRepository, + private val usersRepository: AdminUsersRepository, private val eventsStream: EventsStream, ) : ViewModel() { @@ -44,11 +51,19 @@ class AdminRequestsViewModel @Inject constructor( fun refresh(): Job = viewModelScope.launch { internal.value = AdminRequestsUiState.Loading try { - val rows = repository.list() + val (rows, usernames) = coroutineScope { + val requestsJob = async { repository.list() } + val usernamesJob = async { + runCatching { + usersRepository.list().associate { it.id to it.username } + }.getOrDefault(emptyMap()) + } + requestsJob.await() to usernamesJob.await() + } internal.value = if (rows.isEmpty()) { AdminRequestsUiState.Empty } else { - AdminRequestsUiState.Success(rows) + AdminRequestsUiState.Success(rows = rows, usernames = usernames) } } catch ( @Suppress("TooGenericExceptionCaught") e: Throwable, @@ -75,7 +90,7 @@ class AdminRequestsViewModel @Inject constructor( internal.value = if (filtered.isEmpty()) { AdminRequestsUiState.Empty } else { - AdminRequestsUiState.Success(filtered) + AdminRequestsUiState.Success(rows = filtered, usernames = before.usernames) } } viewModelScope.launch {