From e625297718bbb81e268f68aba73af3767d014ec7 Mon Sep 17 00:00:00 2001 From: Infi Date: Fri, 8 Sep 2023 03:45:40 +0200 Subject: [PATCH] feat: changelog system Signed-off-by: Infi --- app/src/main/assets/changelogs/6000.md | 90 ++++++++++++++ .../assets/changelogs/assets/6000/header.png | Bin 0 -> 21053 bytes app/src/main/assets/changelogs/index.json | 10 ++ app/src/main/assets/webmarkdown/renderer.html | 19 +-- .../chat/revolt/activities/MainActivity.kt | 2 + .../revolt/components/generic/WebMarkdown.kt | 11 +- .../java/chat/revolt/internals/Changelogs.kt | 45 +++++++ .../revolt/screens/chat/ChatRouterScreen.kt | 36 +++++- .../screens/settings/ChangelogsScreen.kt | 115 ++++++++++++++++++ .../screens/settings/DebugSettingsScreen.kt | 19 +++ .../revolt/screens/settings/SettingsScreen.kt | 20 +++ .../java/chat/revolt/sheets/ChangelogSheet.kt | 106 ++++++++++++++++ app/src/main/res/values/strings.xml | 5 + 13 files changed, 469 insertions(+), 9 deletions(-) create mode 100644 app/src/main/assets/changelogs/6000.md create mode 100644 app/src/main/assets/changelogs/assets/6000/header.png create mode 100644 app/src/main/assets/changelogs/index.json create mode 100644 app/src/main/java/chat/revolt/internals/Changelogs.kt create mode 100644 app/src/main/java/chat/revolt/screens/settings/ChangelogsScreen.kt create mode 100644 app/src/main/java/chat/revolt/sheets/ChangelogSheet.kt diff --git a/app/src/main/assets/changelogs/6000.md b/app/src/main/assets/changelogs/6000.md new file mode 100644 index 00000000..c2faeadf --- /dev/null +++ b/app/src/main/assets/changelogs/6000.md @@ -0,0 +1,90 @@ +# ![Revolt for Android 0.6.0](/_android_assets/changelogs/assets/6000/header.png) + +## Welcome Beta Ring II 🎉 + +For many of you, this is the first time you're seeing this app. Welcome to the second beta ring! +You'll be helping us test the app and find bugs before we release it to the general public. Everyone +is so excited to have you here! + +Crashes are expected, and we're working hard to fix them. If you find a crash, it will be reported +automatically. If you have anything else to say, use the **channels on Jenvolt** or the **Feedback** +button in settings. + +## Server Identities are here + +Server identities and role colours will now be shown across the app. This should help make the app +feel a lot more like the web client, which is our compatibility target. Servers look a lot closer +now! + +We'll still exploring how to best show these identities in user sheets, but for now, they're only +shown inline in chat and in the member list. + +## Changelogs + +You're reading one right now! New releases will now come with changelogs, so you can see what's +been cooking in the kitchen. We'll also be posting these on the website after general availability, +so feel free to check them out there too. + +## Updated to Android 14 SDK + +We've updated the app to use the latest Android SDK, which is Android 14. This means we're now +ahead of the actual Android release schedule! 14 is still in beta, but the SDK is stable by now. + +This will help us keep the +app [in the Play Store](https://support.google.com/googleplay/android-developer/answer/11926878?hl=en) +for longer, and it also means we can use the latest and greatest APIs. As always, the app's aim is +to make use of the Android platform as much as possible, and being on the newest SDK helps us do +that. + +## Extended Markdown in Bios and Changelogs + +There is now a separate **web-based** Markdown renderer, currently in use on user bios and +changelogs. +This renderer is more powerful than the one we use in chat, and it's also more accurate to the web +client. It is a little slower, but we're working on that. The aim will be to instantly render +Markdown in it, however the current placeholder implementation works alright. Look forward to KaTeX +and more! + +Now, our focus will go back to the native chat Markdown renderer. It is quite a bit behind in terms +of feature support. Some features (such as KaTeX) will be impossible to implement natively, so we +will be looking at ways to fuse the two renderers together on-demand. As always, this is a long-term +goal, but we're getting there. + +## Member List + +Here it is, the member list sheet! This is equivalent to the right sidebar on the web client. It +shows all the members of the server, sorted by role and position, along with the correct role colour +and identity. + +In the future, you will be able to filter this list by role, and search for members. For now, it's +just a list. + +## The Small Things + +- Latest and greatest dependency versions are now used, including Kotlin 1.9.10 and Compose 1.5.3. +- Audio player gained a "share URL" menu item. +- Message timestamps now use native time formatting APIs, which means they'll be formatted + correctly for your locale and will stay accurate in all cases. +- The disconnected/reconnected/connected banner is now using Material You colouring if your theme is + set to that. +- Roles in the user sheet are now sorted by position. +- If a users' profile is empty or fails to load, the fallback messages are now clearly + distinguishable as such. +- Debug builds now have "+debug" appended to their version string, an app ID of "chat.revolt.debug", + and a different name. This allows you to install the debug build alongside the release build. + +## Squished Bug Showcase + +- Fixed a crash when opening the user sheet for a user that has blocked you. +- Fixed a condition in which messages from yesterday would be shown as "Today" in the chat. +- Fixed a condition in which GIFs would not play in the chat. +- Fixed a condition in which animated WebP images would not play in the chat. +- Fixed a condition in which users were eagerly shown as offline when they were actually online. +- Fixed a condition in which the ripple area for server icons would be too small compared to the + icon. + +## 🫡✨ + +That's all for now! We hope you enjoy this release, and we're looking forward to your feedback. +Please report any bugs you find, and let us know what you think of the app so far. Thank you for +testing! \ No newline at end of file diff --git a/app/src/main/assets/changelogs/assets/6000/header.png b/app/src/main/assets/changelogs/assets/6000/header.png new file mode 100644 index 0000000000000000000000000000000000000000..6656c543de3a46f0a38573699b1a8d30f6d97cf7 GIT binary patch literal 21053 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

U^K~Ty07)c1a zV{rtO<;yEL?hQd#Z%9!gC^8-ic5?_8>&pp23VbwBukZg2aF*S+5Cvn7pO`gq(_8`< zaR{mAC95Tlfq{=w={3phLgH@#)jxUD*duFS5_1~-?Bsjf$L{f_-AF9>64Q2N)7FD& zY9R``9p^T$I;Yvdn8OifN)o{T+6onFv9Ad7i)Q@N9zN}-4F)LEM=m}5e&s=Hb8sh?UJ0rj6`E6g`kWesbImTrkHwq@~OYdIL+xhW^2ThZk zT&pE#eM%}Q%&Y)_b$Q6uLE!mA98iAnE7QMj3dHRp{n7+rNd|Jsh z6^sU@ZoP9C&ICLKt-Uzan+X3dlO*90ad;vd@j%6Rgmh+Qz~U^?#OdZr=B zYc-k}(%08q7)~gcUk(l|_dP8TXvqOZ*3S1XQbw`6GjF&gpT;R_b=JWV&BI^&$g+BJ zrDZRrfwx8Iy=mT=<5u1M2I0NIG*U;OER&Kmn`O0nL;Pnwp{eJ}5wKQx(RN)J%6iqx z`+m+2*VFk_Un|d@p~qA9sXzU+F=C4X@?I$;(xn#3Y3exsBaO^0*(qj0mehdH*Q}iA|0du2S>8VV*mgE literal 0 HcmV?d00001 diff --git a/app/src/main/assets/changelogs/index.json b/app/src/main/assets/changelogs/index.json new file mode 100644 index 00000000..3946607a --- /dev/null +++ b/app/src/main/assets/changelogs/index.json @@ -0,0 +1,10 @@ +{ + "list": { + "6000": { + "summary": "Beta Ring II, Server Identities, Changelogs, SDK34", + "version": "0.6.0", + "date": "2023-09-08" + } + }, + "latest": "6000" +} \ No newline at end of file diff --git a/app/src/main/assets/webmarkdown/renderer.html b/app/src/main/assets/webmarkdown/renderer.html index 0ed13253..a99006a0 100644 --- a/app/src/main/assets/webmarkdown/renderer.html +++ b/app/src/main/assets/webmarkdown/renderer.html @@ -62,11 +62,8 @@ diff --git a/app/src/main/java/chat/revolt/activities/MainActivity.kt b/app/src/main/java/chat/revolt/activities/MainActivity.kt index b1d5a2d4..00d0a880 100644 --- a/app/src/main/java/chat/revolt/activities/MainActivity.kt +++ b/app/src/main/java/chat/revolt/activities/MainActivity.kt @@ -39,6 +39,7 @@ import chat.revolt.screens.register.RegisterDetailsScreen import chat.revolt.screens.register.RegisterGreetingScreen import chat.revolt.screens.register.RegisterVerifyScreen import chat.revolt.screens.settings.AppearanceSettingsScreen +import chat.revolt.screens.settings.ChangelogsSettingsScreen import chat.revolt.screens.settings.ClosedBetaUpdaterScreen import chat.revolt.screens.settings.DebugSettingsScreen import chat.revolt.screens.settings.SettingsScreen @@ -137,6 +138,7 @@ fun AppEntrypoint(windowSizeClass: WindowSizeClass) { composable("settings/appearance") { AppearanceSettingsScreen(navController) } composable("settings/debug") { DebugSettingsScreen(navController) } composable("settings/updater") { ClosedBetaUpdaterScreen(navController) } + composable("settings/changelogs") { ChangelogsSettingsScreen(navController) } dialog("settings/feedback") { FeedbackDialog(navController) } composable("about") { AboutScreen(navController) } diff --git a/app/src/main/java/chat/revolt/components/generic/WebMarkdown.kt b/app/src/main/java/chat/revolt/components/generic/WebMarkdown.kt index d31e1762..76193610 100644 --- a/app/src/main/java/chat/revolt/components/generic/WebMarkdown.kt +++ b/app/src/main/java/chat/revolt/components/generic/WebMarkdown.kt @@ -49,6 +49,7 @@ private fun argbAsCssColour(argb: Int): String { fun WebMarkdown( text: String, maskLoading: Boolean = false, + simpleLineBreaks: Boolean = true, modifier: Modifier = Modifier, ) { val contentColour = LocalContentColor.current @@ -128,7 +129,7 @@ fun WebMarkdown( } loadUrl( - "https://app.revolt.chat/_android_assets/webmarkdown/renderer.html", + "$REVOLT_APP/_android_assets/webmarkdown/renderer.html", ) settings.apply { @@ -164,6 +165,11 @@ fun WebMarkdown( fun getPrimaryColour(): String { return argbAsCssColour(materialColourScheme.primary.toArgb()) } + + @JavascriptInterface + fun shouldUseSimpleLineBreaks(): Boolean { + return simpleLineBreaks + } }, "Bridge" ) @@ -174,6 +180,9 @@ fun WebMarkdown( LayoutParams.WRAP_CONTENT ) } + }, + update = { + it.evaluateJavascript("renderMarkdown()", null) } ) } \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/internals/Changelogs.kt b/app/src/main/java/chat/revolt/internals/Changelogs.kt new file mode 100644 index 00000000..ef97b306 --- /dev/null +++ b/app/src/main/java/chat/revolt/internals/Changelogs.kt @@ -0,0 +1,45 @@ +package chat.revolt.internals + +import android.content.Context +import chat.revolt.api.RevoltJson +import chat.revolt.persistence.KVStorage +import kotlinx.serialization.Serializable + +@Serializable +data class Changelog( + val summary: String, + val version: String, + val date: String, +) + +@Serializable +data class ChangelogIndex( + val list: Map, + val latest: String +) + +class Changelogs(val context: Context, val kvStorage: KVStorage? = null) { + val index = context.assets.open("changelogs/index.json").use { + it.reader().readText() + }.let { + RevoltJson.decodeFromString(ChangelogIndex.serializer(), it) + } + + fun getChangelog(version: String): String { + return context.assets.open("changelogs/${version}.md").use { + it.reader().readText() + } + } + + suspend fun hasSeenLatest(): Boolean { + if (kvStorage == null) throw IllegalStateException("Not supported for non-KVStorage instances of Changelogs") + + return kvStorage.get("latestChangelogRead") == index.latest + } + + suspend fun markAsSeen() { + if (kvStorage == null) throw IllegalStateException("Not supported for non-KVStorage instances of Changelogs") + + kvStorage.set("latestChangelogRead", index.latest) + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt b/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt index 805c6d37..30ececc5 100644 --- a/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt +++ b/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt @@ -1,5 +1,7 @@ package chat.revolt.screens.chat +import android.annotation.SuppressLint +import android.content.Context import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.Crossfade @@ -73,12 +75,14 @@ import chat.revolt.components.screens.chat.drawer.channel.ChannelList import chat.revolt.components.screens.chat.drawer.server.DrawerServer import chat.revolt.components.screens.chat.drawer.server.DrawerServerlikeIcon import chat.revolt.components.screens.chat.drawer.server.ServerDrawerSeparator +import chat.revolt.internals.Changelogs import chat.revolt.persistence.KVStorage import chat.revolt.screens.chat.dialogs.safety.ReportMessageDialog import chat.revolt.screens.chat.views.HomeScreen import chat.revolt.screens.chat.views.NoCurrentChannelScreen import chat.revolt.screens.chat.views.channel.ChannelScreen import chat.revolt.sheets.AddServerSheet +import chat.revolt.sheets.ChangelogSheet import chat.revolt.sheets.ServerContextSheet import chat.revolt.sheets.StatusSheet import chat.revolt.sheets.UserContextSheet @@ -88,27 +92,41 @@ import com.airbnb.lottie.compose.LottieCompositionSpec import com.airbnb.lottie.compose.animateLottieCompositionAsState import com.airbnb.lottie.compose.rememberLottieComposition import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel +@SuppressLint("StaticFieldLeak") class ChatRouterViewModel @Inject constructor( - private val kvStorage: KVStorage + private val kvStorage: KVStorage, + @ApplicationContext val context: Context ) : ViewModel() { var currentServer by mutableStateOf("home") var currentChannel by mutableStateOf(null) var sidebarSparkDisplayed by mutableStateOf(true) + var latestChangelogRead by mutableStateOf(true) + var latestChangelog by mutableStateOf("") + + private val changelogs = Changelogs(context, kvStorage) init { viewModelScope.launch { currentServer = kvStorage.get("currentServer") ?: "home" currentChannel = kvStorage.get("currentChannel") + sidebarSparkDisplayed = if (kvStorage.getBoolean("sidebarSpark") == null) { false } else { kvStorage.getBoolean("sidebarSpark")!! } + + latestChangelogRead = changelogs.hasSeenLatest() + latestChangelog = changelogs.index.latest + if (!latestChangelogRead) { + changelogs.markAsSeen() + } } } @@ -291,6 +309,22 @@ fun ChatRouterScreen( } } + if (!viewModel.latestChangelogRead) { + val changelogSheetState = rememberModalBottomSheetState() + + ModalBottomSheet( + sheetState = changelogSheetState, + onDismissRequest = { + viewModel.latestChangelogRead = true + }, + ) { + ChangelogSheet( + version = viewModel.latestChangelog, + new = true + ) + } + } + if (showSidebarSpark.value) { AlertDialog( onDismissRequest = {}, diff --git a/app/src/main/java/chat/revolt/screens/settings/ChangelogsScreen.kt b/app/src/main/java/chat/revolt/screens/settings/ChangelogsScreen.kt new file mode 100644 index 00000000..b9797185 --- /dev/null +++ b/app/src/main/java/chat/revolt/screens/settings/ChangelogsScreen.kt @@ -0,0 +1,115 @@ +package chat.revolt.screens.settings + +import android.content.Context +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawingPadding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.Divider +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.Text +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.ViewModel +import androidx.navigation.NavController +import chat.revolt.R +import chat.revolt.components.generic.PageHeader +import chat.revolt.internals.Changelogs +import chat.revolt.persistence.KVStorage +import chat.revolt.sheets.ChangelogSheet +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject + +@HiltViewModel +class ChangelogsSettingsScreenViewModel @Inject constructor( + kvStorage: KVStorage, + @ApplicationContext context: Context +) : ViewModel() { + val index = Changelogs(context, kvStorage).index +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ChangelogsSettingsScreen( + navController: NavController, + viewModel: ChangelogsSettingsScreenViewModel = hiltViewModel() +) { + var currentChangelog by remember { mutableStateOf(viewModel.index.latest) } + var sheetOpen by remember { mutableStateOf(false) } + + if (sheetOpen) { + val sheetState = rememberModalBottomSheetState() + + ModalBottomSheet( + sheetState = sheetState, + onDismissRequest = { + sheetOpen = false + } + ) { + ChangelogSheet(version = currentChangelog) + } + } + + Column( + modifier = Modifier + .fillMaxSize() + .safeDrawingPadding() + ) { + PageHeader( + text = stringResource(R.string.settings_changelogs), + showBackButton = true, + onBackButtonClicked = { + navController.popBackStack() + }) + + LazyColumn { + items( + viewModel.index.list.size, + key = { viewModel.index.list.keys.elementAt(it) } + ) { index -> + val version = viewModel.index.list.keys.elementAt(index) + val changelog = viewModel.index.list[version]!! + + Column( + modifier = Modifier + .clickable { + currentChangelog = version + sheetOpen = true + } + .fillMaxWidth() + ) { + Column( + modifier = Modifier.padding(16.dp) + ) { + Text( + text = changelog.version, + style = MaterialTheme.typography.headlineSmall + ) + Text( + text = changelog.summary, + style = MaterialTheme.typography.bodyMedium, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + Divider() + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/screens/settings/DebugSettingsScreen.kt b/app/src/main/java/chat/revolt/screens/settings/DebugSettingsScreen.kt index 7c722f06..e2c5e27b 100644 --- a/app/src/main/java/chat/revolt/screens/settings/DebugSettingsScreen.kt +++ b/app/src/main/java/chat/revolt/screens/settings/DebugSettingsScreen.kt @@ -38,6 +38,12 @@ class DebugSettingsScreenViewModel @Inject constructor( fun forgetAllSparks() { this.forgetSidebarSparkShown() } + + fun forgetLatestChangelog() { + viewModelScope.launch { + kvStorage.remove("latestChangelogRead") + } + } } @Composable @@ -79,6 +85,19 @@ fun DebugSettingsScreen( Text("Forget all sparks") } } + + Text( + text = "Changelogs", + style = MaterialTheme.typography.headlineSmall, + modifier = Modifier.padding(bottom = 10.dp) + ) + Row( + modifier = Modifier.horizontalScroll(rememberScrollState()) + ) { + ElevatedButton(onClick = { viewModel.forgetLatestChangelog() }) { + Text("Mark latest changelog as unread") + } + } } } } \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/screens/settings/SettingsScreen.kt b/app/src/main/java/chat/revolt/screens/settings/SettingsScreen.kt index 9f69511e..05f8beeb 100644 --- a/app/src/main/java/chat/revolt/screens/settings/SettingsScreen.kt +++ b/app/src/main/java/chat/revolt/screens/settings/SettingsScreen.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Build import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.DateRange import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.filled.Star @@ -154,6 +155,25 @@ fun SettingsScreen( modifier = Modifier.padding(bottom = 10.dp, start = 10.dp, top = 20.dp) ) + SheetClickable( + icon = { modifier -> + Icon( + imageVector = Icons.Default.DateRange, + contentDescription = stringResource(id = R.string.settings_changelogs), + modifier = modifier + ) + }, + label = { textStyle -> + Text( + text = stringResource(id = R.string.settings_changelogs), + style = textStyle + ) + }, + modifier = Modifier.testTag("settings_view_changelogs") + ) { + navController.navigate("settings/changelogs") + } + SheetClickable( icon = { modifier -> Icon( diff --git a/app/src/main/java/chat/revolt/sheets/ChangelogSheet.kt b/app/src/main/java/chat/revolt/sheets/ChangelogSheet.kt new file mode 100644 index 00000000..5dc75aac --- /dev/null +++ b/app/src/main/java/chat/revolt/sheets/ChangelogSheet.kt @@ -0,0 +1,106 @@ +package chat.revolt.sheets + +import android.annotation.SuppressLint +import android.content.Context +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.key +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.ViewModel +import chat.revolt.R +import chat.revolt.components.generic.PageHeader +import chat.revolt.components.generic.WebMarkdown +import chat.revolt.internals.Changelog +import chat.revolt.internals.Changelogs +import chat.revolt.persistence.KVStorage +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject + +@HiltViewModel +@SuppressLint("StaticFieldLeak") +class ChangelogSheetViewModel @Inject constructor( + val kvStorage: KVStorage, + @ApplicationContext val context: Context +) : ViewModel() { + private val changelogs = Changelogs(context, kvStorage) + var changelogContents by mutableStateOf(null as String?) + var changelog by mutableStateOf(null as Changelog?) + + private fun getContents(version: String): String { + return changelogs.getChangelog(version) + } + + private fun getChangelog(version: String): Changelog { + return changelogs.index.list[version] ?: throw IllegalStateException("Changelog not found") + } + + fun populate(version: String) { + changelogContents = getContents(version) + changelog = getChangelog(version) + } +} + +@Composable +fun ChangelogSheet( + version: String, + new: Boolean = false, + viewModel: ChangelogSheetViewModel = hiltViewModel() +) { + LaunchedEffect(version) { + viewModel.populate(version) + } + + Column { + PageHeader( + if (new) { + stringResource(R.string.settings_changelogs_new_header) + } else { + stringResource( + R.string.settings_changelogs_historical_version_header, + viewModel.changelog?.version + ?: stringResource(R.string.settings_changelogs_historical_version_header_placeholder) + ) + } + ) + + if (viewModel.changelogContents == null) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(200.dp) + ) { + CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) + } + } + + key(viewModel.changelogContents) { + Column( + modifier = Modifier + .padding(horizontal = 16.dp) + .verticalScroll(rememberScrollState()) + ) { + WebMarkdown( + text = viewModel.changelogContents ?: "", + maskLoading = true, + simpleLineBreaks = false + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ae0a1e20..6b8770f3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -359,4 +359,9 @@ Feedback unavailable Feedback is not available on this build of Revolt. Support for this build is limited. (Build: %1$s %2$s) + + Changelogs + What\'s been cooking ✨ + Changelog for %1$s + that version