SelfUpdateWorker: Move self-updates logic into dedicated worker
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
|
||||
package com.aurora.extensions
|
||||
|
||||
import com.aurora.gplayapi.data.models.File
|
||||
|
||||
fun <T> MutableList<T>.flushAndAdd(list: List<T>) {
|
||||
clear()
|
||||
addAll(list)
|
||||
@@ -28,3 +30,7 @@ fun <T> MutableSet<T>.flushAndAdd(list: Set<T>) {
|
||||
clear()
|
||||
addAll(list)
|
||||
}
|
||||
|
||||
fun List<File>.requiresObbDir(): Boolean {
|
||||
return this.any { it.type == File.FileType.OBB || it.type == File.FileType.PATCH }
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.activity.addCallback
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.ColorUtils
|
||||
@@ -60,16 +59,12 @@ import com.aurora.extensions.isMAndAbove
|
||||
import com.aurora.extensions.isRAndAbove
|
||||
import com.aurora.extensions.toast
|
||||
import com.aurora.store.data.model.NetworkStatus
|
||||
import com.aurora.store.data.model.SelfUpdate
|
||||
import com.aurora.store.data.providers.NetworkProvider
|
||||
import com.aurora.store.databinding.ActivityMainBinding
|
||||
import com.aurora.store.util.Log
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_DEFAULT_SELECTED_TAB
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_SELF_UPDATE
|
||||
import com.aurora.store.view.ui.sheets.NetworkDialogSheet
|
||||
import com.aurora.store.view.ui.sheets.SelfUpdateSheet
|
||||
import com.aurora.store.viewmodel.MainViewModel
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -81,8 +76,6 @@ class MainActivity : AppCompatActivity() {
|
||||
private lateinit var navController: NavController
|
||||
private lateinit var appConfig: AppBarConfiguration
|
||||
|
||||
private val viewModel: MainViewModel by viewModels()
|
||||
|
||||
private val startForPermissions =
|
||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
|
||||
if (!it) toast(R.string.permissions_denied)
|
||||
@@ -154,20 +147,6 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
/* Check self update only for stable release, skip debug & nightlies*/
|
||||
if (Preferences.getBoolean(this, PREFERENCE_SELF_UPDATE)) {
|
||||
if (BuildConfig.APPLICATION_ID == Constants.APP_ID) viewModel.checkSelfUpdate(this)
|
||||
this.lifecycleScope.launch {
|
||||
viewModel.selfUpdateAvailable.collect {
|
||||
if (it != null) {
|
||||
showUpdatesSheet(it)
|
||||
} else {
|
||||
Log.i("No Aurora Store update available")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle quick exit from back actions
|
||||
val defaultTab = when (Preferences.getInteger(this, PREFERENCE_DEFAULT_SELECTED_TAB)) {
|
||||
1 -> R.id.gamesContainerFragment
|
||||
@@ -296,14 +275,6 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUpdatesSheet(selfUpdate: SelfUpdate) {
|
||||
if (!supportFragmentManager.isDestroyed) {
|
||||
val sheet = SelfUpdateSheet.newInstance(selfUpdate)
|
||||
sheet.isCancelable = false
|
||||
sheet.show(supportFragmentManager, SelfUpdateSheet.TAG)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isIntroDone(): Boolean {
|
||||
return Preferences.getBoolean(this@MainActivity, Preferences.PREFERENCE_INTRO)
|
||||
}
|
||||
|
||||
@@ -19,21 +19,53 @@
|
||||
|
||||
package com.aurora.store.data.model
|
||||
|
||||
import android.content.Context
|
||||
import com.aurora.Constants
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.gplayapi.data.models.Artwork
|
||||
import com.aurora.gplayapi.data.models.File
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.util.CertUtil
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class SelfUpdate {
|
||||
@SerializedName("version_name")
|
||||
var versionName: String = String()
|
||||
data class SelfUpdate(
|
||||
@SerializedName("version_name") var versionName: String = String(),
|
||||
@SerializedName("version_code") var versionCode: Int = 0,
|
||||
@SerializedName("aurora_build") var auroraBuild: String = String(),
|
||||
@SerializedName("fdroid_build") var fdroidBuild: String = String(),
|
||||
val changelog: String = String(),
|
||||
val size: Long = 0L
|
||||
) {
|
||||
companion object {
|
||||
private const val BASE_URL = "https://gitlab.com/AuroraOSS/AuroraStore/-/raw/master"
|
||||
|
||||
@SerializedName("version_code")
|
||||
var versionCode: Int = 0
|
||||
fun toApp(selfUpdate: SelfUpdate, context: Context): App {
|
||||
// Keep paths updated with fastlane data on project
|
||||
val icon = "fastlane/metadata/android/en-US/images/icon.png"
|
||||
|
||||
@SerializedName("aurora_build")
|
||||
var auroraBuild: String = String()
|
||||
val downloadURL = if (CertUtil.isFDroidApp(context, BuildConfig.APPLICATION_ID)) {
|
||||
selfUpdate.fdroidBuild
|
||||
} else {
|
||||
selfUpdate.auroraBuild
|
||||
}
|
||||
|
||||
@SerializedName("fdroid_build")
|
||||
var fdroidBuild: String = String()
|
||||
|
||||
@SerializedName("changelog")
|
||||
var changelog: String = String()
|
||||
}
|
||||
return App(
|
||||
packageName = Constants.APP_ID,
|
||||
versionCode = selfUpdate.versionCode,
|
||||
versionName = selfUpdate.versionName,
|
||||
changes = selfUpdate.changelog,
|
||||
size = selfUpdate.size,
|
||||
displayName = context.getString(R.string.app_name),
|
||||
iconArtwork = Artwork(url = "$BASE_URL/$icon"),
|
||||
fileList = mutableListOf(
|
||||
File(
|
||||
name = "${Constants.APP_ID}.apk",
|
||||
url = downloadURL,
|
||||
size = selfUpdate.size
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.os.Parcelable
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.gplayapi.data.models.File
|
||||
import com.aurora.store.data.model.DownloadStatus
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@@ -24,6 +25,7 @@ data class Download(
|
||||
var timeRemaining: Long,
|
||||
var totalFiles: Int,
|
||||
var downloadedFiles: Int,
|
||||
var fileList: List<File>,
|
||||
val sharedLibs: List<SharedLib>
|
||||
) : Parcelable {
|
||||
val isFinished get() = status in DownloadStatus.finished
|
||||
@@ -45,6 +47,7 @@ data class Download(
|
||||
0L,
|
||||
0,
|
||||
0,
|
||||
app.fileList.filterNot { it.url.isBlank() },
|
||||
app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.aurora.store.data.room.download
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import com.aurora.gplayapi.data.models.File
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
|
||||
@@ -16,4 +17,15 @@ object DownloadConverter {
|
||||
fun fromSharedLibList(list: List<SharedLib>): String {
|
||||
return Gson().toJson(list)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toGPlayFileList(string: String): List<File> {
|
||||
val listType = object : TypeToken<List<File>>() {}.type
|
||||
return Gson().fromJson(string, listType)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromGPlayFileList(list: List<File>): String {
|
||||
return Gson().toJson(list)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,22 @@ package com.aurora.store.data.room.download
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.gplayapi.data.models.File
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class SharedLib(
|
||||
val packageName: String,
|
||||
val versionCode: Int
|
||||
val versionCode: Int,
|
||||
var fileList: List<File>
|
||||
) : Parcelable {
|
||||
companion object {
|
||||
fun fromApp(app: App): SharedLib {
|
||||
return SharedLib(app.packageName, app.versionCode)
|
||||
return SharedLib(
|
||||
app.packageName,
|
||||
app.versionCode,
|
||||
app.fileList.filterNot { it.url.isBlank() }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.work.WorkerParameters
|
||||
import com.aurora.Constants
|
||||
import com.aurora.extensions.copyTo
|
||||
import com.aurora.extensions.isQAndAbove
|
||||
import com.aurora.extensions.requiresObbDir
|
||||
import com.aurora.gplayapi.helpers.PurchaseHelper
|
||||
import com.aurora.store.data.model.DownloadInfo
|
||||
import com.aurora.store.data.model.DownloadStatus
|
||||
@@ -80,9 +81,10 @@ class DownloadWorker @AssistedInject constructor(
|
||||
appContext.getSystemService(Service.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
// Bail out if file list is empty
|
||||
val files =
|
||||
download.fileList = download.fileList.ifEmpty {
|
||||
purchaseHelper.purchase(download.packageName, download.versionCode, download.offerType)
|
||||
if (files.isEmpty()) {
|
||||
}
|
||||
if (download.fileList.isEmpty()) {
|
||||
Log.i(TAG, "Nothing to download!")
|
||||
notifyStatus(DownloadStatus.FAILED)
|
||||
return Result.failure()
|
||||
@@ -90,7 +92,7 @@ class DownloadWorker @AssistedInject constructor(
|
||||
|
||||
// Create dirs & generate download request for files and shared libs (if any)
|
||||
PathUtil.getAppDownloadDir(appContext, download.packageName, download.versionCode).mkdirs()
|
||||
if (files.any { it.type == GPlayFile.FileType.OBB || it.type == GPlayFile.FileType.PATCH }) {
|
||||
if (download.fileList.requiresObbDir()) {
|
||||
PathUtil.getObbDownloadDir(download.packageName).mkdirs()
|
||||
}
|
||||
|
||||
@@ -104,11 +106,13 @@ class DownloadWorker @AssistedInject constructor(
|
||||
download.versionCode,
|
||||
it.packageName
|
||||
).mkdirs()
|
||||
val libs = purchaseHelper.purchase(it.packageName, it.versionCode, 0)
|
||||
requestList.addAll(getDownloadRequest(libs, it.packageName))
|
||||
it.fileList = it.fileList.ifEmpty {
|
||||
purchaseHelper.purchase(it.packageName, it.versionCode, 0)
|
||||
}
|
||||
requestList.addAll(getDownloadRequest(it.fileList, it.packageName))
|
||||
}
|
||||
}
|
||||
requestList.addAll(getDownloadRequest(files, null))
|
||||
requestList.addAll(getDownloadRequest(download.fileList, null))
|
||||
|
||||
// Update data for notification
|
||||
download.totalFiles = requestList.size
|
||||
|
||||
101
app/src/main/java/com/aurora/store/data/work/SelfUpdateWorker.kt
Normal file
101
app/src/main/java/com/aurora/store/data/work/SelfUpdateWorker.kt
Normal file
@@ -0,0 +1,101 @@
|
||||
package com.aurora.store.data.work
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.hilt.work.HiltWorker
|
||||
import androidx.work.Constraints
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.ExistingPeriodicWorkPolicy.KEEP
|
||||
import androidx.work.NetworkType
|
||||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkerParameters
|
||||
import com.aurora.Constants
|
||||
import com.aurora.extensions.isMAndAbove
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.data.model.SelfUpdate
|
||||
import com.aurora.store.data.network.HttpClient
|
||||
import com.aurora.store.util.CertUtil
|
||||
import com.aurora.store.util.DownloadWorkerUtil
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_SELF_UPDATE
|
||||
import com.google.gson.Gson
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import java.util.concurrent.TimeUnit.HOURS
|
||||
import java.util.concurrent.TimeUnit.MINUTES
|
||||
|
||||
@HiltWorker
|
||||
class SelfUpdateWorker @AssistedInject constructor(
|
||||
private val downloadWorkerUtil: DownloadWorkerUtil,
|
||||
private val gson: Gson,
|
||||
@Assisted private val appContext: Context,
|
||||
@Assisted workerParams: WorkerParameters
|
||||
) : CoroutineWorker(appContext, workerParams) {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "SelfUpdateWorker"
|
||||
private const val SELF_UPDATE_WORKER = "SELF_UPDATE_WORKER"
|
||||
|
||||
fun cancelAutomatedCheck(context: Context) {
|
||||
Log.i(TAG, "Cancelling periodic self-updates!")
|
||||
WorkManager.getInstance(context).cancelUniqueWork(SELF_UPDATE_WORKER)
|
||||
}
|
||||
|
||||
fun scheduleAutomatedCheck(context: Context) {
|
||||
Log.i(TAG, "Scheduling periodic self-updates!")
|
||||
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.UNMETERED)
|
||||
.setRequiresBatteryNotLow(true)
|
||||
|
||||
if (isMAndAbove()) constraints.setRequiresDeviceIdle(true)
|
||||
|
||||
val workRequest = PeriodicWorkRequestBuilder<UpdateWorker>(
|
||||
repeatInterval = 24,
|
||||
repeatIntervalTimeUnit = HOURS,
|
||||
flexTimeInterval = 30,
|
||||
flexTimeIntervalUnit = MINUTES
|
||||
).setConstraints(constraints.build()).build()
|
||||
|
||||
val workManager = WorkManager.getInstance(context)
|
||||
workManager.enqueueUniquePeriodicWork(SELF_UPDATE_WORKER, KEEP, workRequest)
|
||||
}
|
||||
}
|
||||
|
||||
private val TAG = SelfUpdateWorker::class.java.simpleName
|
||||
private val RELEASE = "release"
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
@Suppress("KotlinConstantConditions") // False-positive for build type always not being release
|
||||
if (BuildConfig.BUILD_TYPE != RELEASE && Preferences.getBoolean(appContext, PREFERENCE_SELF_UPDATE)) {
|
||||
Log.e(TAG, "Either build type is not release or self-update check is disabled")
|
||||
return Result.failure()
|
||||
}
|
||||
|
||||
try {
|
||||
val response = HttpClient.getPreferredClient(appContext)
|
||||
.get(Constants.UPDATE_URL, mapOf())
|
||||
val selfUpdate = gson.fromJson(String(response.responseBytes), SelfUpdate::class.java)
|
||||
|
||||
if (selfUpdate.versionCode > BuildConfig.VERSION_CODE) {
|
||||
if (CertUtil.isFDroidApp(appContext, BuildConfig.APPLICATION_ID)) {
|
||||
if (selfUpdate.fdroidBuild.isNotEmpty()) {
|
||||
downloadWorkerUtil.enqueueApp(SelfUpdate.toApp(selfUpdate, appContext))
|
||||
}
|
||||
} else if (selfUpdate.auroraBuild.isNotEmpty()) {
|
||||
downloadWorkerUtil.enqueueApp(SelfUpdate.toApp(selfUpdate, appContext))
|
||||
} else {
|
||||
Log.e(TAG, "Update file is missing!")
|
||||
return Result.failure()
|
||||
}
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, "Failed to check Aurora Store updates", exception)
|
||||
return Result.failure()
|
||||
}
|
||||
|
||||
Log.i(TAG, "No updates found")
|
||||
return Result.success()
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@ import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.aurora.Constants
|
||||
import com.aurora.extensions.browse
|
||||
import com.aurora.store.MobileNavigationDirections
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.room.download.Download
|
||||
@@ -48,6 +50,8 @@ class DownloadFragment : BaseFragment(R.layout.fragment_download) {
|
||||
@Inject
|
||||
lateinit var downloadWorkerUtil: DownloadWorkerUtil
|
||||
|
||||
private val AURORA_STORE_URL = "https://gitlab.com/AuroraOSS/AuroraStore"
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
@@ -101,7 +105,13 @@ class DownloadFragment : BaseFragment(R.layout.fragment_download) {
|
||||
DownloadViewModel_()
|
||||
.id(it.packageName)
|
||||
.download(it)
|
||||
.click { _ -> openDetailsFragment(it.packageName) }
|
||||
.click { _ ->
|
||||
if (it.packageName == Constants.APP_ID) {
|
||||
requireContext().browse(AURORA_STORE_URL)
|
||||
} else {
|
||||
openDetailsFragment(it.packageName)
|
||||
}
|
||||
}
|
||||
.longClick { _ ->
|
||||
openDownloadMenuSheet(it)
|
||||
true
|
||||
|
||||
@@ -30,6 +30,7 @@ import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
|
||||
import com.aurora.extensions.isSAndAbove
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.work.SelfUpdateWorker
|
||||
import com.aurora.store.data.work.UpdateWorker
|
||||
import com.aurora.store.databinding.FragmentOnboardingBinding
|
||||
import com.aurora.store.util.CertUtil
|
||||
@@ -63,6 +64,7 @@ import com.aurora.store.util.Preferences.PREFERENCE_VENDING_VERSION
|
||||
import com.aurora.store.util.save
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
@AndroidEntryPoint
|
||||
class OnboardingFragment : Fragment(R.layout.fragment_onboarding) {
|
||||
@@ -70,6 +72,7 @@ class OnboardingFragment : Fragment(R.layout.fragment_onboarding) {
|
||||
private var _binding: FragmentOnboardingBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private var shouldSelfUpdate by Delegates.notNull<Boolean>()
|
||||
private var lastPosition = 0
|
||||
|
||||
internal class PagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
|
||||
@@ -95,6 +98,8 @@ class OnboardingFragment : Fragment(R.layout.fragment_onboarding) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
_binding = FragmentOnboardingBinding.bind(view)
|
||||
|
||||
shouldSelfUpdate = CertUtil.isFDroidApp(requireContext(), BuildConfig.APPLICATION_ID)
|
||||
|
||||
val isDefaultPrefLoaded = Preferences.getBoolean(requireContext(), PREFERENCE_DEFAULT)
|
||||
if (!isDefaultPrefLoaded) {
|
||||
save(PREFERENCE_DEFAULT, true)
|
||||
@@ -144,6 +149,7 @@ class OnboardingFragment : Fragment(R.layout.fragment_onboarding) {
|
||||
binding.btnForward.setOnClickListener {
|
||||
save(PREFERENCE_INTRO, true)
|
||||
UpdateWorker.scheduleAutomatedCheck(requireContext())
|
||||
if (shouldSelfUpdate) SelfUpdateWorker.scheduleAutomatedCheck(requireContext())
|
||||
findNavController().navigate(
|
||||
OnboardingFragmentDirections.actionOnboardingFragmentToSplashFragment()
|
||||
)
|
||||
@@ -192,9 +198,6 @@ class OnboardingFragment : Fragment(R.layout.fragment_onboarding) {
|
||||
save(PREFERENCE_UPDATES_EXTENDED, false)
|
||||
save(PREFERENCE_UPDATES_AUTO, 2)
|
||||
save(PREFERENCE_UPDATES_CHECK_INTERVAL, 3)
|
||||
save(
|
||||
PREFERENCE_SELF_UPDATE,
|
||||
CertUtil.isFDroidApp(requireContext(), BuildConfig.APPLICATION_ID)
|
||||
)
|
||||
save(PREFERENCE_SELF_UPDATE, shouldSelfUpdate)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import androidx.preference.SeekBarPreference
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.work.SelfUpdateWorker
|
||||
import com.aurora.store.data.work.UpdateWorker
|
||||
import com.aurora.store.util.CertUtil
|
||||
import com.aurora.store.util.Preferences
|
||||
@@ -55,6 +56,11 @@ class UpdatesPreference : PreferenceFragmentCompat() {
|
||||
}
|
||||
|
||||
it.setOnPreferenceChangeListener { _, newValue ->
|
||||
if (newValue.toString().toBoolean()) {
|
||||
SelfUpdateWorker.scheduleAutomatedCheck(requireContext())
|
||||
} else {
|
||||
SelfUpdateWorker.cancelAutomatedCheck(requireContext())
|
||||
}
|
||||
save(PREFERENCE_SELF_UPDATE, newValue.toString().toBoolean())
|
||||
true
|
||||
}
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2019, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
package com.aurora.store.view.ui.sheets
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.aurora.Constants
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.model.SelfUpdate
|
||||
import com.aurora.store.data.service.SelfUpdateService
|
||||
import com.aurora.store.databinding.SheetSelfUpdateBinding
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SelfUpdateSheet : BaseBottomSheet() {
|
||||
|
||||
private lateinit var B: SheetSelfUpdateBinding
|
||||
private lateinit var selfUpdate: SelfUpdate
|
||||
|
||||
companion object {
|
||||
|
||||
const val TAG = "ManualDownloadSheet"
|
||||
|
||||
@JvmStatic
|
||||
fun newInstance(
|
||||
selfUpdate: SelfUpdate
|
||||
): SelfUpdateSheet {
|
||||
return SelfUpdateSheet().apply {
|
||||
arguments = Bundle().apply {
|
||||
putString(Constants.STRING_EXTRA, gson.toJson(selfUpdate))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateContentView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
B = SheetSelfUpdateBinding.inflate(inflater)
|
||||
return B.root
|
||||
}
|
||||
|
||||
override fun onContentViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val bundle = arguments
|
||||
bundle?.let {
|
||||
val rawUpdate = bundle.getString(Constants.STRING_EXTRA, "{}")
|
||||
selfUpdate = gson.fromJson(rawUpdate, SelfUpdate::class.java)
|
||||
if (selfUpdate.versionName.isNotEmpty()) {
|
||||
inflateData()
|
||||
attachActions()
|
||||
} else {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun inflateData() {
|
||||
B.txtLine2.text = ("${selfUpdate.versionName} (${selfUpdate.versionCode})")
|
||||
|
||||
val messages: String = if (selfUpdate.changelog.isEmpty())
|
||||
getString(R.string.details_changelog_unavailable)
|
||||
else
|
||||
selfUpdate.changelog
|
||||
|
||||
B.txtChangelog.text = messages.trim()
|
||||
}
|
||||
|
||||
private fun attachActions() {
|
||||
B.btnPrimary.setOnClickListener {
|
||||
val intent = Intent(requireContext(), SelfUpdateService::class.java)
|
||||
intent.putExtra(Constants.STRING_EXTRA, gson.toJson(selfUpdate))
|
||||
requireContext().startService(intent)
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
|
||||
B.btnSecondary.setOnClickListener {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.aurora.store.viewmodel
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.aurora.Constants
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.data.model.SelfUpdate
|
||||
import com.aurora.store.data.network.HttpClient
|
||||
import com.aurora.store.util.CertUtil
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
class MainViewModel : ViewModel() {
|
||||
|
||||
private val TAG = MainViewModel::class.java.simpleName
|
||||
|
||||
private val _selfUpdateAvailable = MutableSharedFlow<SelfUpdate?>()
|
||||
val selfUpdateAvailable = _selfUpdateAvailable.asSharedFlow()
|
||||
|
||||
fun checkSelfUpdate(context: Context) {
|
||||
Log.i(TAG, "Checking for Aurora Store updates")
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val gson: Gson =
|
||||
GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT).create()
|
||||
val response = HttpClient.getPreferredClient(context).get(Constants.UPDATE_URL, mapOf())
|
||||
val selfUpdate =
|
||||
gson.fromJson(String(response.responseBytes), SelfUpdate::class.java)
|
||||
|
||||
if (selfUpdate.versionCode > BuildConfig.VERSION_CODE) {
|
||||
if (CertUtil.isFDroidApp(context, BuildConfig.APPLICATION_ID)) {
|
||||
if (selfUpdate.fdroidBuild.isNotEmpty()) {
|
||||
_selfUpdateAvailable.emit(selfUpdate)
|
||||
}
|
||||
} else if (selfUpdate.auroraBuild.isNotEmpty()) {
|
||||
_selfUpdateAvailable.emit(selfUpdate)
|
||||
} else {
|
||||
_selfUpdateAvailable.emit(null)
|
||||
}
|
||||
} else {
|
||||
_selfUpdateAvailable.emit(null)
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
_selfUpdateAvailable.emit(null)
|
||||
Log.d(TAG, "Failed to check Aurora Store updates", exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Aurora Store
|
||||
~ Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
~
|
||||
~ Aurora Store is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 2 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ Aurora Store is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
~
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:divider="@drawable/divider"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/padding_large"
|
||||
android:showDividers="middle">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/img_icon"
|
||||
android:layout_width="@dimen/icon_size_category"
|
||||
android:layout_height="@dimen/icon_size_category"
|
||||
android:layout_centerVertical="true"
|
||||
app:srcCompat="@drawable/ic_logo" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txt_header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="@dimen/margin_normal"
|
||||
android:layout_marginBottom="@dimen/margin_normal"
|
||||
android:layout_toEndOf="@id/img_icon"
|
||||
android:maxLines="1"
|
||||
android:text="@string/dialog_title_self_update"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/TextAppearance.Aurora.SubTitle" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txt_line1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="2"
|
||||
android:text="@string/app_name"
|
||||
android:textAppearance="@style/TextAppearance.Aurora.Line1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txt_line2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/txt_line1"
|
||||
android:layout_alignStart="@id/txt_line1"
|
||||
android:layout_alignEnd="@id/txt_line1"
|
||||
android:textAppearance="@style/TextAppearance.Aurora.Line2"
|
||||
tools:text="Version" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txt_changelog"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/txt_line2"
|
||||
android:layout_alignStart="@id/txt_line1"
|
||||
android:layout_alignEnd="@id/txt_line1"
|
||||
android:layout_marginTop="@dimen/margin_small"
|
||||
android:background="@drawable/bg_outlined_padded"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/TextAppearance.Aurora.Line2"
|
||||
tools:text="Base version" />
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:weightSum="2">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_secondary"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton.Dialog.Flush"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/height_button"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/action_ignore" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_primary"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton.Dialog.Flush"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/height_button"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/action_update" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
Reference in New Issue
Block a user