show changelog for launcher updates

This commit is contained in:
Chloe committed 2025-01-18 18:17:53 -07:00
1 parent 500d3ba015
commit 10a0670a47
4 files changed
+104 -2

No files matched your search

+2
View File
@@ -100,6 +100,8 @@ dependencies {
implementation ("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") implementation ("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
implementation ("org.jetbrains.kotlinx:kotlinx-serialization-json-okio:1.7.3") implementation ("org.jetbrains.kotlinx:kotlinx-serialization-json-okio:1.7.3")
implementation ("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1") implementation ("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")
implementation ("com.mikepenz:multiplatform-markdown-renderer-android:0.29.0")
implementation ("com.mikepenz:multiplatform-markdown-renderer-m3:0.29.0")
debugImplementation ("androidx.compose.ui:ui-tooling") debugImplementation ("androidx.compose.ui:ui-tooling")
coreLibraryDesugaring ("com.android.tools:desugar_jdk_libs:2.1.3") coreLibraryDesugaring ("com.android.tools:desugar_jdk_libs:2.1.3")
} }
@@ -8,40 +8,60 @@ import android.provider.DocumentsContract
import android.text.format.Formatter import android.text.format.Formatter
import android.widget.Toast import android.widget.Toast
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Refresh import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ElevatedCard import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.geode.launcher.R import com.geode.launcher.R
import com.geode.launcher.UserDirectoryProvider import com.geode.launcher.UserDirectoryProvider
import com.geode.launcher.ui.theme.Typography
import com.geode.launcher.updater.ReleaseManager import com.geode.launcher.updater.ReleaseManager
import com.geode.launcher.updater.ReleaseViewModel import com.geode.launcher.updater.ReleaseViewModel
import com.geode.launcher.utils.LaunchUtils import com.geode.launcher.utils.LaunchUtils
import com.geode.launcher.utils.PreferenceUtils import com.geode.launcher.utils.PreferenceUtils
import com.mikepenz.markdown.compose.LocalBulletListHandler
import com.mikepenz.markdown.m3.Markdown
import com.mikepenz.markdown.m3.markdownColor
import com.mikepenz.markdown.m3.markdownTypography
import kotlinx.datetime.toJavaInstant
import java.io.File import java.io.File
import java.net.ConnectException import java.net.ConnectException
import java.net.UnknownHostException import java.net.UnknownHostException
import java.text.DateFormat
import java.util.Date
fun clearDownloadedApks(context: Context) { fun clearDownloadedApks(context: Context) {
// technically we should be using the activity results but it was too inconsistent for my liking // technically we should be using the activity results but it was too inconsistent for my liking
@@ -101,10 +121,78 @@ fun installLauncherUpdate(context: Context) {
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LauncherUpdateInformation(onDismiss: () -> Unit) {
val context = LocalContext.current
val nextRelease = remember { ReleaseManager.get(context).availableLauncherUpdate.value }
val sheetState = rememberModalBottomSheetState()
if (nextRelease != null) {
ModalBottomSheet(onDismissRequest = { onDismiss() }, sheetState = sheetState) {
Box(Modifier.verticalScroll(rememberScrollState())) {
Column(modifier = Modifier.padding(horizontal = 24.dp)) {
Text(
stringResource(R.string.launcher_update_name, nextRelease.release.tagName),
style = Typography.headlineSmall,
)
val releasedTime = remember {
DateFormat.getDateInstance().format(
Date.from(nextRelease.release.publishedAt.toJavaInstant())
)
}
Text(
stringResource(R.string.launcher_update_released, "$releasedTime"),
style = Typography.labelLarge
)
Spacer(modifier = Modifier.size(8.dp))
if (nextRelease.release.body != null) {
CompositionLocalProvider(LocalBulletListHandler provides { _, _, _ -> "•  " }) {
Markdown(
content = nextRelease.release.body.replace("\r", ""),
colors = markdownColor(
linkText = MaterialTheme.colorScheme.primary
),
typography = markdownTypography(
link = MaterialTheme.typography.bodyLarge.copy(
textDecoration = TextDecoration.Underline
)
),
)
}
}
TextButton(
modifier = Modifier.align(Alignment.End),
onClick = { installLauncherUpdate(context) },
) {
Icon(painterResource(R.drawable.icon_download), contentDescription = null)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text(stringResource(R.string.launcher_install))
}
}
}
}
}
}
@Composable @Composable
fun LauncherUpdateIndicator(modifier: Modifier = Modifier) { fun LauncherUpdateIndicator(modifier: Modifier = Modifier) {
val context = LocalContext.current val context = LocalContext.current
var showInfoDialog by remember { mutableStateOf(false) }
if (showInfoDialog) {
LauncherUpdateInformation {
showInfoDialog = false
}
}
ElevatedCard(modifier) { ElevatedCard(modifier) {
Column( Column(
// buttons add enough padding already, lower to compensate // buttons add enough padding already, lower to compensate
@@ -121,14 +209,21 @@ fun LauncherUpdateIndicator(modifier: Modifier = Modifier) {
modifier = Modifier.padding(horizontal = 10.dp) modifier = Modifier.padding(horizontal = 10.dp)
) )
Row(modifier = Modifier.align(Alignment.End)) {
TextButton(
onClick = { showInfoDialog = true },
) {
Text(stringResource(R.string.launcher_update_view))
}
TextButton( TextButton(
onClick = { installLauncherUpdate(context) }, onClick = { installLauncherUpdate(context) },
modifier = Modifier.align(Alignment.End)
) { ) {
Text(stringResource(R.string.launcher_install)) Text(stringResource(R.string.launcher_install))
} }
} }
} }
}
} }
@Composable @Composable
@@ -24,7 +24,9 @@ data class Release(
val createdAt: Instant, val createdAt: Instant,
val publishedAt: Instant, val publishedAt: Instant,
val assets: List<Asset>, val assets: List<Asset>,
val htmlUrl: String val htmlUrl: String,
val body: String?,
val name: String?,
) )
@Serializable @Serializable
+3
View File
@@ -39,6 +39,9 @@
<string name="launcher_update_available">A new launcher update is available!</string> <string name="launcher_update_available">A new launcher update is available!</string>
<string name="launcher_update_dismiss">Dismiss</string> <string name="launcher_update_dismiss">Dismiss</string>
<string name="launcher_update_view">View</string>
<string name="launcher_update_name">Geode Launcher v%1$s</string>
<string name="launcher_update_released">Released %1$s</string>
<string name="safe_mode_enable_title">Enable safe mode?</string> <string name="safe_mode_enable_title">Enable safe mode?</string>
<string name="safe_mode_enable_description">Safe mode disables loading of all mods, allowing one to remove problematic mods or diagnose crashes. If you\'re not experiencing issues with Geode, you should probably not be using safe mode.</string> <string name="safe_mode_enable_description">Safe mode disables loading of all mods, allowing one to remove problematic mods or diagnose crashes. If you\'re not experiencing issues with Geode, you should probably not be using safe mode.</string>
<string name="launcher_failed_to_load">Geode failed to load.</string> <string name="launcher_failed_to_load">Geode failed to load.</string>