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 @@
+
+
+
+
,
+
+ )
+
+data class Asset(
+ val browser_download_url: String,
+)
+
+@Parcelize
+data class HRelease(
+ val version: String,
+ val downloadUrl: String
+) : Parcelable
\ 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..84af0e1 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,15 @@
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.HRelease
+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 +18,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 +116,39 @@ object Github {
return null
}
}
+
+ suspend fun checkForUpdate(
+ currentVersion: String,
+ 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 ->
+ 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?.invoke(latestVersion, downloadUrl)
+ return HRelease(latestVersion, downloadUrl)
+ }
+ return null
+ }
+ }
+
+ 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)
+ }
}
@@ -121,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/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/ui/page/AppViewModel.kt b/app/src/main/java/com/paulcoding/hviewer/ui/page/AppViewModel.kt
index 37a726d..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
@@ -1,5 +1,9 @@
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
import com.paulcoding.hviewer.BuildConfig
@@ -66,6 +70,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 +190,43 @@ class AppViewModel : ViewModel() {
}
}
}
+
+ fun checkForUpdate(
+ currentVersion: String,
+ onUpToDate: () -> Unit,
+ onUpdateAvailable: (String, String) -> Unit
+ ) {
+ viewModelScope.launch {
+ _stateFlow.update { it.copy(updatingApk = true) }
+ val release = Github.checkForUpdate(currentVersion)
+ if (release != null)
+ onUpdateAvailable(release.version, release.downloadUrl)
+ else
+ onUpToDate()
+ _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
+ )
+ 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 d010383..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
@@ -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,23 @@ 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,
+ onUpToDate = {
+ makeToast(R.string.up_to_date)
+ },
+ onUpdateAvailable = { version, url ->
+ newVersion = version
+ downloadUrl = url
+ })
+ }
}
}
}
@@ -169,6 +195,34 @@ fun SettingsPage(
if (lockModalVisible) LockModal(onDismiss = { lockModalVisible = false }) {
onAppLockEnabled(it)
}
+
+ ConfirmDialog(
+ showDialog = newVersion.isNotEmpty(),
+ title = stringResource(R.string.update_available),
+ text = newVersion,
+ confirmColor = MaterialTheme.colorScheme.primary,
+ confirmText = stringResource(R.string.install_now),
+ 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/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..90815a8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -42,9 +42,15 @@
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
Are you sure you want to clear history?
+ New version available
+ Downloading APK
+ Install now
+ Error
+ Install
+ Update Available
\ No newline at end of file
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