feat: remove old changelogs

This commit is contained in:
infi 2026-05-10 20:10:46 +02:00
parent 779275ce62
commit 7b763d0e9c
11 changed files with 13 additions and 647 deletions

View File

@ -111,7 +111,6 @@ import chat.stoat.screens.register.RegisterGreetingScreen
import chat.stoat.screens.register.RegisterVerifyScreen
import chat.stoat.screens.services.DiscoverScreen
import chat.stoat.screens.settings.AppearanceSettingsScreen
import chat.stoat.screens.settings.ChangelogsSettingsScreen
import chat.stoat.screens.settings.ChatSettingsScreen
import chat.stoat.screens.settings.DebugSettingsScreen
import chat.stoat.screens.settings.ExperimentsSettingsScreen
@ -711,7 +710,6 @@ fun AppEntrypoint(
composable("settings/chat") { ChatSettingsScreen(navController) }
composable("settings/debug") { DebugSettingsScreen(navController) }
composable("settings/experiments") { ExperimentsSettingsScreen(navController) }
composable("settings/changelogs") { ChangelogsSettingsScreen(navController) }
composable("settings/language") { LanguagePickerSettingsScreen(navController) }
composable("settings/channel/{channelId}") { backStackEntry ->

View File

@ -11,14 +11,14 @@ import chat.stoat.api.internals.Members
import chat.stoat.api.realtime.DisconnectionState
import chat.stoat.api.realtime.RealtimeSocket
import chat.stoat.api.routes.user.fetchSelf
import chat.stoat.core.model.util.ChannelVoiceState
import chat.stoat.core.model.schemas.Emoji
import chat.stoat.core.model.schemas.Message
import chat.stoat.core.model.schemas.Server
import chat.stoat.api.unreads.Unreads
import chat.stoat.core.model.schemas.AutumnResource
import chat.stoat.core.model.schemas.ChannelType
import chat.stoat.core.model.schemas.Emoji
import chat.stoat.core.model.schemas.Message
import chat.stoat.core.model.schemas.Server
import chat.stoat.core.model.schemas.User
import chat.stoat.core.model.util.ChannelVoiceState
import chat.stoat.persistence.Database
import chat.stoat.persistence.SqlStorage
import com.chuckerteam.chucker.api.ChuckerCollector
@ -68,7 +68,6 @@ const val STOAT_WEB_APP = "https://stoat.chat"
const val STOAT_INVITES = "https://stt.gg"
val STOAT_WEBSOCKET =
if (USE_ALPHA_API) "wss://alpha.revolt.chat/ws" else "wss://events.stoat.chat"
const val STOAT_KJBOOK = "https://stoatchat.github.io/for-android"
fun String.api(): String {
return "$STOAT_BASE$this"

View File

@ -7,7 +7,6 @@ import chat.stoat.screens.chat.views.channel.ChannelScreenViewModel
import chat.stoat.screens.login.LoginViewModel
import chat.stoat.screens.login.MfaScreenViewModel
import chat.stoat.screens.settings.AppearanceSettingsScreenViewModel
import chat.stoat.screens.settings.ChangelogsSettingsScreenViewModel
import chat.stoat.screens.settings.DebugSettingsScreenViewModel
import chat.stoat.screens.settings.ProfileSettingsScreenViewModel
import chat.stoat.screens.settings.SettingsScreenViewModel
@ -29,7 +28,6 @@ val viewModelModule = module {
viewModel { DebugSettingsScreenViewModel(get()) }
viewModel { LoginViewModel(get()) }
viewModel { ProfileSettingsScreenViewModel(androidApplication()) }
viewModel { ChangelogsSettingsScreenViewModel(get(), androidApplication()) }
viewModel { AppearanceSettingsScreenViewModel(androidApplication()) }
viewModel { ChannelSettingsOverviewViewModel(androidApplication()) }
}

View File

@ -1,197 +0,0 @@
package chat.stoat.fragments
import android.annotation.SuppressLint
import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.JavascriptInterface
import android.webkit.WebChromeClient
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.browser.customtabs.CustomTabColorSchemeParams
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.res.ResourcesCompat
import androidx.webkit.WebViewAssetLoader
import chat.stoat.R
import chat.stoat.activities.InviteActivity
import chat.stoat.api.STOAT_WEB_APP
import chat.stoat.core.model.schemas.isInviteUri
import chat.stoat.databinding.SheetChangelogBinding
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.color.MaterialColors
class ChangelogBottomSheetFragment(
val onDismiss: () -> Unit
) : BottomSheetDialogFragment() {
private lateinit var binding: SheetChangelogBinding
private fun argbAsCssColour(argb: Int): String {
val alpha = (argb shr 24 and 0xff) / 255.0f
val red = argb shr 16 and 0xff
val green = argb shr 8 and 0xff
val blue = argb and 0xff
return String.format("#%02x%02x%02x%02x", red, green, blue, (alpha * 255).toInt())
}
@SuppressLint("SetJavaScriptEnabled")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = SheetChangelogBinding.inflate(inflater, container, false)
requireArguments().run {
binding.tvTitle.apply {
text = when {
getBoolean(ARG_HISTORICAL) -> requireContext().getString(
R.string.settings_changelogs_historical_version_header,
getString(ARG_VERSION_NAME)
)
else -> requireContext().getString(R.string.settings_changelogs_new_header)
}
typeface = ResourcesCompat.getFont(requireContext(), R.font.inter_display_semibold)
}
binding.wvChangelog.apply {
val assetLoader = WebViewAssetLoader.Builder()
.setDomain(Uri.parse(STOAT_WEB_APP).host!!)
.addPathHandler(
"/_android_assets/",
WebViewAssetLoader.AssetsPathHandler(context)
)
.addPathHandler(
"/_android_res/",
WebViewAssetLoader.ResourcesPathHandler(context)
)
.build()
webChromeClient = object : WebChromeClient() {}
webViewClient = object : WebViewClient() {
override fun shouldInterceptRequest(
view: WebView?,
request: WebResourceRequest?
): WebResourceResponse? {
return request?.let { assetLoader.shouldInterceptRequest(it.url) }
}
override fun shouldOverrideUrlLoading(
view: WebView?,
webResourceRequest: WebResourceRequest
): Boolean {
// Capture clicks on invite links
if (webResourceRequest.url.isInviteUri()) {
val intent = Intent(
context,
InviteActivity::class.java
).setAction(Intent.ACTION_VIEW)
intent.data = webResourceRequest.url
context.startActivity(intent)
return true
}
// Otherwise, open the link in the browser using androidx.browser
val customTab = CustomTabsIntent.Builder()
.setShowTitle(true)
.setDefaultColorSchemeParams(
CustomTabColorSchemeParams.Builder()
.setToolbarColor(
MaterialColors.getColor(
binding.wvChangelog,
com.google.android.material.R.attr.backgroundColor
)
)
.build()
)
.build()
customTab.launchUrl(context, webResourceRequest.url)
// Prevent the WebView from navigating to the URL
return true
}
}
loadUrl(
"$STOAT_WEB_APP/_android_assets/changelogs/renderer.html"
)
settings.apply {
javaScriptEnabled = true
setSupportZoom(false)
setSupportMultipleWindows(false)
isVerticalScrollBarEnabled = false
isHorizontalScrollBarEnabled = false
cacheMode = WebSettings.LOAD_NO_CACHE
}
addJavascriptInterface(
object {
@JavascriptInterface
fun getMarkdown(): String {
return getString(ARG_RENDERED_CONTENTS) ?: ""
}
@JavascriptInterface
fun getContentColour(): String {
return argbAsCssColour(
MaterialColors.getColor(
binding.wvChangelog,
com.google.android.material.R.attr.colorOnSurface
)
)
}
@JavascriptInterface
fun getPrimaryColour(): String {
return argbAsCssColour(
MaterialColors.getColor(
binding.wvChangelog,
androidx.appcompat.R.attr.colorPrimary
)
)
}
},
"Bridge"
)
setBackgroundColor(android.graphics.Color.TRANSPARENT)
}
}
return binding.root
}
override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog)
onDismiss()
}
companion object {
const val TAG = "ChangelogBottomSheetFragment"
private const val ARG_VERSION_NAME = "version_name"
private const val ARG_HISTORICAL = "historical"
private const val ARG_RENDERED_CONTENTS = "rendered_contents"
fun createArguments(
versionName: String,
historical: Boolean,
renderedContents: String,
): Bundle {
return Bundle().apply {
putString(ARG_VERSION_NAME, versionName)
putBoolean(ARG_HISTORICAL, historical)
putString(ARG_RENDERED_CONTENTS, renderedContents)
}
}
}
}

View File

@ -1,130 +0,0 @@
package chat.stoat.internals
import android.content.Context
import chat.stoat.api.STOAT_KJBOOK
import chat.stoat.api.StoatHttp
import chat.stoat.api.StoatJson
import chat.stoat.internals.IndexHolder.cachedIndex
import chat.stoat.persistence.KVStorage
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
import kotlinx.serialization.Serializable
@Serializable
data class ChangelogIndex(
val changelogs: List<ChangelogData> = emptyList()
)
@Serializable
data class ChangelogData(
val version: ChangelogVersion,
val date: ChangelogDate,
val summary: String
)
@Serializable
data class ChangelogDate(
val publish: String
)
@Serializable
data class ChangelogVersion(
val code: Long,
val name: String,
val title: String
)
@Serializable
data class Changelog(
val id: String,
val slug: String,
val body: String,
val collection: String,
val data: ChangelogData,
val rendered: String
)
object IndexHolder {
var cachedIndex: ChangelogIndex? = null
}
class Changelogs(val context: Context, val kvStorage: KVStorage? = null) {
suspend fun fetchChangelogIndex(): ChangelogIndex {
if (cachedIndex != null) {
return cachedIndex as ChangelogIndex
}
try {
val response = StoatHttp.get("$STOAT_KJBOOK/changelogs.json")
cachedIndex =
StoatJson.decodeFromString(ChangelogIndex.serializer(), response.bodyAsText())
return cachedIndex as ChangelogIndex
} catch (e: Error) {
return ChangelogIndex()
}
}
suspend fun fetchChangelogByVersionCode(versionCode: Long): Changelog {
try {
val response = StoatHttp.get("$STOAT_KJBOOK/changelogs/$versionCode.json")
return StoatJson.decodeFromString(Changelog.serializer(), response.bodyAsText())
} catch (e: Error) {
return Changelog(
id = "",
slug = "",
body = e.localizedMessage ?: "",
collection = "",
data = ChangelogData(
version = ChangelogVersion(
code = 0L,
name = "",
title = e.localizedMessage ?: "",
),
date = ChangelogDate(
publish = "1970-01-01T00:00:00.000Z"
),
summary = e.localizedMessage ?: ""
),
rendered = e.localizedMessage ?: ""
)
}
}
suspend fun getLatestChangelog(): ChangelogData {
return fetchChangelogIndex().changelogs.maxByOrNull { it.version.code }!!
}
suspend fun getLatestChangelogCode(): String {
return getLatestChangelog().version.code.toString()
}
suspend fun hasSeenCurrent(): Boolean {
if (kvStorage == null) {
throw IllegalStateException(
"Not supported for non-KVStorage instances of Changelogs"
)
}
val latest = getLatestChangelog().version.code
val lastRead = kvStorage.get("latestChangelogRead")
if (lastRead == null) {
return false
}
// If the last read changelog is >= the latest, it has been read
return lastRead.toLong() >= latest
}
suspend fun markAsSeen() {
if (kvStorage == null) {
throw IllegalStateException(
"Not supported for non-KVStorage instances of Changelogs"
)
}
val index = fetchChangelogIndex()
val latest = index.changelogs.maxByOrNull { it.version.code }!!.version.code.toString()
kvStorage.set("latestChangelogRead", latest)
}
}

View File

@ -76,7 +76,6 @@ import chat.stoat.callbacks.ActionChannel
import chat.stoat.composables.chat.DisconnectedNotice
import chat.stoat.composables.screens.chat.drawer.ChannelSideDrawer
import chat.stoat.dialogs.NotificationRationaleDialog
import chat.stoat.internals.Changelogs
import chat.stoat.internals.extensions.zero
import chat.stoat.persistence.KVStorage
import chat.stoat.screens.chat.dialogs.safety.ReportMessageDialog
@ -87,7 +86,6 @@ import chat.stoat.screens.chat.views.NoCurrentChannelScreen
import chat.stoat.screens.chat.views.OverviewScreen
import chat.stoat.screens.chat.views.channel.ChannelScreen
import chat.stoat.sheets.AddServerSheet
import chat.stoat.sheets.ChangelogSheet
import chat.stoat.sheets.EarlyAccessSheet
import chat.stoat.sheets.EmoteInfoSheet
import chat.stoat.sheets.LinkInfoSheet
@ -153,25 +151,11 @@ class ChatRouterViewModel(
var showEarlyAccessSpark by mutableStateOf(false)
var showSwipeToReplySpark by mutableStateOf(false)
private val changelogs = Changelogs(context, kvStorage)
init {
viewModelScope.launch {
val current = kvStorage.get("currentDestination")
setSaveDestination(ChatRouterDestination.fromString(current ?: ""))
try {
latestChangelogRead = changelogs.hasSeenCurrent()
latestChangelog = changelogs.getLatestChangelogCode()
latestChangelogBody =
changelogs.fetchChangelogByVersionCode(latestChangelog.toLong()).rendered
if (!latestChangelogRead) {
changelogs.markAsSeen()
}
} catch (e: Exception) {
e.printStackTrace()
}
val seenEarlyAccess = kvStorage.getBoolean("spark/earlyAccess/dismissed")
val seenSwipeToReply = kvStorage.getBoolean("spark/swipeToReply/dismissed")
if (seenEarlyAccess == null) {
@ -473,17 +457,6 @@ fun ChatRouterScreen(
}
}
if (!viewModel.latestChangelogRead) {
ChangelogSheet(
versionName = viewModel.latestChangelog,
versionIsHistorical = false,
renderedContents = viewModel.latestChangelogBody,
onDismiss = {
viewModel.latestChangelogRead = true
}
)
}
if (showPlatformModDMHint) {
AlertDialog(
onDismissRequest = {},

View File

@ -54,6 +54,7 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalResources
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
@ -61,10 +62,10 @@ import androidx.navigation.NavController
import chat.stoat.R
import chat.stoat.api.StoatAPI
import chat.stoat.api.routes.user.fetchSelf
import chat.stoat.core.model.schemas.User
import chat.stoat.composables.generic.NonIdealState
import chat.stoat.composables.screens.settings.UserOverview
import chat.stoat.composables.skeletons.UserOverviewSkeleton
import chat.stoat.core.model.schemas.User
import chat.stoat.internals.extensions.zero
import chat.stoat.screens.chat.LocalIsConnected
import chat.stoat.sheets.UserCardSheet
@ -79,6 +80,7 @@ fun OverviewScreen(
includePadding: Boolean = true
) {
val context = LocalContext.current
val resources = LocalResources.current
var isLoading by rememberSaveable { mutableStateOf(true) }
var user by rememberSaveable { mutableStateOf<User?>(null) }
@ -329,7 +331,8 @@ fun OverviewScreen(
item(key = "changelog") {
OverviewScreenLink(
onClick = {
navController.navigate("settings/changelogs")
// navController.navigate("settings/changelogs")
// TODO replace with new changelog
},
backgroundColour = MaterialTheme.colorScheme.errorContainer,
foregroundColour = MaterialTheme.colorScheme.onErrorContainer,
@ -349,12 +352,13 @@ fun OverviewScreen(
body = { Text(stringResource(R.string.overview_screen_changelog_description)) }
)
}
item(key = "feedback") {
OverviewScreenLink(
onClick = {
Toast.makeText(
context,
context.getString(R.string.comingsoon_toast),
resources.getString(R.string.comingsoon_toast),
Toast.LENGTH_SHORT
).show()
// navController.navigate("feedback")

View File

@ -1,207 +0,0 @@
package chat.stoat.screens.settings
import android.app.Application
import android.text.format.DateUtils
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
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.lazy.LazyColumn
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LargeTopAppBar
import androidx.compose.material3.ListItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.navigation.NavController
import chat.stoat.R
import chat.stoat.internals.ChangelogIndex
import chat.stoat.internals.Changelogs
import chat.stoat.persistence.KVStorage
import chat.stoat.sheets.ChangelogSheet
import kotlinx.coroutines.launch
import kotlinx.datetime.Instant
import org.koin.androidx.compose.koinViewModel
class ChangelogsSettingsScreenViewModel(
val kvStorage: KVStorage,
val context: Application
) : ViewModel() {
var index by mutableStateOf<ChangelogIndex?>(null)
var renderedChangelog by mutableStateOf("")
suspend fun requestChangelog(version: String) {
viewModelScope.launch {
try {
renderedChangelog = Changelogs(
context,
kvStorage
).fetchChangelogByVersionCode(version.toLong()).rendered
} catch (e: Exception) {
e.printStackTrace()
}
}
}
suspend fun populate() {
viewModelScope.launch {
try {
index = Changelogs(context, kvStorage).fetchChangelogIndex()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ChangelogsSettingsScreen(
navController: NavController,
viewModel: ChangelogsSettingsScreenViewModel = koinViewModel()
) {
LaunchedEffect(Unit) {
viewModel.populate()
}
var currentChangelog by remember { mutableStateOf("") }
var sheetOpen by remember { mutableStateOf(false) }
LaunchedEffect(currentChangelog) {
if (currentChangelog.isNotEmpty())
viewModel.requestChangelog(currentChangelog)
}
if (sheetOpen) {
val changelog =
viewModel.index?.changelogs?.firstOrNull { it.version.code.toString() == currentChangelog }
?: return
ChangelogSheet(
versionName = changelog.version.name,
versionIsHistorical = true,
renderedContents = viewModel.renderedChangelog,
onDismiss = {
sheetOpen = false
}
)
}
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
LargeTopAppBar(
scrollBehavior = scrollBehavior,
title = {
Text(
text = stringResource(R.string.settings_changelogs),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
},
navigationIcon = {
IconButton(onClick = {
navController.popBackStack()
}) {
Icon(
painter = painterResource(R.drawable.ic_arrow_back_24dp),
contentDescription = stringResource(id = R.string.back)
)
}
},
)
},
) { pv ->
Column(
modifier = Modifier
.padding(pv)
.fillMaxSize()
) {
Crossfade(targetState = viewModel.index, label = "index has items") { index ->
if (index == null) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
) {
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
}
} else {
LazyColumn {
items(
viewModel.index?.changelogs?.size ?: 0,
key = { index ->
viewModel.index?.changelogs?.get(index)?.version?.name ?: ""
}
) { index ->
val changelog = viewModel.index?.changelogs?.get(index) ?: return@items
val relativeTimeString = DateUtils.getRelativeTimeSpanString(
Instant.parse(changelog.date.publish).toEpochMilliseconds(),
System.currentTimeMillis(),
DateUtils.DAY_IN_MILLIS,
DateUtils.FORMAT_ABBREV_ALL
)
Column(
modifier = Modifier
.clickable {
currentChangelog = changelog.version.code.toString()
sheetOpen = true
}
.fillMaxWidth()
) {
ListItem(
headlineContent = {
Text(
text = changelog.version.title,
modifier = Modifier.padding(bottom = 8.dp)
)
},
supportingContent = {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Text(
text = changelog.summary,
)
Text(
text = "${changelog.version.name} · $relativeTimeString",
modifier = Modifier.alpha(0.7f),
)
}
}
)
HorizontalDivider()
}
}
}
}
}
}
}
}

View File

@ -315,27 +315,6 @@ fun SettingsScreen(
)
}
ListItem(
headlineContent = {
Text(
text = stringResource(id = R.string.settings_changelogs)
)
},
leadingContent = {
SettingsIcon {
Icon(
painter = painterResource(R.drawable.ic_wand_shine_24dp),
contentDescription = null,
)
}
},
modifier = Modifier
.testTag("settings_view_changelogs")
.clickable {
navController.navigate("settings/changelogs")
}
)
ListItem(
headlineContent = {
Text(
@ -363,7 +342,7 @@ fun SettingsScreen(
InviteActivity::class.java
).setAction(Intent.ACTION_VIEW)
intent.data = "https://rvlt.gg/Testers".toUri()
intent.data = "https://stt.gg/Testers".toUri()
context.startActivity(intent)
}
)

View File

@ -1,50 +0,0 @@
package chat.stoat.sheets
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import chat.stoat.api.internals.getFragmentActivity
import chat.stoat.fragments.ChangelogBottomSheetFragment
@Composable
fun ChangelogSheet(
versionName: String,
versionIsHistorical: Boolean,
renderedContents: String,
onDismiss: () -> Unit
) {
val activity = LocalContext.current.getFragmentActivity()
var lastRenderedContents by remember { mutableStateOf("") }
DisposableEffect(versionName, renderedContents) {
if (lastRenderedContents == renderedContents) return@DisposableEffect onDispose {}
if (renderedContents.isEmpty()) return@DisposableEffect onDispose {}
lastRenderedContents = renderedContents
val sheet = ChangelogBottomSheetFragment(onDismiss)
sheet.arguments =
ChangelogBottomSheetFragment.createArguments(
versionName,
versionIsHistorical,
renderedContents,
)
activity?.supportFragmentManager?.let {
sheet.show(it, ChangelogBottomSheetFragment.TAG)
}
onDispose {
try {
sheet.dismissAllowingStateLoss()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}

View File

@ -7,5 +7,4 @@ const val STOAT_FILES = "https://cdn.stoatusercontent.com"
const val STOAT_PROXY = "https://proxy.stoatusercontent.com"
const val STOAT_WEB_APP = "https://stoat.chat"
const val STOAT_INVITES = "https://stt.gg"
const val STOAT_WEBSOCKET = "wss://events.stoat.chat"
const val STOAT_KJBOOK = "https://stoatchat.github.io/for-android"
const val STOAT_WEBSOCKET = "wss://events.stoat.chat"