Skip to content

Commit a687f84

Browse files
committed
make updater abstract
1 parent b409a20 commit a687f84

File tree

8 files changed

+188
-66
lines changed

8 files changed

+188
-66
lines changed

app/src/main/java/com/geode/launcher/AltMainActivity.kt

+6-4
Original file line numberDiff line numberDiff line change
@@ -185,16 +185,18 @@ fun mapLaunchStatusToInfo(state: LaunchViewModel.LaunchUIState, inSafeMode: Bool
185185
}
186186

187187
val outOf = remember(state.outOf) {
188-
Formatter.formatShortFileSize(context, state.outOf)
188+
state.outOf?.apply {
189+
Formatter.formatShortFileSize(context, this)
190+
}
189191
}
190192

191193
LaunchStatusInfo(
192194
title = stringResource(R.string.launcher_downloading_update),
193-
details = stringResource(R.string.launcher_downloading_update_details, downloaded, outOf),
195+
details = stringResource(R.string.launcher_downloading_update_details, downloaded, outOf ?: ""),
194196
progress = {
195-
val progress = state.downloaded / state.outOf.toDouble()
197+
val progress = state.downloaded / state.outOf!!.toDouble()
196198
progress.toFloat()
197-
}
199+
}.takeIf { state.outOf != null }
198200
)
199201
}
200202
is LaunchViewModel.LaunchUIState.Cancelled -> {

app/src/main/java/com/geode/launcher/main/LaunchViewModel.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class LaunchViewModel(private val application: Application): ViewModel() {
7070
sealed class LaunchUIState {
7171
data object Initial : LaunchUIState()
7272
data object UpdateCheck : LaunchUIState()
73-
data class Updating(val downloaded: Long, val outOf: Long) : LaunchUIState()
73+
data class Updating(val downloaded: Long, val outOf: Long?) : LaunchUIState()
7474
data class Cancelled(val reason: LaunchCancelReason, val inProgress: Boolean = false) : LaunchUIState()
7575
data object Working : LaunchUIState()
7676
data object Ready : LaunchUIState()

app/src/main/java/com/geode/launcher/main/UpdateComponents.kt

+8-6
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,10 @@ fun generateInstallIntent(uri: Uri): Intent {
7373

7474
fun installLauncherUpdate(context: Context) {
7575
val nextUpdate = ReleaseManager.get(context).availableLauncherUpdate.value
76-
val launcherDownload = nextUpdate?.getLauncherDownload()
76+
val launcherDownload = nextUpdate?.getDownload()
7777

7878
if (launcherDownload != null) {
79-
val outputFile = launcherDownload.name
79+
val outputFile = launcherDownload.filename
8080
val baseDirectory = LaunchUtils.getBaseDirectory(context)
8181

8282
val outputPathFile = File(baseDirectory, outputFile)
@@ -237,21 +237,23 @@ fun UpdateCard(releaseViewModel: ReleaseViewModel, modifier: Modifier = Modifier
237237
}
238238

239239
val outOf = remember(state.outOf) {
240-
Formatter.formatShortFileSize(context, state.outOf)
240+
state.outOf?.run {
241+
Formatter.formatShortFileSize(context, this)
242+
}
241243
}
242244

243245
UpdateProgressIndicator(
244246
stringResource(
245247
R.string.release_fetch_downloading,
246248
downloaded,
247-
outOf
249+
outOf ?: ""
248250
),
249251
modifier = modifier,
250252
releaseViewModel = releaseViewModel,
251253
progress = {
252-
val progress = state.downloaded / state.outOf.toDouble()
254+
val progress = state.downloaded / state.outOf!!.toDouble()
253255
progress.toFloat()
254-
}
256+
}.takeIf { state.outOf != null }
255257
)
256258
}
257259
is ReleaseViewModel.ReleaseUIState.InUpdateCheck -> {

app/src/main/java/com/geode/launcher/preferences/SettingsActivity.kt

+10-5
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,16 @@ fun UpdateIndicator(
151151
is ReleaseViewModel.ReleaseUIState.InDownload -> {
152152
// is this the ideal design? idk
153153
enablePopup = true
154-
val progress = updateStatus.downloaded / updateStatus.outOf.toDouble()
155-
156-
CircularProgressIndicator(
157-
progress = { progress.toFloat() },
158-
)
154+
if (updateStatus.outOf != null) {
155+
CircularProgressIndicator(
156+
progress = {
157+
val progress = updateStatus.downloaded / updateStatus.outOf.toDouble()
158+
progress.toFloat()
159+
},
160+
)
161+
} else {
162+
CircularProgressIndicator()
163+
}
159164
}
160165
else -> {}
161166
}

app/src/main/java/com/geode/launcher/updater/Release.kt

+83-12
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ data class Asset(
1616
)
1717

1818
@Serializable
19-
class Release(
19+
data class Release(
2020
val url: String,
2121
val id: Int,
2222
val targetCommitish: String,
@@ -25,39 +25,83 @@ class Release(
2525
val publishedAt: Instant,
2626
val assets: List<Asset>,
2727
val htmlUrl: String
28-
) {
29-
fun getDescription(): String {
30-
if (tagName == "nightly") {
28+
)
29+
30+
@Serializable
31+
data class LoaderVersion(
32+
val tag: String,
33+
val version: String,
34+
val createdAt: Instant,
35+
val commitHash: String,
36+
val prerelease: Boolean
37+
)
38+
39+
@Serializable
40+
data class LoaderPayload<T>(
41+
val payload: T?,
42+
val error: String
43+
)
44+
45+
data class DownloadableAsset(val url: String, val filename: String, val size: Long? = null)
46+
47+
abstract class Downloadable {
48+
abstract fun getDescription(): String
49+
abstract fun getDescriptor(): Long
50+
abstract fun getDownload(): DownloadableAsset?
51+
}
52+
53+
class DownloadableGitHubLoaderRelease(private val release: Release) : Downloadable() {
54+
override fun getDescription(): String {
55+
if (release.tagName == "nightly") {
3156
// get the commit from the assets
3257
// otherwise, a separate request is needed to get the hash (ew)
33-
val asset = assets.first()
58+
val asset = release.assets.first()
3459
val commit = asset.name.substring(6..12)
3560

3661
return "nightly-$commit"
3762
}
3863

39-
return tagName
64+
return release.tagName
4065
}
4166

42-
fun getDescriptor(): Long {
43-
return createdAt.epochSeconds
67+
override fun getDescriptor(): Long {
68+
return release.createdAt.epochSeconds
4469
}
4570

46-
fun getGeodeDownload(): Asset? {
71+
private fun getGitHubDownload(): Asset? {
4772
// try to find an asset that matches the architecture first
4873
val platform = LaunchUtils.platformName
4974

5075
val releaseSuffix = "$platform.zip"
51-
return assets.find {
76+
return release.assets.find {
5277
it.name.endsWith(releaseSuffix)
5378
}
5479
}
5580

56-
fun getLauncherDownload(): Asset? {
81+
override fun getDownload(): DownloadableAsset? {
82+
val download = getGitHubDownload() ?: return null
83+
return DownloadableAsset(
84+
url = download.browserDownloadUrl,
85+
filename = download.name,
86+
size = download.size.toLong()
87+
)
88+
}
89+
}
90+
91+
class DownloadableLauncherRelease(val release: Release) : Downloadable() {
92+
override fun getDescription(): String {
93+
return release.tagName
94+
}
95+
96+
override fun getDescriptor(): Long {
97+
return release.createdAt.epochSeconds
98+
}
99+
100+
private fun getGitHubDownload(): Asset? {
57101
val platform = LaunchUtils.platformName
58102
val use32BitPlatform = platform == "android32"
59103

60-
return assets.find { asset ->
104+
return release.assets.find { asset ->
61105
/* you know it's good when you pull out the truth table
62106
* u32bp | contains | found
63107
* 1 | 1 | 1
@@ -70,4 +114,31 @@ class Release(
70114
(asset.name.contains("android32")) == use32BitPlatform
71115
}
72116
}
117+
118+
override fun getDownload(): DownloadableAsset? {
119+
val download = getGitHubDownload() ?: return null
120+
return DownloadableAsset(
121+
url = download.browserDownloadUrl,
122+
filename = download.name,
123+
size = download.size.toLong()
124+
)
125+
}
126+
}
127+
128+
class DownloadableLoaderRelease(private val version: LoaderVersion) : Downloadable() {
129+
override fun getDescription(): String {
130+
return version.tag
131+
}
132+
133+
override fun getDescriptor(): Long {
134+
return version.createdAt.epochSeconds
135+
}
136+
137+
override fun getDownload(): DownloadableAsset? {
138+
val filename = "geode-${version.tag}-${LaunchUtils.platformName}.zip"
139+
return DownloadableAsset(
140+
url = "https://github.com/geode-sdk/geode/releases/download/${version.tag}/$filename",
141+
filename = filename
142+
)
143+
}
73144
}

app/src/main/java/com/geode/launcher/updater/ReleaseManager.kt

+24-27
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class ReleaseManager private constructor(
6161
sealed class ReleaseManagerState {
6262
data object InUpdateCheck : ReleaseManagerState()
6363
data class Failure(val exception: Exception) : ReleaseManagerState()
64-
data class InDownload(val downloaded: Long, val outOf: Long) : ReleaseManagerState()
64+
data class InDownload(val downloaded: Long, val outOf: Long?) : ReleaseManagerState()
6565
data class Finished(val hasUpdated: Boolean = false) : ReleaseManagerState()
6666
}
6767

@@ -82,7 +82,7 @@ class ReleaseManager private constructor(
8282
val isInUpdate: Boolean
8383
get() = _uiState.value !is ReleaseManagerState.Failure && _uiState.value !is ReleaseManagerState.Finished
8484

85-
private val _availableLauncherUpdate = MutableStateFlow<Release?>(null)
85+
private val _availableLauncherUpdate = MutableStateFlow<DownloadableLauncherRelease?>(null)
8686
val availableLauncherUpdate = _availableLauncherUpdate.asStateFlow()
8787

8888
private fun sendError(e: Exception) {
@@ -106,24 +106,21 @@ class ReleaseManager private constructor(
106106
}
107107
}
108108

109-
private fun getBestReleaseForGameVersion(): String? {
109+
private fun getBestReleaseForGameVersion(gameVersion: Long): String? = when {
110+
gameVersion >= 40L -> mapSelectedReleaseToTag()
111+
gameVersion == 39L -> "v3.9.2"
112+
gameVersion == 38L -> "v2.0.0-beta.27"
113+
gameVersion == 37L -> "v2.0.0-beta.4"
114+
else -> null
115+
}
116+
117+
private suspend fun getLatestRelease(): Downloadable? {
110118
if (!GamePackageUtils.isGameInstalled(applicationContext.packageManager)) {
111119
return null
112120
}
113121

114122
val gameVersion = GamePackageUtils.getGameVersionCode(applicationContext.packageManager)
115-
116-
return when {
117-
gameVersion >= 40L -> mapSelectedReleaseToTag()
118-
gameVersion == 39L -> "v3.9.2"
119-
gameVersion == 38L -> "v2.0.0-beta.27"
120-
gameVersion == 37L -> "v2.0.0-beta.4"
121-
else -> null
122-
}
123-
}
124-
125-
private suspend fun getLatestRelease(): Release? {
126-
val targetTag = getBestReleaseForGameVersion() ?: return null
123+
val targetTag = getBestReleaseForGameVersion(gameVersion) ?: return null
127124

128125
return when (targetTag) {
129126
TAG_LATEST -> releaseRepository.getLatestGeodeRelease()
@@ -132,23 +129,23 @@ class ReleaseManager private constructor(
132129
}
133130
}
134131

135-
private suspend fun downloadLauncherUpdate(release: Release) {
136-
val download = release.getLauncherDownload() ?: return
132+
private suspend fun downloadLauncherUpdate(release: Downloadable) {
133+
val download = release.getDownload() ?: return
137134

138135
val outputDirectory = LaunchUtils.getBaseDirectory(applicationContext)
139-
val outputFile = File(outputDirectory, download.name)
136+
val outputFile = File(outputDirectory, download.filename)
140137

141138
if (outputFile.exists()) {
142139
// only download the apk once
143140
return
144141
}
145142

146-
_uiState.value = ReleaseManagerState.InDownload(0, download.size.toLong())
143+
_uiState.value = ReleaseManagerState.InDownload(0, download.size)
147144

148145
try {
149146
val fileStream = DownloadUtils.downloadStream(
150147
httpClient,
151-
download.browserDownloadUrl
148+
download.url
152149
) { progress, outOf ->
153150
_uiState.value = ReleaseManagerState.InDownload(progress, outOf)
154151
}
@@ -160,8 +157,8 @@ class ReleaseManager private constructor(
160157
}
161158
}
162159

163-
private suspend fun performUpdate(release: Release) {
164-
val releaseAsset = release.getGeodeDownload()
160+
private suspend fun performUpdate(release: Downloadable) {
161+
val releaseAsset = release.getDownload()
165162
if (releaseAsset == null) {
166163
val noAssetException = Exception("missing Android download")
167164
_uiState.value = ReleaseManagerState.Failure(noAssetException)
@@ -170,12 +167,12 @@ class ReleaseManager private constructor(
170167
}
171168

172169
// set an initial download size
173-
_uiState.value = ReleaseManagerState.InDownload(0, releaseAsset.size.toLong())
170+
_uiState.value = ReleaseManagerState.InDownload(0, releaseAsset.size)
174171

175172
try {
176173
val fileStream = DownloadUtils.downloadStream(
177174
httpClient,
178-
releaseAsset.browserDownloadUrl
175+
releaseAsset.url
179176
) { progress, outOf ->
180177
_uiState.value = ReleaseManagerState.InDownload(progress, outOf)
181178
}
@@ -223,8 +220,8 @@ class ReleaseManager private constructor(
223220
return originalFileHash != currentFileHash
224221
}
225222

226-
private fun checkLauncherUpdate(launcherUpdate: Release) {
227-
if (launcherUpdate.tagName != BuildConfig.VERSION_NAME) {
223+
private fun checkLauncherUpdate(launcherUpdate: DownloadableLauncherRelease) {
224+
if (launcherUpdate.release.tagName != BuildConfig.VERSION_NAME) {
228225
_availableLauncherUpdate.value = launcherUpdate
229226
}
230227
}
@@ -286,7 +283,7 @@ class ReleaseManager private constructor(
286283
performUpdate(release)
287284
}
288285

289-
private fun updatePreferences(release: Release) {
286+
private fun updatePreferences(release: Downloadable) {
290287
val sharedPreferences = PreferenceUtils.get(applicationContext)
291288

292289
sharedPreferences.setString(

0 commit comments

Comments
 (0)