AppDetailsFragment: Improvements to action buttons
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -48,7 +48,6 @@ import com.aurora.Constants
|
|||||||
import com.aurora.Constants.EXODUS_SUBMIT_PAGE
|
import com.aurora.Constants.EXODUS_SUBMIT_PAGE
|
||||||
import com.aurora.extensions.browse
|
import com.aurora.extensions.browse
|
||||||
import com.aurora.extensions.hide
|
import com.aurora.extensions.hide
|
||||||
import com.aurora.extensions.invisible
|
|
||||||
import com.aurora.extensions.px
|
import com.aurora.extensions.px
|
||||||
import com.aurora.extensions.requiresObbDir
|
import com.aurora.extensions.requiresObbDir
|
||||||
import com.aurora.extensions.runOnUiThread
|
import com.aurora.extensions.runOnUiThread
|
||||||
@@ -90,8 +89,9 @@ import com.aurora.store.view.ui.commons.BaseFragment
|
|||||||
import com.aurora.store.viewmodel.details.AppDetailsViewModel
|
import com.aurora.store.viewmodel.details.AppDetailsViewModel
|
||||||
import com.aurora.store.viewmodel.details.DetailsClusterViewModel
|
import com.aurora.store.viewmodel.details.DetailsClusterViewModel
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -115,11 +115,6 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
|
|||||||
|
|
||||||
private val isExternal get() = activity?.intent?.action != Intent.ACTION_MAIN
|
private val isExternal get() = activity?.intent?.action != Intent.ACTION_MAIN
|
||||||
|
|
||||||
private var downloadStatus = DownloadStatus.UNAVAILABLE
|
|
||||||
private var isUpdatable: Boolean = false
|
|
||||||
|
|
||||||
private val tags = mutableSetOf<String>()
|
|
||||||
|
|
||||||
private val isExtendedUpdateEnabled: Boolean
|
private val isExtendedUpdateEnabled: Boolean
|
||||||
get() = Preferences.getBoolean(requireContext(), PREFERENCE_UPDATES_EXTENDED)
|
get() = Preferences.getBoolean(requireContext(), PREFERENCE_UPDATES_EXTENDED)
|
||||||
private val showSimilarApps: Boolean
|
private val showSimilarApps: Boolean
|
||||||
@@ -130,25 +125,12 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
|
|||||||
is InstallerEvent.Installed -> {
|
is InstallerEvent.Installed -> {
|
||||||
if (app.packageName == event.packageName) {
|
if (app.packageName == event.packageName) {
|
||||||
checkAndSetupInstall()
|
checkAndSetupInstall()
|
||||||
transformIcon(false)
|
|
||||||
binding.toolbar.menu.apply {
|
|
||||||
findItem(R.id.action_home_screen)?.isVisible =
|
|
||||||
ShortcutManagerUtil.canPinShortcut(requireContext(), app.packageName)
|
|
||||||
findItem(R.id.action_uninstall)?.isVisible = true
|
|
||||||
findItem(R.id.menu_app_settings)?.isVisible = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is InstallerEvent.Uninstalled -> {
|
is InstallerEvent.Uninstalled -> {
|
||||||
if (app.packageName == event.packageName) {
|
if (app.packageName == event.packageName) {
|
||||||
checkAndSetupInstall()
|
checkAndSetupInstall()
|
||||||
transformIcon(false)
|
|
||||||
binding.toolbar.menu.apply {
|
|
||||||
findItem(R.id.action_home_screen)?.isVisible = false
|
|
||||||
findItem(R.id.action_uninstall)?.isVisible = false
|
|
||||||
findItem(R.id.menu_app_settings)?.isVisible = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,32 +218,25 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewModel.download.filterNotNull().onEach {
|
||||||
viewModel.downloadsList
|
when (it.downloadStatus) {
|
||||||
.filter { list -> list.any { it.packageName == app.packageName } }
|
DownloadStatus.QUEUED,
|
||||||
.collectLatest { downloadsList ->
|
DownloadStatus.DOWNLOADING -> {
|
||||||
val download = downloadsList.find { it.packageName == app.packageName }
|
updateProgress(it.progress)
|
||||||
download?.let {
|
binding.layoutDetailsApp.btnPrimaryAction.apply {
|
||||||
downloadStatus = it.downloadStatus
|
isEnabled = false
|
||||||
|
text = getString(R.string.action_open)
|
||||||
when (it.downloadStatus) {
|
setOnClickListener { openApp() }
|
||||||
DownloadStatus.QUEUED -> {
|
}
|
||||||
updateProgress(it.progress)
|
binding.layoutDetailsApp.btnSecondaryAction.apply {
|
||||||
}
|
text = getString(R.string.action_cancel)
|
||||||
|
setOnClickListener { viewModel.cancelDownload(app) }
|
||||||
DownloadStatus.DOWNLOADING -> {
|
|
||||||
updateSecondaryAction(true)
|
|
||||||
updateProgress(it.progress, it.speed, it.timeRemaining)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
transformIcon(false)
|
|
||||||
updateSecondaryAction(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
else -> checkAndSetupInstall()
|
||||||
|
}
|
||||||
|
}.launchIn(viewLifecycleOwner.lifecycleScope)
|
||||||
|
|
||||||
// Reviews
|
// Reviews
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
@@ -499,8 +474,20 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
|
|||||||
|
|
||||||
// Do not show tags for web apps or unknown apps
|
// Do not show tags for web apps or unknown apps
|
||||||
if (isFullApp) {
|
if (isFullApp) {
|
||||||
tags.add(getString((if (app.isFree) R.string.details_free else R.string.details_paid)))
|
val tags = mutableSetOf<String>().apply {
|
||||||
tags.add(getString((if (app.containsAds) R.string.details_contains_ads else R.string.details_no_ads)))
|
if (app.isFree) {
|
||||||
|
add(getString(R.string.details_free))
|
||||||
|
} else {
|
||||||
|
add(getString(R.string.details_paid))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (app.containsAds) {
|
||||||
|
add(getString(R.string.details_contains_ads))
|
||||||
|
} else {
|
||||||
|
add(getString(R.string.details_no_ads))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
txtLine4.text = tags.joinToString(separator = " • ")
|
txtLine4.text = tags.joinToString(separator = " • ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -517,19 +504,6 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
private fun startDownload() {
|
|
||||||
when (downloadStatus) {
|
|
||||||
DownloadStatus.DOWNLOADING -> {
|
|
||||||
toast("Already downloading")
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
purchase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun purchase() {
|
private fun purchase() {
|
||||||
if (app.fileList.requiresObbDir()) {
|
if (app.fileList.requiresObbDir()) {
|
||||||
if (permissionProvider.isGranted(PermissionType.STORAGE_MANAGER)) {
|
if (permissionProvider.isGranted(PermissionType.STORAGE_MANAGER)) {
|
||||||
@@ -546,82 +520,33 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateProgress(progress: Int, speed: Long = -1, timeRemaining: Long = -1) {
|
private fun updateProgress(progress: Int) {
|
||||||
runOnUiThread {
|
// No need to update progress if it is already 100% / completed
|
||||||
updatePrimaryAction(false)
|
transformIcon(progress != 100)
|
||||||
updateSecondaryAction(true)
|
if (progress == 100) return
|
||||||
|
|
||||||
if (progress == 100) {
|
binding.layoutDetailsApp.apply {
|
||||||
transformIcon(false)
|
progressDownload.progress = progress
|
||||||
binding.layoutDetailsApp.apply {
|
progressDownload.isIndeterminate = progress < 1
|
||||||
txtLine3.text = ("${app.versionName} (${app.versionCode})")
|
|
||||||
txtLine4.text = tags.joinToString(separator = " • ")
|
|
||||||
}
|
|
||||||
return@runOnUiThread
|
|
||||||
}
|
|
||||||
|
|
||||||
transformIcon(true)
|
|
||||||
binding.layoutDetailsApp.apply {
|
|
||||||
if (progress < 1) {
|
|
||||||
progressDownload.isIndeterminate = true
|
|
||||||
} else {
|
|
||||||
progressDownload.isIndeterminate = false
|
|
||||||
progressDownload.progress = progress
|
|
||||||
txtLine3.text = CommonUtil.getETAString(requireContext(), timeRemaining)
|
|
||||||
txtLine4.text = CommonUtil.getDownloadSpeedString(requireContext(), speed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updatePrimaryAction(enabled: Boolean = false) {
|
|
||||||
binding.layoutDetailsApp.btnPrimaryAction.apply {
|
|
||||||
isEnabled = enabled
|
|
||||||
text = if (app.isInstalled) {
|
|
||||||
getString(R.string.action_open)
|
|
||||||
} else {
|
|
||||||
getString(R.string.action_install)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
private fun updateSecondaryAction(enabled: Boolean = false) {
|
|
||||||
runOnUiThread {
|
|
||||||
binding.layoutDetailsApp.btnSecondaryAction.apply {
|
|
||||||
isEnabled = enabled
|
|
||||||
isVisible = enabled
|
|
||||||
text = getString(R.string.action_cancel)
|
|
||||||
setOnClickListener {
|
|
||||||
viewModel.cancelDownload(app)
|
|
||||||
updatePrimaryAction(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun transformIcon(ongoing: Boolean = false) {
|
private fun transformIcon(ongoing: Boolean = false) {
|
||||||
if (::iconDrawable.isInitialized.not()) return
|
if (::iconDrawable.isInitialized.not()) return
|
||||||
|
|
||||||
val scaleFactor = if (ongoing) 0.75f else 1f
|
val imgIcon = binding.layoutDetailsApp.imgIcon
|
||||||
val isDownloadVisible = binding.layoutDetailsApp.progressDownload.isShown
|
val progressDownload = binding.layoutDetailsApp.progressDownload
|
||||||
|
|
||||||
// Avoids flickering when the download is in progress
|
// Avoids flickering when the download is in progress
|
||||||
if (isDownloadVisible && scaleFactor != 1f)
|
if (progressDownload.isShown && ongoing) return
|
||||||
return
|
if (!progressDownload.isShown && !ongoing) return
|
||||||
|
|
||||||
if (!isDownloadVisible && scaleFactor == 1f)
|
binding.layoutDetailsApp.progressDownload.isVisible = ongoing
|
||||||
return
|
|
||||||
|
|
||||||
if (scaleFactor == 1f) {
|
|
||||||
binding.layoutDetailsApp.progressDownload.invisible()
|
|
||||||
} else {
|
|
||||||
binding.layoutDetailsApp.progressDownload.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
val scaleFactor = if (ongoing) 0.75f else 1f
|
||||||
val scale = listOf(
|
val scale = listOf(
|
||||||
ObjectAnimator.ofFloat(binding.layoutDetailsApp.imgIcon, "scaleX", scaleFactor),
|
ObjectAnimator.ofFloat(imgIcon, "scaleX", scaleFactor),
|
||||||
ObjectAnimator.ofFloat(binding.layoutDetailsApp.imgIcon, "scaleY", scaleFactor)
|
ObjectAnimator.ofFloat(imgIcon, "scaleY", scaleFactor)
|
||||||
)
|
)
|
||||||
|
|
||||||
scale.forEach { animation ->
|
scale.forEach { animation ->
|
||||||
@@ -632,103 +557,118 @@ class AppDetailsFragment : BaseFragment<FragmentDetailsBinding>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iconDrawable.let {
|
imgIcon.load(iconDrawable) {
|
||||||
binding.layoutDetailsApp.imgIcon.load(it) {
|
transformations(
|
||||||
transformations(
|
if (ongoing) {
|
||||||
if (scaleFactor == 1f)
|
CircleCropTransformation()
|
||||||
RoundedCornersTransformation(8.px.toFloat())
|
} else {
|
||||||
else
|
RoundedCornersTransformation(8.px.toFloat())
|
||||||
CircleCropTransformation()
|
}
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
private fun checkAndSetupInstall() {
|
private fun checkAndSetupInstall() {
|
||||||
runOnUiThread {
|
app.isInstalled = PackageUtil.isInstalled(requireContext(), app.packageName)
|
||||||
app.isInstalled = PackageUtil.isInstalled(requireContext(), app.packageName)
|
|
||||||
|
|
||||||
if (app.isInstalled) {
|
// Setup primary and secondary action buttons
|
||||||
val needsExtendedUpdate = !app.certificateSetList.any {
|
binding.layoutDetailsApp.btnPrimaryAction.isEnabled = true
|
||||||
it.certificateSet in CertUtil.getEncodedCertificateHashes(
|
binding.layoutDetailsApp.btnPrimaryAction.isEnabled = true
|
||||||
requireContext(),
|
|
||||||
app.packageName
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
isUpdatable = PackageUtil.isUpdatable(
|
if (app.isInstalled) {
|
||||||
requireContext(),
|
val isUpdatable = PackageUtil.isUpdatable(requireContext(), app.packageName, app.versionCode.toLong())
|
||||||
app.packageName,
|
val hasValidCert = app.certificateSetList.any {
|
||||||
app.versionCode.toLong()
|
it.certificateSet in CertUtil.getEncodedCertificateHashes(requireContext(), app.packageName)
|
||||||
)
|
}
|
||||||
|
|
||||||
val installedVersion = PackageUtil.getInstalledVersion(
|
if ((isUpdatable && hasValidCert) || (isUpdatable && isExtendedUpdateEnabled)) {
|
||||||
requireContext(),
|
binding.layoutDetailsApp.btnPrimaryAction.apply {
|
||||||
app.packageName
|
text = getString(R.string.action_update)
|
||||||
)
|
setOnClickListener {
|
||||||
|
if (app.versionCode == 0) {
|
||||||
if ((isUpdatable && !needsExtendedUpdate) || (isUpdatable && isExtendedUpdateEnabled)) {
|
toast(R.string.toast_app_unavailable)
|
||||||
binding.layoutDetailsApp.apply {
|
setText(R.string.status_unavailable)
|
||||||
txtLine3.text =
|
} else {
|
||||||
("$installedVersion ➔ ${app.versionName} (${app.versionCode})")
|
purchase()
|
||||||
txtLine4.text = tags.joinToString(separator = " • ")
|
|
||||||
btnPrimaryAction.apply {
|
|
||||||
isEnabled = true
|
|
||||||
setText(R.string.action_update)
|
|
||||||
setOnClickListener {
|
|
||||||
if (app.versionCode == 0) {
|
|
||||||
toast(R.string.toast_app_unavailable)
|
|
||||||
btnPrimaryAction.setText(R.string.status_unavailable)
|
|
||||||
} else {
|
|
||||||
startDownload()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
binding.layoutDetailsApp.apply {
|
|
||||||
txtLine3.text = installedVersion
|
|
||||||
btnPrimaryAction.apply {
|
|
||||||
isEnabled = true
|
|
||||||
setText(R.string.action_open)
|
|
||||||
setOnClickListener { openApp() }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (downloadStatus in DownloadStatus.running) {
|
binding.layoutDetailsApp.apply {
|
||||||
updateProgress(-1)
|
txtLine3.text = PackageUtil.getInstalledVersion(requireContext(), app.packageName)
|
||||||
} else if (app.isFree) {
|
btnPrimaryAction.apply {
|
||||||
binding.layoutDetailsApp.btnPrimaryAction.setText(R.string.action_install)
|
setText(R.string.action_open)
|
||||||
} else {
|
setOnClickListener { openApp() }
|
||||||
binding.layoutDetailsApp.btnPrimaryAction.text = app.price
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.layoutDetailsApp.btnPrimaryAction.setOnClickListener {
|
|
||||||
if (authProvider.isAnonymous && !app.isFree) {
|
|
||||||
toast(R.string.toast_purchase_blocked)
|
|
||||||
return@setOnClickListener
|
|
||||||
} else if (app.versionCode == 0) {
|
|
||||||
toast(R.string.toast_app_unavailable)
|
|
||||||
return@setOnClickListener
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!permissionProvider.isGranted(PermissionType.INSTALL_UNKNOWN_APPS)) {
|
|
||||||
permissionProvider.request(PermissionType.INSTALL_UNKNOWN_APPS) {
|
|
||||||
if (it) {
|
|
||||||
startDownload()
|
|
||||||
} else {
|
|
||||||
toast(R.string.permissions_denied)
|
|
||||||
// TODO: Warn & redirect to Permission Manager
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
startDownload()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.layoutDetailsApp.btnSecondaryAction.apply {
|
||||||
|
text = getString(R.string.action_uninstall)
|
||||||
|
setOnClickListener {
|
||||||
|
AppInstaller.uninstall(requireContext(), app.packageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (app.isFree) {
|
||||||
|
binding.layoutDetailsApp.btnPrimaryAction.setText(R.string.action_install)
|
||||||
|
} else {
|
||||||
|
binding.layoutDetailsApp.btnPrimaryAction.text = app.price
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.layoutDetailsApp.btnPrimaryAction.setOnClickListener {
|
||||||
|
if (authProvider.isAnonymous && !app.isFree) {
|
||||||
|
toast(R.string.toast_purchase_blocked)
|
||||||
|
return@setOnClickListener
|
||||||
|
} else if (app.versionCode == 0) {
|
||||||
|
toast(R.string.toast_app_unavailable)
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!permissionProvider.isGranted(PermissionType.INSTALL_UNKNOWN_APPS)) {
|
||||||
|
permissionProvider.request(PermissionType.INSTALL_UNKNOWN_APPS) {
|
||||||
|
if (it) {
|
||||||
|
purchase()
|
||||||
|
} else {
|
||||||
|
toast(R.string.permissions_denied)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
purchase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.layoutDetailsApp.btnSecondaryAction.apply {
|
||||||
|
text = getString(R.string.title_manual_download)
|
||||||
|
setOnClickListener {
|
||||||
|
findNavController().navigate(
|
||||||
|
AppDetailsFragmentDirections
|
||||||
|
.actionAppDetailsFragmentToManualDownloadSheet(app)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lay out the toolbar again
|
||||||
|
binding.toolbar.invalidateMenu()
|
||||||
|
|
||||||
|
if (app.isInstalled) {
|
||||||
|
binding.toolbar.menu.apply {
|
||||||
|
findItem(R.id.action_home_screen)?.isVisible =
|
||||||
|
ShortcutManagerUtil.canPinShortcut(requireContext(), app.packageName)
|
||||||
|
findItem(R.id.action_uninstall)?.isVisible = true
|
||||||
|
findItem(R.id.menu_app_settings)?.isVisible = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.toolbar.menu.apply {
|
||||||
|
findItem(R.id.action_home_screen)?.isVisible = false
|
||||||
|
findItem(R.id.action_uninstall)?.isVisible = false
|
||||||
|
findItem(R.id.menu_app_settings)?.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore icon and progress
|
||||||
|
updateProgress(100)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateExtraDetails(app: App) {
|
private fun updateExtraDetails(app: App) {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import com.aurora.gplayapi.helpers.AppDetailsHelper
|
|||||||
import com.aurora.gplayapi.helpers.ReviewsHelper
|
import com.aurora.gplayapi.helpers.ReviewsHelper
|
||||||
import com.aurora.gplayapi.helpers.web.WebDataSafetyHelper
|
import com.aurora.gplayapi.helpers.web.WebDataSafetyHelper
|
||||||
import com.aurora.gplayapi.network.IHttpClient
|
import com.aurora.gplayapi.network.IHttpClient
|
||||||
|
import com.aurora.store.AuroraApp
|
||||||
import com.aurora.store.BuildConfig
|
import com.aurora.store.BuildConfig
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
import com.aurora.store.data.helper.DownloadHelper
|
import com.aurora.store.data.helper.DownloadHelper
|
||||||
@@ -27,8 +28,11 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.asSharedFlow
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.lang.reflect.Modifier
|
import java.lang.reflect.Modifier
|
||||||
@@ -75,7 +79,10 @@ class AppDetailsViewModel @Inject constructor(
|
|||||||
private val _favourite = MutableStateFlow<Boolean>(false)
|
private val _favourite = MutableStateFlow<Boolean>(false)
|
||||||
val favourite = _favourite.asStateFlow()
|
val favourite = _favourite.asStateFlow()
|
||||||
|
|
||||||
val downloadsList get() = downloadHelper.downloadsList
|
val download = combine(app, downloadHelper.downloadsList) { a, list ->
|
||||||
|
if (a.packageName.isBlank()) return@combine null
|
||||||
|
list.find { d -> d.packageName == a.packageName }
|
||||||
|
}.stateIn(viewModelScope, SharingStarted.Eagerly, null)
|
||||||
|
|
||||||
fun fetchAppDetails(packageName: String) {
|
fun fetchAppDetails(packageName: String) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
|||||||
@@ -110,26 +110,22 @@
|
|||||||
android:layout_marginTop="@dimen/margin_medium"
|
android:layout_marginTop="@dimen/margin_medium"
|
||||||
android:divider="@drawable/divider"
|
android:divider="@drawable/divider"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:showDividers="middle">
|
android:showDividers="middle"
|
||||||
|
android:weightSum="2">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btn_secondary_action"
|
android:id="@+id/btn_secondary_action"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:backgroundTint="?colorError"
|
tools:text="@string/title_manual_download" />
|
||||||
android:textColor="?colorOnError"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:cornerRadius="@dimen/radius_small"
|
|
||||||
tools:text="@string/action_cancel"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btn_primary_action"
|
android:id="@+id/btn_primary_action"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
app:cornerRadius="@dimen/radius_small"
|
|
||||||
tools:text="@string/action_install" />
|
tools:text="@string/action_install" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user