diff --git a/app/src/main/java/com/github/libretube/SettingsActivity.kt b/app/src/main/java/com/github/libretube/SettingsActivity.kt index 20a91a1c7..de2eb29d0 100644 --- a/app/src/main/java/com/github/libretube/SettingsActivity.kt +++ b/app/src/main/java/com/github/libretube/SettingsActivity.kt @@ -30,6 +30,7 @@ import androidx.preference.PreferenceManager import com.github.libretube.dialogs.LoginDialog import com.github.libretube.util.RetrofitInstance import com.github.libretube.util.changeIcon +import com.github.libretube.util.checkUpdate import com.github.libretube.util.restartMainActivity import com.github.libretube.util.updateTheme import com.google.android.material.color.DynamicColors @@ -154,6 +155,11 @@ class SettingsActivity : } } super.onCreate(savedInstanceState) + try { + checkUpdate(childFragmentManager) + } catch (e: Exception) { + e.printStackTrace() + } } override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { diff --git a/app/src/main/java/com/github/libretube/dialogs/UpdateAvailableDialog.kt b/app/src/main/java/com/github/libretube/dialogs/UpdateAvailableDialog.kt new file mode 100644 index 000000000..aab997947 --- /dev/null +++ b/app/src/main/java/com/github/libretube/dialogs/UpdateAvailableDialog.kt @@ -0,0 +1,32 @@ +package com.github.libretube.dialogs + +import android.app.Dialog +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import com.github.libretube.R +import com.google.android.material.dialog.MaterialAlertDialogBuilder + +class UpdateAvailableDialog( + private val versionTag: String, + private val updateLink: String +) : DialogFragment() { + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return activity?.let { + MaterialAlertDialogBuilder(requireContext()) + .setTitle(context?.getString(R.string.update_available, versionTag)) + .setMessage(context?.getString(R.string.update_available_text)) + .setNegativeButton(context?.getString(R.string.cancel)) { _, _ -> + dismiss() + } + .setPositiveButton(context?.getString(R.string.okay)) { _, _ -> + val uri = Uri.parse(updateLink) + val intent = Intent(Intent.ACTION_VIEW).setData(uri) + startActivity(intent) + } + .show() + } ?: throw IllegalStateException("Activity cannot be null") + } +} diff --git a/app/src/main/java/com/github/libretube/util/UpdateChecker.kt b/app/src/main/java/com/github/libretube/util/UpdateChecker.kt new file mode 100644 index 000000000..8b7b6f6b0 --- /dev/null +++ b/app/src/main/java/com/github/libretube/util/UpdateChecker.kt @@ -0,0 +1,74 @@ +package com.github.libretube.util + +import android.util.Log +import androidx.fragment.app.FragmentManager +import com.github.libretube.BuildConfig +import com.github.libretube.dialogs.UpdateAvailableDialog +import java.io.BufferedReader +import java.io.InputStreamReader +import java.net.URL +import javax.net.ssl.HttpsURLConnection +import org.json.JSONArray +import org.json.JSONObject + +fun checkUpdate(childFragmentManager: FragmentManager) { + var updateInfo: UpdateInfo? = UpdateInfo("", "") + // run http request as thread to make it async + val thread = Thread { + // otherwise crashes without internet + try { + updateInfo = getUpdateInfo() + } catch (e: Exception) { + } + } + thread.start() + // wait for the thread to finish + thread.join() + // show the UpdateAvailableDialog if there's an update available + if (updateInfo?.tagName != "" && BuildConfig.VERSION_NAME != updateInfo?.tagName) { + val updateAvailableDialog = UpdateAvailableDialog( + updateInfo?.tagName!!, + updateInfo?.updateUrl!! + ) + updateAvailableDialog.show(childFragmentManager, "UpdateAvailableDialog") + } +} + +fun getUpdateInfo(): UpdateInfo? { + val latest = URL("https://api.github.com/repos/libre-tube/LibreTube/releases/latest") + val json = StringBuilder() + val urlConnection: HttpsURLConnection? + urlConnection = latest.openConnection() as HttpsURLConnection + val br = BufferedReader(InputStreamReader(urlConnection.inputStream)) + + var line: String? + while (br.readLine().also { line = it } != null) json.append(line) + + // Parse and return json data + val jsonRoot = JSONObject(json.toString()) + if (jsonRoot.has("tag_name") && + jsonRoot.has("html_url") && + jsonRoot.has("assets") + ) { + val updateUrl = jsonRoot.getString("html_url") + val jsonAssets: JSONArray = jsonRoot.getJSONArray("assets") + for (i in 0 until jsonAssets.length()) { + val jsonAsset = jsonAssets.getJSONObject(i) + if (jsonAsset.has("name")) { + val name = jsonAsset.getString("name") + if (name.endsWith(".apk")) { + val tagName = jsonRoot.getString("name") + Log.i("", "Lastest version: $tagName") + return UpdateInfo(updateUrl, tagName) + } + } + } + } + return null +} + +// data class for the update info, required to return the data +data class UpdateInfo( + val updateUrl: String, + val tagName: String +) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3d8c4f410..efbd62c9d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -116,4 +116,6 @@ Piped YouTube Play on background + Version %1$s is available + There is a new update available. Click okay to become redirected to the update page on GitHub. \ No newline at end of file