installer adjustments

This commit is contained in:
X1nto 2021-07-12 18:00:23 +04:00
parent 493b6d3963
commit 0a50882412
27 changed files with 492 additions and 279 deletions

View File

@ -120,7 +120,7 @@ dependencies {
implementation("com.squareup.retrofit2:retrofit:$retrofitVersion")
implementation("com.squareup.retrofit2:converter-gson:$retrofitVersion")
implementation("com.github.x1nto:apkhelper:1.1.0")
implementation("com.github.x1nto:apkhelper:1.1.2")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.2")

View File

@ -3,6 +3,18 @@
package="com.vanced.manager">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<queries>
<package android:name="com.vanced.android.youtube" />
<package android:name="com.google.android.youtube" />
<package android:name="com.vanced.android.apps.youtube.music" />
<package android:name="com.google.android.apps.youtube.music" />
<package android:name="com.mgoogle.android.gms" />
<package android:name="com.vanced.faq" />
<package android:name="com.android.vending" />
</queries>
<application
android:name=".ManagerApplication"
@ -29,6 +41,8 @@
android:theme="@style/Theme.MaterialComponents.NoActionBar"
android:label="@string/app_name"/>
<service android:name="com.xinto.apkhelper.services.PackageManagerService" />
</application>
</manifest>

View File

@ -16,6 +16,7 @@ class ManagerApplication : Application() {
modules(
apiModule,
downloaderModule,
installerModule,
mapperModule,
networkModule,
packageManagerModule,

View File

@ -2,16 +2,28 @@ package com.vanced.manager.di
import com.vanced.manager.downloader.api.VancedAPI
import com.vanced.manager.downloader.impl.VancedDownloader
import com.vanced.manager.installer.VancedInstaller
import org.koin.dsl.module
val downloaderModule = module {
fun provideVancedDownloader(
vancedAPI: VancedAPI,
): VancedDownloader = VancedDownloader(vancedAPI)
vancedInstaller: VancedInstaller
): VancedDownloader = VancedDownloader(vancedAPI, vancedInstaller)
single {
provideVancedDownloader(get())
}
fun provideMusicDownloader(
vancedAPI: VancedAPI,
vancedInstaller: VancedInstaller
): VancedDownloader = VancedDownloader(vancedAPI, vancedInstaller)
fun provideMicrogDownloader(
vancedAPI: VancedAPI,
vancedInstaller: VancedInstaller
): VancedDownloader = VancedDownloader(vancedAPI, vancedInstaller)
single { provideVancedDownloader(get(), get()) }
single { provideMusicDownloader(get(), get()) }
single { provideMicrogDownloader(get(), get()) }
}

View File

@ -1,15 +1,19 @@
package com.vanced.manager.di
import android.content.Context
import com.vanced.manager.installer.AppInstaller
import com.vanced.manager.ui.viewmodel.HomeViewModel
import com.vanced.manager.installer.MicrogInstaller
import com.vanced.manager.installer.MusicInstaller
import com.vanced.manager.installer.VancedInstaller
import org.koin.dsl.module
val installerModule = module {
fun provideAppInstaller(
context: Context,
homeViewModel: HomeViewModel
) = AppInstaller(context, homeViewModel)
single { provideAppInstaller(get(), get()) }
fun provideVancedInstaller() = VancedInstaller()
fun provideMusicInstaller() = MusicInstaller()
fun provideMicrogInstaller() = MicrogInstaller()
single { provideVancedInstaller() }
single { provideMusicInstaller() }
single { provideMicrogInstaller() }
}

View File

@ -10,10 +10,8 @@ val mapperModule = module {
fun provideAppMapper(
packageInformationDataSource: PackageInformationDataSource,
vancedDownloader: VancedDownloader,
): AppDtoMapper = AppDtoMapper(
packageInformationDataSource = packageInformationDataSource,
vancedDownloader = vancedDownloader
packageInformationDataSource = packageInformationDataSource
)
fun provideJsonMapper(
@ -22,7 +20,7 @@ val mapperModule = module {
appDtoMapper = appDtoMapper
)
single { provideAppMapper(get(), get()) }
single { provideAppMapper(get()) }
single { provideJsonMapper(get()) }
}

View File

@ -1,6 +1,6 @@
package com.vanced.manager.domain.model
import com.vanced.manager.downloader.base.BaseDownloader
import com.vanced.manager.downloader.base.AppDownloader
import com.vanced.manager.ui.widgets.home.installation.InstallationOption
data class App(
@ -21,6 +21,6 @@ data class App(
val versions: List<String>? = null,
val themes: List<String>? = null,
val languages: List<String>? = null,
val downloader: BaseDownloader? = null,
val downloader: AppDownloader? = null,
val installationOptions: List<InstallationOption>? = null
)

View File

@ -8,7 +8,7 @@ import retrofit2.http.Streaming
interface VancedAPI {
@GET("apks/{version}/{variant}/{type}/{apkName}.apk")
@GET("apks/v{version}/{variant}/{type}/{apkName}")
@Streaming
fun getApk(
@Path("version") version: String,

View File

@ -0,0 +1,167 @@
package com.vanced.manager.downloader.base
import android.content.Context
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import com.vanced.manager.domain.model.App
import com.vanced.manager.installer.base.AppInstaller
import com.vanced.manager.ui.viewmodel.HomeViewModel
import com.vanced.manager.util.log
import okhttp3.ResponseBody
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import retrofit2.Call
import retrofit2.awaitResponse
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
abstract class AppDownloader(
val appName: String,
val appInstaller: AppInstaller
) : KoinComponent {
data class File(
val call: Call<ResponseBody>,
val fileName: String
)
var downloadProgress by mutableStateOf(0f)
private set
var downloadFile by mutableStateOf("")
private set
var installing by mutableStateOf(false)
var error by mutableStateOf(false)
val showDownloadScreen = mutableStateOf(false)
private var canceled = false
private lateinit var call: Call<ResponseBody>
private val tag = this::class.simpleName!!
private fun resetValues() {
showDownloadScreen.value = false
downloadProgress = 0f
downloadFile = ""
installing = false
error = false
canceled = false
}
val context: Context by inject()
abstract suspend fun download(
app: App,
viewModel: HomeViewModel
)
private fun install(viewModel: HomeViewModel) {
installing = true
appInstaller.install {
viewModel.fetch()
resetValues()
}
}
suspend fun downloadFile(
file: File,
viewModel: HomeViewModel,
folderStructure: String,
onError: (error: String) -> Unit = {},
) {
downloadFiles(
files = listOf(file),
viewModel = viewModel,
folderStructure = folderStructure,
onError = onError
)
}
suspend fun downloadFiles(
files: List<File>,
viewModel: HomeViewModel,
folderStructure: String,
onError: (error: String) -> Unit = {},
) {
showDownloadScreen.value = true
fun error(errorBody: String) {
error = true
onError(errorBody)
log(tag, errorBody)
}
try {
for (file in files) {
if (canceled) {
break
}
val fileName = file.fileName
downloadFile = fileName
this.call = file.call
val response = call.awaitResponse()
if (response.isSuccessful) {
val body = response.body()
if (body != null) {
if (!writeFile(body, fileName, folderStructure)) {
error("Failed to write file data")
}
}
} else {
val error = response.errorBody()?.toString()
if (error != null) {
error(error)
}
}
}
} catch (e: Exception) {
error(e.stackTraceToString())
}
if (canceled) {
resetValues()
return
}
install(viewModel)
}
fun cancelDownload() {
canceled = true
call.cancel()
}
private fun writeFile(
body: ResponseBody,
fileName: String,
folderStructure: String
): Boolean {
val folder = File("${context.getExternalFilesDir(appName)?.path}/$folderStructure")
folder.mkdirs()
val file = File("${folder.path}/$fileName")
val inputStream = body.byteStream()
val outputStream = FileOutputStream(file)
return try {
val totalBytes = body.contentLength()
val fileReader = ByteArray(4096)
var downloadedBytes = 0L
var read: Int
while (inputStream.read(fileReader).also { read = it } != -1) {
outputStream.write(fileReader, 0, read)
downloadedBytes += read
downloadProgress = (downloadedBytes * 100 / totalBytes).toFloat()
}
true
} catch (e: IOException) {
false
} finally {
inputStream.close()
outputStream.close()
}
}
}

View File

@ -1,106 +0,0 @@
package com.vanced.manager.downloader.base
import android.content.Context
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import com.vanced.manager.installer.AppInstaller
import com.vanced.manager.util.log
import okhttp3.ResponseBody
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import retrofit2.Call
import retrofit2.awaitResponse
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
abstract class BaseDownloader(
val appName: String
) : KoinComponent {
var downloadProgress by mutableStateOf(0f)
private set
var downloadFile by mutableStateOf("")
private set
var installing by mutableStateOf(false)
private lateinit var call: Call<ResponseBody>
private val tag = this::class.simpleName!!
val context: Context by inject()
val appInstaller: AppInstaller by inject()
abstract suspend fun download()
suspend fun downloadFile(
call: Call<ResponseBody>,
folderStructure: String,
fileName: String,
onError: (error: String) -> Unit = {},
onComplete: suspend () -> Unit = {},
) {
fun error(errorBody: String) {
downloadFile = "Error downloading $fileName"
onError(errorBody)
log(tag, errorBody)
}
try {
this.call = call
val response = call.awaitResponse()
if (response.isSuccessful) {
val body = response.body()
if (body != null) {
if (writeFile(body, fileName, folderStructure)) {
onComplete()
}
}
} else {
val error = response.errorBody()?.toString()
if (error != null) {
error(error)
}
}
} catch (e: Exception) {
error(e.stackTraceToString())
}
downloadProgress = 0f
}
fun cancelDownload() {
call.cancel()
}
private fun writeFile(
body: ResponseBody,
fileName: String,
folderStructure: String
): Boolean {
val file = File("${context.getExternalFilesDir(appName)?.path}/$folderStructure/$fileName")
val inputStream = body.byteStream()
val outputStream = FileOutputStream(file)
return try {
val totalBytes = body.contentLength()
val fileReader = ByteArray(4096)
var downloadedBytes = 0L
var read: Int
while (inputStream.read(fileReader).also { read = it } != -1) {
outputStream.write(fileReader, 0, read)
downloadedBytes += read
downloadProgress = (downloadedBytes * 100 / totalBytes).toFloat()
}
true
} catch (e: IOException) {
false
} finally {
inputStream.close()
outputStream.close()
}
}
}

View File

@ -1,11 +1,13 @@
package com.vanced.manager.downloader.impl
import com.vanced.manager.downloader.base.BaseDownloader
import com.vanced.manager.domain.model.App
import com.vanced.manager.downloader.base.AppDownloader
import com.vanced.manager.ui.viewmodel.HomeViewModel
object MicrogDownloader : BaseDownloader("") {
override suspend fun download() {
class MicrogDownloader : AppDownloader("") {
override suspend fun download(app: App, viewModel: HomeViewModel) {
TODO("Not yet implemented")
}
}

View File

@ -1,11 +1,13 @@
package com.vanced.manager.downloader.impl
import com.vanced.manager.downloader.base.BaseDownloader
import com.vanced.manager.domain.model.App
import com.vanced.manager.downloader.base.AppDownloader
import com.vanced.manager.ui.viewmodel.HomeViewModel
object MusicDownloader : BaseDownloader("") {
override suspend fun download() {
class MusicDownloader : AppDownloader("") {
override suspend fun download(app: App, viewModel: HomeViewModel) {
TODO("Not yet implemented")
}
}

View File

@ -1,73 +1,119 @@
package com.vanced.manager.downloader.impl
import com.vanced.manager.domain.model.App
import com.vanced.manager.downloader.api.VancedAPI
import com.vanced.manager.downloader.base.BaseDownloader
import com.vanced.manager.downloader.base.AppDownloader
import com.vanced.manager.installer.VancedInstaller
import com.vanced.manager.ui.preferences.holder.managerVariantPref
import com.vanced.manager.ui.preferences.holder.vancedLanguagesPref
import com.vanced.manager.ui.preferences.holder.vancedThemePref
import com.vanced.manager.ui.preferences.holder.vancedVersionPref
import com.vanced.manager.ui.viewmodel.HomeViewModel
import com.vanced.manager.util.arch
import com.vanced.manager.util.log
class VancedDownloader(
private val vancedAPI: VancedAPI,
) : BaseDownloader(
appName = "vanced"
vancedInstaller: VancedInstaller
) : AppDownloader(
appName = "vanced",
appInstaller = vancedInstaller
) {
private lateinit var version: String
private lateinit var variant: String
private val theme by vancedThemePref
private val version by vancedVersionPref
private val variant by managerVariantPref
private val languages by vancedLanguagesPref
private lateinit var folderStructure: String
override suspend fun download() {
version = "v16.16.38"
variant = "nonroot"
folderStructure = "$appName/$version/$variant"
downloadTheme()
}
private suspend fun downloadTheme() {
downloadVancedApk(
type = "Theme",
apkName = "black.apk"
) {
downloadArch()
override suspend fun download(app: App, viewModel: HomeViewModel) {
val files = listOf(
getFile(
type = "Theme",
apkName = "$theme.apk"
),
getFile(
type = "Arch",
apkName = "split_config.$arch.apk"
)
) + languages.map { language ->
getFile("Language", "split_config.$language.apk")
}
downloadFiles(
files = files,
viewModel,
folderStructure = "$version/$variant",
onError = {
log("error", it)
}
)
}
private suspend fun downloadArch() {
downloadVancedApk(
type = "Arch",
apkName = "split_config.x86.apk"
) {
downloadLanguage()
}
}
private suspend fun downloadLanguage() {
downloadVancedApk(
type = "Language",
apkName = "split_config.en.apk"
) {
appInstaller.installVanced(version)
}
}
private suspend fun downloadVancedApk(
private fun getFile(
type: String,
apkName: String,
onDownload: suspend () -> Unit,
) {
downloadFile(
vancedAPI.getApk(
version = version,
variant = variant,
type = type,
apkName = apkName
),
folderStructure = folderStructure,
fileName = apkName,
onError = {
) = File(
call = vancedAPI.getApk(
version = version,
variant = variant,
type = type,
apkName = apkName
),
fileName = apkName
)
}
) {
onDownload()
}
}
// private suspend fun downloadTheme() {
// val theme by vancedThemePref
// downloadVancedApk(
// type = "Theme",
// apkName = "$theme.apk"
// ) {
// downloadArch()
// }
// }
//
// private suspend fun downloadArch() {
// downloadVancedApk(
// type = "Arch",
// apkName = "split_config.x86.apk"
// ) {
// downloadLanguage()
// }
// }
//
// private suspend fun downloadLanguage() {
// val languages by vancedLanguagesPref
// languages.forEach { language ->
// downloadVancedApk(
// type = "Language",
// apkName = "split_config.$language.apk"
// ) {}
// }
// install()
// }
//
//
//
//
// private suspend fun downloadVancedApk(
// type: String,
// apkName: String,
// onDownload: suspend () -> Unit,
// ) {
// downloadFile(
// vancedAPI.getApk(
// version = version,
// variant = variant,
// type = type,
// apkName = apkName
// ),
// folderStructure = "$version/$variant",
// fileName = apkName,
// onError = {
// log("error", it)
// }
// ) {
// onDownload()
// }
// }
}

View File

@ -1,34 +0,0 @@
package com.vanced.manager.installer
import android.content.Context
import com.vanced.manager.ui.viewmodel.HomeViewModel
import com.xinto.apkhelper.installSplitApks
import com.xinto.apkhelper.statusCallback
import com.xinto.apkhelper.statusCallbackBuilder
class AppInstaller(
private val context: Context,
private val viewModel: HomeViewModel
) {
fun installVanced(version: String) {
installSplitApks(context.getExternalFilesDir("vanced/$version")!!.path, context)
}
fun installMusic() {
}
fun installMicrog() {
}
init {
statusCallback = statusCallbackBuilder(
onAction = {
viewModel.fetch()
}
)
}
}

View File

@ -0,0 +1,26 @@
package com.vanced.manager.installer
import androidx.compose.runtime.MutableState
import com.vanced.manager.installer.base.AppInstaller
import com.vanced.manager.ui.preferences.holder.managerVariantPref
import com.vanced.manager.ui.preferences.holder.vancedVersionPref
import com.vanced.manager.ui.viewmodel.HomeViewModel
import com.xinto.apkhelper.installSplitApks
class MicrogInstaller : AppInstaller() {
override fun install(
onDone: () -> Unit
) {
super.install(onDone)
val version by vancedVersionPref
val variant by managerVariantPref
installSplitApks(
apksPath = context.getExternalFilesDir("vanced/$version/$variant")!!.path,
context = context
)
}
}

View File

@ -0,0 +1,24 @@
package com.vanced.manager.installer
import com.vanced.manager.installer.base.AppInstaller
import com.vanced.manager.ui.preferences.holder.managerVariantPref
import com.vanced.manager.ui.preferences.holder.vancedVersionPref
import com.xinto.apkhelper.installSplitApks
class MusicInstaller : AppInstaller() {
override fun install(
onDone: () -> Unit
) {
super.install(onDone)
val version by vancedVersionPref
val variant by managerVariantPref
installSplitApks(
apksPath = context.getExternalFilesDir("vanced/$version/$variant")!!.path,
context = context
)
}
}

View File

@ -0,0 +1,26 @@
package com.vanced.manager.installer
import androidx.compose.runtime.MutableState
import com.vanced.manager.installer.base.AppInstaller
import com.vanced.manager.ui.preferences.holder.managerVariantPref
import com.vanced.manager.ui.preferences.holder.vancedVersionPref
import com.vanced.manager.ui.viewmodel.HomeViewModel
import com.xinto.apkhelper.installSplitApks
class VancedInstaller : AppInstaller() {
override fun install(
onDone: () -> Unit
) {
super.install(onDone)
val version by vancedVersionPref
val variant by managerVariantPref
installSplitApks(
apksPath = context.getExternalFilesDir("vanced/$version/$variant")!!.path,
context = context
)
}
}

View File

@ -0,0 +1,36 @@
package com.vanced.manager.installer.base
import android.content.Context
import androidx.annotation.CallSuper
import com.vanced.manager.util.log
import com.xinto.apkhelper.statusCallback
import com.xinto.apkhelper.statusCallbackBuilder
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
open class AppInstaller : KoinComponent {
val context: Context by inject()
@CallSuper
open fun install(
onDone: () -> Unit
) {
setStatusCallback(onDone = onDone)
}
private fun setStatusCallback(
onDone: () -> Unit
) {
statusCallback = statusCallbackBuilder(
onInstall = { _, _ ->
onDone()
},
onInstallFailed = { error, _, _ ->
onDone()
log("install", error)
}
)
}
}

View File

@ -5,11 +5,6 @@ import com.vanced.manager.domain.datasource.PackageInformationDataSource
import com.vanced.manager.domain.model.App
import com.vanced.manager.domain.model.AppStatus
import com.vanced.manager.domain.util.EntityMapper
import com.vanced.manager.downloader.base.BaseDownloader
import com.vanced.manager.downloader.impl.MicrogDownloader
import com.vanced.manager.downloader.impl.MusicDownloader
import com.vanced.manager.downloader.impl.VancedDownloader
import com.vanced.manager.network.util.MICROG_NAME
import com.vanced.manager.network.util.MUSIC_NAME
import com.vanced.manager.network.util.VANCED_NAME
import com.vanced.manager.ui.preferences.CheckboxPreference
@ -24,8 +19,7 @@ import com.vanced.manager.ui.widgets.home.installation.RadiobuttonInstallationOp
import java.util.*
class AppDtoMapper(
private val packageInformationDataSource: PackageInformationDataSource,
private val vancedDownloader: VancedDownloader
private val packageInformationDataSource: PackageInformationDataSource
) : EntityMapper<AppDto, App> {
override suspend fun mapToModel(entity: AppDto): App =
@ -52,7 +46,6 @@ class AppDtoMapper(
versions = versions,
themes = themes,
languages = languages,
downloader = getDownloader(name),
installationOptions = getInstallationOptions(entity)
)
}
@ -68,14 +61,6 @@ class AppDtoMapper(
AppStatus.Install
}
private fun getDownloader(app: String?): BaseDownloader? =
when (app) {
VANCED_NAME -> vancedDownloader
MUSIC_NAME -> MusicDownloader
MICROG_NAME -> MicrogDownloader
else -> null
}
private fun getInstallationOptions(app: AppDto): List<InstallationOption>? =
when (app.name) {
VANCED_NAME -> listOf(

View File

@ -38,7 +38,7 @@ fun HomeLayout() {
),
contentPaddingHorizontal = 0.dp
) {
HomeAppsItem(viewModel, isFetching)
HomeAppsItem(viewModel)
}
CategoryLayout(
categoryName = managerString(

View File

@ -4,7 +4,7 @@ const val MANAGER_VARIANT_DEFAULT_VALUE = "nonroot"
const val MANAGER_THEME_DEFAULT_VALUE = "System Default"
const val VANCED_THEME_DEFAULT_VALUE = "Dark"
const val VANCED_THEME_DEFAULT_VALUE = "dark"
val VANCED_LANGUAGE_DEFAULT_VALUE = setOf("en")
const val APP_VERSION_DEFAULT_VALUE = "latest"

View File

@ -13,15 +13,14 @@ import com.vanced.manager.ui.widgets.home.apps.card.AppCard
@Composable
fun HomeAppsItem(
viewModel: HomeViewModel,
isFetching: Boolean
viewModel: HomeViewModel
) {
Column(
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
viewModel.apps.fastForEach { app ->
val observedApp by app.observeAsState(initial = App())
AppCard(observedApp, isFetching)
AppCard(observedApp, viewModel)
}
}
}

View File

@ -1,14 +1,12 @@
package com.vanced.manager.ui.widgets.home.apps.card
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.*
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandVertically
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
@ -18,21 +16,25 @@ import com.vanced.manager.ui.components.card.ManagerThemedCard
import com.vanced.manager.ui.components.layout.ManagerButtonColumn
import com.vanced.manager.ui.utils.defaultContentPaddingHorizontal
import com.vanced.manager.ui.utils.defaultContentPaddingVertical
import com.vanced.manager.ui.viewmodel.HomeViewModel
import com.vanced.manager.ui.widgets.button.ManagerCancelButton
import com.vanced.manager.ui.widgets.button.ManagerDownloadButton
import com.vanced.manager.ui.widgets.home.apps.dialog.AppChangelogDialog
import com.vanced.manager.ui.widgets.home.apps.dialog.AppDownloadDialog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun AppCard(
app: App,
fetching: Boolean
viewModel: HomeViewModel
) {
var showDownloadDialog by remember { mutableStateOf(false) }
var showAppInfoDialog by remember { mutableStateOf(false) }
var showAppInfoDialog by rememberSaveable { mutableStateOf(false) }
var showInstallationOptions by remember { mutableStateOf(false) }
val coroutineScope = rememberCoroutineScope { Dispatchers.IO }
val icon = rememberGlidePainter(
request = app.iconUrl ?: "",
fadeIn = true
@ -41,17 +43,21 @@ fun AppCard(
val hasInstallationOptions = app.installationOptions != null
val animationSpec = tween<IntSize>(400)
fun download() {
val downloader = app.downloader
val download: () -> Unit = {
showInstallationOptions = false
coroutineScope.launch {
downloader!!.download(app, viewModel)
}
}
Column {
ManagerThemedCard {
Column {
AppInfoCard(
appName = app.name ?: "",
appName = app.name,
icon = icon,
fetching = fetching
)
Column(
modifier = Modifier.padding(vertical = defaultContentPaddingVertical)
@ -63,7 +69,7 @@ fun AppCard(
if (hasInstallationOptions) {
showInstallationOptions = true
} else {
showDownloadDialog = true
download()
}
},
onInfoClick = {
@ -97,9 +103,9 @@ fun AppCard(
.padding(horizontal = defaultContentPaddingHorizontal)
.padding(top = defaultContentPaddingVertical)
) {
ManagerDownloadButton {
showDownloadDialog = true
}
ManagerDownloadButton(
onClick = download
)
ManagerCancelButton {
showInstallationOptions = false
}
@ -109,12 +115,12 @@ fun AppCard(
}
}
if (app.name != null && app.downloader != null && showDownloadDialog) {
if (app.name != null && downloader != null && downloader.showDownloadScreen.value) {
AppDownloadDialog(
app = app.name,
downloader = app.downloader,
downloader = downloader,
onCancelClick = {
showDownloadDialog = false
downloader.cancelDownload()
}
)
}

View File

@ -17,9 +17,8 @@ import com.vanced.manager.ui.utils.defaultContentPaddingHorizontal
@Composable
fun AppInfoCard(
appName: String,
appName: String?,
icon: LoadPainter<Any>,
fetching: Boolean
) {
ManagerCard {
ManagerListItem(
@ -29,8 +28,8 @@ fun AppInfoCard(
),
title = {
ManagerText(
modifier = Modifier.managerPlaceholder(fetching),
text = appName,
modifier = Modifier.managerPlaceholder(appName == null),
text = appName ?: "",
textStyle = MaterialTheme.typography.h5
)
},

View File

@ -1,8 +1,7 @@
package com.vanced.manager.ui.widgets.home.apps.dialog
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.vanced.manager.downloader.base.BaseDownloader
import com.vanced.manager.downloader.base.AppDownloader
import com.vanced.manager.ui.components.dialog.ManagerDialog
import com.vanced.manager.ui.widgets.button.ManagerCancelButton
import com.vanced.manager.ui.widgets.home.download.AppDownloadDialogProgress
@ -10,13 +9,9 @@ import com.vanced.manager.ui.widgets.home.download.AppDownloadDialogProgress
@Composable
fun AppDownloadDialog(
app: String,
downloader: BaseDownloader,
downloader: AppDownloader,
onCancelClick: () -> Unit,
) {
val rememberProgress = remember { downloader.downloadProgress }
val rememberFile = remember { downloader.downloadFile }
val rememberInstalling = remember { downloader.installing }
ManagerDialog(
title = app,
onDismissRequest = {},
@ -25,9 +20,9 @@ fun AppDownloadDialog(
}
) {
AppDownloadDialogProgress(
progress = rememberProgress,
file = rememberFile,
installing = rememberInstalling
progress = downloader.downloadProgress,
file = downloader.downloadFile,
installing = downloader.installing
)
}
}

View File

@ -2,12 +2,14 @@ package com.vanced.manager.ui.widgets.home.download
import androidx.compose.animation.core.animateIntAsState
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.vanced.manager.R
import com.vanced.manager.ui.components.progressindicator.ManagerProgressIndicator
import com.vanced.manager.ui.resources.managerString
@ -20,7 +22,7 @@ fun AppDownloadDialogProgress(
) {
when (installing) {
true -> ManagerProgressIndicator()
false -> ManagerProgressIndicator(progress = progress)
false -> ManagerProgressIndicator(progress = progress / 100f)
}
val animatedProgress by animateIntAsState(targetValue = progress.toInt())
Row {
@ -35,9 +37,9 @@ fun AppDownloadDialogProgress(
)
Text(
modifier = Modifier
.weight(1f)
.padding(start = 4.dp)
.wrapContentWidth(Alignment.End),
text = "%$animatedProgress"
text = "$animatedProgress%"
)
}
}

View File

@ -0,0 +1,9 @@
package com.vanced.manager.util
import android.os.Build
val arch = when {
Build.SUPPORTED_ABIS.contains("x86") -> "x86"
Build.SUPPORTED_ABIS.contains("arm64-v8a") -> "arm64_v8a"
else -> "armeabi_v7a"
}