From c40210c601e40c7a808be51897c9fd670d62fc43 Mon Sep 17 00:00:00 2001 From: paulcoding810 Date: Tue, 18 Mar 2025 12:00:00 +0700 Subject: [PATCH 1/3] Check update in SettingsPage --- .../com/paulcoding/hviewer/model/Github.kt | 13 +++++ .../com/paulcoding/hviewer/network/Github.kt | 35 ++++++++++++ .../hviewer/ui/page/AppViewModel.kt | 31 +++++++++++ .../hviewer/ui/page/settings/SettingsPage.kt | 53 ++++++++++++++++++- app/src/main/res/xml/provider_paths.xml | 3 ++ 5 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/paulcoding/hviewer/model/Github.kt diff --git a/app/src/main/java/com/paulcoding/hviewer/model/Github.kt b/app/src/main/java/com/paulcoding/hviewer/model/Github.kt new file mode 100644 index 0000000..8749497 --- /dev/null +++ b/app/src/main/java/com/paulcoding/hviewer/model/Github.kt @@ -0,0 +1,13 @@ +package com.paulcoding.hviewer.model + +data class Release( + val url: String, + val id: Int, + val tag_name: String, + val assets: List, + + ) + +data class Asset( + val browser_download_url: String, +) \ No newline at end of file diff --git a/app/src/main/java/com/paulcoding/hviewer/network/Github.kt b/app/src/main/java/com/paulcoding/hviewer/network/Github.kt index 21846db..eb4ce9f 100644 --- a/app/src/main/java/com/paulcoding/hviewer/network/Github.kt +++ b/app/src/main/java/com/paulcoding/hviewer/network/Github.kt @@ -1,11 +1,14 @@ package com.paulcoding.hviewer.network +import android.content.Context import com.google.gson.Gson +import com.paulcoding.hviewer.BuildConfig import com.paulcoding.hviewer.MainApp.Companion.appContext import com.paulcoding.hviewer.R import com.paulcoding.hviewer.helper.extractTarGzFromResponseBody import com.paulcoding.hviewer.helper.log import com.paulcoding.hviewer.helper.readConfigFile +import com.paulcoding.hviewer.model.Release import com.paulcoding.hviewer.model.SiteConfigs import com.paulcoding.hviewer.preference.Preferences import io.ktor.client.call.body @@ -14,6 +17,7 @@ import io.ktor.client.statement.readRawBytes import io.ktor.http.HttpStatusCode import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import java.io.File object Github { @Throws(Exception::class) @@ -111,6 +115,37 @@ object Github { return null } } + + suspend fun checkForUpdate( + currentVersion: String, + onUpdateAvailable: (String, String) -> Unit + ) { + val (owner, repo) = parseRepo(BuildConfig.REPO_URL) + val url = "https://api.github.com/repos/${owner}/${repo}/releases/latest" + ktorClient.use { client -> + val jsonObject: Release = client.get(url).body() + val latestVersion = jsonObject.tag_name.substring(1) + val downloadUrl = jsonObject.assets[0].browser_download_url + if (latestVersion != currentVersion) { + onUpdateAvailable(latestVersion, downloadUrl) + } + } + } + + suspend fun downloadApk( + context: Context, + downloadUrl: String, + onDownloadComplete: (File) -> Unit + ) { + val file = File(context.cacheDir, "latest.apk") + ktorClient.use { client -> + val input = client.get(downloadUrl).readRawBytes().inputStream() + file.outputStream().use { output -> + input.copyTo(output) + } + } + onDownloadComplete(file) + } } diff --git a/app/src/main/java/com/paulcoding/hviewer/ui/page/AppViewModel.kt b/app/src/main/java/com/paulcoding/hviewer/ui/page/AppViewModel.kt index 37a726d..f4ebba9 100644 --- a/app/src/main/java/com/paulcoding/hviewer/ui/page/AppViewModel.kt +++ b/app/src/main/java/com/paulcoding/hviewer/ui/page/AppViewModel.kt @@ -1,5 +1,8 @@ package com.paulcoding.hviewer.ui.page +import android.content.Context +import android.content.Intent +import androidx.core.content.FileProvider import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.paulcoding.hviewer.BuildConfig @@ -66,6 +69,7 @@ class AppViewModel : ViewModel() { val siteConfigs: SiteConfigs? = appContext.readConfigFile().getOrNull(), val error: Throwable? = null, val checkingForUpdateScripts: Boolean = false, + val updatingApk: Boolean = false, ) private fun setError(throwable: Throwable) { @@ -185,4 +189,31 @@ class AppViewModel : ViewModel() { } } } + + fun checkForUpdate(currentVersion: String, onUpdateAvailable: (String, String) -> Unit) { + viewModelScope.launch { + _stateFlow.update { it.copy(updatingApk = true) } + Github.checkForUpdate(currentVersion, onUpdateAvailable) + _stateFlow.update { it.copy(updatingApk = false) } + } + } + + fun downloadAndInstallApk(context: Context, downloadUrl: String) { + viewModelScope.launch { + _stateFlow.update { it.copy(updatingApk = true) } + Github.downloadApk(context, downloadUrl) { file -> + val uri = FileProvider.getUriForFile( + context, + "${context.packageName}.fileprovider", + file + ) + val intent = Intent(Intent.ACTION_VIEW).apply { + setDataAndType(uri, "application/vnd.android.package-archive") + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION + } + context.startActivity(intent) + } + _stateFlow.update { it.copy(updatingApk = false) } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/paulcoding/hviewer/ui/page/settings/SettingsPage.kt b/app/src/main/java/com/paulcoding/hviewer/ui/page/settings/SettingsPage.kt index d010383..feec135 100644 --- a/app/src/main/java/com/paulcoding/hviewer/ui/page/settings/SettingsPage.kt +++ b/app/src/main/java/com/paulcoding/hviewer/ui/page/settings/SettingsPage.kt @@ -1,9 +1,11 @@ package com.paulcoding.hviewer.ui.page.settings import androidx.activity.ComponentActivity +import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope @@ -16,10 +18,12 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.BugReport import androidx.compose.material.icons.outlined.Description import androidx.compose.material.icons.outlined.Edit +import androidx.compose.material.icons.outlined.Update import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.LocalMinimumInteractiveComponentSize +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Switch import androidx.compose.material3.SwitchColors @@ -35,17 +39,22 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.paulcoding.hviewer.BuildConfig import com.paulcoding.hviewer.R import com.paulcoding.hviewer.extensions.setSecureScreen import com.paulcoding.hviewer.helper.makeToast import com.paulcoding.hviewer.preference.Preferences +import com.paulcoding.hviewer.ui.component.ConfirmDialog import com.paulcoding.hviewer.ui.component.H7Tap import com.paulcoding.hviewer.ui.component.HBackIcon +import com.paulcoding.hviewer.ui.component.HIcon +import com.paulcoding.hviewer.ui.component.HLoading import com.paulcoding.hviewer.ui.page.AppViewModel @OptIn(ExperimentalMaterial3Api::class) @@ -63,6 +72,8 @@ fun SettingsPage( val window = (context as ComponentActivity).window var lockModalVisible by remember { mutableStateOf(false) } var appLockEnabled by remember { mutableStateOf(Preferences.pin.isNotEmpty()) } + var newVersion by remember { mutableStateOf("") } + var downloadUrl by remember { mutableStateOf("") } val scrollState = rememberScrollState() fun onAppLockEnabled(pin: String) { @@ -147,8 +158,19 @@ fun SettingsPage( } } - H7Tap(modifier = Modifier.align(Alignment.CenterHorizontally)) { - appViewModel.setDevMode(it) + Row( + modifier = Modifier.align(Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically + ) { + H7Tap() { + appViewModel.setDevMode(it) + } + HIcon(Icons.Outlined.Update, tint = MaterialTheme.colorScheme.primary) { + appViewModel.checkForUpdate(BuildConfig.VERSION_NAME) { version, url -> + newVersion = version + downloadUrl = url + } + } } } } @@ -169,6 +191,33 @@ fun SettingsPage( if (lockModalVisible) LockModal(onDismiss = { lockModalVisible = false }) { onAppLockEnabled(it) } + + ConfirmDialog( + showDialog = newVersion.isNotEmpty(), + title = "Update Available", + text = newVersion, + confirmColor = MaterialTheme.colorScheme.primary, + dismissColor = MaterialTheme.colorScheme.onBackground, + onDismiss = { + newVersion = "" + }, + onConfirm = { + appViewModel.downloadAndInstallApk(context, downloadUrl) + newVersion = "" + } + ) + + if (appState.updatingApk) { + Box( + modifier = Modifier + .fillMaxSize() + .background(Color.Black.copy(alpha = 0.5f)) + ) { + Box(modifier = Modifier.align(Alignment.Center)) { + HLoading() + } + } + } } @Composable diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml index 4cb486c..1609c7e 100644 --- a/app/src/main/res/xml/provider_paths.xml +++ b/app/src/main/res/xml/provider_paths.xml @@ -3,4 +3,7 @@ + \ No newline at end of file From 8458195cccaff69ddab7e038c932ce28b695af39 Mon Sep 17 00:00:00 2001 From: paulcoding810 Date: Wed, 19 Mar 2025 12:00:00 +0700 Subject: [PATCH 2/3] Work to update apk --- app/src/main/AndroidManifest.xml | 6 + .../java/com/paulcoding/hviewer/Constants.kt | 2 + .../java/com/paulcoding/hviewer/MainApp.kt | 8 + .../com/paulcoding/hviewer/model/Github.kt | 11 +- .../com/paulcoding/hviewer/network/Github.kt | 9 +- .../paulcoding/hviewer/ui/page/AppEntry.kt | 6 + .../hviewer/worker/DownloadApkService.kt | 158 ++++++++++++++++++ .../com/paulcoding/hviewer/worker/Schedule.kt | 16 ++ .../hviewer/worker/UpdateApkWork.kt | 69 ++++++++ .../hviewer/worker/UpdateScriptsWork.kt | 9 +- app/src/main/res/values/strings.xml | 5 + 11 files changed, 294 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/paulcoding/hviewer/worker/DownloadApkService.kt create mode 100644 app/src/main/java/com/paulcoding/hviewer/worker/UpdateApkWork.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b08c44f..5b80e12 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ + + + + Unit - ) { + onUpdateAvailable: ((String, String) -> Unit)? = null + ): HRelease? { val (owner, repo) = parseRepo(BuildConfig.REPO_URL) val url = "https://api.github.com/repos/${owner}/${repo}/releases/latest" ktorClient.use { client -> @@ -127,8 +128,10 @@ object Github { val latestVersion = jsonObject.tag_name.substring(1) val downloadUrl = jsonObject.assets[0].browser_download_url if (latestVersion != currentVersion) { - onUpdateAvailable(latestVersion, downloadUrl) + onUpdateAvailable?.invoke(latestVersion, downloadUrl) + return HRelease(latestVersion, downloadUrl) } + return null } } diff --git a/app/src/main/java/com/paulcoding/hviewer/ui/page/AppEntry.kt b/app/src/main/java/com/paulcoding/hviewer/ui/page/AppEntry.kt index e49908d..fdbc3df 100644 --- a/app/src/main/java/com/paulcoding/hviewer/ui/page/AppEntry.kt +++ b/app/src/main/java/com/paulcoding/hviewer/ui/page/AppEntry.kt @@ -14,6 +14,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.platform.LocalContext +import androidx.core.net.toUri import androidx.navigation.NamedNavArgument import androidx.navigation.NavBackStackEntry import androidx.navigation.NavDeepLink @@ -24,6 +25,7 @@ import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument import androidx.navigation.navDeepLink +import com.paulcoding.hviewer.ACTION_INSTALL_APK import com.paulcoding.hviewer.BuildConfig import com.paulcoding.hviewer.R import com.paulcoding.hviewer.helper.makeToast @@ -100,6 +102,10 @@ fun AppEntry(intent: Intent?, appViewModel: AppViewModel) { } } + ACTION_INSTALL_APK -> { + appViewModel.installApk(context, data.toString().toUri()) + } + else -> { } } diff --git a/app/src/main/java/com/paulcoding/hviewer/worker/DownloadApkService.kt b/app/src/main/java/com/paulcoding/hviewer/worker/DownloadApkService.kt new file mode 100644 index 0000000..9d0aa03 --- /dev/null +++ b/app/src/main/java/com/paulcoding/hviewer/worker/DownloadApkService.kt @@ -0,0 +1,158 @@ +package com.paulcoding.hviewer.worker + +import android.app.Notification +import android.app.NotificationManager +import android.app.PendingIntent +import android.app.Service +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.IBinder +import androidx.core.app.NotificationCompat +import androidx.core.content.FileProvider +import com.paulcoding.hviewer.ACTION_INSTALL_APK +import com.paulcoding.hviewer.CHECK_FOR_UPDATE_APK_CHANNEL +import com.paulcoding.hviewer.MainActivity +import com.paulcoding.hviewer.R +import com.paulcoding.hviewer.model.HRelease +import com.paulcoding.hviewer.network.Github +import com.paulcoding.hviewer.ui.page.post.DownloadService +import com.paulcoding.hviewer.ui.page.post.DownloadService.Companion.ACTION_STOP_SERVICE +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlin.coroutines.CoroutineContext + +class DownloadApkService : Service() { + private lateinit var notificationManager: NotificationManager + private lateinit var notificationBuilder: NotificationCompat.Builder + + private val job = SupervisorJob() + private val coroutineContext: CoroutineContext + get() = Dispatchers.IO + job + + private val notificationId = 2 + + private fun stopService() { + job.cancel() + stopForeground(STOP_FOREGROUND_REMOVE) + stopSelf() + } + + + override fun onBind(intent: Intent?): IBinder? { + return null + } + + override fun onCreate() { + super.onCreate() + notificationManager = getSystemService(NotificationManager::class.java) + } + + override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { + if (intent.action == ACTION_STOP_SERVICE) { + stopService() + return START_NOT_STICKY + } + + val release = intent.getParcelableExtra("release") + + if (release == null) { + stopSelf() + return START_NOT_STICKY + } else { + startForeground(notificationId, createNotification()) + downloadAndInstall(this, release) + } + return START_NOT_STICKY + } + + override fun onDestroy() { + job.cancel() + super.onDestroy() + } + + + private fun downloadAndInstall(context: Context, release: HRelease) { + try { + CoroutineScope(coroutineContext).launch { + Github.downloadApk(context, release.downloadUrl) { file -> + val uri = FileProvider.getUriForFile( + context, + "${context.packageName}.fileprovider", + file + ) + showDownloadCompleteNotification(release, uri) + } + } + } catch (e: Exception) { + e.printStackTrace() + showErrorNotification(e.message ?: "Unknown error") + stopSelf() + } + } + + private fun showErrorNotification(msg: String) { + notificationBuilder + .setContentTitle(getString(R.string.error)) + .setContentText(msg) + .setSmallIcon(android.R.drawable.stat_notify_error) + .setAutoCancel(true) + + notificationManager.notify(notificationId, notificationBuilder.build()) + } + + private fun createNotification(): Notification { + val stopIntent = Intent(this, DownloadService::class.java).apply { + action = ACTION_STOP_SERVICE + } + val stopPendingIntent = + PendingIntent.getService(this, 0, stopIntent, PendingIntent.FLAG_IMMUTABLE) + + notificationBuilder = + NotificationCompat.Builder(this, CHECK_FOR_UPDATE_APK_CHANNEL) + .setContentTitle(this.getString(R.string.downloading_apk)) + .setSmallIcon(android.R.drawable.stat_sys_download) + .setPriority(NotificationCompat.PRIORITY_LOW) + .setProgress(0, 0, true) + .addAction(android.R.drawable.ic_delete, "Cancel", stopPendingIntent) + val notification = notificationBuilder.build() + notificationManager.notify(notificationId, notification) + return notification + } + + + private fun showDownloadCompleteNotification(release: HRelease, uri: Uri) { + val intent = Intent(this, MainActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + data = uri + action = ACTION_INSTALL_APK + } + val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE) + notificationBuilder + .setContentTitle(getString(R.string.install_now)) + .setContentText( + this.getString( + R.string.version_, + release.version, + ) + ) + .setSmallIcon(R.mipmap.ic_launcher_foreground) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + + notificationManager.notify(notificationId, notificationBuilder.build()) + + val completedNotification = + NotificationCompat.Builder(this, CHECK_FOR_UPDATE_APK_CHANNEL) + .setContentTitle(getString(R.string.download_complete)) + .setContentText(getString(R.string.tap_to_open)) + .setSmallIcon(android.R.drawable.stat_sys_download_done) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + .build() + + notificationManager.notify(notificationId, completedNotification) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/paulcoding/hviewer/worker/Schedule.kt b/app/src/main/java/com/paulcoding/hviewer/worker/Schedule.kt index fe39dfc..4ab9be5 100644 --- a/app/src/main/java/com/paulcoding/hviewer/worker/Schedule.kt +++ b/app/src/main/java/com/paulcoding/hviewer/worker/Schedule.kt @@ -25,6 +25,22 @@ fun scheduleScriptsUpdate(context: Context) { ) } +fun scheduleApkUpdate(context: Context) { + val constraints = Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() + val updateScriptsWorkRequest = + PeriodicWorkRequestBuilder(1, TimeUnit.DAYS) + .setConstraints(constraints) + .setInitialDelay(calculateDelayUntilMidnight(), TimeUnit.MILLISECONDS) + .build() + WorkManager.getInstance(context).enqueueUniquePeriodicWork( + "updateApk", + ExistingPeriodicWorkPolicy.KEEP, + updateScriptsWorkRequest + ) +} + fun calculateDelayUntilMidnight(): Long { val now = Calendar.getInstance() val midnight = Calendar.getInstance().apply { diff --git a/app/src/main/java/com/paulcoding/hviewer/worker/UpdateApkWork.kt b/app/src/main/java/com/paulcoding/hviewer/worker/UpdateApkWork.kt new file mode 100644 index 0000000..2c4e84c --- /dev/null +++ b/app/src/main/java/com/paulcoding/hviewer/worker/UpdateApkWork.kt @@ -0,0 +1,69 @@ +package com.paulcoding.hviewer.worker + +import android.app.NotificationManager +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import androidx.core.app.NotificationCompat +import androidx.work.CoroutineWorker +import androidx.work.Data +import androidx.work.WorkerParameters +import com.paulcoding.hviewer.BuildConfig +import com.paulcoding.hviewer.CHECK_FOR_UPDATE_APK_CHANNEL +import com.paulcoding.hviewer.R +import com.paulcoding.hviewer.model.HRelease +import com.paulcoding.hviewer.network.Github + +class UpdateApkWorker( + val context: Context, + workerParams: WorkerParameters +) : CoroutineWorker(context, workerParams) { + private val notificationId = 2 + + override suspend fun doWork(): Result { + try { + val hRelease = Github.checkForUpdate(BuildConfig.VERSION_NAME) + if (hRelease != null) { + notify(context, hRelease) + } + return Result.success() + } catch (e: Exception) { + e.printStackTrace() + val data = Data.Builder().putString("error", e.message).build() + return Result.failure(data) + } + } + + private fun notify(context: Context, release: HRelease) { + val intent = Intent(context, DownloadApkService::class.java).apply { + putExtra("release", release) + } + + val pendingIntent = + PendingIntent.getService( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + + val notificationManager = context.getSystemService(NotificationManager::class.java) + val notificationBuilder = NotificationCompat.Builder(context, CHECK_FOR_UPDATE_APK_CHANNEL) + .setContentTitle(context.getString(R.string.new_version_available)) + .setContentText( + context.getString( + R.string.version_, + release.version, + ) + ) + .setSmallIcon(R.mipmap.ic_launcher_foreground) + .addAction( + android.R.drawable.ic_media_play, + context.getString(R.string.install), pendingIntent + ) + + .setAutoCancel(false) + + notificationManager.notify(notificationId, notificationBuilder.build()) + } +} diff --git a/app/src/main/java/com/paulcoding/hviewer/worker/UpdateScriptsWork.kt b/app/src/main/java/com/paulcoding/hviewer/worker/UpdateScriptsWork.kt index 1c674df..123540e 100644 --- a/app/src/main/java/com/paulcoding/hviewer/worker/UpdateScriptsWork.kt +++ b/app/src/main/java/com/paulcoding/hviewer/worker/UpdateScriptsWork.kt @@ -13,6 +13,8 @@ import com.paulcoding.hviewer.MainActivity import com.paulcoding.hviewer.R import com.paulcoding.hviewer.network.Github import com.paulcoding.hviewer.network.SiteConfigsState +import java.time.LocalDateTime +import kotlin.random.Random class UpdateScriptsWorker( val context: Context, @@ -60,7 +62,12 @@ class UpdateScriptsWorker( notificationManager.notify(1, notificationBuilder.build()) } - else -> {} + else -> { + notificationBuilder + .setContentTitle("Up to date") + .setContentText(LocalDateTime.now().toString()) + notificationManager.notify(Random.nextInt(2, 100), notificationBuilder.build()) + } } } } \ 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 c7ebf66..d4eb138 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -47,4 +47,9 @@ Branch Clear history Are you sure you want to clear history? + New version available + Downloading APK + Install now + Error + Install \ No newline at end of file From c1ff6325ae802f97d6a57eaa8ad733ddc6f5f02e Mon Sep 17 00:00:00 2001 From: paulcoding810 Date: Thu, 20 Mar 2025 17:15:12 +0700 Subject: [PATCH 3/3] Toast on up to date * Update confirm dialog button texts --- .../com/paulcoding/hviewer/network/Github.kt | 2 +- .../hviewer/ui/component/ConfirmDialog.kt | 6 +++-- .../hviewer/ui/page/AppViewModel.kt | 27 ++++++++++++++----- .../hviewer/ui/page/settings/SettingsPage.kt | 15 +++++++---- app/src/main/res/values/strings.xml | 3 ++- 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/paulcoding/hviewer/network/Github.kt b/app/src/main/java/com/paulcoding/hviewer/network/Github.kt index ca900c3..84af0e1 100644 --- a/app/src/main/java/com/paulcoding/hviewer/network/Github.kt +++ b/app/src/main/java/com/paulcoding/hviewer/network/Github.kt @@ -159,7 +159,7 @@ sealed class SiteConfigsState { fun getToastMessage() = when (this) { is NewConfigsInstall -> R.string.scripts_installed - is UpToDate -> R.string.up_to_Date + is UpToDate -> R.string.up_to_date is Updated -> R.string.scripts_updated } } \ No newline at end of file diff --git a/app/src/main/java/com/paulcoding/hviewer/ui/component/ConfirmDialog.kt b/app/src/main/java/com/paulcoding/hviewer/ui/component/ConfirmDialog.kt index a2ec6d5..1c834da 100644 --- a/app/src/main/java/com/paulcoding/hviewer/ui/component/ConfirmDialog.kt +++ b/app/src/main/java/com/paulcoding/hviewer/ui/component/ConfirmDialog.kt @@ -17,6 +17,8 @@ fun ConfirmDialog( text: String = "", confirmColor: Color? = null, dismissColor: Color? = null, + confirmText: String? = null, + dismissText: String? = null, onDismiss: () -> Unit, onConfirm: () -> Unit ) { @@ -28,7 +30,7 @@ fun ConfirmDialog( confirmButton = { TextButton(onClick = { onConfirm() }) { Text( - stringResource(R.string.confirm), + confirmText ?: stringResource(R.string.confirm), color = confirmColor ?: MaterialTheme.colorScheme.error ) } @@ -36,7 +38,7 @@ fun ConfirmDialog( dismissButton = { TextButton(onClick = { onDismiss() }) { Text( - stringResource(R.string.cancel), + dismissText ?: stringResource(R.string.cancel), color = dismissColor ?: MaterialTheme.colorScheme.onBackground ) } diff --git a/app/src/main/java/com/paulcoding/hviewer/ui/page/AppViewModel.kt b/app/src/main/java/com/paulcoding/hviewer/ui/page/AppViewModel.kt index f4ebba9..99bf911 100644 --- a/app/src/main/java/com/paulcoding/hviewer/ui/page/AppViewModel.kt +++ b/app/src/main/java/com/paulcoding/hviewer/ui/page/AppViewModel.kt @@ -2,6 +2,7 @@ package com.paulcoding.hviewer.ui.page import android.content.Context import android.content.Intent +import android.net.Uri import androidx.core.content.FileProvider import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -190,10 +191,18 @@ class AppViewModel : ViewModel() { } } - fun checkForUpdate(currentVersion: String, onUpdateAvailable: (String, String) -> Unit) { + fun checkForUpdate( + currentVersion: String, + onUpToDate: () -> Unit, + onUpdateAvailable: (String, String) -> Unit + ) { viewModelScope.launch { _stateFlow.update { it.copy(updatingApk = true) } - Github.checkForUpdate(currentVersion, onUpdateAvailable) + val release = Github.checkForUpdate(currentVersion) + if (release != null) + onUpdateAvailable(release.version, release.downloadUrl) + else + onUpToDate() _stateFlow.update { it.copy(updatingApk = false) } } } @@ -207,13 +216,17 @@ class AppViewModel : ViewModel() { "${context.packageName}.fileprovider", file ) - val intent = Intent(Intent.ACTION_VIEW).apply { - setDataAndType(uri, "application/vnd.android.package-archive") - flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION - } - context.startActivity(intent) + installApk(context, uri) } _stateFlow.update { it.copy(updatingApk = false) } } } + + fun installApk(context: Context, uri: Uri) { + val intent = Intent(Intent.ACTION_VIEW).apply { + setDataAndType(uri, "application/vnd.android.package-archive") + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION + } + context.startActivity(intent) + } } \ No newline at end of file diff --git a/app/src/main/java/com/paulcoding/hviewer/ui/page/settings/SettingsPage.kt b/app/src/main/java/com/paulcoding/hviewer/ui/page/settings/SettingsPage.kt index feec135..4b733f8 100644 --- a/app/src/main/java/com/paulcoding/hviewer/ui/page/settings/SettingsPage.kt +++ b/app/src/main/java/com/paulcoding/hviewer/ui/page/settings/SettingsPage.kt @@ -166,10 +166,14 @@ fun SettingsPage( appViewModel.setDevMode(it) } HIcon(Icons.Outlined.Update, tint = MaterialTheme.colorScheme.primary) { - appViewModel.checkForUpdate(BuildConfig.VERSION_NAME) { version, url -> - newVersion = version - downloadUrl = url - } + appViewModel.checkForUpdate(BuildConfig.VERSION_NAME, + onUpToDate = { + makeToast(R.string.up_to_date) + }, + onUpdateAvailable = { version, url -> + newVersion = version + downloadUrl = url + }) } } } @@ -194,9 +198,10 @@ fun SettingsPage( ConfirmDialog( showDialog = newVersion.isNotEmpty(), - title = "Update Available", + title = stringResource(R.string.update_available), text = newVersion, confirmColor = MaterialTheme.colorScheme.primary, + confirmText = stringResource(R.string.install_now), dismissColor = MaterialTheme.colorScheme.onBackground, onDismiss = { newVersion = "" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d4eb138..90815a8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -42,7 +42,7 @@ Version %1$s Scripts Installed From repo %1$s - Up to date + Up to date https://github.com/paulcoding810/h-viewer-scripts Branch Clear history @@ -52,4 +52,5 @@ Install now Error Install + Update Available \ No newline at end of file