Improve icon display when selecting apps for restore

This commit is contained in:
Torsten Grote 2024-05-23 18:06:57 -03:00
parent 787b9346a8
commit eecfcdb285
No known key found for this signature in database
GPG key ID: 3E5F77D92CF891FF
4 changed files with 27 additions and 24 deletions

View file

@ -1,6 +1,6 @@
package com.stevesoltys.seedvault.restore
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.text.format.DateUtils
import android.text.format.Formatter
import android.view.LayoutInflater
@ -39,7 +39,7 @@ internal data class SelectableAppItem(
internal class AppSelectionAdapter(
val scope: CoroutineScope,
val iconLoader: suspend (SelectableAppItem, (Bitmap) -> Unit) -> Unit,
val iconLoader: suspend (SelectableAppItem, (Drawable) -> Unit) -> Unit,
val listener: (SelectableAppItem) -> Unit,
) : Adapter<RecyclerView.ViewHolder>() {
@ -156,16 +156,18 @@ internal class AppSelectionAdapter(
checkBox.visibility = if (item.hasIcon == null) INVISIBLE else VISIBLE
progressBar.visibility = if (item.hasIcon == null) VISIBLE else INVISIBLE
val isSpecial = item.metadata.isInternalSystem
appIcon.scaleType = FIT_CENTER
appIcon.setImageResource(R.drawable.ic_launcher_default)
if (item.hasIcon == null) {
appIcon.scaleType = if (isSpecial) CENTER else FIT_CENTER
if (item.hasIcon == null && !isSpecial) {
appIcon.alpha = 0.5f
} else if (item.hasIcon) {
} else if (item.hasIcon == true || isSpecial) {
appIcon.alpha = 0.5f
iconJob = scope.launch {
iconLoader(item) { bitmap ->
val isSpecial = item.metadata.system && !item.metadata.isLaunchableSystemApp
appIcon.scaleType = if (isSpecial) CENTER else FIT_CENTER
appIcon.setImageBitmap(bitmap)
appIcon.setImageDrawable(bitmap)
appIcon.alpha = 1f
}
}

View file

@ -1,6 +1,6 @@
package com.stevesoltys.seedvault.restore
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -73,7 +73,7 @@ class AppSelectionFragment : Fragment() {
}
}
private suspend fun loadIcon(item: SelectableAppItem, callback: (Bitmap) -> Unit) {
private suspend fun loadIcon(item: SelectableAppItem, callback: (Drawable) -> Unit) {
viewModel.loadIcon(item, callback)
}

View file

@ -13,14 +13,13 @@ import android.app.backup.IRestoreObserver
import android.app.backup.IRestoreSession
import android.app.backup.RestoreSet
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.os.RemoteException
import android.os.UserHandle
import android.util.Log
import androidx.annotation.UiThread
import androidx.annotation.WorkerThread
import androidx.appcompat.content.res.AppCompatResources.getDrawable
import androidx.core.graphics.drawable.toBitmap
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.asLiveData
@ -199,7 +198,7 @@ internal class RestoreViewModel(
?: return@mapNotNull null
if (metadata.time == 0L && !metadata.hasApk()) return@mapNotNull null
val name = app.getString(data.nameRes)
SelectableAppItem(packageName, metadata.copy(name = name), true, hasIcon = true)
SelectableAppItem(packageName, metadata.copy(name = name), true)
}
val systemItem = SelectableAppItem(
packageName = PACKAGE_NAME_SYSTEM,
@ -227,10 +226,10 @@ internal class RestoreViewModel(
} catch (e: Exception) {
Log.e(TAG, "Error loading icons:", e)
emptySet()
}
} + systemData.keys + setOf(PACKAGE_NAME_SYSTEM)
// update state, so it knows that icons have loaded
val updatedItems = items.map { item ->
item.copy(hasIcon = item.hasIcon ?: false || item.packageName in packagesWithIcons)
item.copy(hasIcon = item.packageName in packagesWithIcons)
}
val newState =
SelectedAppsState(updatedItems, allSelected = true, iconsLoaded = true)
@ -239,13 +238,13 @@ internal class RestoreViewModel(
mDisplayFragment.setEvent(SELECT_APPS)
}
suspend fun loadIcon(item: SelectableAppItem, callback: (Bitmap) -> Unit) {
suspend fun loadIcon(item: SelectableAppItem, callback: (Drawable) -> Unit) {
if (item.packageName == PACKAGE_NAME_SYSTEM) {
val bitmap = getDrawable(app, R.drawable.ic_app_settings)!!.toBitmap()
callback(bitmap)
val drawable = getDrawable(app, R.drawable.ic_app_settings)!!
callback(drawable)
} else if (item.metadata.isInternalSystem && item.packageName in systemData.keys) {
val bitmap = getDrawable(app, systemData[item.packageName]!!.iconRes)!!.toBitmap()
callback(bitmap)
val drawable = getDrawable(app, systemData[item.packageName]!!.iconRes)!!
callback(drawable)
} else {
iconManager.loadIcon(item.packageName, callback)
}

View file

@ -6,12 +6,13 @@
package com.stevesoltys.seedvault.worker
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat.WEBP_LOSSY
import android.graphics.BitmapFactory
import android.graphics.drawable.Drawable
import android.util.Log
import androidx.appcompat.content.res.AppCompatResources.getDrawable
import androidx.core.graphics.drawable.toBitmap
import androidx.core.graphics.drawable.toDrawable
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.transport.backup.PackageService
import kotlinx.coroutines.Dispatchers
@ -92,23 +93,24 @@ internal class IconManager(
}
private val defaultIcon by lazy {
getDrawable(context, R.drawable.ic_launcher_default)!!.toBitmap()
getDrawable(context, R.drawable.ic_launcher_default)!!
}
/**
* Tries to load the icons for the given [packageName]
* that was downloaded before with [downloadIcons].
* Calls [callback] on the UiThread with the loaded [Bitmap] or the default icon.
* Calls [callback] on the UiThread with the loaded [Drawable] or the default icon.
*/
suspend fun loadIcon(packageName: String, callback: (Bitmap) -> Unit) {
suspend fun loadIcon(packageName: String, callback: (Drawable) -> Unit) {
try {
withContext(Dispatchers.IO) {
val folder = File(context.cacheDir, CACHE_FOLDER)
val file = File(folder, packageName)
file.inputStream().use { inputStream ->
val bitmap = BitmapFactory.decodeStream(inputStream)
val drawable =
BitmapFactory.decodeStream(inputStream).toDrawable(context.resources)
withContext(Dispatchers.Main) {
callback(bitmap)
callback(drawable)
}
}
}