mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-10 06:42:05 +01:00
Add update checker
This commit is contained in:
1
.github/workflows/Preview.yml
vendored
1
.github/workflows/Preview.yml
vendored
@@ -86,6 +86,7 @@ jobs:
|
||||
-Pcompose.desktop.mac.notarization.appleID=${{ secrets.APPLE_ID }}
|
||||
-Pcompose.desktop.mac.notarization.password=${{ secrets.APPLE_PASSWORD }}
|
||||
-Pidentity="${{ secrets.APPLE_IDENTITY }}"
|
||||
-Ppreview="${{ env.COMMIT_COUNT }}"
|
||||
--stacktrace
|
||||
|
||||
# Upload runner package tar.gz/zip as artifact
|
||||
|
||||
@@ -230,9 +230,11 @@ buildConfig {
|
||||
buildConfigField("String", "NAME", project.name.wrap())
|
||||
buildConfigField("String", "VERSION", project.version.toString().wrap())
|
||||
buildConfigField("int", "MIGRATION_CODE", migrationCode.toString())
|
||||
buildConfigField("boolean", "DEBUG", project.hasProperty("debugApp").toString())
|
||||
buildConfigField("boolean", "IS_PREVIEW", project.hasProperty("preview").toString())
|
||||
buildConfigField("int", "PREVIEW_BUILD", project.properties["preview"]?.toString() ?: 0.toString())
|
||||
|
||||
// Tachidesk
|
||||
buildConfigField("boolean", "DEBUG", project.hasProperty("debugApp").toString())
|
||||
buildConfigField("String", "TACHIDESK_SP_VERSION", tachideskVersion.wrap())
|
||||
buildConfigField("int", "SERVER_CODE", serverCode.toString())
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ import ca.gosyer.data.server.interactions.SourceInteractionHandler
|
||||
import ca.gosyer.data.translation.ResourceProvider
|
||||
import ca.gosyer.data.translation.XmlResourceBundle
|
||||
import ca.gosyer.data.ui.UiPreferences
|
||||
import ca.gosyer.data.update.UpdateChecker
|
||||
import ca.gosyer.data.update.UpdatePreferences
|
||||
import io.kamel.core.config.KamelConfig
|
||||
import toothpick.ktp.binding.bind
|
||||
import toothpick.ktp.binding.module
|
||||
@@ -71,6 +73,10 @@ val DataModule = module {
|
||||
.toProviderInstance { MigrationPreferences(preferenceFactory.create("migration")) }
|
||||
.providesSingleton()
|
||||
|
||||
bind<UpdatePreferences>()
|
||||
.toProviderInstance { UpdatePreferences(preferenceFactory.create("update")) }
|
||||
.providesSingleton()
|
||||
|
||||
bind<Http>()
|
||||
.toProvider(HttpProvider::class)
|
||||
.providesSingleton()
|
||||
@@ -114,4 +120,7 @@ val DataModule = module {
|
||||
bind<Migrations>()
|
||||
.toClass<Migrations>()
|
||||
.singleton()
|
||||
bind<UpdateChecker>()
|
||||
.toClass<UpdateChecker>()
|
||||
.singleton()
|
||||
}
|
||||
|
||||
61
src/main/kotlin/ca/gosyer/data/update/UpdateChecker.kt
Normal file
61
src/main/kotlin/ca/gosyer/data/update/UpdateChecker.kt
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.data.update
|
||||
|
||||
import ca.gosyer.build.BuildConfig
|
||||
import ca.gosyer.data.server.Http
|
||||
import ca.gosyer.data.update.model.GithubRelease
|
||||
import ca.gosyer.util.lang.launch
|
||||
import ca.gosyer.util.lang.withIOContext
|
||||
import io.ktor.client.request.get
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
class UpdateChecker @Inject constructor(
|
||||
private val updatePreferences: UpdatePreferences,
|
||||
private val client: Http
|
||||
) {
|
||||
val updateFound = MutableSharedFlow<GithubRelease>()
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun checkForUpdates() {
|
||||
if (!updatePreferences.enabled().get()) return
|
||||
launch {
|
||||
val latestRelease = withIOContext {
|
||||
client.get<GithubRelease>("https://api.github.com/repos/$GITHUB_REPO/releases/latest")
|
||||
}
|
||||
if (isNewVersion(latestRelease.version)) {
|
||||
updateFound.emit(latestRelease)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Thanks to Tachiyomi for inspiration
|
||||
private fun isNewVersion(versionTag: String): Boolean {
|
||||
// Removes prefixes like "r" or "v"
|
||||
val newVersion = versionTag.replace("[^\\d.]".toRegex(), "")
|
||||
|
||||
return if (BuildConfig.IS_PREVIEW) {
|
||||
// Preview builds: based on releases in "Suwayomi/Tachidesk-JUI-preview" repo
|
||||
// tagged as something like "r123"
|
||||
newVersion.toInt() > BuildConfig.PREVIEW_BUILD
|
||||
} else {
|
||||
// Release builds: based on releases in "Suwayomi/Tachidesk-JUI" repo
|
||||
// tagged as something like "v1.1.2"
|
||||
newVersion != BuildConfig.VERSION
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val GITHUB_REPO = if (BuildConfig.IS_PREVIEW) {
|
||||
"Suwayomi/Tachidesk-JUI-preview"
|
||||
} else {
|
||||
"Suwayomi/Tachidesk-JUI"
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/main/kotlin/ca/gosyer/data/update/UpdatePreferences.kt
Normal file
16
src/main/kotlin/ca/gosyer/data/update/UpdatePreferences.kt
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.data.update
|
||||
|
||||
import ca.gosyer.common.prefs.Preference
|
||||
import ca.gosyer.common.prefs.PreferenceStore
|
||||
|
||||
class UpdatePreferences(private val preferenceStore: PreferenceStore) {
|
||||
fun enabled(): Preference<Boolean> {
|
||||
return preferenceStore.getBoolean("enabled", true)
|
||||
}
|
||||
}
|
||||
17
src/main/kotlin/ca/gosyer/data/update/model/GithubRelease.kt
Normal file
17
src/main/kotlin/ca/gosyer/data/update/model/GithubRelease.kt
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.data.update.model
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class GithubRelease(
|
||||
@SerialName("tag_name") val version: String,
|
||||
@SerialName("body") val info: String,
|
||||
@SerialName("html_url") val releaseLink: String
|
||||
)
|
||||
@@ -12,6 +12,7 @@ import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -21,6 +22,7 @@ import androidx.compose.ui.input.key.KeyEventType
|
||||
import androidx.compose.ui.input.key.key
|
||||
import androidx.compose.ui.input.key.type
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.window.Notification
|
||||
import androidx.compose.ui.window.Tray
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.awaitApplication
|
||||
@@ -35,6 +37,7 @@ import ca.gosyer.data.server.ServerService.ServerResult
|
||||
import ca.gosyer.data.translation.XmlResourceBundle
|
||||
import ca.gosyer.data.ui.UiPreferences
|
||||
import ca.gosyer.data.ui.model.ThemeMode
|
||||
import ca.gosyer.data.update.UpdateChecker
|
||||
import ca.gosyer.ui.base.WindowDialog
|
||||
import ca.gosyer.ui.base.components.LoadingScreen
|
||||
import ca.gosyer.ui.base.prefs.asStateIn
|
||||
@@ -55,7 +58,9 @@ import io.kamel.image.config.LocalKamelConfig
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.skiko.SystemTheme
|
||||
import org.jetbrains.skiko.currentSystemTheme
|
||||
import toothpick.configuration.Configuration
|
||||
@@ -89,6 +94,7 @@ suspend fun main() {
|
||||
|
||||
val serverService = scope.getInstance<ServerService>()
|
||||
val uiPreferences = scope.getInstance<UiPreferences>()
|
||||
val updateChecker = scope.getInstance<UpdateChecker>()
|
||||
|
||||
// Call setDefault before getting a resource bundle
|
||||
val language = uiPreferences.language().get()
|
||||
@@ -165,6 +171,21 @@ suspend fun main() {
|
||||
}
|
||||
)
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
launch {
|
||||
updateChecker.checkForUpdates()
|
||||
updateChecker.updateFound.collect {
|
||||
trayState.sendNotification(
|
||||
Notification(
|
||||
resources.getStringA("new_update_title"),
|
||||
resources.getString("new_update_message", it.version),
|
||||
Notification.Type.Info
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Window(
|
||||
onCloseRequest = {
|
||||
if (confirmExit.value) {
|
||||
|
||||
@@ -9,15 +9,30 @@ package ca.gosyer.ui.settings
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.runtime.Composable
|
||||
import ca.gosyer.data.update.UpdatePreferences
|
||||
import ca.gosyer.ui.base.components.MenuController
|
||||
import ca.gosyer.ui.base.components.Toolbar
|
||||
import ca.gosyer.ui.base.prefs.SwitchPreference
|
||||
import ca.gosyer.ui.base.resources.stringResource
|
||||
import ca.gosyer.ui.base.vm.ViewModel
|
||||
import ca.gosyer.ui.base.vm.viewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
class SettingsAdvancedViewModel @Inject constructor(
|
||||
updatePreferences: UpdatePreferences,
|
||||
) : ViewModel() {
|
||||
val updatesEnabled = updatePreferences.enabled().asStateFlow()
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsAdvancedScreen(menuController: MenuController) {
|
||||
val vm = viewModel<SettingsAdvancedViewModel>()
|
||||
Column {
|
||||
Toolbar(stringResource("settings_advanced_screen"), menuController, true)
|
||||
LazyColumn {
|
||||
item {
|
||||
SwitchPreference(preference = vm.updatesEnabled, title = stringResource("update_checker"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
<string name="unable_to_start_server">Cannot start server</string>
|
||||
<string name="confirm_exit">Confirm exit</string>
|
||||
<string name="confirm_exit_message">Are you sure you want to exit?</string>
|
||||
<string name="new_update_title">Tachidesk-JUI update available</string>
|
||||
<string name="new_update_message">%1$s is now available!</string>
|
||||
|
||||
<!-- Actions -->
|
||||
<string name="action_yes">Yes</string>
|
||||
@@ -219,4 +221,7 @@
|
||||
<string name="digest_auth">Digest auth</string>
|
||||
<string name="auth_username">Auth username</string>
|
||||
<string name="auth_password">Auth password</string>
|
||||
|
||||
<!-- Advanced Settings -->
|
||||
<string name="update_checker">Check for updates</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user