retrofit goes brrrrrr

This commit is contained in:
X1nto 2021-01-16 18:36:46 +04:00
parent e670b5764e
commit 1ceb53d2d4
7 changed files with 165 additions and 81 deletions

View File

@ -31,7 +31,6 @@
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:largeHeap="true"
tools:ignore="UnusedAttribute"> tools:ignore="UnusedAttribute">
<activity <activity

View File

@ -2,8 +2,10 @@ package com.vanced.manager.core.downloader
import android.content.Context import android.content.Context
import com.vanced.manager.R import com.vanced.manager.R
import com.vanced.manager.utils.DownloadHelper.download
import com.vanced.manager.utils.DownloadHelper.downloadProgress import com.vanced.manager.utils.DownloadHelper.downloadProgress
import com.vanced.manager.utils.DownloadHelper.fuelDownload import com.vanced.manager.utils.Extensions.getDefaultPrefs
import com.vanced.manager.utils.Extensions.getInstallUrl
import com.vanced.manager.utils.InternetTools.microg import com.vanced.manager.utils.InternetTools.microg
import com.vanced.manager.utils.PackageHelper.install import com.vanced.manager.utils.PackageHelper.install
@ -14,11 +16,13 @@ object MicrogDownloader {
fun downloadMicrog(context: Context) { fun downloadMicrog(context: Context) {
val url = microg.value?.string("url") ?: "" val url = microg.value?.string("url") ?: ""
fuelDownload(url, folderName, fileName, context, onDownloadComplete = { context.getDefaultPrefs().getInstallUrl()?.let {
startMicrogInstall(context) download(url, "$it/", folderName, fileName, context, onDownloadComplete = {
}, onError = { startMicrogInstall(context)
downloadProgress.value?.downloadingFile?.postValue(context.getString(R.string.error_downloading, fileName)) }, onError = {
}) downloadProgress.value?.downloadingFile?.postValue(context.getString(R.string.error_downloading, fileName))
})
}
} }

View File

@ -6,8 +6,8 @@ import com.vanced.manager.R
import com.vanced.manager.utils.AppUtils.musicRootPkg import com.vanced.manager.utils.AppUtils.musicRootPkg
import com.vanced.manager.utils.AppUtils.validateTheme import com.vanced.manager.utils.AppUtils.validateTheme
import com.vanced.manager.utils.DeviceUtils.getArch import com.vanced.manager.utils.DeviceUtils.getArch
import com.vanced.manager.utils.DownloadHelper.download
import com.vanced.manager.utils.DownloadHelper.downloadProgress import com.vanced.manager.utils.DownloadHelper.downloadProgress
import com.vanced.manager.utils.DownloadHelper.fuelDownload
import com.vanced.manager.utils.Extensions.getInstallUrl import com.vanced.manager.utils.Extensions.getInstallUrl
import com.vanced.manager.utils.Extensions.getLatestAppVersion import com.vanced.manager.utils.Extensions.getLatestAppVersion
import com.vanced.manager.utils.InternetTools.getFileNameFromUrl import com.vanced.manager.utils.InternetTools.getFileNameFromUrl
@ -42,10 +42,10 @@ object MusicDownloader {
private fun downloadApk(context: Context, apk: String = "music") { private fun downloadApk(context: Context, apk: String = "music") {
val url = if (apk == "stock") "$baseurl/stock/${getArch()}.apk" else "$baseurl/$variant.apk" val url = if (apk == "stock") "$baseurl/stock/${getArch()}.apk" else "$baseurl/$variant.apk"
fuelDownload(url, folderName!!, getFileNameFromUrl(url), context, onDownloadComplete = { download(url, baseurl + "/", folderName!!, getFileNameFromUrl(url), context, onDownloadComplete = {
if (variant == "root" && apk != "stock") { if (variant == "root" && apk != "stock") {
downloadApk(context, "stock") downloadApk(context, "stock")
return@fuelDownload return@download
} }
when (apk) { when (apk) {

View File

@ -9,8 +9,8 @@ import com.vanced.manager.R
import com.vanced.manager.utils.AppUtils.validateTheme import com.vanced.manager.utils.AppUtils.validateTheme
import com.vanced.manager.utils.AppUtils.vancedRootPkg import com.vanced.manager.utils.AppUtils.vancedRootPkg
import com.vanced.manager.utils.DeviceUtils.getArch import com.vanced.manager.utils.DeviceUtils.getArch
import com.vanced.manager.utils.DownloadHelper.download
import com.vanced.manager.utils.DownloadHelper.downloadProgress import com.vanced.manager.utils.DownloadHelper.downloadProgress
import com.vanced.manager.utils.DownloadHelper.fuelDownload
import com.vanced.manager.utils.Extensions.getInstallUrl import com.vanced.manager.utils.Extensions.getInstallUrl
import com.vanced.manager.utils.Extensions.getLatestAppVersion import com.vanced.manager.utils.Extensions.getLatestAppVersion
import com.vanced.manager.utils.InternetTools.getFileNameFromUrl import com.vanced.manager.utils.InternetTools.getFileNameFromUrl
@ -77,48 +77,50 @@ object VancedDownloader {
else -> throw NotImplementedError("This type of APK is NOT valid. What the hell did you even do?") else -> throw NotImplementedError("This type of APK is NOT valid. What the hell did you even do?")
} }
fuelDownload(url, folderName!!, getFileNameFromUrl(url), context, onDownloadComplete = { installUrl?.let {
when (type) { download(url, "$it/", folderName!!, getFileNameFromUrl(url), context, onDownloadComplete = {
"theme" -> when (type) {
if (variant == "root") { "theme" ->
if (validateTheme(downloadPath!!, theme!!, hashUrl, context)) { if (variant == "root") {
if (downloadStockCheck(vancedRootPkg, vancedVersionCode, context)) if (validateTheme(downloadPath!!, theme!!, hashUrl, context)) {
downloadSplits(context, "arch") if (downloadStockCheck(vancedRootPkg, vancedVersionCode, context))
else downloadSplits(context, "arch")
startVancedInstall(context) else
startVancedInstall(context)
} else
downloadSplits(context, "theme")
} else } else
downloadSplits(context, "theme") downloadSplits(context, "arch")
} else "arch" -> if (variant == "root") downloadSplits(context, "stock") else downloadSplits(context, "lang")
downloadSplits(context, "arch") "stock" -> downloadSplits(context, "dpi")
"arch" -> if (variant == "root") downloadSplits(context, "stock") else downloadSplits(context, "lang") "dpi" -> downloadSplits(context, "lang")
"stock" -> downloadSplits(context, "dpi") "lang" -> {
"dpi" -> downloadSplits(context, "lang") count++
"lang" -> { succesfulLangCount++
count++ if (count < lang.size)
succesfulLangCount++ downloadSplits(context, "lang")
if (count < lang.size) else
downloadSplits(context, "lang") startVancedInstall(context)
else
startVancedInstall(context)
}
}
}, onError = {
if (type == "lang") {
count++
when {
count < lang.size -> downloadSplits(context, "lang")
succesfulLangCount == 0 -> {
lang.add("en")
downloadSplits(context, "lang")
} }
else -> startVancedInstall(context)
}
} else { }
downloadProgress.value?.downloadingFile?.postValue(context.getString(R.string.error_downloading, getFileNameFromUrl(url))) }, onError = {
} if (type == "lang") {
}) count++
when {
count < lang.size -> downloadSplits(context, "lang")
succesfulLangCount == 0 -> {
lang.add("en")
downloadSplits(context, "lang")
}
else -> startVancedInstall(context)
}
} else {
downloadProgress.value?.downloadingFile?.postValue(context.getString(R.string.error_downloading, getFileNameFromUrl(url)))
}
})
}
} }
fun startVancedInstall(context: Context, variant: String? = this.variant) { fun startVancedInstall(context: Context, variant: String? = this.variant) {

View File

@ -2,6 +2,8 @@ package com.vanced.manager.model
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.github.kittinunf.fuel.core.requests.CancellableRequest import com.github.kittinunf.fuel.core.requests.CancellableRequest
import okhttp3.ResponseBody
import retrofit2.Call
open class ProgressModel { open class ProgressModel {
@ -9,7 +11,7 @@ open class ProgressModel {
val downloadingFile = MutableLiveData<String>() val downloadingFile = MutableLiveData<String>()
val installing = MutableLiveData<Boolean>() val installing = MutableLiveData<Boolean>()
var currentDownload: CancellableRequest? = null var currentDownload: Call<ResponseBody>? = null
fun reset() { fun reset() {
downloadProgress.value = 0 downloadProgress.value = 0

View File

@ -7,43 +7,106 @@ import android.os.Build
import android.util.Log import android.util.Log
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.github.kittinunf.fuel.Fuel
import com.vanced.manager.R import com.vanced.manager.R
import com.vanced.manager.library.network.providers.createService
import com.vanced.manager.model.ProgressModel import com.vanced.manager.model.ProgressModel
import com.vanced.manager.utils.AppUtils.sendCloseDialog import com.vanced.manager.utils.AppUtils.sendCloseDialog
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File import okhttp3.ResponseBody
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Streaming
import retrofit2.http.Url
import java.io.*
object DownloadHelper : CoroutineScope by CoroutineScope(Dispatchers.IO) { object DownloadHelper : CoroutineScope by CoroutineScope(Dispatchers.IO) {
fun fuelDownload(url: String, fileFolder: String, fileName: String, context: Context, onDownloadComplete: () -> Unit, onError: (error: String) -> Unit) = launch { interface DownloadHelper {
try {
downloadProgress.value?.downloadingFile?.postValue(context.getString(R.string.downloading_file, fileName))
downloadProgress.value?.currentDownload = Fuel.download(url)
.fileDestination { _, _ ->
File(context.getExternalFilesDir(fileFolder)?.path, fileName)
}
.progress { readBytes, totalBytes ->
downloadProgress.value?.downloadProgress?.postValue((readBytes * 100 / totalBytes).toInt())
}
.responseString { _, _, result ->
result.fold(success = {
downloadProgress.value?.downloadProgress?.postValue(0)
onDownloadComplete()
}, failure = { error ->
downloadProgress.value?.downloadProgress?.postValue(0)
Log.d("VMDownloader", error.cause.toString())
onError(error.errorData.toString())
})
}
} catch (e: Exception) {
downloadProgress.value?.downloadProgress?.postValue(0)
Log.d("VMDownloader", "Failed to download file: $url")
onError("")
}
@Streaming
@GET
fun download(@Url url: String): Call<ResponseBody>
}
fun download(
url: String,
baseUrl: String,
fileFolder: String,
fileName: String,
context: Context,
onDownloadComplete: () -> Unit,
onError: (error: String) -> Unit
) {
downloadProgress.value?.downloadingFile?.postValue(context.getString(R.string.downloading_file, fileName))
val downloadInterface = createService(DownloadHelper::class, baseUrl)
val download = downloadInterface.download(url)
downloadProgress.value?.currentDownload = download
download.enqueue(object : Callback<ResponseBody> {
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
if (response.isSuccessful) {
CoroutineScope(Dispatchers.IO).launch {
if (response.body()?.let { writeFile(it, context.getExternalFilesDir(fileFolder)?.path + "/" + fileName) } == true) {
onDownloadComplete()
} else {
onError("Could not save file")
downloadProgress.value?.downloadProgress?.postValue(0)
Log.d("VMDownloader", "Failed to download file: $url")
}
}
} else {
onError(response.errorBody().toString())
downloadProgress.value?.downloadProgress?.postValue(0)
Log.d("VMDownloader", "Failed to download file: $url")
}
}
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
if (call.isCanceled) {
Log.d("VMDownloader", "Download canceled")
downloadProgress.value?.downloadProgress?.postValue(0)
} else {
onError(t.stackTraceToString())
downloadProgress.value?.downloadProgress?.postValue(0)
Log.d("VMDownloader", "Failed to download file: $url")
}
}
})
}
fun writeFile(body: ResponseBody, filePath: String): Boolean {
return try {
val file = File(filePath)
val totalBytes = body.contentLength()
var inputStream: InputStream? = null
var outputStream: OutputStream? = null
try {
val fileReader = ByteArray(4096)
var downloadedBytes: Long = 0
inputStream = body.byteStream()
outputStream = FileOutputStream(file)
var read: Int
while (inputStream.read(fileReader).also { read = it } != -1) {
outputStream.write(fileReader, 0, read)
downloadedBytes += read.toLong()
downloadProgress.value?.downloadProgress?.postValue((downloadedBytes * 100 / totalBytes).toInt())
}
outputStream.flush()
true
} catch (e: IOException) {
false
} finally {
inputStream?.close()
outputStream?.close()
}
} catch (e: IOException) {
false
}
} }
val downloadProgress = MutableLiveData<ProgressModel>() val downloadProgress = MutableLiveData<ProgressModel>()
@ -54,7 +117,7 @@ object DownloadHelper : CoroutineScope by CoroutineScope(Dispatchers.IO) {
fun downloadManager(context: Context) { fun downloadManager(context: Context) {
val url = "https://github.com/YTVanced/VancedManager/releases/latest/download/manager.apk" val url = "https://github.com/YTVanced/VancedManager/releases/latest/download/manager.apk"
fuelDownload(url, "manager", "manager.apk", context, onDownloadComplete = { download(url,"https://github.com/YTVanced/VancedManager", "manager", "manager.apk", context, onDownloadComplete = {
val apk = File("${context.getExternalFilesDir("manager")?.path}/manager.apk") val apk = File("${context.getExternalFilesDir("manager")?.path}/manager.apk")
val uri = val uri =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
@ -69,7 +132,12 @@ object DownloadHelper : CoroutineScope by CoroutineScope(Dispatchers.IO) {
context.startActivity(intent) context.startActivity(intent)
sendCloseDialog(context) sendCloseDialog(context)
}, onError = { }, onError = {
downloadProgress.value?.downloadingFile?.postValue(context.getString(R.string.error_downloading, "manager.apk")) downloadProgress.value?.downloadingFile?.postValue(
context.getString(
R.string.error_downloading,
"manager.apk"
)
)
}) })
} }

View File

@ -4,6 +4,7 @@ import com.squareup.moshi.Moshi
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory import retrofit2.converter.moshi.MoshiConverterFactory
import kotlin.reflect.KClass
fun provideRetrofit( fun provideRetrofit(
okHttpClient: OkHttpClient, okHttpClient: OkHttpClient,
@ -13,4 +14,12 @@ fun provideRetrofit(
.addConverterFactory(MoshiConverterFactory.create(moshi)) .addConverterFactory(MoshiConverterFactory.create(moshi))
.client(okHttpClient) .client(okHttpClient)
.baseUrl(url) .baseUrl(url)
.build() .build()
fun <S: Any> createService(service: KClass<S>, baseurl: String): S {
return provideRetrofit(
provideOkHttpClient(),
provideMoshi(),
baseurl
).create(service.java)
}