mirror of
https://github.com/bbara04/Purefin.git
synced 2026-07-24 03:36:51 +00:00
refactor(app): refactor update logic to make core logic more reusable by moving it into the core.feature.update package
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
package hu.bbara.purefin.feature.update
|
||||
|
||||
data class AppUpdateInfo(
|
||||
val versionCode: Long,
|
||||
val versionName: String?,
|
||||
val releaseNotes: String?,
|
||||
val apkUrl: String,
|
||||
val manifestUrl: String
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
package hu.bbara.purefin.feature.update
|
||||
|
||||
interface AppUpdateInstaller {
|
||||
suspend fun installUpdate(update: AppUpdateInfo): String
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package hu.bbara.purefin.feature.update
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import javax.inject.Inject
|
||||
|
||||
class AppUpdateRepository @Inject constructor(
|
||||
private val appVersionProvider: AppVersionProvider
|
||||
) {
|
||||
private val client = OkHttpClient()
|
||||
private val json = Json { ignoreUnknownKeys = true }
|
||||
|
||||
suspend fun checkForUpdate(): AppUpdateInfo? {
|
||||
val manifestUrl = "http://purefin.t.bbara.hu/app/update.json"
|
||||
if (manifestUrl.isBlank()) {
|
||||
throw IllegalStateException("Update manifest URL not configured")
|
||||
}
|
||||
|
||||
val manifest = withContext(Dispatchers.IO) { fetchManifest(manifestUrl) }
|
||||
if (manifest.versionCode <= appVersionProvider.versionCode) {
|
||||
return null
|
||||
}
|
||||
|
||||
return AppUpdateInfo(
|
||||
versionCode = manifest.versionCode,
|
||||
versionName = manifest.versionName,
|
||||
releaseNotes = manifest.releaseNotes,
|
||||
apkUrl = manifest.apkUrl,
|
||||
manifestUrl = manifestUrl
|
||||
)
|
||||
}
|
||||
|
||||
private fun fetchManifest(manifestUrl: String): AppUpdateManifest {
|
||||
val request = Request.Builder()
|
||||
.url(manifestUrl)
|
||||
.build()
|
||||
client.newCall(request).execute().use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
throw IllegalStateException("Update check failed: HTTP ${response.code}")
|
||||
}
|
||||
val body = response.body?.string() ?: throw IllegalStateException("Update manifest empty")
|
||||
return json.decodeFromString<AppUpdateManifest>(body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
private data class AppUpdateManifest(
|
||||
val versionCode: Long,
|
||||
val versionName: String? = null,
|
||||
val apkUrl: String,
|
||||
val releaseNotes: String? = null
|
||||
)
|
||||
@@ -0,0 +1,76 @@
|
||||
package hu.bbara.purefin.feature.update
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class AppUpdateViewModel @Inject constructor(
|
||||
private val appUpdateRepository: AppUpdateRepository,
|
||||
private val appUpdateInstaller: AppUpdateInstaller
|
||||
) : ViewModel() {
|
||||
|
||||
private val _isCheckingForUpdates = MutableStateFlow(false)
|
||||
val isCheckingForUpdates: StateFlow<Boolean> = _isCheckingForUpdates.asStateFlow()
|
||||
|
||||
private val _availableUpdate = MutableStateFlow<AppUpdateInfo?>(null)
|
||||
val availableUpdate: StateFlow<AppUpdateInfo?> = _availableUpdate.asStateFlow()
|
||||
|
||||
private val _snackbarMessages = MutableSharedFlow<String>()
|
||||
val snackbarMessages: SharedFlow<String> = _snackbarMessages.asSharedFlow()
|
||||
|
||||
private var isInstallingUpdate = false
|
||||
|
||||
fun checkForUpdates() {
|
||||
if (_isCheckingForUpdates.value) {
|
||||
return
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
_isCheckingForUpdates.value = true
|
||||
try {
|
||||
val update = appUpdateRepository.checkForUpdate()
|
||||
if (update == null) {
|
||||
_snackbarMessages.emit("Purefin is up to date")
|
||||
} else {
|
||||
_availableUpdate.value = update
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
_snackbarMessages.emit(e.message ?: "Update check failed")
|
||||
} finally {
|
||||
_isCheckingForUpdates.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun acceptUpdate() {
|
||||
val update = _availableUpdate.value ?: return
|
||||
if (isInstallingUpdate) {
|
||||
return
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
isInstallingUpdate = true
|
||||
_availableUpdate.value = null
|
||||
try {
|
||||
_snackbarMessages.emit(appUpdateInstaller.installUpdate(update))
|
||||
} catch (e: Exception) {
|
||||
_snackbarMessages.emit(e.message ?: "Update install failed")
|
||||
} finally {
|
||||
isInstallingUpdate = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun declineUpdate() {
|
||||
_availableUpdate.value = null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package hu.bbara.purefin.feature.update
|
||||
|
||||
interface AppVersionProvider {
|
||||
val versionCode: Long
|
||||
}
|
||||
Reference in New Issue
Block a user