diff --git a/app/phone/build.gradle.kts b/app/phone/build.gradle.kts index 9ecc2e7d..06dccfd6 100644 --- a/app/phone/build.gradle.kts +++ b/app/phone/build.gradle.kts @@ -26,6 +26,7 @@ android { buildConfigField( "String", "DEFAULT_SERVER_ADDRESS", "\" \"") buildConfigField( "String", "REQUEST_SERVER_ADDRESS", "\" \"") buildConfigField("String", "FORGET_PASSWORD_ADDRESS", "\" \"") + buildConfigField("String", "UPDATE_ADDRESS", "\" \"") } applicationVariants.all { @@ -70,6 +71,7 @@ android { buildConfigField( "String", "DEFAULT_SERVER_ADDRESS", "\"https://askar.tv\"") buildConfigField( "String", "REQUEST_SERVER_ADDRESS", "\"https://r.askar.tv\"") buildConfigField("String", "FORGET_PASSWORD_ADDRESS", "\"https://user.askar.tv/my/account\"") + buildConfigField("String", "UPDATE_ADDRESS", "\"https://fs.nmd.mov/p/ananas.apk\"") } } diff --git a/app/phone/src/main/java/com/nomadics9/ananas/fragments/SettingsFragment.kt b/app/phone/src/main/java/com/nomadics9/ananas/fragments/SettingsFragment.kt index f1b4eac4..b0492f0d 100644 --- a/app/phone/src/main/java/com/nomadics9/ananas/fragments/SettingsFragment.kt +++ b/app/phone/src/main/java/com/nomadics9/ananas/fragments/SettingsFragment.kt @@ -3,12 +3,23 @@ package com.nomadics9.ananas.fragments import android.content.Intent import android.net.Uri import android.os.Bundle +import androidx.core.content.res.ResourcesCompat +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat -import dagger.hilt.android.AndroidEntryPoint import com.nomadics9.ananas.AppPreferences +import com.nomadics9.ananas.BuildConfig import com.nomadics9.ananas.utils.restart +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import timber.log.Timber +import java.net.HttpURLConnection +import java.net.URL +import java.text.SimpleDateFormat +import java.util.* import javax.inject.Inject import com.nomadics9.ananas.core.R as CoreR @@ -17,6 +28,10 @@ class SettingsFragment : PreferenceFragmentCompat() { @Inject lateinit var appPreferences: AppPreferences + private val updateUrl = BuildConfig.UPDATE_ADDRESS + private var isUpdateAvailable: Boolean = false + private var newLastModifiedDate: Date? = null + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(CoreR.xml.fragment_settings, rootKey) @@ -27,13 +42,21 @@ class SettingsFragment : PreferenceFragmentCompat() { findPreference("switchUser")?.setOnPreferenceClickListener { val serverId = appPreferences.currentServer!! - findNavController().navigate(TwoPaneSettingsFragmentDirections.actionNavigationSettingsToUsersFragment(serverId)) + findNavController().navigate( + TwoPaneSettingsFragmentDirections.actionNavigationSettingsToUsersFragment( + serverId + ) + ) true } findPreference("switchAddress")?.setOnPreferenceClickListener { val serverId = appPreferences.currentServer!! - findNavController().navigate(TwoPaneSettingsFragmentDirections.actionNavigationSettingsToServerAddressesFragment(serverId)) + findNavController().navigate( + TwoPaneSettingsFragmentDirections.actionNavigationSettingsToServerAddressesFragment( + serverId + ) + ) true } @@ -51,14 +74,101 @@ class SettingsFragment : PreferenceFragmentCompat() { true } + findPreference("appInfo")?.setOnPreferenceClickListener { - findNavController().navigate(TwoPaneSettingsFragmentDirections.actionSettingsFragmentToAboutLibraries()) - true + if (isUpdateAvailable && newLastModifiedDate != null) { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(updateUrl)) + startActivity(intent) + storeDate(newLastModifiedDate!!) + true + } else { + false + } } findPreference("requests")?.setOnPreferenceClickListener { findNavController().navigate(TwoPaneSettingsFragmentDirections.actionNavigationSettingsToRequestsWebFragment()) true } + + // Check for updates when the settings screen is opened + checkForUpdates() + } + + private fun checkForUpdates() { + lifecycleScope.launch { + val lastModifiedDate = fetchLastModifiedDate(updateUrl) + if (lastModifiedDate != null) { + Timber.d("Fetched Last-Modified date: $lastModifiedDate") + val storedDate = getStoredDate() + Timber.d("Stored date: $storedDate") + if (storedDate == Date(0L) || lastModifiedDate.after(storedDate)) { + Timber.d("Update available") + isUpdateAvailable = true + newLastModifiedDate = lastModifiedDate + showUpdateAvailable() + } else { + Timber.d("No update available") + isUpdateAvailable = false + } + } else { + Timber.d("Failed to fetch Last-Modified date") + isUpdateAvailable = false + } + } + } + + private suspend fun fetchLastModifiedDate(urlString: String): Date? { + return withContext(Dispatchers.IO) { + var urlConnection: HttpURLConnection? = null + try { + val url = URL(urlString) + urlConnection = url.openConnection() as HttpURLConnection + urlConnection.requestMethod = "HEAD" + val lastModified = urlConnection.getHeaderField("Last-Modified") + if (lastModified != null) { + val dateFormat = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US) + dateFormat.parse(lastModified) + } else { + null + } + } catch (e: Exception) { + Timber.e(e, "Error fetching Last-Modified date") + null + } finally { + urlConnection?.disconnect() + } + } + } + + private fun getStoredDate(): Date { + val sharedPreferences = preferenceManager.sharedPreferences + val storedDateString = sharedPreferences?.getString("stored_date", null) + Timber.d("Retrieved stored date string: $storedDateString") + return if (storedDateString != null) { + try { + SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).parse(storedDateString) ?: Date(0) + } catch (e: Exception) { + Timber.e(e, "Error parsing stored date string") + Date(0) + } + } else { + Date(0) + } + } + + private fun storeDate(date: Date) { + val dateString = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).format(date) + preferenceManager.sharedPreferences?.edit()?.putString("stored_date", dateString)?.apply() + Timber.d("Stored new date: $dateString") + } + + private fun showUpdateAvailable() { + val appInfoPreference = findPreference("appInfo") + appInfoPreference?.let { + it.summary = "Update available!" + it.icon = ResourcesCompat.getDrawable(resources, CoreR.drawable.ic_download, null) // Ensure this drawable exists + Timber.d("Update available UI shown") + } } } diff --git a/core/src/main/res/xml/fragment_settings.xml b/core/src/main/res/xml/fragment_settings.xml index de9fa3f3..9328af37 100644 --- a/core/src/main/res/xml/fragment_settings.xml +++ b/core/src/main/res/xml/fragment_settings.xml @@ -75,7 +75,8 @@ + app:title="@string/app_info" + app:summary="" />