Refactor: Update server invite handling and API URLs
- Changed the base URL for the PEP platform in `RevoltAPI.kt` to `https://pepchat.io/api`. - Updated the `DiscoverServersList` to handle server invites more effectively by passing the server ID to the `ServerInviteHandler`. - Enhanced `ServerInviteHandler` to utilize pre-loaded invite data and manage loading states. - Modified `ServerInviteDialog` to improve UI elements and added previews for different states. - Updated string resources for invite dialog messages to enhance clarity and user experience.
This commit is contained in:
parent
330e92abdc
commit
4ddcfd8fa9
|
|
@ -91,14 +91,14 @@ private val PLATFORM_URLS = mapOf(
|
|||
kjbook = "https://revoltchat.github.io/android"
|
||||
),
|
||||
ApplicationPlatform.PEP to PlatformUrls(
|
||||
base = "https://a-pep.peptide.chat/api",
|
||||
base = "https://pepchat.io/api",
|
||||
marketing = "https://peptide.chat",
|
||||
files = "https://cdn.pepusercontent.com",
|
||||
january = "https://a-pep.peptide.chat/january",
|
||||
january = "https://pepchat.io/january",
|
||||
app = "https://peptide.chat",
|
||||
invites = "https://pep.gg",
|
||||
websocket = "wss://a-pep.peptide.chat/ws",
|
||||
autumn = "https://a-pep.peptide.chat/autumn",
|
||||
websocket = "wss://pepchat.io/ws",
|
||||
autumn = "https://pepchat.io/autumn",
|
||||
// TODO: Replace with correct URL
|
||||
kjbook = "https://revoltchat.github.io/android"
|
||||
// TODO: Replace with correct URL
|
||||
|
|
@ -220,7 +220,7 @@ object RevoltAPI {
|
|||
* The currently selected platform.
|
||||
* Default is REVOLT.
|
||||
*/
|
||||
var selectedApplicationPlatform: ApplicationPlatform = ApplicationPlatform.REVOLT
|
||||
var selectedApplicationPlatform: ApplicationPlatform = ApplicationPlatform.PEP
|
||||
private set
|
||||
|
||||
/**
|
||||
|
|
@ -258,7 +258,7 @@ object RevoltAPI {
|
|||
// URL getter functions
|
||||
fun getCurrentBaseUrl(): String = getUrlForPlatform(selectedApplicationPlatform) { it.base }
|
||||
fun getCurrentMarketingUrl(): String = getUrlForPlatform(selectedApplicationPlatform) { it.marketing }
|
||||
fun getCurrentFilesUrl(): String = getUrlForPlatform(selectedApplicationPlatform) { it.files }
|
||||
fun getCurrentFilesUrl(): String = getUrlForPlatform(selectedApplicationPlatform) { it.autumn }
|
||||
fun getCurrentJanuaryUrl(): String = getUrlForPlatform(selectedApplicationPlatform) { it.january }
|
||||
fun getCurrentAppUrl(): String = getUrlForPlatform(selectedApplicationPlatform) { it.app }
|
||||
fun getCurrentInvitesUrl(): String = getUrlForPlatform(selectedApplicationPlatform) { it.invites }
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
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.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
|
|
@ -32,6 +33,7 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import chat.revolt.R
|
||||
import chat.revolt.api.routes.googlesheets.ServerData
|
||||
import chat.revolt.composables.screens.chat.discover.ServerInviteHandler
|
||||
|
||||
@Composable
|
||||
fun DiscoverServersList() {
|
||||
|
|
@ -40,20 +42,26 @@ fun DiscoverServersList() {
|
|||
val isLoading by viewModel.isLoading.collectAsState()
|
||||
val error by viewModel.error.collectAsState()
|
||||
val selectedInviteCode by viewModel.selectedServerInviteCodeFlow.collectAsState()
|
||||
val processingServerId by viewModel.processingServerId.collectAsState()
|
||||
|
||||
// Handle server invite dialog
|
||||
selectedInviteCode?.let { inviteCode ->
|
||||
ServerInviteHandler(
|
||||
inviteCode = inviteCode,
|
||||
viewModel = viewModel,
|
||||
onDismiss = {
|
||||
viewModel.selectedServerInviteCode = null
|
||||
},
|
||||
onJoinSuccess = {
|
||||
// Show a success message or navigate to the joined server
|
||||
viewModel.selectedServerInviteCode = null
|
||||
}
|
||||
)
|
||||
// Find the server with this invite code
|
||||
val selectedServer = servers.find { it.inviteCode == inviteCode }
|
||||
selectedServer?.let { server ->
|
||||
ServerInviteHandler(
|
||||
inviteCode = inviteCode,
|
||||
serverId = server.id,
|
||||
viewModel = viewModel,
|
||||
onDismiss = {
|
||||
viewModel.selectedServerInviteCode = null
|
||||
},
|
||||
onJoinSuccess = {
|
||||
// Show a success message or navigate to the joined server
|
||||
viewModel.selectedServerInviteCode = null
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
|
|
@ -106,9 +114,11 @@ fun DiscoverServersList() {
|
|||
items(servers) { server ->
|
||||
ServerItem(
|
||||
server = server,
|
||||
isProcessing = processingServerId == server.id,
|
||||
onClick = {
|
||||
if (server.inviteCode.isNotEmpty()) {
|
||||
viewModel.selectedServerInviteCode = server.inviteCode
|
||||
// First load server data, dialog will be shown after data is loaded
|
||||
viewModel.loadServerDataAndShowDialog(server.inviteCode, server.id)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
@ -125,13 +135,14 @@ fun DiscoverServersList() {
|
|||
@Composable
|
||||
fun ServerItem(
|
||||
server: ServerData,
|
||||
onClick: () -> Unit
|
||||
onClick: () -> Unit,
|
||||
isProcessing: Boolean = false
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp)
|
||||
.clickable { onClick() }
|
||||
.clickable(enabled = !isProcessing) { onClick() }
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
|
|
@ -167,19 +178,28 @@ fun ServerItem(
|
|||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
IconButton(
|
||||
onClick = onClick,
|
||||
) {
|
||||
Box(
|
||||
|
||||
if (isProcessing) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.size(24.dp),
|
||||
strokeWidth = 2.dp
|
||||
)
|
||||
} else {
|
||||
IconButton(
|
||||
onClick = onClick,
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.icn_arrow_forward_24dp),
|
||||
contentDescription = "",
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
)
|
||||
.fillMaxSize()
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.icn_arrow_forward_24dp),
|
||||
contentDescription = "",
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,14 @@ class DiscoverServersListViewModel @Inject constructor(
|
|||
set(value) {
|
||||
_selectedServerInviteCode.value = value
|
||||
}
|
||||
|
||||
// Currently processing server ID
|
||||
private val _processingServerId = MutableStateFlow<String?>(null)
|
||||
val processingServerId: StateFlow<String?> = _processingServerId.asStateFlow()
|
||||
|
||||
// Server invite data that has been loaded
|
||||
private val _loadedInviteData = MutableStateFlow<Invite?>(null)
|
||||
val loadedInviteData: StateFlow<Invite?> = _loadedInviteData.asStateFlow()
|
||||
|
||||
// Initialize by loading servers
|
||||
init {
|
||||
|
|
@ -75,8 +83,8 @@ class DiscoverServersListViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun loadServerInviteInfo(inviteCode: String): Flow<RsResult<Invite, RevoltError>> = flow {
|
||||
_isLoading.value = true
|
||||
fun loadServerInviteInfo(inviteCode: String, serverId: String): Flow<RsResult<Invite, RevoltError>> = flow {
|
||||
_processingServerId.value = serverId
|
||||
_error.value = null
|
||||
|
||||
try {
|
||||
|
|
@ -86,7 +94,7 @@ class DiscoverServersListViewModel @Inject constructor(
|
|||
_error.value = e.message ?: "Unknown error occurred"
|
||||
emit(RsResult.err(RevoltError("Unknown")))
|
||||
} finally {
|
||||
_isLoading.value = false
|
||||
_processingServerId.value = null
|
||||
}
|
||||
}.flowOn(Dispatchers.IO)
|
||||
|
||||
|
|
@ -104,4 +112,38 @@ class DiscoverServersListViewModel @Inject constructor(
|
|||
_isLoading.value = false
|
||||
}
|
||||
}.flowOn(Dispatchers.IO)
|
||||
|
||||
/**
|
||||
* Load server data first, then show the dialog with the loaded data
|
||||
*/
|
||||
fun loadServerDataAndShowDialog(inviteCode: String, serverId: String) {
|
||||
_loadedInviteData.value = null
|
||||
_processingServerId.value = serverId
|
||||
_error.value = null
|
||||
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
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"
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
_error.value = e.message ?: "Unknown error occurred"
|
||||
} finally {
|
||||
_processingServerId.value = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear loaded data when dialog is dismissed
|
||||
*/
|
||||
fun clearLoadedData() {
|
||||
_loadedInviteData.value = null
|
||||
_selectedServerInviteCode.value = null
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,18 @@
|
|||
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
|
||||
import androidx.compose.foundation.layout.Box
|
||||
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.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
|
|
@ -18,14 +25,17 @@ 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
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.revolt.R
|
||||
import chat.revolt.api.REVOLT_FILES
|
||||
import chat.revolt.api.RevoltAPI
|
||||
import chat.revolt.api.RevoltError
|
||||
import chat.revolt.api.schemas.Invite
|
||||
import chat.revolt.composables.generic.IconPlaceholder
|
||||
|
|
@ -114,13 +124,25 @@ fun ServerInviteDialog(
|
|||
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = {
|
||||
Text(
|
||||
text = invite.serverName ?: stringResource(id = R.string.unknown),
|
||||
textAlign = TextAlign.Center,
|
||||
fontWeight = FontWeight.Bold,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
confirmButton = {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Bottom // Align buttons to the bottom
|
||||
) {
|
||||
Button(
|
||||
onClick = onJoinClick,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.invite_join))
|
||||
}
|
||||
TextButton(
|
||||
onClick = onDismiss,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.invite_cancel))
|
||||
}
|
||||
}
|
||||
},
|
||||
text = {
|
||||
Column(
|
||||
|
|
@ -129,7 +151,7 @@ fun ServerInviteDialog(
|
|||
) {
|
||||
if (invite.serverIcon != null) {
|
||||
RemoteImage(
|
||||
url = "$REVOLT_FILES/icons/${invite.serverIcon.id}/${invite.serverIcon.filename}",
|
||||
url = "${RevoltAPI.getCurrentFilesUrl()}/icons/${invite.serverIcon.id}/${invite.serverIcon.filename}",
|
||||
allowAnimation = false,
|
||||
description = invite.serverName ?: stringResource(id = R.string.unknown),
|
||||
modifier = Modifier
|
||||
|
|
@ -152,28 +174,122 @@ fun ServerInviteDialog(
|
|||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = invite.serverName ?: stringResource(id = R.string.unknown),
|
||||
textAlign = TextAlign.Center,
|
||||
fontSize = 26.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
// Invited by section
|
||||
if (invite.userName != null) {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.border(
|
||||
width = 1.dp,
|
||||
color = MaterialTheme.colorScheme.outlineVariant,
|
||||
shape = MaterialTheme.shapes.large
|
||||
)
|
||||
.padding(horizontal = 12.dp, vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Text(text = "Invited by")
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
if (invite.userAvatar != null) {
|
||||
RemoteImage(
|
||||
url = "${RevoltAPI.getCurrentFilesUrl()}/avatars/${invite.userAvatar.id}/${invite.userAvatar.filename}",
|
||||
description = invite.userName,
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.clip(CircleShape)
|
||||
)
|
||||
} else {
|
||||
IconPlaceholder(name = invite.userName, modifier = Modifier.size(24.dp).clip(CircleShape), fontSize = 12.sp)
|
||||
}
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(text = invite.userName, fontWeight = FontWeight.SemiBold)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (invite.memberCount != null) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = stringResource(
|
||||
id = R.string.members_count,
|
||||
invite.memberCount
|
||||
),
|
||||
fontSize = 14.sp,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.three_person),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(
|
||||
alpha = 0.6f
|
||||
)
|
||||
)
|
||||
)
|
||||
Text(
|
||||
text = stringResource(
|
||||
id = R.string.members_count,
|
||||
invite.memberCount
|
||||
),
|
||||
fontSize = 14.sp,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(
|
||||
alpha = 0.6f
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
Button(onClick = onJoinClick) {
|
||||
Text(text = stringResource(id = R.string.invite_join))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(text = stringResource(id = R.string.invite_cancel))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ServerInviteDialogPreviewLoading() {
|
||||
ServerInviteDialog(
|
||||
isLoading = true,
|
||||
invite = null,
|
||||
error = null,
|
||||
onJoinClick = {},
|
||||
onDismiss = {}
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ServerInviteDialogPreviewError() {
|
||||
ServerInviteDialog(
|
||||
isLoading = false,
|
||||
invite = null,
|
||||
error = RevoltError(type = "NotFound"),
|
||||
onJoinClick = {},
|
||||
onDismiss = {}
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ServerInviteDialogPreviewSuccess() {
|
||||
val invite = Invite(
|
||||
serverName = "Revolt Test Server",
|
||||
serverIcon = null, // Replace with a real AutumnResource if needed for preview
|
||||
memberCount = 123,
|
||||
userName = "TestUser",
|
||||
userAvatar = null // Replace with a real AutumnResource if needed for preview
|
||||
)
|
||||
ServerInviteDialog(
|
||||
isLoading = false,
|
||||
invite = invite,
|
||||
error = null,
|
||||
onJoinClick = {},
|
||||
onDismiss = {}
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package chat.revolt.composables.screens.chat.discover
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
|
|
@ -18,40 +19,32 @@ import kotlinx.coroutines.launch
|
|||
@Composable
|
||||
fun ServerInviteHandler(
|
||||
inviteCode: String,
|
||||
serverId: String,
|
||||
viewModel: DiscoverServersListViewModel = viewModel(),
|
||||
onDismiss: () -> Unit = {},
|
||||
onJoinSuccess: () -> Unit = {}
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
var isLoading by remember { mutableStateOf(true) }
|
||||
var isJoining by remember { mutableStateOf(false) }
|
||||
var showDialog by remember { mutableStateOf(true) }
|
||||
var inviteResult by remember { mutableStateOf<RsResult<Invite, RevoltError>?>(null) }
|
||||
var error by remember { mutableStateOf<RevoltError?>(null) }
|
||||
|
||||
// Fetch server invite info
|
||||
LaunchedEffect(inviteCode) {
|
||||
viewModel.loadServerInviteInfo(inviteCode).collectLatest { result ->
|
||||
inviteResult = result
|
||||
isLoading = false
|
||||
|
||||
if (result.err) {
|
||||
error = result.error
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get the pre-loaded invite data
|
||||
val loadedInviteData by viewModel.loadedInviteData.collectAsState()
|
||||
|
||||
if (showDialog) {
|
||||
if (showDialog && loadedInviteData != null) {
|
||||
ServerInviteDialog(
|
||||
isLoading = isLoading,
|
||||
invite = inviteResult?.value,
|
||||
isLoading = isJoining,
|
||||
invite = loadedInviteData,
|
||||
error = error,
|
||||
onJoinClick = {
|
||||
isLoading = true
|
||||
isJoining = true
|
||||
scope.launch {
|
||||
viewModel.joinServer(inviteCode).collectLatest { result ->
|
||||
isLoading = false
|
||||
isJoining = false
|
||||
if (result.ok) {
|
||||
showDialog = false
|
||||
viewModel.clearLoadedData()
|
||||
onJoinSuccess()
|
||||
} else {
|
||||
error = result.error
|
||||
|
|
@ -61,6 +54,7 @@ fun ServerInviteHandler(
|
|||
},
|
||||
onDismiss = {
|
||||
showDialog = false
|
||||
viewModel.clearLoadedData()
|
||||
onDismiss()
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -543,9 +543,9 @@
|
|||
<string name="link_type_no_intent">No app found to handle this link</string>
|
||||
<string name="link_open">Open</string>
|
||||
|
||||
<string name="invite_message">You\'ve been invited to join this server. Would you like to join?</string>
|
||||
<string name="invite_join">Join</string>
|
||||
<string name="invite_cancel">Cancel</string>
|
||||
<string name="invite_message">You’ve been invited to join</string>
|
||||
<string name="invite_join">Accept Invite</string>
|
||||
<string name="invite_cancel">No Thanks</string>
|
||||
<string name="invite_already_member">You are already a member of this server.</string>
|
||||
<string name="members_count">%1$d members</string>
|
||||
<string name="invite_error_header">There was an error</string>
|
||||
|
|
|
|||
Loading…
Reference in New Issue