mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-28 16:00:31 +05:30
feat(ui): option for automatic update checks (#5668)
This commit is contained in:
parent
8ffa79ffcc
commit
5532301aa4
@ -18,7 +18,7 @@ interface ExternalApi {
|
||||
|
||||
// fetch latest version info
|
||||
@GET(GITHUB_API_URL)
|
||||
suspend fun getUpdateInfo(): UpdateInfo
|
||||
suspend fun getLatestRelease(): UpdateInfo
|
||||
|
||||
@POST("$SB_API_URL/api/skipSegments")
|
||||
suspend fun submitSegment(
|
||||
|
@ -22,7 +22,8 @@ object IntentData {
|
||||
const val shareData = "shareData"
|
||||
const val currentPosition = "currentPosition"
|
||||
const val duration = "duration"
|
||||
const val updateInfo = "updateInfo"
|
||||
const val appUpdateChangelog = "updateChangelog"
|
||||
const val appUpdateURL = "updateURL"
|
||||
const val backupFile = "backupFile"
|
||||
const val playlistTask = "playlistTask"
|
||||
const val loginTask = "loginTask"
|
||||
|
@ -134,6 +134,7 @@ object PreferenceKeys {
|
||||
/**
|
||||
* Advanced
|
||||
*/
|
||||
const val AUTOMATIC_UPDATE_CHECKS = "automatic_update_checks"
|
||||
const val DATA_SAVER_MODE = "data_saver_mode_key"
|
||||
const val MAX_IMAGE_CACHE = "image_cache_size"
|
||||
const val RESET_SETTINGS = "reset_settings"
|
||||
|
@ -8,6 +8,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
@Parcelize
|
||||
data class UpdateInfo(
|
||||
val name: String,
|
||||
val body: String,
|
||||
@SerialName("html_url") val htmlUrl: String,
|
||||
val name: String
|
||||
) : Parcelable
|
||||
|
@ -18,6 +18,7 @@ import androidx.core.view.allViews
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.NestedScrollView
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
@ -44,6 +45,9 @@ import com.github.libretube.ui.fragments.PlayerFragment
|
||||
import com.github.libretube.ui.models.PlayerViewModel
|
||||
import com.github.libretube.ui.models.SearchViewModel
|
||||
import com.github.libretube.ui.models.SubscriptionsViewModel
|
||||
import com.github.libretube.util.UpdateChecker
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class MainActivity : BaseActivity() {
|
||||
lateinit var binding: ActivityMainBinding
|
||||
@ -82,6 +86,13 @@ class MainActivity : BaseActivity() {
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
// Check update automatically
|
||||
if (PreferenceHelper.getBoolean(PreferenceKeys.AUTOMATIC_UPDATE_CHECKS, false)) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
UpdateChecker(this@MainActivity).checkUpdate(false)
|
||||
}
|
||||
}
|
||||
|
||||
// set the action bar for the activity
|
||||
setSupportActionBar(binding.toolbar)
|
||||
|
||||
|
@ -6,28 +6,33 @@ import android.os.Bundle
|
||||
import androidx.core.net.toUri
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.extensions.parcelable
|
||||
import com.github.libretube.obj.update.UpdateInfo
|
||||
import com.github.libretube.constants.IntentData.appUpdateChangelog
|
||||
import com.github.libretube.constants.IntentData.appUpdateURL
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
class UpdateAvailableDialog : DialogFragment() {
|
||||
private lateinit var updateInfo: UpdateInfo
|
||||
private var changelog: String? = null
|
||||
private var releaseUrl: String? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
updateInfo = requireArguments().parcelable(IntentData.updateInfo)!!
|
||||
arguments?.run {
|
||||
changelog = getString(appUpdateChangelog)
|
||||
releaseUrl = getString(appUpdateURL)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(context?.getString(R.string.update_available, updateInfo.name))
|
||||
.setMessage(context?.getString(R.string.update_available_text))
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setPositiveButton(context?.getString(R.string.okay)) { _, _ ->
|
||||
val intent = Intent(Intent.ACTION_VIEW).setData(updateInfo.htmlUrl.toUri())
|
||||
startActivity(intent)
|
||||
.setTitle(R.string.update_available)
|
||||
.setMessage(changelog)
|
||||
.setPositiveButton(R.string.download) { _, _ ->
|
||||
releaseUrl?.let {
|
||||
startActivity(Intent(Intent.ACTION_VIEW, it.toUri()))
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.tooltip_dismiss, null)
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,14 @@
|
||||
package com.github.libretube.ui.preferences
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import com.github.libretube.BuildConfig
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.ui.activities.SettingsActivity
|
||||
import com.github.libretube.ui.base.BasePreferenceFragment
|
||||
import com.github.libretube.ui.dialogs.UpdateAvailableDialog
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.github.libretube.util.UpdateChecker
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class MainSettings : BasePreferenceFragment() {
|
||||
override val titleResourceId: Int = R.string.settings
|
||||
@ -24,50 +17,16 @@ class MainSettings : BasePreferenceFragment() {
|
||||
setPreferencesFromResource(R.xml.settings, rootKey)
|
||||
|
||||
val update = findPreference<Preference>("update")
|
||||
update?.summary = "v${BuildConfig.VERSION_NAME}"
|
||||
|
||||
// set the version of the update preference
|
||||
val versionString = if (BuildConfig.DEBUG) {
|
||||
"${BuildConfig.VERSION_NAME} Debug"
|
||||
} else {
|
||||
getString(R.string.version, BuildConfig.VERSION_NAME)
|
||||
}
|
||||
update?.title = versionString
|
||||
|
||||
// checking for update: yes -> dialog, no -> snackBar
|
||||
// check app update manually
|
||||
update?.setOnPreferenceClickListener {
|
||||
lifecycleScope.launch {
|
||||
// check for update
|
||||
val updateInfo = try {
|
||||
withContext(Dispatchers.IO) {
|
||||
RetrofitInstance.externalApi.getUpdateInfo()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
showSnackBar(R.string.unknown_error)
|
||||
return@launch
|
||||
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
UpdateChecker(requireContext()).checkUpdate(true)
|
||||
}
|
||||
|
||||
if (BuildConfig.VERSION_NAME != updateInfo.name) {
|
||||
// show the UpdateAvailableDialog if there's an update available
|
||||
val newUpdateAvailableDialog = UpdateAvailableDialog()
|
||||
newUpdateAvailableDialog.arguments =
|
||||
bundleOf(IntentData.updateInfo to updateInfo)
|
||||
newUpdateAvailableDialog.show(
|
||||
childFragmentManager,
|
||||
UpdateAvailableDialog::class.java.name
|
||||
)
|
||||
} else {
|
||||
// otherwise show the no update available snackBar
|
||||
showSnackBar(R.string.app_uptodate)
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSnackBar(@StringRes text: Int) {
|
||||
(activity as? SettingsActivity)?.binding?.let {
|
||||
Snackbar.make(it.root, text, Snackbar.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
70
app/src/main/java/com/github/libretube/util/UpdateChecker.kt
Normal file
70
app/src/main/java/com/github/libretube/util/UpdateChecker.kt
Normal file
@ -0,0 +1,70 @@
|
||||
package com.github.libretube.util
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.github.libretube.BuildConfig
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.constants.IntentData.appUpdateChangelog
|
||||
import com.github.libretube.constants.IntentData.appUpdateURL
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.toastFromMainDispatcher
|
||||
import com.github.libretube.ui.dialogs.UpdateAvailableDialog
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.Locale
|
||||
|
||||
class UpdateChecker(private val context: Context) {
|
||||
suspend fun checkUpdate(isManualCheck: Boolean = false) {
|
||||
val currentAppVersion = BuildConfig.VERSION_NAME.replace(".", "").toInt()
|
||||
|
||||
try {
|
||||
val response = RetrofitInstance.externalApi.getLatestRelease()
|
||||
// version would be in the format "0.21.1"
|
||||
val update = response.name.replace(".", "").toIntOrNull()
|
||||
|
||||
if (update != null && currentAppVersion < update) {
|
||||
withContext(Dispatchers.Main) {
|
||||
showUpdateAvailableDialog(response.body, response.htmlUrl)
|
||||
}
|
||||
Log.i(TAG(), response.toString())
|
||||
} else if (isManualCheck) {
|
||||
context.toastFromMainDispatcher(R.string.app_uptodate)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUpdateAvailableDialog(
|
||||
changelog: String,
|
||||
url: String,
|
||||
) {
|
||||
val dialog = UpdateAvailableDialog()
|
||||
val args =
|
||||
Bundle().apply {
|
||||
putString(appUpdateChangelog, sanitizeChangelog(changelog))
|
||||
putString(appUpdateURL, url)
|
||||
}
|
||||
dialog.arguments = args
|
||||
val fragmentManager = (context as? FragmentActivity)?.supportFragmentManager
|
||||
fragmentManager?.let {
|
||||
dialog.show(it, UpdateAvailableDialog::class.java.simpleName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun sanitizeChangelog(changelog: String): String {
|
||||
val removeBloat = changelog.substringBeforeLast("**Full Changelog**")
|
||||
val removeLinks = removeBloat.replace(Regex("in https://github\\.com/\\S+"), "")
|
||||
val uppercaseChangeType =
|
||||
removeLinks.lines().joinToString("\n") { line ->
|
||||
if (line.startsWith("##")) line.uppercase(Locale.ROOT) + " :" else line
|
||||
}
|
||||
val removeHashes = uppercaseChangeType.replace("## ", "")
|
||||
val cleanPrefix = removeHashes.replace("*", "•")
|
||||
|
||||
return cleanPrefix.trim()
|
||||
}
|
||||
}
|
@ -122,7 +122,7 @@
|
||||
<string name="piped">Piped</string>
|
||||
<string name="youtube">YouTube</string>
|
||||
<string name="playOnBackground">Play in the background</string>
|
||||
<string name="update_available">Version %1$s is available</string>
|
||||
<string name="update_available">Update available</string>
|
||||
<string name="update_available_text">New update available. Click to open the GitHub releases page.</string>
|
||||
<string name="appearance">Appearance</string>
|
||||
<string name="downloads">Downloads</string>
|
||||
@ -154,6 +154,7 @@
|
||||
<string name="clear_customInstances">Clear added</string>
|
||||
<string name="invalid_url">Please enter a URL that works</string>
|
||||
<string name="version">Version %1$s</string>
|
||||
<string name="show_updates">Check updates automatically</string>
|
||||
<string name="related_streams">Related content</string>
|
||||
<string name="related_streams_summary">Show similar streams alongside what you watch</string>
|
||||
<string name="buffering_goal">Preloading</string>
|
||||
|
@ -4,6 +4,12 @@
|
||||
|
||||
<PreferenceCategory app:title="@string/advanced">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:icon="@drawable/ic_download_filled"
|
||||
app:key="automatic_update_checks"
|
||||
app:title="@string/show_updates" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="disabled"
|
||||
android:entries="@array/dataSaverModeOptions"
|
||||
|
@ -77,9 +77,8 @@
|
||||
<Preference
|
||||
android:icon="@drawable/ic_update"
|
||||
app:key="update"
|
||||
app:summary="@string/update_summary"
|
||||
app:title="App version" />
|
||||
|
||||
app:summary="@string/version"
|
||||
app:title="@string/update_summary" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user