1
0
Fork 0
seedvault/app/src/main/java/com/stevesoltys/seedvault/settings/AppStatusAdapter.kt
Torsten Grote b1a0c1b2e2
Group app status list into three sections
* important system apps
* user apps
* apps not allowing backup
2020-11-18 16:35:45 -03:00

167 lines
6.2 KiB
Kotlin

package com.stevesoltys.seedvault.settings
import android.content.Intent
import android.net.Uri
import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.ImageView.ScaleType
import android.widget.TextView
import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.DiffUtil.DiffResult
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.Adapter
import androidx.recyclerview.widget.RecyclerView.NO_POSITION
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.ui.AppBackupState.FAILED_NOT_ALLOWED
import com.stevesoltys.seedvault.ui.AppBackupState.SUCCEEDED
import com.stevesoltys.seedvault.ui.AppViewHolder
import com.stevesoltys.seedvault.ui.toRelativeTime
internal class AppStatusAdapter(private val toggleListener: AppStatusToggleListener) :
Adapter<RecyclerView.ViewHolder>() {
private val items = ArrayList<AppListItem>()
private var editMode = false
override fun getItemViewType(position: Int): Int = when (items[position]) {
is AppStatus -> 0
is AppSectionTitle -> 1
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
0 -> {
val v = LayoutInflater.from(parent.context)
.inflate(R.layout.list_item_app_status, parent, false)
AppStatusViewHolder(v)
}
1 -> {
val v = LayoutInflater.from(parent.context)
.inflate(R.layout.list_item_app_section_title, parent, false)
AppSectionTitleViewHolder(v)
}
else -> throw AssertionError("unknown view type")
}
}
override fun getItemCount() = items.size
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is AppStatusViewHolder -> holder.bind(items[position] as AppStatus)
is AppSectionTitleViewHolder -> holder.bind(items[position] as AppSectionTitle)
}
}
fun setEditMode(enabled: Boolean) {
editMode = enabled
notifyDataSetChanged()
}
fun update(newItems: List<AppListItem>, diff: DiffResult) {
items.clear()
items.addAll(newItems)
diff.dispatchUpdatesTo(this)
}
fun onItemChanged(item: AppStatus) {
val pos = items.indexOfFirst { it is AppStatus && it.packageName == item.packageName }
if (pos != NO_POSITION) notifyItemChanged(pos, item)
}
class AppSectionTitleViewHolder(v: View) : RecyclerView.ViewHolder(v) {
private val titleView: TextView = v as TextView
fun bind(item: AppSectionTitle) {
titleView.setText(item.titleRes)
}
}
inner class AppStatusViewHolder(v: View) : AppViewHolder(v) {
fun bind(item: AppStatus) {
appName.text = item.name
appIcon.scaleType = if (item.isSpecial) ScaleType.CENTER else ScaleType.FIT_CENTER
appIcon.setImageDrawable(item.icon)
v.background = clickableBackground
if (editMode) {
v.setOnClickListener {
switchView.toggle()
item.enabled = switchView.isChecked
toggleListener.onAppStatusToggled(item)
}
appInfo.visibility = GONE
appStatus.visibility = INVISIBLE
progressBar.visibility = INVISIBLE
switchView.visibility = VISIBLE
switchView.isChecked = item.enabled
} else {
v.setOnClickListener(null)
v.setOnLongClickListener {
val intent = Intent(ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", item.packageName, null)
}
startActivity(context, intent, null)
true
}
if (item.status == FAILED_NOT_ALLOWED) {
appStatus.visibility = INVISIBLE
progressBar.visibility = INVISIBLE
appInfo.visibility = GONE
} else {
setState(item.status, false)
}
if (item.status == SUCCEEDED) {
appInfo.text = item.time.toRelativeTime(context)
appInfo.visibility = VISIBLE
}
switchView.visibility = INVISIBLE
}
// show disabled items differently
showEnabled(item.enabled)
}
private fun showEnabled(enabled: Boolean) {
val alpha = if (enabled) 1.0f else 0.5f
// setting the alpha on root view v only doesn't work as the ItemAnimator messes with it
appIcon.alpha = alpha
appName.alpha = alpha
appInfo.alpha = alpha
appStatus.alpha = alpha
}
}
}
internal class AppStatusDiff(
private val oldItems: List<AppListItem>,
private val newItems: List<AppListItem>
) : DiffUtil.Callback() {
override fun getOldListSize() = oldItems.size
override fun getNewListSize() = newItems.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val old = oldItems[oldItemPosition]
val new = newItems[newItemPosition]
if (old is AppSectionTitle && new is AppSectionTitle) return old.titleRes == new.titleRes
if (old is AppStatus && new is AppStatus) return old.packageName == new.packageName
return false
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val old = oldItems[oldItemPosition]
val new = newItems[newItemPosition]
if (old is AppSectionTitle && new is AppSectionTitle) return old.titleRes == new.titleRes
return old == new
}
}
internal class AppStatusResult(
val appStatusList: List<AppListItem>,
val diff: DiffResult
)