tell people where to go for an updated game

This commit is contained in:
qimiko committed 2024-04-20 05:13:09 -07:00
1 parent b384da1825
commit 52b997a5b4
6 files changed
+144 -18

No files matched your search

@@ -3,6 +3,7 @@ package com.geode.launcher
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.DocumentsContract import android.provider.DocumentsContract
@@ -12,10 +13,13 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.AbsoluteRoundedCornerShape
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.material.icons.filled.PlayArrow
@@ -34,6 +38,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue 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.draw.clip
import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@@ -44,8 +49,10 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
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.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
@@ -594,6 +601,82 @@ fun ErrorInfoActions(extraDetails: String?, modifier: Modifier = Modifier) {
} }
} }
fun onDownloadGame(context: Context) {
val appUrl = "https://play.google.com/store/apps/details?id=${Constants.PACKAGE_NAME}"
try {
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse(appUrl)
setPackage("com.android.vending")
}
context.startActivity(intent)
} catch (_: ActivityNotFoundException) {
Toast.makeText(context, R.string.no_activity_found, Toast.LENGTH_SHORT).show()
}
}
@Composable
fun GooglePlayBadge(modifier: Modifier = Modifier) {
val context = LocalContext.current
Image(
painter = painterResource(id = R.drawable.google_play_badge),
contentDescription = stringResource(R.string.launcher_download_game),
modifier = modifier
.width(196.dp)
.clip(AbsoluteRoundedCornerShape(4.dp))
.clickable { onDownloadGame(context) }
)
}
@Composable
fun DownloadRecommendation(needsUniversal: Boolean, modifier: Modifier = Modifier) {
val uriHandler = LocalUriHandler.current
val context = LocalContext.current
val version = BuildConfig.VERSION_NAME
val showDownload = remember {
!GamePackageUtils.isGameInstalled(context.packageManager) ||
!GamePackageUtils.identifyGameLegitimacy(context.packageManager)
}
val downloadBase = "https://github.com/geode-sdk/android-launcher/releases/download/$version"
val legacyDownloadUrl = "$downloadBase/geode-launcher-v$version-android32.apk"
val universalDownloadUrl = "$downloadBase/geode-launcher-v$version.apk"
val downloadUrl = if (needsUniversal)
universalDownloadUrl else legacyDownloadUrl
val downloadText = if (needsUniversal)
stringResource(R.string.launcher_download_universal)
else
stringResource(R.string.launcher_download_32bit)
Column(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(
12.dp, alignment = Alignment.CenterVertically
)
) {
ClickableText(
text = AnnotatedString(downloadText),
onClick = {
uriHandler.openUri(downloadUrl)
},
style = TextStyle.Default.copy(
color = MaterialTheme.colorScheme.primary,
textDecoration = TextDecoration.Underline
),
)
if (showDownload) {
GooglePlayBadge(
modifier = Modifier.align(Alignment.CenterHorizontally)
)
}
}
}
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ErrorInfoSheet(failureInfo: LoadFailureInfo, onDismiss: () -> Unit) { fun ErrorInfoSheet(failureInfo: LoadFailureInfo, onDismiss: () -> Unit) {
@@ -611,19 +694,28 @@ fun ErrorInfoSheet(failureInfo: LoadFailureInfo, onDismiss: () -> Unit) {
ErrorInfoBody(failureInfo.title) ErrorInfoBody(failureInfo.title)
if (failureInfo.description != null) { if (failureInfo.description != null && !failureInfo.title.isAbiFailure()) {
ErrorInfoDescription( ErrorInfoDescription(
failureInfo.description, failureInfo.description,
modifier = Modifier.padding(vertical = 8.dp) modifier = Modifier.padding(vertical = 8.dp)
) )
} }
ErrorInfoActions( if (failureInfo.title.isAbiFailure()) {
extraDetails = failureInfo.extendedMessage ?: failureInfo.description, DownloadRecommendation(
modifier = Modifier needsUniversal = failureInfo.title == LaunchUtils.LauncherError.LINKER_NEEDS_64BIT,
.fillMaxWidth() modifier = Modifier
.padding(top = 8.dp, bottom = 16.dp) .fillMaxWidth()
) .padding(top = 8.dp, bottom = 16.dp)
)
} else {
ErrorInfoActions(
extraDetails = failureInfo.extendedMessage ?: failureInfo.description,
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp, bottom = 16.dp)
)
}
} }
} }
} }
@@ -782,12 +874,22 @@ fun PlayButton(
fun LaunchBlockedLabel(text: String) { fun LaunchBlockedLabel(text: String) {
val context = LocalContext.current val context = LocalContext.current
val showDownload = remember {
!GamePackageUtils.isGameInstalled(context.packageManager) ||
!GamePackageUtils.identifyGameLegitimacy(context.packageManager)
}
Column(horizontalAlignment = Alignment.CenterHorizontally) { Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text, modifier = Modifier.padding(12.dp)) Text(text, textAlign = TextAlign.Center, modifier = Modifier.padding(12.dp))
OutlinedButton(onClick = { onSettings(context) }) {
Icon(Icons.Filled.Settings, contentDescription = null) if (showDownload) {
Spacer(Modifier.size(ButtonDefaults.IconSpacing)) GooglePlayBadge()
Text(context.getString(R.string.launcher_settings)) } else {
OutlinedButton(onClick = { onSettings(context) }) {
Icon(Icons.Filled.Settings, contentDescription = null)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text(context.getString(R.string.launcher_settings))
}
} }
} }
} }
@@ -868,7 +970,11 @@ fun MainScreen(
} }
if (gdVersion < Constants.SUPPORTED_VERSION_CODE) { if (gdVersion < Constants.SUPPORTED_VERSION_CODE) {
LaunchBlockedLabel(stringResource(R.string.game_outdated)) val versionName = remember {
GamePackageUtils.getUnifiedVersionName(context.packageManager)
}
LaunchBlockedLabel(stringResource(R.string.game_outdated, versionName))
} else { } else {
val stopLaunch = releaseViewModel.isInUpdate || hasError val stopLaunch = releaseViewModel.isInUpdate || hasError
PlayButton( PlayButton(
@@ -36,6 +36,19 @@ object GamePackageUtils {
return game.versionName return game.versionName
} }
private val gameVersionMap = mapOf(
37L to "2.200",
38L to "2.205"
)
/**
* Gets the version name that more closely aligns to the Windows/macOS releases
*/
fun getUnifiedVersionName(packageManager: PackageManager): String {
val versionCode = getGameVersionCode(packageManager)
return gameVersionMap[versionCode] ?: getGameVersionString(packageManager)
}
fun detectAbiMismatch(context: Context, packageInfo: PackageInfo, loadException: Error): Boolean { fun detectAbiMismatch(context: Context, packageInfo: PackageInfo, loadException: Error): Boolean {
val abi = LaunchUtils.applicationArchitecture val abi = LaunchUtils.applicationArchitecture
val isExtracted = val isExtracted =
@@ -359,8 +359,7 @@ object GeodeUtils {
fun getGameVersion(): String { fun getGameVersion(): String {
// these versions should be aligned to windows releases, not what android says // these versions should be aligned to windows releases, not what android says
activity.get()?.run { activity.get()?.run {
val versionCode = GamePackageUtils.getGameVersionCode(packageManager) return GamePackageUtils.getUnifiedVersionName(packageManager)
return gameVersionMap[versionCode] ?: GamePackageUtils.getGameVersionString(packageManager)
} }
return "" return ""
@@ -97,7 +97,11 @@ object LaunchUtils {
LINKER_NEEDS_32BIT, LINKER_NEEDS_32BIT,
LINKER_FAILED, LINKER_FAILED,
GENERIC, GENERIC,
CRASHED CRASHED;
fun isAbiFailure(): Boolean {
return this == LINKER_NEEDS_32BIT || this == LINKER_NEEDS_64BIT
}
} }
const val LAUNCHER_KEY_RETURN_ERROR = "return_error" const val LAUNCHER_KEY_RETURN_ERROR = "return_error"
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

+6 -2
View File
@@ -11,10 +11,14 @@
<string name="launcher_logo_alt">geode logo</string> <string name="launcher_logo_alt">geode logo</string>
<string name="launcher_launch_icon_alt">play icon</string> <string name="launcher_launch_icon_alt">play icon</string>
<string name="launcher_download_icon_alt">download icon</string> <string name="launcher_download_icon_alt">download icon</string>
<string name="launcher_purchase_reminder">If you enjoy the game, please consider purchasing it for a smoother launcher experience.</string>
<string name="launcher_download_game">Download Game</string>
<string name="launcher_download_32bit">Download the 32-bit version of launcher.</string>
<string name="launcher_download_universal">Download the non 32-bit version of launcher.</string>
<string name="launcher_settings_icon_alt">settings icon</string> <string name="launcher_settings_icon_alt">settings icon</string>
<string name="launcher_retry_icon_alt">retry icon</string> <string name="launcher_retry_icon_alt">retry icon</string>
<string name="geode_download_title">Geode is not installed.</string> <string name="geode_download_title">Geode is not installed.</string>
<string name="game_outdated">A Geometry Dash update is required.</string> <string name="game_outdated">A Geometry Dash update is required.\nYou currently have version %1$s.</string>
<string name="geode_download_description">Geode is downloading. Please wait.</string> <string name="geode_download_description">Geode is downloading. Please wait.</string>
<plurals name="automatically_load_countdown"> <plurals name="automatically_load_countdown">
<item quantity="one">Automatically launching game in %1$d second.</item> <item quantity="one">Automatically launching game in %1$d second.</item>
@@ -65,7 +69,7 @@
<string name="load_failed_generic_error_description">Uncaught error during game load. Try to:</string> <string name="load_failed_generic_error_description">Uncaught error during game load. Try to:</string>
<string name="load_failed_crashed">Geode crashed</string> <string name="load_failed_crashed">Geode crashed</string>
<string name="load_failed_crashed_description">A crash was reported during the last session. Try to:</string> <string name="load_failed_crashed_description">A crash was reported during the last session. Try to:</string>
<string name="load_failed_recommendation_reinstall">Reinstall Geometry Dash from the Play Store.</string> <string name="load_failed_recommendation_reinstall">Reinstall Geometry Dash.</string>
<string name="load_failed_recommendation_switch_32bit_abi">Install the 32-bit version of the launcher.</string> <string name="load_failed_recommendation_switch_32bit_abi">Install the 32-bit version of the launcher.</string>
<string name="load_failed_recommendation_switch_64bit_abi">Install the non 32-bit version of the launcher.</string> <string name="load_failed_recommendation_switch_64bit_abi">Install the non 32-bit version of the launcher.</string>
<string name="load_failed_recommendation_update">Verify that the latest versions of the launcher and Geometry Dash are installed.</string> <string name="load_failed_recommendation_update">Verify that the latest versions of the launcher and Geometry Dash are installed.</string>