From 8de2f2d8bdf57fc663ba3672922138a789df2307 Mon Sep 17 00:00:00 2001 From: AbronStudio Date: Tue, 5 Aug 2025 16:30:32 +0330 Subject: [PATCH] feat(discover): Enhance server invite handling and error management - Added a new state flow for loaded errors in `DiscoverServersListViewModel` to manage server loading errors. - Implemented `joinServerWithoutProcessingIndicator` method to join servers without affecting the loading state in the UI. - Updated `ServerInviteDialog` to display a loading indicator while joining a server and improved error handling. - Modified `ServerInviteHandler` to utilize the new error state and streamline the dialog's behavior. - Added a new string resource for the joining state message to enhance user feedback. --- .../discover/DiscoverServersListViewModel.kt | 33 ++++++++++-- .../chat/discover/ServerInviteDialog.kt | 52 +++++++------------ .../chat/discover/ServerInviteHandler.kt | 10 ++-- app/src/main/res/values/strings.xml | 1 + 4 files changed, 54 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/chat/revolt/composables/screens/chat/discover/DiscoverServersListViewModel.kt b/app/src/main/java/chat/revolt/composables/screens/chat/discover/DiscoverServersListViewModel.kt index 81148847..83ed6137 100644 --- a/app/src/main/java/chat/revolt/composables/screens/chat/discover/DiscoverServersListViewModel.kt +++ b/app/src/main/java/chat/revolt/composables/screens/chat/discover/DiscoverServersListViewModel.kt @@ -57,6 +57,10 @@ class DiscoverServersListViewModel @Inject constructor( private val _loadedInviteData = MutableStateFlow(null) val loadedInviteData: StateFlow = _loadedInviteData.asStateFlow() + // Error that occurred during loading server data + private val _loadedError = MutableStateFlow(null) + val loadedError: StateFlow = _loadedError.asStateFlow() + // Initialize by loading servers init { loadServers() @@ -113,6 +117,23 @@ class DiscoverServersListViewModel @Inject constructor( } }.flowOn(Dispatchers.IO) + /** + * Join server without showing loading in the server list + * This is used when joining from the dialog where we only want the button to show loading + */ + fun joinServerWithoutProcessingIndicator(inviteCode: String): Flow> = flow { + // Don't set _processingServerId or _isLoading here + _error.value = null + + try { + val result = joinInviteByCode(inviteCode) + emit(result) + } catch (e: Exception) { + _error.value = e.message ?: "Unknown error occurred" + emit(RsResult.err(RevoltError("Unknown"))) + } + }.flowOn(Dispatchers.IO) + /** * Load server data first, then show the dialog with the loaded data */ @@ -126,13 +147,16 @@ class DiscoverServersListViewModel @Inject constructor( val result = fetchInviteByCode(inviteCode) if (result.ok) { _loadedInviteData.value = result.value - // Only set the selected invite code after data is loaded - _selectedServerInviteCode.value = inviteCode } else { - _error.value = result.error?.type ?: "Unknown error occurred" + // Store the error in loadedError + _loadedError.value = result.error } + // Set the selected invite code to show the dialog in both success and error cases + _selectedServerInviteCode.value = inviteCode } catch (e: Exception) { - _error.value = e.message ?: "Unknown error occurred" + // Handle exception by creating a generic error + _loadedError.value = RevoltError("Unknown") + _selectedServerInviteCode.value = inviteCode } finally { _processingServerId.value = null } @@ -144,6 +168,7 @@ class DiscoverServersListViewModel @Inject constructor( */ fun clearLoadedData() { _loadedInviteData.value = null + _loadedError.value = null _selectedServerInviteCode.value = null } } \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/composables/screens/chat/discover/ServerInviteDialog.kt b/app/src/main/java/chat/revolt/composables/screens/chat/discover/ServerInviteDialog.kt index 1ab95a73..6b602649 100644 --- a/app/src/main/java/chat/revolt/composables/screens/chat/discover/ServerInviteDialog.kt +++ b/app/src/main/java/chat/revolt/composables/screens/chat/discover/ServerInviteDialog.kt @@ -1,6 +1,5 @@ package chat.revolt.composables.screens.chat.discover -import android.widget.Space import androidx.compose.foundation.Image import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement @@ -9,8 +8,8 @@ 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.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape @@ -25,7 +24,6 @@ import androidx.compose.runtime.Composable 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.graphics.ColorFilter import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -49,35 +47,6 @@ fun ServerInviteDialog( onJoinClick: () -> Unit, onDismiss: () -> Unit ) { - if (isLoading) { - AlertDialog( - onDismissRequest = onDismiss, - title = { - Text( - text = stringResource(id = R.string.loading), - textAlign = TextAlign.Center, - modifier = Modifier.fillMaxWidth() - ) - }, - text = { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier.fillMaxWidth() - ) { - CircularProgressIndicator( - modifier = Modifier.size(48.dp) - ) - } - }, - confirmButton = {}, - dismissButton = { - TextButton(onClick = onDismiss) { - Text(text = stringResource(id = R.string.invite_cancel)) - } - } - ) - return - } if (error != null) { AlertDialog( @@ -132,9 +101,24 @@ fun ServerInviteDialog( ) { Button( onClick = onJoinClick, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), + enabled = !isLoading ) { - Text(text = stringResource(id = R.string.invite_join)) + if (isLoading) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + CircularProgressIndicator( + modifier = Modifier.size(18.dp), + strokeWidth = 2.dp + ) + Spacer(modifier = Modifier.width(8.dp)) + Text(text = stringResource(id = R.string.joining)) + } + } else { + Text(text = stringResource(id = R.string.invite_join)) + } } TextButton( onClick = onDismiss, diff --git a/app/src/main/java/chat/revolt/composables/screens/chat/discover/ServerInviteHandler.kt b/app/src/main/java/chat/revolt/composables/screens/chat/discover/ServerInviteHandler.kt index 636226bc..89edf669 100644 --- a/app/src/main/java/chat/revolt/composables/screens/chat/discover/ServerInviteHandler.kt +++ b/app/src/main/java/chat/revolt/composables/screens/chat/discover/ServerInviteHandler.kt @@ -29,18 +29,20 @@ fun ServerInviteHandler( var showDialog by remember { mutableStateOf(true) } var error by remember { mutableStateOf(null) } - // Get the pre-loaded invite data + // Get the pre-loaded invite data and error val loadedInviteData by viewModel.loadedInviteData.collectAsState() + val loadedError by viewModel.loadedError.collectAsState() - if (showDialog && loadedInviteData != null) { + if (showDialog) { ServerInviteDialog( isLoading = isJoining, invite = loadedInviteData, - error = error, + error = error ?: loadedError, onJoinClick = { isJoining = true scope.launch { - viewModel.joinServer(inviteCode).collectLatest { result -> + // Don't set the processing server ID here to avoid showing loading in the list + viewModel.joinServerWithoutProcessingIndicator(inviteCode).collectLatest { result -> isJoining = false if (result.ok) { showDialog = false diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d862e20d..9cb5ae53 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -553,6 +553,7 @@ Could not find an invite with the specified code. You are banned from this server. An unknown error occurred. + Joining… %1$s %1$s