refactor: Update API references and platform handling

This commit refines the API references throughout the application to utilize the new `RevoltAPI` structure, enhancing maintainability and clarity. Key changes include:
- Replaced all instances of `REVOLT_FILES`, `REVOLT_BASE`, and other constants with calls to `RevoltAPI` methods for dynamic URL generation.
- Introduced an `ApplicationPlatform` enum to manage platform-specific URLs, allowing for easier switching between Revolt and PepChat.
- Updated various screens and components to reflect the new API structure, ensuring consistent URL handling across the application.
- Enhanced the `ChoosePlatformScreen` to set the selected platform and navigate accordingly.

These changes improve the overall architecture and prepare the codebase for future enhancements.
This commit is contained in:
AbronStudio 2025-08-03 13:41:44 +03:30
parent 9f92a9fe45
commit 8b693c737b
44 changed files with 629 additions and 513 deletions

View File

@ -1 +1 @@
PEP
Revolt

View File

@ -0,0 +1,8 @@
<component name="ProjectDictionaryState">
<dictionary name="project">
<words>
<w>kjbook</w>
<w>unreads</w>
</words>
</dictionary>
</component>

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">

View File

@ -1,6 +1,8 @@
package chat.revolt
import android.app.Application
import chat.revolt.api.RevoltHttp
import chat.revolt.persistence.KVStorage
import com.google.android.material.color.DynamicColors
import dagger.hilt.android.HiltAndroidApp
import logcat.AndroidLogcatLogger
@ -15,6 +17,7 @@ class RevoltApplication : Application() {
override fun onCreate() {
super.onCreate()
AndroidLogcatLogger.installOnDebuggableApp(this, minPriority = LogPriority.VERBOSE)
RevoltHttp // Trigger initialization
}
init {
@ -22,3 +25,11 @@ class RevoltApplication : Application() {
DynamicColors.applyToActivitiesIfAvailable(this)
}
}
/**
* Extension function to get KVStorage instance.
* @return KVStorage instance
*/
fun RevoltApplication.getKVStorage(): KVStorage {
return KVStorage(this)
}

View File

@ -47,7 +47,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.compose.viewModel
import chat.revolt.R
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.RevoltError
import chat.revolt.api.routes.invites.fetchInviteByCode
import chat.revolt.api.routes.invites.joinInviteByCode
@ -180,7 +180,7 @@ fun InviteScreen(
contentAlignment = Alignment.Center
) {
GlideImage(
model = "$REVOLT_FILES/banners/${invite?.serverBanner?.id}/${invite?.serverBanner?.filename}",
model = "${RevoltAPI.getCurrentFilesUrl()}/banners/${invite?.serverBanner?.id}/${invite?.serverBanner?.filename}",
contentScale = ContentScale.Crop,
contentDescription = null,
modifier = Modifier
@ -205,7 +205,7 @@ fun InviteScreen(
) {
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 = viewModel.inviteResult?.value?.serverName
?: stringResource(id = R.string.unknown),

View File

@ -41,7 +41,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.core.view.WindowCompat
import chat.revolt.R
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.RevoltHttp
import chat.revolt.api.schemas.AutumnResource
import chat.revolt.api.settings.LoadedSettings
@ -85,7 +85,7 @@ class ImageViewActivity : ComponentActivity() {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ImageViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) {
val resourceUrl = "$REVOLT_FILES/attachments/${resource.id}/${resource.filename}"
val resourceUrl = "${RevoltAPI.getCurrentFilesUrl()}/attachments/${resource.id}/${resource.filename}"
val context = LocalContext.current

View File

@ -19,7 +19,7 @@ import androidx.lifecycle.lifecycleScope
import androidx.media3.common.MediaItem
import androidx.media3.exoplayer.ExoPlayer
import chat.revolt.R
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.RevoltHttp
import chat.revolt.api.schemas.AutumnResource
import chat.revolt.databinding.ActivityVideoplayerBinding
@ -54,7 +54,7 @@ class VideoViewActivity : FragmentActivity() {
}
val resourceUrl =
"$REVOLT_FILES/attachments/${autumnResource.id}/${autumnResource.filename}"
"${RevoltAPI.getCurrentFilesUrl()}/attachments/${autumnResource.id}/${autumnResource.filename}"
WindowCompat.setDecorFitsSystemWindows(window, false)

View File

@ -18,6 +18,7 @@ import chat.revolt.api.schemas.Message
import chat.revolt.api.schemas.Server
import chat.revolt.api.schemas.User
import chat.revolt.api.unreads.Unreads
import chat.revolt.getKVStorage
import chat.revolt.persistence.Database
import chat.revolt.persistence.SqlStorage
import com.chuckerteam.chucker.api.ChuckerCollector
@ -53,24 +54,65 @@ import kotlinx.serialization.json.Json
import java.net.SocketException
import chat.revolt.api.schemas.Channel as ChannelSchema
private const val USE_ALPHA_API = false
/**
* Enum representing available platforms in the application.
*/
enum class ApplicationPlatform(val baseUrl: String) {
REVOLT("https://api.revolt.chat"),
PEP("https://peptide.chat/api")
}
val REVOLT_BASE =
if (USE_ALPHA_API) "https://alpha.revolt.chat/api" else "https://api.revolt.chat/0.8"
const val REVOLT_SUPPORT = "https://support.revolt.chat"
const val REVOLT_MARKETING = "https://revolt.chat"
val REVOLT_FILES =
if (USE_ALPHA_API) "https://alpha.revolt.chat/autumn" else "https://cdn.revoltusercontent.com"
val REVOLT_JANUARY =
if (USE_ALPHA_API) "https://alpha.revolt.chat/january" else "https://jan.revolt.chat"
const val REVOLT_APP = "https://app.revolt.chat"
const val REVOLT_INVITES = "https://rvlt.gg"
val REVOLT_WEBSOCKET =
if (USE_ALPHA_API) "wss://alpha.revolt.chat/ws" else "wss://ws.revolt.chat"
const val REVOLT_KJBOOK = "https://revoltchat.github.io/android"
/**
* Platform URL configuration
*/
data class PlatformUrls(
val base: String,
val marketing: String,
val files: String,
val january: String,
val app: String,
val invites: String,
val websocket: String,
val kjbook: String
)
// Platform URL configurations
private val PLATFORM_URLS = mapOf(
ApplicationPlatform.REVOLT to PlatformUrls(
base = "https://api.revolt.chat/0.8",
marketing = "https://revolt.chat",
files = "https://cdn.revoltusercontent.com",
january = "https://jan.revolt.chat",
app = "https://app.revolt.chat",
invites = "https://rvlt.gg",
websocket = "wss://ws.revolt.chat",
kjbook = "https://revoltchat.github.io/android"
),
ApplicationPlatform.PEP to PlatformUrls(
base = "https://api.pep.chat/0.8",
marketing = "https://pep.chat",
files = "https://cdn.pepusercontent.com",
january = "https://jan.pep.chat",
app = "https://app.pep.chat",
invites = "https://pep.gg",
websocket = "wss://ws.pep.chat",
kjbook = "https://pepchat.github.io/android"
)
)
object UrlsStorageKeys {
const val PLATFORM = "platform_key"
}
fun String.api(): String {
return "$REVOLT_BASE$this"
return "${RevoltAPI.getCurrentBaseUrl()}$this"
}
/**
* Helper functions to get URLs for a specific platform
*/
private fun getUrlForPlatform(platform: ApplicationPlatform, urlSelector: (PlatformUrls) -> String): String {
return urlSelector(PLATFORM_URLS[platform]!!)
}
fun buildUserAgent(accessMethod: String = "Ktor"): String {
@ -90,58 +132,60 @@ val RevoltCbor = Cbor {
ignoreUnknownKeys = true
}
val RevoltHttp = HttpClient(OkHttp) {
install(DefaultRequest)
install(ContentNegotiation) {
json(RevoltJson)
}
install(WebSockets)
install(HttpRequestRetry) {
retryOnServerErrors(maxRetries = 5)
retryOnException(maxRetries = 5)
modifyRequest { request ->
request.headers.append("x-retry-count", retryCount.toString())
val RevoltHttp by lazy {
HttpClient(OkHttp) {
install(DefaultRequest)
install(ContentNegotiation) {
json(RevoltJson)
}
exponentialDelay()
}
install(WebSockets)
install(Logging) { level = LogLevel.INFO }
install(HttpRequestRetry) {
retryOnServerErrors(maxRetries = 5)
retryOnException(maxRetries = 5)
val chuckerCollector = ChuckerCollector(
context = RevoltApplication.instance,
showNotification = true,
retentionPeriod = RetentionManager.Period.ONE_DAY
)
modifyRequest { request ->
request.headers.append("x-retry-count", retryCount.toString())
}
val chuckerInterceptor = ChuckerInterceptor.Builder(RevoltApplication.instance)
.collector(chuckerCollector)
.maxContentLength(250_000L)
.redactHeaders(RevoltAPI.TOKEN_HEADER_NAME)
.alwaysReadResponseBody(true)
.createShortcut(false)
.build()
exponentialDelay()
}
engine {
addInterceptor { chain ->
val request = chain.request().newBuilder()
.apply {
if (chain.request().headers[RevoltAPI.TOKEN_HEADER_NAME] == null) {
header(RevoltAPI.TOKEN_HEADER_NAME, RevoltAPI.sessionToken)
install(Logging) { level = LogLevel.INFO }
val chuckerCollector = ChuckerCollector(
context = RevoltApplication.instance,
showNotification = true,
retentionPeriod = RetentionManager.Period.ONE_DAY
)
val chuckerInterceptor = ChuckerInterceptor.Builder(RevoltApplication.instance)
.collector(chuckerCollector)
.maxContentLength(250_000L)
.redactHeaders(RevoltAPI.TOKEN_HEADER_NAME)
.alwaysReadResponseBody(true)
.createShortcut(false)
.build()
engine {
addInterceptor { chain ->
val request = chain.request().newBuilder()
.apply {
if (chain.request().headers[RevoltAPI.TOKEN_HEADER_NAME] == null) {
header(RevoltAPI.TOKEN_HEADER_NAME, RevoltAPI.sessionToken)
}
}
}
.build()
chain.proceed(request)
.build()
chain.proceed(request)
}
addInterceptor(chuckerInterceptor)
}
addInterceptor(chuckerInterceptor)
}
defaultRequest {
url(REVOLT_BASE)
header("User-Agent", buildUserAgent())
defaultRequest {
url(RevoltAPI.getCurrentBaseUrl())
header("User-Agent", buildUserAgent())
}
}
}
@ -167,6 +211,55 @@ object RevoltAPI {
var sessionId: String = ""
private set
/**
* The currently selected platform.
* Default is REVOLT.
*/
var selectedApplicationPlatform: ApplicationPlatform = ApplicationPlatform.REVOLT
private set
/**
* Sets the current platform and saves it to persistent storage.
* @param applicationPlatform The platform to set
*/
fun setPlatform(applicationPlatform: ApplicationPlatform) {
selectedApplicationPlatform = applicationPlatform
CoroutineScope(Dispatchers.IO).launch {
savePlatformSelection()
}
}
/**
* Saves the current platform selection to persistent storage.
*/
private suspend fun savePlatformSelection() {
val kvStorage = RevoltApplication.instance.getKVStorage()
kvStorage.set(UrlsStorageKeys.PLATFORM, selectedApplicationPlatform.name)
}
/**
* Loads the platform selection from persistent storage.
*/
suspend fun loadPlatformSelection() {
val kvStorage = RevoltApplication.instance.getKVStorage()
val applicationPlatformName = kvStorage.get(UrlsStorageKeys.PLATFORM) ?: ApplicationPlatform.REVOLT.name
selectedApplicationPlatform = try {
ApplicationPlatform.valueOf(applicationPlatformName)
} catch (_: IllegalArgumentException) {
ApplicationPlatform.REVOLT
}
}
// 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 getCurrentJanuaryUrl(): String = getUrlForPlatform(selectedApplicationPlatform) { it.january }
fun getCurrentAppUrl(): String = getUrlForPlatform(selectedApplicationPlatform) { it.app }
fun getCurrentInvitesUrl(): String = getUrlForPlatform(selectedApplicationPlatform) { it.invites }
fun getCurrentWebSocketUrl(): String = getUrlForPlatform(selectedApplicationPlatform) { it.websocket }
fun getCurrentKjBookUrl(): String = getUrlForPlatform(selectedApplicationPlatform) { it.kjbook }
@OptIn(DelicateCoroutinesApi::class, ExperimentalCoroutinesApi::class)
val realtimeContext = newSingleThreadContext("RealtimeContext")
val wsFrameChannel = Channel<Any>(Channel.UNLIMITED)
@ -191,7 +284,7 @@ object RevoltAPI {
}
@OptIn(ExperimentalCoroutinesApi::class)
suspend fun connectWS() {
fun connectWS() {
socketCoroutine = CoroutineScope(Dispatchers.IO).launch {
try {
withContext(realtimeContext) {
@ -220,7 +313,7 @@ object RevoltAPI {
}
}
private suspend fun startSocketOps() {
private fun startSocketOps() {
connectWS()
// Send a ping every roughly 30 seconds else the socket dies
@ -237,6 +330,7 @@ object RevoltAPI {
}
suspend fun initialize() {
loadPlatformSelection()
if (sessionToken != "") {
fetchSelf()
}
@ -281,7 +375,7 @@ object RevoltAPI {
setSessionHeader(token)
fetchSelf()
true
} catch (e: Exception) {
} catch (_: Exception) {
false
}
}
@ -304,7 +398,7 @@ object RevoltAPI {
id = it.id,
channelType = try {
ChannelType.valueOf(it.channelType)
} catch (e: Exception) {
} catch (_: Exception) {
null
},
user = it.userId,

View File

@ -1,13 +1,13 @@
package chat.revolt.api.internals
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.api
import chat.revolt.api.schemas.User
object ResourceLocations {
fun userAvatarUrl(user: User?): String {
if (user?.avatar != null) {
return "$REVOLT_FILES/avatars/${user.avatar.id}"
return "${RevoltAPI.getCurrentFilesUrl()}/avatars/${user.avatar.id}"
}
return "/users/${(user?.id ?: "").ifBlank { "0".repeat(26) }}/default_avatar".api()
}

View File

@ -3,7 +3,6 @@ package chat.revolt.api.realtime
import android.util.Log
import androidx.compose.runtime.mutableStateOf
import chat.revolt.RevoltApplication
import chat.revolt.api.REVOLT_WEBSOCKET
import chat.revolt.api.RevoltAPI
import chat.revolt.api.RevoltHttp
import chat.revolt.api.RevoltJson
@ -88,7 +87,7 @@ object RealtimeSocket {
socket?.close(CloseReason(CloseReason.Codes.NORMAL, "Reconnecting to websocket."))
RevoltHttp.ws(REVOLT_WEBSOCKET) {
RevoltHttp.ws(RevoltAPI.getCurrentWebSocketUrl()) {
socket = this
Log.d("RealtimeSocket", "Connected to websocket.")

View File

@ -1,7 +1,6 @@
package chat.revolt.api.routes.microservices.autumn
import chat.revolt.api.HitRateLimitException
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.RevoltHttp
import chat.revolt.api.RevoltJson
@ -37,7 +36,7 @@ suspend fun uploadToAutumn(
contentType: ContentType,
onProgress: (Long, Long) -> Unit = { _, _ -> }
): String {
val uploadUrl = "$REVOLT_FILES/$tag"
val uploadUrl = "${RevoltAPI.getCurrentFilesUrl()}/$tag"
val response = RevoltHttp.post(uploadUrl) {
setBody(

View File

@ -1,8 +1,8 @@
package chat.revolt.api.routes.microservices.january
import chat.revolt.api.REVOLT_JANUARY
import chat.revolt.api.RevoltAPI
import java.net.URLEncoder
fun asJanuaryProxyUrl(url: String): String {
return "$REVOLT_JANUARY/proxy?url=${URLEncoder.encode(url, "utf-8")}"
return "${RevoltAPI.getCurrentJanuaryUrl()}/proxy?url=${URLEncoder.encode(url, "utf-8")}"
}

View File

@ -2,8 +2,7 @@ package chat.revolt.api.schemas
import android.net.Uri
import androidx.core.net.toUri
import chat.revolt.api.REVOLT_APP
import chat.revolt.api.REVOLT_INVITES
import chat.revolt.api.RevoltAPI
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@ -52,8 +51,8 @@ data class InviteJoined(
fun Uri.isInviteUri(): Boolean {
val firstPathSegmentIsInvite = this.pathSegments.firstOrNull() == "invite"
val isAppRevoltChat = this.host == REVOLT_APP.toUri().host
val matchRvltGG = this.host == REVOLT_INVITES.toUri().host
val isAppRevoltChat = this.host == RevoltAPI.getCurrentAppUrl().toUri().host
val matchRvltGG = this.host == RevoltAPI.getCurrentInvitesUrl().toUri().host
val matchApp = isAppRevoltChat && firstPathSegmentIsInvite

View File

@ -12,7 +12,7 @@ import androidx.core.app.RemoteInput
import androidx.core.graphics.drawable.IconCompat
import chat.revolt.R
import chat.revolt.activities.MainActivity
import chat.revolt.api.REVOLT_BASE
import chat.revolt.api.RevoltAPI
import chat.revolt.api.RevoltJson
import chat.revolt.api.internals.ULID
import chat.revolt.api.routes.push.subscribePush
@ -78,7 +78,7 @@ class HandlerService : FirebaseMessagingService() {
if (authorIcon == null) {
authorIcon =
"$REVOLT_BASE/users/${message.author?.ifBlank { "0".repeat(26) }}/default_avatar"
"${RevoltAPI.getCurrentBaseUrl()}/users/${message.author?.ifBlank { "0".repeat(26) }}/default_avatar"
}
val db = Database(SqlStorage.driver)

View File

@ -8,7 +8,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.text.style.TextOverflow
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.internals.BrushCompat
import chat.revolt.api.internals.Roles
import chat.revolt.api.internals.solidColor
@ -74,7 +74,7 @@ fun MemberListItem(
?: user?.id
?: userId,
avatar = user?.avatar,
rawUrl = member?.avatar?.let { "$REVOLT_FILES/avatars/${it.id}" },
rawUrl = member?.avatar?.let { "${RevoltAPI.getCurrentFilesUrl()}/avatars/${it.id}" },
userId = userId,
presence = presenceFromStatus(
user?.status?.presence,

View File

@ -62,7 +62,6 @@ import androidx.compose.ui.unit.sp
import chat.revolt.R
import chat.revolt.activities.media.ImageViewActivity
import chat.revolt.activities.media.VideoViewActivity
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.internals.BrushCompat
import chat.revolt.api.internals.MessageFlag
@ -142,7 +141,7 @@ fun authorAvatarUrl(message: MessageSchema): String? {
val member = message.author?.let { RevoltAPI.members.getMember(serverId, it) }
?: return null
return member.avatar?.let { "$REVOLT_FILES/avatars/${it.id}" }
return member.avatar?.let { "${RevoltAPI.getCurrentFilesUrl()}/avatars/${it.id}" }
}
fun viewUrlInBrowser(ctx: android.content.Context, url: String) {
@ -153,7 +152,7 @@ fun viewUrlInBrowser(ctx: android.content.Context, url: String) {
}
fun viewAttachmentInBrowser(ctx: android.content.Context, attachment: AutumnResource) {
val url = "$REVOLT_FILES/attachments/${attachment.id}/${attachment.filename}"
val url = "${RevoltAPI.getCurrentFilesUrl()}/attachments/${attachment.id}/${attachment.filename}"
viewUrlInBrowser(ctx, url)
}

View File

@ -33,7 +33,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import chat.revolt.R
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.schemas.AutumnResource
import chat.revolt.composables.generic.RemoteImage
import chat.revolt.composables.media.AudioPlayer
@ -83,7 +83,7 @@ fun FileAttachment(attachment: AutumnResource) {
@SuppressLint("UnusedBoxWithConstraintsScope")
@Composable
fun ImageAttachment(attachment: AutumnResource) {
val url = "$REVOLT_FILES/attachments/${attachment.id}/${attachment.filename}"
val url = "${RevoltAPI.getCurrentFilesUrl()}/attachments/${attachment.id}/${attachment.filename}"
var spoilerShown by remember { mutableStateOf(false) }
val hazeState =
if (attachment.filename?.startsWith("SPOILER_") == true) rememberHazeState() else null
@ -149,7 +149,7 @@ fun VideoPlayButton() {
@SuppressLint("UnusedBoxWithConstraintsScope")
@Composable
fun VideoAttachment(attachment: AutumnResource) {
val url = "$REVOLT_FILES/attachments/${attachment.id}/${attachment.filename}"
val url = "${RevoltAPI.getCurrentFilesUrl()}/attachments/${attachment.id}/${attachment.filename}"
BoxWithConstraints {
Box(
@ -179,7 +179,7 @@ fun VideoAttachment(attachment: AutumnResource) {
@Composable
fun AudioAttachment(attachment: AutumnResource) {
val url = "$REVOLT_FILES/attachments/${attachment.id}/${attachment.filename}"
val url = "${RevoltAPI.getCurrentFilesUrl()}/attachments/${attachment.id}/${attachment.filename}"
AudioPlayer(
url = url,
filename = attachment.filename ?: "Audio",

View File

@ -82,7 +82,7 @@ import androidx.compose.ui.unit.dp
import chat.revolt.R
import chat.revolt.activities.RevoltTweenFloat
import chat.revolt.activities.RevoltTweenInt
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.internals.BrushCompat
import chat.revolt.api.schemas.ChannelType
import chat.revolt.api.schemas.Member
@ -318,7 +318,7 @@ fun MessageField(
userId = item.user.id ?: "",
avatar = item.user.avatar,
rawUrl = item.member?.avatar?.id?.let {
"$REVOLT_FILES/avatars/$it"
"${RevoltAPI.getCurrentFilesUrl()}/avatars/$it"
},
size = SuggestionChipDefaults.IconSize,
)
@ -444,7 +444,7 @@ fun MessageField(
)
} else {
RemoteImage(
url = "$REVOLT_FILES/emojis/${item.custom?.id}",
url = "${RevoltAPI.getCurrentFilesUrl()}/emojis/${item.custom?.id}",
description = null,
contentScale = ContentScale.Fit,
modifier = Modifier

View File

@ -28,7 +28,6 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.internals.isUlid
import chat.revolt.composables.generic.RemoteImage
@ -74,7 +73,7 @@ fun Reaction(
CompositionLocalProvider(LocalContentColor provides foreground) {
if (emoji.isUlid()) {
RemoteImage(
url = "$REVOLT_FILES/emojis/${emoji}",
url = "${RevoltAPI.getCurrentFilesUrl()}/emojis/${emoji}",
description = null,
modifier = Modifier.size(16.dp)
)

View File

@ -62,7 +62,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.revolt.R
import chat.revolt.activities.RevoltTweenFloat
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.callbacks.Action
import chat.revolt.callbacks.ActionChannel
import chat.revolt.composables.generic.IconPlaceholder
@ -401,7 +401,7 @@ fun EmojiPicker(
)
} else {
RemoteImage(
url = "$REVOLT_FILES/icons/${server.icon.id}",
url = "${RevoltAPI.getCurrentFilesUrl()}/icons/${server.icon.id}",
allowAnimation = false,
description = server.name,
modifier = Modifier
@ -619,7 +619,7 @@ fun ColumnScope.PickerItem(
verticalArrangement = Arrangement.Center
) {
RemoteImage(
url = "$REVOLT_FILES/emojis/${item.emote.id}",
url = "${RevoltAPI.getCurrentFilesUrl()}/emojis/${item.emote.id}",
description = item.emote.name,
contentScale = ContentScale.Fit,
modifier = Modifier

View File

@ -1,5 +1,7 @@
package chat.revolt.composables.generic
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.border
@ -23,8 +25,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import chat.revolt.R
import chat.revolt.api.REVOLT_BASE
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.schemas.AutumnResource
import chat.revolt.api.settings.LoadedSettings
@ -102,7 +103,7 @@ fun UserAvatar(
) {
if (avatar != null) {
RemoteImage(
url = rawUrl ?: "$REVOLT_FILES/avatars/${avatar.id}",
url = rawUrl ?: "${RevoltAPI.getCurrentFilesUrl()}/avatars/${avatar.id}",
contentScale = ContentScale.Crop,
description = stringResource(id = R.string.avatar_alt, username),
allowAnimation = allowAnimation,
@ -123,7 +124,7 @@ fun UserAvatar(
)
} else {
RemoteImage(
url = "$REVOLT_BASE/users/${userId.ifBlank { "0".repeat(26) }}/default_avatar",
url = "${RevoltAPI.getCurrentBaseUrl()}/users/${userId.ifBlank { "0".repeat(26) }}/default_avatar",
description = stringResource(id = R.string.avatar_alt, username),
allowAnimation = allowAnimation,
modifier = Modifier
@ -167,7 +168,7 @@ fun GroupIcon(
) {
if (icon?.id != null) {
RemoteImage(
url = rawUrl ?: "$REVOLT_FILES/icons/${icon.id}",
url = rawUrl ?: "${RevoltAPI.getCurrentFilesUrl()}/icons/${icon.id}",
allowAnimation = false,
contentScale = ContentScale.Crop,
description = stringResource(id = R.string.avatar_alt, name),

View File

@ -35,7 +35,6 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.core.net.toUri
import chat.revolt.R
import chat.revolt.activities.InviteActivity
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.routes.custom.fetchEmoji
import chat.revolt.api.schemas.isInviteUri
@ -434,7 +433,7 @@ fun MarkdownText(textNode: AstNode, modifier: Modifier = Modifier) {
} else {
with(LocalDensity.current) {
RemoteImage(
url = "$REVOLT_FILES/emojis/${id}",
url = "${RevoltAPI.getCurrentFilesUrl()}/emojis/${id}",
description = emote.name,
contentScale = ContentScale.Fit,
modifier = Modifier

View File

@ -26,7 +26,7 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.schemas.AutumnResource
import chat.revolt.api.schemas.ChannelType
import chat.revolt.api.schemas.User
@ -66,7 +66,7 @@ fun ChannelSheetHeader(
) {
if (channelIcon != null) {
RemoteImage(
url = "$REVOLT_FILES/icons/${channelIcon.id ?: ""}",
url = "${RevoltAPI.getCurrentFilesUrl()}/icons/${channelIcon.id ?: ""}",
description = null, // decorative
contentScale = ContentScale.Crop,
height = 48,

View File

@ -24,7 +24,6 @@ import androidx.compose.ui.unit.sp
import chat.revolt.R
import chat.revolt.activities.RevoltTweenFloat
import chat.revolt.activities.RevoltTweenInt
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.schemas.User
import chat.revolt.composables.generic.UserAvatar
@ -50,7 +49,7 @@ fun StackedUserAvatars(
userId = userId,
username = user?.let { User.resolveDefaultName(it) }
?: stringResource(id = R.string.unknown),
rawUrl = maybeMember?.avatar?.let { "$REVOLT_FILES/avatars/${it.id}" },
rawUrl = maybeMember?.avatar?.let { "${RevoltAPI.getCurrentFilesUrl()}/avatars/${it.id}" },
size = size,
modifier = Modifier
.offset(

View File

@ -74,7 +74,6 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import chat.revolt.R
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.internals.CategorisedChannelList
import chat.revolt.api.internals.ChannelUtils
@ -357,7 +356,7 @@ fun ChannelSideDrawer(
serverInList.id?.let { srvId -> navigateToServer(srvId) }
}) {
val icon = serverInList.icon?.id?.let { iconId ->
"$REVOLT_FILES/icons/$iconId"
"${RevoltAPI.getCurrentFilesUrl()}/icons/$iconId"
}
if (icon != null) {
RemoteImage(
@ -468,7 +467,7 @@ fun ChannelSideDrawer(
) {
if (server?.banner != null) {
RemoteImage(
url = "$REVOLT_FILES/banners/${server.banner.id}",
url = "${RevoltAPI.getCurrentFilesUrl()}/banners/${server.banner.id}",
description = null,
contentScale = ContentScale.Crop,
modifier = Modifier

View File

@ -23,7 +23,7 @@ import androidx.compose.ui.draw.alpha
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import chat.revolt.activities.InviteActivity
import chat.revolt.api.REVOLT_APP
import chat.revolt.api.RevoltAPI
import chat.revolt.api.RevoltJson
import chat.revolt.api.buildUserAgent
import chat.revolt.api.internals.ThemeCompat
@ -101,7 +101,7 @@ fun ColumnScope.DiscoverView() {
view: WebView?,
request: WebResourceRequest?
): Boolean {
if (request?.url?.host.equals(Uri.parse(REVOLT_APP).host)) {
if (request?.url?.host.equals(Uri.parse(RevoltAPI.getCurrentAppUrl()).host)) {
val intent = Intent(
context,
InviteActivity::class.java

View File

@ -27,7 +27,7 @@ import androidx.compose.ui.res.stringResource
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.schemas.Server
import chat.revolt.api.schemas.ServerFlags
import chat.revolt.api.schemas.has
@ -51,7 +51,7 @@ fun ServerOverview(server: Server) {
)
RemoteImage(
url = "$REVOLT_FILES/banners/${it.id}/${it.filename}",
url = "${RevoltAPI.getCurrentFilesUrl()}/banners/${it.id}/${it.filename}",
description = null,
modifier = Modifier
.height(166.dp)
@ -80,7 +80,7 @@ fun ServerOverview(server: Server) {
) {
server.icon?.let {
RemoteImage(
url = "$REVOLT_FILES/icons/${it.id}",
url = "${RevoltAPI.getCurrentFilesUrl()}/icons/${it.id}",
description = null,
allowAnimation = false,
modifier = Modifier

View File

@ -31,7 +31,6 @@ import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import chat.revolt.R
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.internals.SpecialUsers
import chat.revolt.api.internals.ULID
@ -116,7 +115,7 @@ fun RawUserOverview(
if (background != null) {
RemoteImage(
url = backgroundUrl
?: "$REVOLT_FILES/backgrounds/${if (background is AutumnResource) background.id else null}/${if (background is AutumnResource) background.filename else background}",
?: "${RevoltAPI.getCurrentFilesUrl()}/backgrounds/${if (background is AutumnResource) background.id else null}/${if (background is AutumnResource) background.filename else background}",
description = null,
modifier = Modifier
.height(128.dp)

View File

@ -21,7 +21,7 @@ import androidx.core.content.res.ResourcesCompat
import androidx.webkit.WebViewAssetLoader
import chat.revolt.R
import chat.revolt.activities.InviteActivity
import chat.revolt.api.REVOLT_APP
import chat.revolt.api.RevoltAPI
import chat.revolt.databinding.SheetChangelogBinding
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.color.MaterialColors
@ -62,7 +62,7 @@ class ChangelogBottomSheetFragment(
binding.wvChangelog.apply {
val assetLoader = WebViewAssetLoader.Builder()
.setDomain(Uri.parse(REVOLT_APP).host!!)
.setDomain(Uri.parse(RevoltAPI.getCurrentAppUrl()).host!!)
.addPathHandler(
"/_android_assets/",
WebViewAssetLoader.AssetsPathHandler(context)
@ -127,7 +127,7 @@ class ChangelogBottomSheetFragment(
}
loadUrl(
"$REVOLT_APP/_android_assets/changelogs/renderer.html"
"${RevoltAPI.getCurrentAppUrl()}/_android_assets/changelogs/renderer.html"
)
settings.apply {

View File

@ -1,7 +1,7 @@
package chat.revolt.internals
import android.content.Context
import chat.revolt.api.REVOLT_KJBOOK
import chat.revolt.api.RevoltAPI
import chat.revolt.api.RevoltHttp
import chat.revolt.api.RevoltJson
import chat.revolt.internals.IndexHolder.cachedIndex
@ -55,7 +55,7 @@ class Changelogs(val context: Context, val kvStorage: KVStorage? = null) {
}
try {
val response = RevoltHttp.get("$REVOLT_KJBOOK/changelogs.json")
val response = RevoltHttp.get("${RevoltAPI.getCurrentKjBookUrl()}/changelogs.json")
cachedIndex =
RevoltJson.decodeFromString(ChangelogIndex.serializer(), response.bodyAsText())
return cachedIndex as ChangelogIndex
@ -66,7 +66,7 @@ class Changelogs(val context: Context, val kvStorage: KVStorage? = null) {
suspend fun fetchChangelogByVersionCode(versionCode: Long): Changelog {
try {
val response = RevoltHttp.get("$REVOLT_KJBOOK/changelogs/$versionCode.json")
val response = RevoltHttp.get("${RevoltAPI.getCurrentKjBookUrl()}/changelogs/$versionCode.json")
return RevoltJson.decodeFromString(Changelog.serializer(), response.bodyAsText())
} catch (e: Error) {
return Changelog(

View File

@ -17,8 +17,6 @@ import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.viewinterop.AndroidView
import androidx.webkit.WebViewAssetLoader
import chat.revolt.activities.InviteActivity
import chat.revolt.api.REVOLT_APP
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.internals.ResourceLocations
import chat.revolt.markdown.jbm.LocalJBMarkdownTreeState
@ -36,7 +34,7 @@ fun FallbackRenderer(content: String, modifier: Modifier = Modifier) {
factory = { context ->
WebView(context).apply {
val assetLoader = WebViewAssetLoader.Builder()
.setDomain(Uri.parse(REVOLT_APP).host!!)
.setDomain(Uri.parse(RevoltAPI.getCurrentAppUrl()).host!!)
.addPathHandler(
"/_android_assets/",
WebViewAssetLoader.AssetsPathHandler(context)
@ -128,7 +126,7 @@ fun FallbackRenderer(content: String, modifier: Modifier = Modifier) {
@JavascriptInterface
fun getCustomEmoteUrl(emoteId: String): String {
return "$REVOLT_FILES/emojis/$emoteId/original"
return "${RevoltAPI.getCurrentFilesUrl()}/emojis/$emoteId/original"
}
@JavascriptInterface
@ -151,7 +149,7 @@ fun FallbackRenderer(content: String, modifier: Modifier = Modifier) {
setBackgroundColor(android.graphics.Color.TRANSPARENT)
loadUrl(
"$REVOLT_APP/_android_assets/markdown/markdown.html"
"${RevoltAPI.getCurrentAppUrl()}/_android_assets/markdown/markdown.html"
)
}
}

View File

@ -73,7 +73,6 @@ import androidx.compose.ui.unit.sp
import androidx.core.net.toUri
import chat.revolt.R
import chat.revolt.activities.InviteActivity
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.internals.BrushCompat
import chat.revolt.api.internals.InstancedBrushCompat
@ -762,7 +761,7 @@ private fun JBMText(node: ASTNode, modifier: Modifier) {
} else {
with(LocalDensity.current) {
RemoteImage(
url = "$REVOLT_FILES/emojis/${id}",
url = "${RevoltAPI.getCurrentFilesUrl()}/emojis/${id}",
description = emote.name,
contentScale = ContentScale.Fit,
modifier = Modifier

View File

@ -20,7 +20,7 @@ import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.viewinterop.AndroidView
import androidx.webkit.WebViewAssetLoader
import chat.revolt.activities.InviteActivity
import chat.revolt.api.REVOLT_APP
import chat.revolt.api.RevoltAPI
internal fun Color.asHexString(includeAlphaComponent: Boolean = true): String {
val argb = toArgb()
@ -46,7 +46,7 @@ fun KatexRenderer(content: String, modifier: Modifier = Modifier) {
factory = { context ->
WebView(context).apply {
val assetLoader = WebViewAssetLoader.Builder()
.setDomain(Uri.parse(REVOLT_APP).host!!)
.setDomain(Uri.parse(RevoltAPI.getCurrentAppUrl()).host!!)
.addPathHandler(
"/_android_assets/",
WebViewAssetLoader.AssetsPathHandler(context)
@ -131,7 +131,7 @@ fun KatexRenderer(content: String, modifier: Modifier = Modifier) {
setBackgroundColor(android.graphics.Color.TRANSPARENT)
loadUrl(
"$REVOLT_APP/_android_assets/katex/katex.html"
"${RevoltAPI.getCurrentAppUrl()}/_android_assets/katex/katex.html"
)
}
}

View File

@ -53,7 +53,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import chat.revolt.BuildConfig
import chat.revolt.R
import chat.revolt.api.REVOLT_BASE
import chat.revolt.api.RevoltAPI
import chat.revolt.api.RevoltJson
import chat.revolt.api.routes.misc.Root
import chat.revolt.api.routes.misc.getRootRoute
@ -72,7 +72,7 @@ class AboutViewModel : ViewModel() {
"App ID" to BuildConfig.APPLICATION_ID,
"App Version" to BuildConfig.VERSION_NAME,
"App Type" to BuildConfig.FLAVOUR_ID,
"API Host" to URI(REVOLT_BASE).host,
"API Host" to URI(RevoltAPI.getCurrentBaseUrl()).host,
"API Version" to (root?.revolt ?: "Unknown"),
"Runtime SDK" to Build.VERSION.SDK_INT.toString(),
"Model" to "${Build.MANUFACTURER} ${

View File

@ -42,7 +42,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.revolt.R
import chat.revolt.api.REVOLT_INVITES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.routes.channel.createInvite
import chat.revolt.internals.Platform
@ -120,6 +119,9 @@ fun InviteDialog(channelId: String, onDismissRequest: () -> Unit) {
}
BoxWithConstraints {
val maxWidth = this.maxWidth
val maxHeight = this.maxHeight
Column(
modifier = Modifier
.clip(MaterialTheme.shapes.large)
@ -139,7 +141,7 @@ fun InviteDialog(channelId: String, onDismissRequest: () -> Unit) {
Spacer(Modifier.height(16.dp))
Text(
(Uri.parse(REVOLT_INVITES).host ?: "rvlt.gg") + "/",
(Uri.parse(RevoltAPI.getCurrentInvitesUrl()).host ?: "rvlt.gg") + "/",
style = MaterialTheme.typography.bodySmall,
textAlign = TextAlign.Center,
modifier = Modifier
@ -202,7 +204,7 @@ fun InviteDialog(channelId: String, onDismissRequest: () -> Unit) {
Spacer(Modifier.width(8.dp))
Button(onClick = {
clipboardManager.setText(AnnotatedString.Builder().apply {
append(REVOLT_INVITES)
append(RevoltAPI.getCurrentInvitesUrl())
append("/")
append(inviteCode)
}.toAnnotatedString())

View File

@ -34,6 +34,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import chat.revolt.R
import chat.revolt.api.ApplicationPlatform
import chat.revolt.api.RevoltAPI
@Composable
fun ChoosePlatformScreen(navController: NavController) {
@ -107,7 +109,7 @@ fun ChoosePlatformScreen(navController: NavController) {
.padding(bottom = 8.dp)
.size(72.dp)
.clickable {
apiUrlValue.value = "https://api.revolt.chat"
apiUrlValue.value = "https://peptide.chat/api"
},
) {
Box(
@ -116,7 +118,7 @@ fun ChoosePlatformScreen(navController: NavController) {
) {
Image(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
contentDescription = "Discord Logo"
contentDescription = "PEP Logo"
)
}
}
@ -150,7 +152,7 @@ fun ChoosePlatformScreen(navController: NavController) {
) {
Image(
painter = painterResource(id = R.drawable.ic_revolt_r),
contentDescription = "Discord Logo"
contentDescription = "Revolt Logo"
)
}
}
@ -189,7 +191,20 @@ fun ChoosePlatformScreen(navController: NavController) {
.padding(vertical = 8.dp)
)
Button(
onClick = { navController.navigate("login/greeting") },
onClick = {
if(apiUrlValue.value.isNotEmpty()){
when(apiUrlValue.value){
ApplicationPlatform.PEP.baseUrl -> RevoltAPI.setPlatform(
ApplicationPlatform.PEP
)
ApplicationPlatform.REVOLT.baseUrl -> RevoltAPI.setPlatform(
ApplicationPlatform.REVOLT
)
else -> return@Button
}
}
navController.navigate("login/greeting")
},
modifier = Modifier
.padding(top = 32.dp, bottom = 16.dp)
.fillMaxWidth()

View File

@ -51,7 +51,6 @@ import androidx.lifecycle.viewModelScope
import androidx.navigation.NavController
import chat.revolt.R
import chat.revolt.RevoltApplication
import chat.revolt.api.REVOLT_APP
import chat.revolt.api.RevoltAPI
import chat.revolt.api.routes.account.EmailPasswordAssessment
import chat.revolt.api.routes.account.negotiateAuthentication
@ -325,7 +324,7 @@ fun LoginScreen(navController: NavController, viewModel: LoginViewModel = hiltVi
)
Weblink(
text = stringResource(R.string.password_forgot),
url = "$REVOLT_APP/login/reset",
url = "${RevoltAPI.getCurrentAppUrl()}/login/reset",
modifier = Modifier.padding(vertical = 12.dp)
)
Spacer(modifier = Modifier.height(32.dp))

View File

@ -1,5 +1,7 @@
package chat.revolt.screens.login2
import android.content.Intent
import android.net.Uri
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@ -33,7 +35,7 @@ import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import chat.revolt.BuildConfig
import chat.revolt.R
import chat.revolt.api.REVOLT_MARKETING
import chat.revolt.api.RevoltAPI
import chat.revolt.api.settings.LoadedSettings
import chat.revolt.composables.generic.AnyLink
import chat.revolt.composables.generic.Weblink
@ -156,15 +158,15 @@ private fun LinkPart(windowSizeClass: WindowSizeClass) {
Weblink(
text = stringResource(R.string.terms_of_service),
url = "$REVOLT_MARKETING/terms"
url = "${RevoltAPI.getCurrentMarketingUrl()}/terms"
)
Weblink(
text = stringResource(R.string.privacy_policy),
url = "$REVOLT_MARKETING/privacy"
url = "${RevoltAPI.getCurrentMarketingUrl()}/privacy"
)
Weblink(
text = stringResource(R.string.community_guidelines),
url = "$REVOLT_MARKETING/aup"
url = "${RevoltAPI.getCurrentMarketingUrl()}/aup"
)
if (BuildConfig.DEBUG) {

View File

@ -2,6 +2,7 @@ package chat.revolt.screens.settings.channel
import android.content.Context
import android.net.Uri
import android.util.Log
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.scaleIn
@ -44,6 +45,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
@ -56,7 +58,6 @@ import androidx.lifecycle.viewModelScope
import androidx.navigation.NavController
import chat.revolt.R
import chat.revolt.activities.RevoltTweenFloat
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.routes.channel.patchChannel
import chat.revolt.api.routes.microservices.autumn.uploadToAutumn
@ -93,7 +94,7 @@ class ChannelSettingsOverviewViewModel @Inject constructor(@ApplicationContext v
channel?.let {
channelName = it.name ?: ""
channelDescription = it.description ?: ""
iconModel = it.icon?.let { icon -> "$REVOLT_FILES/icons/${icon.id}" }
iconModel = it.icon?.let { icon -> "${RevoltAPI.getCurrentFilesUrl()}/icons/${icon.id}" }
}
}

View File

@ -54,7 +54,7 @@ import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import chat.revolt.R
import chat.revolt.activities.InviteActivity
import chat.revolt.api.REVOLT_APP
import chat.revolt.api.RevoltAPI
import chat.revolt.api.routes.server.createServer
import chat.revolt.callbacks.Action
import chat.revolt.callbacks.ActionChannel
@ -122,368 +122,368 @@ fun AddServerSheet(onDismiss: () -> Unit) {
Box(
modifier = Modifier.padding(16.dp)
) {
if (step == AddServerSheetStep.Initial) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Image(
imageVector = NewServer,
contentDescription = null,
modifier = Modifier
.fillMaxWidth(0.5f)
)
Text(
text = stringResource(id = R.string.add_server_sheet_step_0_title),
style = MaterialTheme.typography.titleLarge,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Text(
text = stringResource(id = R.string.add_server_sheet_step_0_description),
style = MaterialTheme.typography.bodyMedium,
color = LocalContentColor.current.copy(alpha = 0.7f),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
SheetSelection(
icon = {
Image(
imageVector = JoinServer,
contentDescription = null,
modifier = Modifier
.size(48.dp)
)
},
title = {
Text(
text = stringResource(id = R.string.add_server_sheet_step_0_join)
)
},
description = {
Text(
text = stringResource(id = R.string.add_server_sheet_step_0_join_description)
)
},
) {
currentStep = AddServerSheetStep.JoinFromInvite
}
SheetSelection(
icon = {
Image(
imageVector = CreateServer,
contentDescription = null,
modifier = Modifier
.size(48.dp)
)
},
title = {
Text(
text = stringResource(id = R.string.add_server_sheet_step_0_create)
)
},
description = {
Text(
text = stringResource(id = R.string.add_server_sheet_step_0_create_description)
)
},
) {
currentStep = AddServerSheetStep.CreateServer
}
}
} else if (step == AddServerSheetStep.JoinFromInvite) {
val inviteState = rememberTextFieldState()
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
contentAlignment = Alignment.CenterStart,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.add_server_sheet_step_1j_title),
style = MaterialTheme.typography.titleMedium,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
IconButton(
onClick = {
currentStep = AddServerSheetStep.Initial
}
) {
Icon(
painter = painterResource(R.drawable.icn_arrow_back_24dp),
contentDescription = stringResource(id = R.string.back),
)
}
}
Text(
text = stringResource(id = R.string.add_server_sheet_step_1j_description),
style = MaterialTheme.typography.bodyMedium,
color = LocalContentColor.current.copy(alpha = 0.7f),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Text(
text = stringResource(id = R.string.add_server_sheet_step_1j_examples_heading),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.outline,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Column(
verticalArrangement = Arrangement.spacedBy(4.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = stringResource(id = R.string.add_server_sheet_step_1j_example_1),
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center,
fontFamily = FragmentMono,
modifier = Modifier
.clip(
MaterialTheme.shapes.small.copy(
topStart = MaterialTheme.shapes.large.topStart,
topEnd = MaterialTheme.shapes.large.topEnd,
)
)
.background(MaterialTheme.colorScheme.surfaceContainerHighest)
.padding(16.dp)
.fillMaxWidth()
)
Text(
text = stringResource(id = R.string.add_server_sheet_step_1j_example_2),
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center,
fontFamily = FragmentMono,
modifier = Modifier
.clip(
MaterialTheme.shapes.small
)
.background(MaterialTheme.colorScheme.surfaceContainerHighest)
.padding(16.dp)
.fillMaxWidth()
)
Text(
text = stringResource(id = R.string.add_server_sheet_step_1j_example_3),
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center,
fontFamily = FragmentMono,
modifier = Modifier
.clip(
MaterialTheme.shapes.small.copy(
bottomStart = MaterialTheme.shapes.large.bottomStart,
bottomEnd = MaterialTheme.shapes.large.bottomEnd,
)
)
.background(MaterialTheme.colorScheme.surfaceContainerHighest)
.padding(16.dp)
.fillMaxWidth()
)
}
Spacer(modifier = Modifier.height(8.dp))
TextField(
state = inviteState,
label = {
Text(stringResource(R.string.add_server_sheet_step_1j_label))
},
lineLimits = TextFieldLineLimits.SingleLine,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp, horizontal = 8.dp)
)
Button(
onClick = {
val intent = Intent(context, InviteActivity::class.java)
intent.data = if (inviteState.text.startsWith("https://")) {
try {
inviteState.text.toString().toUri()
} catch (e: Exception) {
Log.e(
"AddServerSheet",
"Invalid URL: ${inviteState.text}",
e
)
return@Button
}
} else {
"https://$REVOLT_APP/invite/${inviteState.text}".toUri()
}
context.startActivity(intent)
onDismiss()
},
modifier = Modifier
.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.add_server_sheet_step_1j_join)
)
}
}
} else if (step == AddServerSheetStep.CreateServer) {
val serverNameState = rememberTextFieldState()
val serverNameIsBlank = remember(serverNameState.text) {
serverNameState.text.isBlank()
}
var serverNameRangeError by remember { mutableStateOf(false) }
var serverCreationError by remember { mutableStateOf(false) }
LaunchedEffect(serverNameState.text) {
if (serverNameState.text.length > 32) {
serverNameRangeError = true
} else {
serverNameRangeError = false
}
}
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
contentAlignment = Alignment.CenterStart,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.add_server_sheet_step_1c_title),
style = MaterialTheme.typography.titleMedium,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
IconButton(
onClick = {
currentStep = AddServerSheetStep.Initial
}
) {
Icon(
painter = painterResource(R.drawable.icn_arrow_back_24dp),
contentDescription = stringResource(id = R.string.back),
)
}
}
Text(
text = stringResource(id = R.string.add_server_sheet_step_1c_description),
style = MaterialTheme.typography.bodyMedium,
color = LocalContentColor.current.copy(alpha = 0.7f),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
val outline = MaterialTheme.colorScheme.outline
when (step) {
AddServerSheetStep.Initial -> {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
horizontalAlignment = Alignment.CenterHorizontally,
) {
Canvas(Modifier.size(80.dp)) {
val stroke = Stroke(
width = 4.dp.toPx(),
pathEffect = PathEffect.dashPathEffect(
floatArrayOf(30f, 40f),
0f
)
)
Image(
imageVector = NewServer,
contentDescription = null,
modifier = Modifier
.fillMaxWidth(0.5f)
)
drawCircle(
color = outline,
style = stroke,
radius = size.minDimension / 2 - stroke.width / 2
)
}
Text(
text = when {
serverNameIsBlank -> stringResource(R.string.add_server_sheet_step_1c_name_placeholder)
else -> serverNameState.text.toString()
},
style = MaterialTheme.typography.bodyLarge,
color = LocalContentColor.current.copy(
alpha = when {
serverNameIsBlank -> 0.5f
else -> 1f
}
),
fontWeight = when {
serverNameIsBlank -> FontWeight.Medium
else -> FontWeight.Bold
},
text = stringResource(id = R.string.add_server_sheet_step_0_title),
style = MaterialTheme.typography.titleLarge,
textAlign = TextAlign.Center,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.fillMaxWidth()
)
Text(
text = stringResource(id = R.string.add_server_sheet_step_0_description),
style = MaterialTheme.typography.bodyMedium,
color = LocalContentColor.current.copy(alpha = 0.7f),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
SheetSelection(
icon = {
Image(
imageVector = JoinServer,
contentDescription = null,
modifier = Modifier
.size(48.dp)
)
},
title = {
Text(
text = stringResource(id = R.string.add_server_sheet_step_0_join)
)
},
description = {
Text(
text = stringResource(id = R.string.add_server_sheet_step_0_join_description)
)
},
) {
currentStep = AddServerSheetStep.JoinFromInvite
}
SheetSelection(
icon = {
Image(
imageVector = CreateServer,
contentDescription = null,
modifier = Modifier
.size(48.dp)
)
},
title = {
Text(
text = stringResource(id = R.string.add_server_sheet_step_0_create)
)
},
description = {
Text(
text = stringResource(id = R.string.add_server_sheet_step_0_create_description)
)
},
) {
currentStep = AddServerSheetStep.CreateServer
}
}
}
AddServerSheetStep.JoinFromInvite -> {
val inviteState = rememberTextFieldState()
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
contentAlignment = Alignment.CenterStart,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.add_server_sheet_step_1j_title),
style = MaterialTheme.typography.titleMedium,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
IconButton(
onClick = {
currentStep = AddServerSheetStep.Initial
}
) {
Icon(
painter = painterResource(R.drawable.icn_arrow_back_24dp),
contentDescription = stringResource(id = R.string.back),
)
}
}
Text(
text = stringResource(id = R.string.add_server_sheet_step_1j_description),
style = MaterialTheme.typography.bodyMedium,
color = LocalContentColor.current.copy(alpha = 0.7f),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Text(
text = stringResource(id = R.string.add_server_sheet_step_1j_examples_heading),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.outline,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Column(
verticalArrangement = Arrangement.spacedBy(4.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = stringResource(id = R.string.add_server_sheet_step_1j_example_1),
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center,
fontFamily = FragmentMono,
modifier = Modifier
.clip(
MaterialTheme.shapes.small.copy(
topStart = MaterialTheme.shapes.large.topStart,
topEnd = MaterialTheme.shapes.large.topEnd,
)
)
.background(MaterialTheme.colorScheme.surfaceContainerHighest)
.padding(16.dp)
.fillMaxWidth()
)
Text(
text = stringResource(id = R.string.add_server_sheet_step_1j_example_2),
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center,
fontFamily = FragmentMono,
modifier = Modifier
.clip(
MaterialTheme.shapes.small
)
.background(MaterialTheme.colorScheme.surfaceContainerHighest)
.padding(16.dp)
.fillMaxWidth()
)
Text(
text = stringResource(id = R.string.add_server_sheet_step_1j_example_3),
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center,
fontFamily = FragmentMono,
modifier = Modifier
.clip(
MaterialTheme.shapes.small.copy(
bottomStart = MaterialTheme.shapes.large.bottomStart,
bottomEnd = MaterialTheme.shapes.large.bottomEnd,
)
)
.background(MaterialTheme.colorScheme.surfaceContainerHighest)
.padding(16.dp)
.fillMaxWidth()
)
}
Spacer(modifier = Modifier.height(8.dp))
TextField(
state = inviteState,
label = {
Text(stringResource(R.string.add_server_sheet_step_1j_label))
},
lineLimits = TextFieldLineLimits.SingleLine,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp, horizontal = 8.dp)
)
Button(
onClick = {
val intent = Intent(context, InviteActivity::class.java)
intent.data = if (inviteState.text.startsWith("https://")) {
try {
inviteState.text.toString().toUri()
} catch (e: Exception) {
Log.e(
"AddServerSheet",
"Invalid URL: ${inviteState.text}",
e
)
return@Button
}
} else {
"https://${RevoltAPI.getCurrentAppUrl()}/invite/${inviteState.text}".toUri()
}
context.startActivity(intent)
onDismiss()
},
modifier = Modifier
.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.add_server_sheet_step_1j_join)
)
}
}
}
AddServerSheetStep.CreateServer -> {
val serverNameState = rememberTextFieldState()
val serverNameIsBlank = remember(serverNameState.text) {
serverNameState.text.isBlank()
}
TextField(
state = serverNameState,
label = {
Text(stringResource(R.string.add_server_sheet_step_1c_name))
},
lineLimits = TextFieldLineLimits.SingleLine,
supportingText = {
Text(
when {
serverCreationError -> stringResource(R.string.add_server_sheet_step_1c_error)
serverNameRangeError -> stringResource(
R.string.add_server_sheet_step_1c_name_error_range,
32
)
var serverNameRangeError by remember { mutableStateOf(false) }
var serverCreationError by remember { mutableStateOf(false) }
else -> ""
}
)
},
isError = serverNameRangeError || serverCreationError,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp, horizontal = 8.dp)
)
LaunchedEffect(serverNameState.text) {
serverNameRangeError = serverNameState.text.length > 32
}
Button(
onClick = {
serverCreationError = false
scope.launch {
try {
val server = createServer(serverNameState.text.toString())
// Backend should've already created a channel for us to go to
server.channels?.first()?.id?.let {
ActionChannel.send(
Action.ChatNavigate(
ChatRouterDestination.Channel(it)
)
)
}
onDismiss()
} catch (e: Exception) {
serverCreationError = true
logcat { "Error creating server: ${e.asLog()}" }
}
}
},
enabled = !serverNameIsBlank && !serverNameRangeError,
modifier = Modifier
.fillMaxWidth()
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
contentAlignment = Alignment.CenterStart,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.add_server_sheet_step_1c_title),
style = MaterialTheme.typography.titleMedium,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
IconButton(
onClick = {
currentStep = AddServerSheetStep.Initial
}
) {
Icon(
painter = painterResource(R.drawable.icn_arrow_back_24dp),
contentDescription = stringResource(id = R.string.back),
)
}
}
Text(
text = stringResource(id = R.string.add_server_sheet_step_1c_create)
text = stringResource(id = R.string.add_server_sheet_step_1c_description),
style = MaterialTheme.typography.bodyMedium,
color = LocalContentColor.current.copy(alpha = 0.7f),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
val outline = MaterialTheme.colorScheme.outline
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Canvas(Modifier.size(80.dp)) {
val stroke = Stroke(
width = 4.dp.toPx(),
pathEffect = PathEffect.dashPathEffect(
floatArrayOf(30f, 40f),
0f
)
)
drawCircle(
color = outline,
style = stroke,
radius = size.minDimension / 2 - stroke.width / 2
)
}
Text(
text = when {
serverNameIsBlank -> stringResource(R.string.add_server_sheet_step_1c_name_placeholder)
else -> serverNameState.text.toString()
},
style = MaterialTheme.typography.bodyLarge,
color = LocalContentColor.current.copy(
alpha = when {
serverNameIsBlank -> 0.5f
else -> 1f
}
),
fontWeight = when {
serverNameIsBlank -> FontWeight.Medium
else -> FontWeight.Bold
},
textAlign = TextAlign.Center,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.fillMaxWidth()
)
}
TextField(
state = serverNameState,
label = {
Text(stringResource(R.string.add_server_sheet_step_1c_name))
},
lineLimits = TextFieldLineLimits.SingleLine,
supportingText = {
Text(
when {
serverCreationError -> stringResource(R.string.add_server_sheet_step_1c_error)
serverNameRangeError -> stringResource(
R.string.add_server_sheet_step_1c_name_error_range,
32
)
else -> ""
}
)
},
isError = serverNameRangeError || serverCreationError,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp, horizontal = 8.dp)
)
Button(
onClick = {
serverCreationError = false
scope.launch {
try {
val server = createServer(serverNameState.text.toString())
// Backend should've already created a channel for us to go to
server.channels?.first()?.id?.let {
ActionChannel.send(
Action.ChatNavigate(
ChatRouterDestination.Channel(it)
)
)
}
onDismiss()
} catch (e: Exception) {
serverCreationError = true
logcat { "Error creating server: ${e.asLog()}" }
}
}
},
enabled = !serverNameIsBlank && !serverNameRangeError,
modifier = Modifier
.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.add_server_sheet_step_1c_create)
)
}
}
}
}

View File

@ -31,7 +31,6 @@ import androidx.compose.ui.text.font.FontWeight
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.routes.custom.fetchEmoji
import chat.revolt.api.schemas.Emoji
@ -65,7 +64,7 @@ fun EmoteInfoSheet(id: String, onDismiss: () -> Unit) {
verticalAlignment = Alignment.CenterVertically
) {
RemoteImage(
url = "$REVOLT_FILES/emojis/$id",
url = "${RevoltAPI.getCurrentFilesUrl()}/emojis/$id",
description = emoteInfo?.name,
contentScale = ContentScale.Fit,
modifier = Modifier

View File

@ -35,7 +35,6 @@ import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.unit.dp
import chat.revolt.BuildConfig
import chat.revolt.R
import chat.revolt.api.REVOLT_APP
import chat.revolt.api.RevoltAPI
import chat.revolt.api.internals.PermissionBit
import chat.revolt.api.internals.Roles
@ -176,7 +175,7 @@ fun MessageContextSheet(
server.channels?.contains(message.channel) ?: false
}
val messageLink =
"$REVOLT_APP/server/${server?.id}/channel/${message.channel}/${message.id}"
"${RevoltAPI.getCurrentAppUrl()}/server/${server?.id}/channel/${message.channel}/${message.id}"
clipboardManager.setText(AnnotatedString(messageLink))
if (Platform.needsShowClipboardNotification()) {

View File

@ -44,7 +44,6 @@ import androidx.compose.ui.text.style.TextAlign
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.internals.isUlid
import chat.revolt.api.routes.custom.fetchEmoji
@ -119,7 +118,7 @@ fun ReactionInfoSheet(messageId: String, emoji: String, onDismiss: () -> Unit) {
if (emoji.isUlid()) {
Row(verticalAlignment = Alignment.CenterVertically) {
RemoteImage(
url = "$REVOLT_FILES/emojis/${emoji}",
url = "${RevoltAPI.getCurrentFilesUrl()}/emojis/${emoji}",
description = null,
modifier = Modifier.size(16.dp)
)
@ -229,7 +228,7 @@ fun ReactionInfoSheet(messageId: String, emoji: String, onDismiss: () -> Unit) {
if (current.isUlid()) {
val cached = extendedEmojiInfo.find { it.id == current }
RemoteImage(
url = "$REVOLT_FILES/emojis/$current",
url = "${RevoltAPI.getCurrentFilesUrl()}/emojis/$current",
description = cached?.name,
contentScale = ContentScale.Fit,
modifier = Modifier

View File

@ -41,7 +41,6 @@ import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import chat.revolt.R
import chat.revolt.api.REVOLT_APP
import chat.revolt.api.RevoltAPI
import chat.revolt.api.routes.server.leaveOrDeleteServer
import chat.revolt.composables.generic.SheetButton
@ -194,7 +193,7 @@ fun ServerContextSheet(
context.startActivity(
Intent(
Intent.ACTION_VIEW,
"$REVOLT_APP/server/${server.id}/settings".toUri()
"${RevoltAPI.getCurrentAppUrl()}/server/${server.id}/settings".toUri()
)
)
}