Improve icon display when selecting apps for restore
This commit is contained in:
parent
787b9346a8
commit
eecfcdb285
4 changed files with 27 additions and 24 deletions
|
@ -1,6 +1,6 @@
|
||||||
package com.stevesoltys.seedvault.restore
|
package com.stevesoltys.seedvault.restore
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.drawable.Drawable
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import android.text.format.Formatter
|
import android.text.format.Formatter
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -39,7 +39,7 @@ internal data class SelectableAppItem(
|
||||||
|
|
||||||
internal class AppSelectionAdapter(
|
internal class AppSelectionAdapter(
|
||||||
val scope: CoroutineScope,
|
val scope: CoroutineScope,
|
||||||
val iconLoader: suspend (SelectableAppItem, (Bitmap) -> Unit) -> Unit,
|
val iconLoader: suspend (SelectableAppItem, (Drawable) -> Unit) -> Unit,
|
||||||
val listener: (SelectableAppItem) -> Unit,
|
val listener: (SelectableAppItem) -> Unit,
|
||||||
) : Adapter<RecyclerView.ViewHolder>() {
|
) : Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
|
@ -156,16 +156,18 @@ internal class AppSelectionAdapter(
|
||||||
checkBox.visibility = if (item.hasIcon == null) INVISIBLE else VISIBLE
|
checkBox.visibility = if (item.hasIcon == null) INVISIBLE else VISIBLE
|
||||||
progressBar.visibility = if (item.hasIcon == null) VISIBLE else INVISIBLE
|
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)
|
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
|
appIcon.alpha = 0.5f
|
||||||
} else if (item.hasIcon) {
|
} else if (item.hasIcon == true || isSpecial) {
|
||||||
appIcon.alpha = 0.5f
|
appIcon.alpha = 0.5f
|
||||||
iconJob = scope.launch {
|
iconJob = scope.launch {
|
||||||
iconLoader(item) { bitmap ->
|
iconLoader(item) { bitmap ->
|
||||||
val isSpecial = item.metadata.system && !item.metadata.isLaunchableSystemApp
|
|
||||||
appIcon.scaleType = if (isSpecial) CENTER else FIT_CENTER
|
appIcon.scaleType = if (isSpecial) CENTER else FIT_CENTER
|
||||||
appIcon.setImageBitmap(bitmap)
|
appIcon.setImageDrawable(bitmap)
|
||||||
appIcon.alpha = 1f
|
appIcon.alpha = 1f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package com.stevesoltys.seedvault.restore
|
package com.stevesoltys.seedvault.restore
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
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)
|
viewModel.loadIcon(item, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,14 +13,13 @@ import android.app.backup.IRestoreObserver
|
||||||
import android.app.backup.IRestoreSession
|
import android.app.backup.IRestoreSession
|
||||||
import android.app.backup.RestoreSet
|
import android.app.backup.RestoreSet
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.RemoteException
|
import android.os.RemoteException
|
||||||
import android.os.UserHandle
|
import android.os.UserHandle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.UiThread
|
import androidx.annotation.UiThread
|
||||||
import androidx.annotation.WorkerThread
|
import androidx.annotation.WorkerThread
|
||||||
import androidx.appcompat.content.res.AppCompatResources.getDrawable
|
import androidx.appcompat.content.res.AppCompatResources.getDrawable
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.asLiveData
|
import androidx.lifecycle.asLiveData
|
||||||
|
@ -199,7 +198,7 @@ internal class RestoreViewModel(
|
||||||
?: return@mapNotNull null
|
?: return@mapNotNull null
|
||||||
if (metadata.time == 0L && !metadata.hasApk()) return@mapNotNull null
|
if (metadata.time == 0L && !metadata.hasApk()) return@mapNotNull null
|
||||||
val name = app.getString(data.nameRes)
|
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(
|
val systemItem = SelectableAppItem(
|
||||||
packageName = PACKAGE_NAME_SYSTEM,
|
packageName = PACKAGE_NAME_SYSTEM,
|
||||||
|
@ -227,10 +226,10 @@ internal class RestoreViewModel(
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Error loading icons:", e)
|
Log.e(TAG, "Error loading icons:", e)
|
||||||
emptySet()
|
emptySet()
|
||||||
}
|
} + systemData.keys + setOf(PACKAGE_NAME_SYSTEM)
|
||||||
// update state, so it knows that icons have loaded
|
// update state, so it knows that icons have loaded
|
||||||
val updatedItems = items.map { item ->
|
val updatedItems = items.map { item ->
|
||||||
item.copy(hasIcon = item.hasIcon ?: false || item.packageName in packagesWithIcons)
|
item.copy(hasIcon = item.packageName in packagesWithIcons)
|
||||||
}
|
}
|
||||||
val newState =
|
val newState =
|
||||||
SelectedAppsState(updatedItems, allSelected = true, iconsLoaded = true)
|
SelectedAppsState(updatedItems, allSelected = true, iconsLoaded = true)
|
||||||
|
@ -239,13 +238,13 @@ internal class RestoreViewModel(
|
||||||
mDisplayFragment.setEvent(SELECT_APPS)
|
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) {
|
if (item.packageName == PACKAGE_NAME_SYSTEM) {
|
||||||
val bitmap = getDrawable(app, R.drawable.ic_app_settings)!!.toBitmap()
|
val drawable = getDrawable(app, R.drawable.ic_app_settings)!!
|
||||||
callback(bitmap)
|
callback(drawable)
|
||||||
} else if (item.metadata.isInternalSystem && item.packageName in systemData.keys) {
|
} else if (item.metadata.isInternalSystem && item.packageName in systemData.keys) {
|
||||||
val bitmap = getDrawable(app, systemData[item.packageName]!!.iconRes)!!.toBitmap()
|
val drawable = getDrawable(app, systemData[item.packageName]!!.iconRes)!!
|
||||||
callback(bitmap)
|
callback(drawable)
|
||||||
} else {
|
} else {
|
||||||
iconManager.loadIcon(item.packageName, callback)
|
iconManager.loadIcon(item.packageName, callback)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,13 @@
|
||||||
package com.stevesoltys.seedvault.worker
|
package com.stevesoltys.seedvault.worker
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.graphics.Bitmap.CompressFormat.WEBP_LOSSY
|
import android.graphics.Bitmap.CompressFormat.WEBP_LOSSY
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.appcompat.content.res.AppCompatResources.getDrawable
|
import androidx.appcompat.content.res.AppCompatResources.getDrawable
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
|
import androidx.core.graphics.drawable.toDrawable
|
||||||
import com.stevesoltys.seedvault.R
|
import com.stevesoltys.seedvault.R
|
||||||
import com.stevesoltys.seedvault.transport.backup.PackageService
|
import com.stevesoltys.seedvault.transport.backup.PackageService
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -92,23 +93,24 @@ internal class IconManager(
|
||||||
}
|
}
|
||||||
|
|
||||||
private val defaultIcon by lazy {
|
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]
|
* Tries to load the icons for the given [packageName]
|
||||||
* that was downloaded before with [downloadIcons].
|
* 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 {
|
try {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
val folder = File(context.cacheDir, CACHE_FOLDER)
|
val folder = File(context.cacheDir, CACHE_FOLDER)
|
||||||
val file = File(folder, packageName)
|
val file = File(folder, packageName)
|
||||||
file.inputStream().use { inputStream ->
|
file.inputStream().use { inputStream ->
|
||||||
val bitmap = BitmapFactory.decodeStream(inputStream)
|
val drawable =
|
||||||
|
BitmapFactory.decodeStream(inputStream).toDrawable(context.resources)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
callback(bitmap)
|
callback(drawable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue