feat: prompt to use Ktor downloader on Android DownloadManager failure

This commit is contained in:
rushiiMachine 2024-08-05 12:08:24 -07:00
parent ad7fc35495
commit 3662b67ad6
No known key found for this signature in database
GPG key ID: DCBE5952BB3B6420
6 changed files with 89 additions and 7 deletions

View file

@ -110,7 +110,7 @@ class AndroidDownloadManager(application: Application) : IDownloadManager {
* Error returned by the system [DownloadManager].
* @param reason The reason code returned by the [DownloadManager.COLUMN_REASON] column.
*/
data class Error(private val reason: Int) : Result.Error() {
data class Error(val reason: Int) : Result.Error() {
/**
* Convert a [DownloadManager.COLUMN_REASON] code into its name.
*/

View file

@ -19,9 +19,12 @@ import org.koin.core.component.inject
* quickly switching the step groups in the UI. (very disorienting)
* Larger delay leads to a perception that it's doing more work than it actually is.
*/
const val MINIMUM_STEP_DELAY: Long = 600L
private const val MINIMUM_STEP_DELAY: Long = 600L
const val ERROR_NOTIF_ID = 200002
/**
* ID used for showing error notifications emanating from this step runner.
*/
private const val ERROR_NOTIF_ID = 200002
abstract class StepRunner : KoinComponent {
private val context: Context by inject()

View file

@ -1,13 +1,22 @@
package com.aliucord.manager.patcher.steps.base
import android.app.DownloadManager
import android.content.Context
import android.util.Log
import android.widget.Toast
import androidx.annotation.CallSuper
import androidx.compose.runtime.Stable
import com.aliucord.manager.BuildConfig
import com.aliucord.manager.R
import com.aliucord.manager.di.DownloadManagerProvider
import com.aliucord.manager.di.DownloaderSetting
import com.aliucord.manager.manager.OverlayManager
import com.aliucord.manager.manager.PreferencesManager
import com.aliucord.manager.manager.download.AndroidDownloadManager
import com.aliucord.manager.manager.download.IDownloadManager
import com.aliucord.manager.patcher.StepRunner
import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.ui.components.dialogs.AlternativeDownloaderDialog
import com.aliucord.manager.util.showToast
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@ -18,6 +27,8 @@ import java.io.File
@Stable
abstract class DownloadStep : Step(), KoinComponent {
private val context: Context by inject()
private val overlays: OverlayManager by inject()
private val prefs: PreferencesManager by inject()
private val downloaders: DownloadManagerProvider by inject()
/**
@ -35,6 +46,7 @@ abstract class DownloadStep : Step(), KoinComponent {
* Verify that the download completely successfully without errors.
* @throws Throwable If verification fails.
*/
@CallSuper
open suspend fun verify() {
if (!targetFile.exists())
throw Error("Downloaded file is missing!")
@ -60,6 +72,9 @@ abstract class DownloadStep : Step(), KoinComponent {
}
when (result) {
is IDownloadManager.Result.Cancelled ->
state = StepState.Error
is IDownloadManager.Result.Success -> {
try {
verify()
@ -80,11 +95,31 @@ abstract class DownloadStep : Step(), KoinComponent {
Toast.makeText(context, toastText, Toast.LENGTH_LONG).show()
}
// If this is a specific Android DownloadManager error, then prompt to use a different downloader
if (result is AndroidDownloadManager.Error
&& result.reason in arrayOf(DownloadManager.ERROR_HTTP_DATA_ERROR, DownloadManager.ERROR_CANNOT_RESUME)
&& prefs.downloader != DownloaderSetting.Ktor
) {
state = StepState.Error
val confirmed = overlays.startComposableForResult { callback ->
AlternativeDownloaderDialog(
onConfirm = { callback(true) },
onDismiss = { callback(false) },
)
}
if (confirmed) {
Log.i(BuildConfig.TAG, "Changing to alternative downloader after failure")
prefs.downloader = DownloaderSetting.Ktor
state = StepState.Running
return execute(container)
}
}
throw Error("Failed to download: $result")
}
is IDownloadManager.Result.Cancelled ->
state = StepState.Error
}
}
}

View file

@ -29,7 +29,7 @@ class DownloadDiscordStep : DownloadStep(), KoinComponent {
private companion object {
/**
* Last version of Discord before the RN transition.
* Last version of Discord before the RNA rewrite
*/
const val DISCORD_KT_VERSION = 126021

View file

@ -0,0 +1,41 @@
package com.aliucord.manager.ui.components.dialogs
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import com.aliucord.manager.R
@Composable
fun AlternativeDownloaderDialog(
onConfirm: () -> Unit,
onDismiss: () -> Unit,
) {
AlertDialog(
onDismissRequest = onDismiss,
confirmButton = {
FilledTonalButton(
onClick = onConfirm,
colors = ButtonDefaults.filledTonalButtonColors(
containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.onPrimary,
),
) {
Text(stringResource(R.string.action_retry))
}
},
dismissButton = {
TextButton(
onClick = onDismiss,
colors = ButtonDefaults.textButtonColors(
contentColor = MaterialTheme.colorScheme.error,
),
) {
Text(stringResource(R.string.action_cancel))
}
},
title = { Text(stringResource(R.string.alt_downloader_dialog_title)) },
text = { Text(stringResource(R.string.alt_downloader_dialog_desc)) },
icon = { Icon(painterResource(R.drawable.ic_download), contentDescription = null) },
)
}

View file

@ -164,6 +164,9 @@
<string name="play_protect_warning_ok">Continue</string>
<string name="play_protect_warning_open_gpp">Open Play Protect</string>
<string name="alt_downloader_dialog_title">Alternative Downloader</string>
<string name="alt_downloader_dialog_desc">This download failed with a specific error that may indicate issues with the system\'s DownloadManager. Would you like to retry with the the alternative downloader implementation?</string>
<string name="fun_fact_prefix">Fun Fact: %s</string>
<string name="fun_fact_1">Did you know that Google Play Protect is useless?</string>
<string name="fun_fact_2">Did you know Aliucord with 150+ plugins somehow runs better than Discord\'s new app?</string>