Cleanup more databinding implementation

This commit is contained in:
topjohnwu 2023-03-31 00:05:33 -07:00
parent 1620e15f99
commit 0b987dd0b0
19 changed files with 124 additions and 176 deletions

View File

@ -1,31 +1,26 @@
package com.topjohnwu.magisk.databinding
import androidx.annotation.MainThread
import androidx.annotation.WorkerThread
import androidx.databinding.ListChangeRegistry
import androidx.databinding.ObservableList
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListUpdateCallback
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.AbstractList
open class DiffObservableList<T>(
private val callback: Callback<T>
) : AbstractList<T>(), ObservableList<T> {
open class DiffObservableList<T : DiffItem<*>>
: AbstractList<T>(), ObservableList<T>, ListUpdateCallback {
protected var list: List<T> = emptyList()
private set
private val listeners = ListChangeRegistry()
protected val listCallback = ObservableListUpdateCallback()
override val size: Int get() = list.size
override fun get(index: Int) = list[index]
/**
* Calculates the list of update operations that can convert this list into the given one.
*
* @param newItems The items that this list will be set to.
* @return A DiffResult that contains the information about the edit sequence to covert this
* list into the given one.
*/
fun calculateDiff(newItems: List<T>): DiffUtil.DiffResult {
return doCalculateDiff(list, newItems)
}
@ -36,31 +31,34 @@ open class DiffObservableList<T>(
override fun getNewListSize() = newItems.size
@Suppress("UNCHECKED_CAST")
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldItems[oldItemPosition]
val newItem = newItems[newItemPosition]
return callback.areItemsTheSame(oldItem, newItem)
return (oldItem as DiffItem<Any>).itemSameAs(newItem)
}
@Suppress("UNCHECKED_CAST")
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldItems[oldItemPosition]
val newItem = newItems[newItemPosition]
return callback.areContentsTheSame(oldItem, newItem)
return (oldItem as DiffItem<Any>).contentSameAs(newItem)
}
}, true)
}
/**
* Updates the contents of this list to the given one using the DiffResults to dispatch change
* notifications.
*
* @param newItems The items to set this list to.
* @param diffResult The diff results to dispatch change notifications.
*/
@MainThread
fun update(newItems: List<T>, diffResult: DiffUtil.DiffResult) {
list = ArrayList(newItems)
diffResult.dispatchUpdatesTo(listCallback)
diffResult.dispatchUpdatesTo(this)
}
@WorkerThread
suspend fun update(newItems: List<T>) {
val diffResult = calculateDiff(newItems)
withContext(Dispatchers.Main) {
update(newItems, diffResult)
}
}
override fun addOnListChangedCallback(listener: ObservableList.OnListChangedCallback<out ObservableList<T>>) {
@ -71,36 +69,21 @@ open class DiffObservableList<T>(
listeners.remove(listener)
}
private fun notifyAdd(start: Int, count: Int) {
listeners.notifyInserted(this, start, count)
override fun onChanged(position: Int, count: Int, payload: Any?) {
listeners.notifyChanged(this, position, count)
}
private fun notifyRemove(start: Int, count: Int) {
listeners.notifyRemoved(this, start, count)
override fun onMoved(fromPosition: Int, toPosition: Int) {
listeners.notifyMoved(this, fromPosition, toPosition, 1)
}
interface Callback<T> {
fun areItemsTheSame(oldItem: T, newItem: T): Boolean
fun areContentsTheSame(oldItem: T, newItem: T): Boolean
override fun onInserted(position: Int, count: Int) {
modCount += 1
listeners.notifyInserted(this, position, count)
}
inner class ObservableListUpdateCallback : ListUpdateCallback {
override fun onChanged(position: Int, count: Int, payload: Any?) {
listeners.notifyChanged(this@DiffObservableList, position, count)
}
override fun onMoved(fromPosition: Int, toPosition: Int) {
listeners.notifyMoved(this@DiffObservableList, fromPosition, toPosition, 1)
}
override fun onInserted(position: Int, count: Int) {
modCount += 1
listeners.notifyInserted(this@DiffObservableList, position, count)
}
override fun onRemoved(position: Int, count: Int) {
modCount += 1
listeners.notifyRemoved(this@DiffObservableList, position, count)
}
override fun onRemoved(position: Int, count: Int) {
modCount += 1
listeners.notifyRemoved(this, position, count)
}
}

View File

@ -6,10 +6,9 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
open class FilterableDiffObservableList<T>(
callback: Callback<T>,
open class FilterableDiffObservableList<T : DiffItem<*>>(
private val scope: CoroutineScope
) : DiffObservableList<T>(callback) {
) : DiffObservableList<T>() {
private var sublist: List<T> = emptyList()
private var job: Job? = null
@ -24,7 +23,7 @@ open class FilterableDiffObservableList<T>(
val diff = doCalculateDiff(oldList, newList)
withContext(Dispatchers.Main) {
sublist = newList
diff.dispatchUpdatesTo(listCallback)
diff.dispatchUpdatesTo(this@FilterableDiffObservableList)
}
}
}

View File

@ -3,69 +3,33 @@ package com.topjohnwu.magisk.databinding
import androidx.databinding.PropertyChangeRegistry
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.CoroutineScope
abstract class RvItem {
abstract val layoutRes: Int
}
interface RvContainer<E> {
val item: E
}
interface ViewAwareRvItem {
fun onBind(binding: ViewDataBinding, recyclerView: RecyclerView)
}
interface ComparableRv<T> : Comparable<T> {
@Suppress("UNCHECKED_CAST")
fun comparableEqual(o: Any?) =
o != null && o::class == this::class && compareTo(o as T) == 0
}
abstract class DiffRvItem<T> : RvItem() {
// Defer to contentSameAs by default
open fun itemSameAs(other: T) = true
open fun contentSameAs(other: T) =
when (this) {
is RvContainer<*> -> item == (other as RvContainer<*>).item
is ComparableRv<*> -> comparableEqual(other)
else -> this == other
}
}
typealias AnyDiffRvItem = DiffRvItem<*>
abstract class ObservableDiffRvItem<T> : DiffRvItem<T>(), ObservableHost {
override var callbacks: PropertyChangeRegistry? = null
}
abstract class ObservableRvItem : RvItem(), ObservableHost {
override var callbacks: PropertyChangeRegistry? = null
}
private object DiffRvItemCallback : DiffObservableList.Callback<DiffRvItem<Any>> {
override fun areItemsTheSame(
oldItem: DiffRvItem<Any>,
newItem: DiffRvItem<Any>
): Boolean {
return oldItem::class == newItem::class && oldItem.itemSameAs(newItem)
}
override fun areContentsTheSame(
oldItem: DiffRvItem<Any>,
newItem: DiffRvItem<Any>
): Boolean {
return oldItem.contentSameAs(newItem)
}
interface ItemWrapper<E> {
val item: E
}
@Suppress("UNCHECKED_CAST")
class DiffRvItemList<T: AnyDiffRvItem> : DiffObservableList<T>(DiffRvItemCallback as Callback<T>)
interface ViewAwareItem {
fun onBind(binding: ViewDataBinding, recyclerView: RecyclerView)
}
@Suppress("UNCHECKED_CAST")
class DiffRvItemFilterList<T: AnyDiffRvItem>(
scope: CoroutineScope
) : FilterableDiffObservableList<T>(DiffRvItemCallback as Callback<T>, scope)
interface DiffItem<T : Any> {
fun itemSameAs(other: T): Boolean {
if (this === other) return true
return when (this) {
is ItemWrapper<*> -> item == (other as ItemWrapper<*>).item
is Comparable<*> -> compareValues(this, other as Comparable<*>) == 0
else -> this == other
}
}
fun contentSameAs(other: T) = true
}

View File

@ -53,7 +53,7 @@ class RvItemAdapter<T: RvItem>(
holder.binding.lifecycleOwner = lifecycleOwner
holder.binding.executePendingBindings()
recyclerView?.let {
if (item is ViewAwareRvItem)
if (item is ViewAwareItem)
item.onBind(holder.binding, it)
}
}

View File

@ -5,8 +5,8 @@ import android.view.ViewGroup
import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ComparableRv
import com.topjohnwu.magisk.databinding.ObservableDiffRvItem
import com.topjohnwu.magisk.databinding.DiffItem
import com.topjohnwu.magisk.databinding.ObservableRvItem
import com.topjohnwu.magisk.databinding.addOnPropertyChangedCallback
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.ktx.startAnimations
@ -15,7 +15,7 @@ import kotlin.math.roundToInt
class DenyListRvItem(
val info: AppProcessInfo
) : ObservableDiffRvItem<DenyListRvItem>(), ComparableRv<DenyListRvItem> {
) : ObservableRvItem(), DiffItem<DenyListRvItem>, Comparable<DenyListRvItem> {
override val layoutRes get() = R.layout.item_hide_md2
@ -100,7 +100,7 @@ class DenyListRvItem(
class ProcessRvItem(
val process: ProcessInfo
) : ObservableDiffRvItem<ProcessRvItem>() {
) : ObservableRvItem(), DiffItem<ProcessRvItem> {
override val layoutRes get() = R.layout.item_hide_process_md2
@ -122,10 +122,9 @@ class ProcessRvItem(
val defaultSelection get() =
process.isIsolated || process.isAppZygote || process.name == process.packageName
override fun contentSameAs(other: ProcessRvItem) =
process.isEnabled == other.process.isEnabled
override fun itemSameAs(other: ProcessRvItem) =
process.name == other.process.name && process.packageName == other.process.packageName
override fun contentSameAs(other: ProcessRvItem) =
process.isEnabled == other.process.isEnabled
}

View File

@ -7,7 +7,7 @@ import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.databinding.DiffRvItemFilterList
import com.topjohnwu.magisk.databinding.FilterableDiffObservableList
import com.topjohnwu.magisk.databinding.bindExtra
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.ktx.concurrentMap
@ -38,7 +38,7 @@ class DenyListViewModel : AsyncLoadViewModel() {
query()
}
val items = DiffRvItemFilterList<DenyListRvItem>(viewModelScope)
val items = FilterableDiffObservableList<DenyListRvItem>(viewModelScope)
val extraBindings = bindExtra {
it.put(BR.viewModel, this)
}
@ -50,7 +50,7 @@ class DenyListViewModel : AsyncLoadViewModel() {
@SuppressLint("InlinedApi")
override suspend fun doLoadWork() {
loading = true
val (apps, diff) = withContext(Dispatchers.Default) {
withContext(Dispatchers.Default) {
val pm = AppContext.packageManager
val denyList = Shell.cmd("magisk --denylist ls").exec().out
.map { CmdlineListItem(it) }
@ -63,9 +63,8 @@ class DenyListViewModel : AsyncLoadViewModel() {
.toCollection(ArrayList(size))
}
apps.sort()
apps to items.calculateDiff(apps)
items.update(apps)
}
items.update(apps, diff)
query()
}

View File

@ -6,14 +6,15 @@ import androidx.core.view.updateLayoutParams
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.DiffRvItem
import com.topjohnwu.magisk.databinding.RvContainer
import com.topjohnwu.magisk.databinding.ViewAwareRvItem
import com.topjohnwu.magisk.databinding.DiffItem
import com.topjohnwu.magisk.databinding.ItemWrapper
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.databinding.ViewAwareItem
import kotlin.math.max
class ConsoleItem(
override val item: String
) : DiffRvItem<ConsoleItem>(), ViewAwareRvItem, RvContainer<String> {
) : RvItem(), ViewAwareItem, DiffItem<ConsoleItem>, ItemWrapper<String> {
override val layoutRes = R.layout.item_console_md2
private var parentWidth = -1

View File

@ -4,18 +4,17 @@ import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.textview.MaterialTextView
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ObservableDiffRvItem
import com.topjohnwu.magisk.databinding.RvContainer
import com.topjohnwu.magisk.databinding.ViewAwareRvItem
import com.topjohnwu.magisk.databinding.DiffItem
import com.topjohnwu.magisk.databinding.ItemWrapper
import com.topjohnwu.magisk.databinding.ObservableRvItem
import com.topjohnwu.magisk.databinding.ViewAwareItem
class LogRvItem(
override val item: String
) : ObservableDiffRvItem<LogRvItem>(), RvContainer<String>, ViewAwareRvItem {
) : ObservableRvItem(), DiffItem<LogRvItem>, ItemWrapper<String>, ViewAwareItem {
override val layoutRes = R.layout.item_log_textview
override fun itemSameAs(other: LogRvItem) = item == other.item
override fun onBind(binding: ViewDataBinding, recyclerView: RecyclerView) {
val view = binding.root as MaterialTextView
view.measure(0, 0)

View File

@ -11,7 +11,7 @@ import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.repository.LogRepository
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import com.topjohnwu.magisk.databinding.DiffRvItemList
import com.topjohnwu.magisk.databinding.DiffObservableList
import com.topjohnwu.magisk.databinding.bindExtra
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.events.SnackbarEvent
@ -37,28 +37,26 @@ class LogViewModel(
// --- su log
val items = DiffRvItemList<SuLogRvItem>()
val items = DiffObservableList<SuLogRvItem>()
val extraBindings = bindExtra {
it.put(BR.viewModel, this)
}
// --- magisk log
val logs = DiffRvItemList<LogRvItem>()
val logs = DiffObservableList<LogRvItem>()
var magiskLogRaw = " "
override suspend fun doLoadWork() {
loading = true
val (logs, logDiff) = withContext(Dispatchers.Default) {
magiskLogRaw = repo.fetchMagiskLogs()
val logs = magiskLogRaw.split('\n').map { LogRvItem(it) }
logs to this@LogViewModel.logs.calculateDiff(logs)
}
this.logs.update(logs, logDiff)
val (suLogs, suDiff) = withContext(Dispatchers.Default) {
magiskLogRaw = repo.fetchMagiskLogs()
val newLogs = magiskLogRaw.split('\n').map { LogRvItem(it) }
logs.update(newLogs)
val suLogs = repo.fetchSuLogs().map { SuLogRvItem(it) }
suLogs to items.calculateDiff(suLogs)
}
items.firstOrNull()?.isTop = false
items.lastOrNull()?.isBottom = false
items.update(suLogs, suDiff)

View File

@ -4,19 +4,17 @@ import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.model.su.SuLog
import com.topjohnwu.magisk.databinding.ObservableDiffRvItem
import com.topjohnwu.magisk.databinding.RvContainer
import com.topjohnwu.magisk.databinding.DiffItem
import com.topjohnwu.magisk.databinding.ObservableRvItem
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.ktx.timeDateFormat
import com.topjohnwu.magisk.ktx.toTime
class SuLogRvItem(
override val item: SuLog
) : ObservableDiffRvItem<SuLogRvItem>(), RvContainer<SuLog> {
class SuLogRvItem(val log: SuLog) : ObservableRvItem(), DiffItem<SuLogRvItem> {
override val layoutRes = R.layout.item_log_access_md2
val date = item.time.toTime(timeDateFormat)
val date = log.time.toTime(timeDateFormat)
@get:Bindable
var isTop = false
@ -26,5 +24,5 @@ class SuLogRvItem(
var isBottom = false
set(value) = set(value, field, { field = it }, BR.bottom)
override fun itemSameAs(other: SuLogRvItem) = item.appName == other.item.appName
override fun itemSameAs(other: SuLogRvItem) = log.appName == other.log.appName
}

View File

@ -5,20 +5,21 @@ import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.model.module.LocalModule
import com.topjohnwu.magisk.databinding.DiffRvItem
import com.topjohnwu.magisk.databinding.ObservableDiffRvItem
import com.topjohnwu.magisk.databinding.RvContainer
import com.topjohnwu.magisk.databinding.DiffItem
import com.topjohnwu.magisk.databinding.ItemWrapper
import com.topjohnwu.magisk.databinding.ObservableRvItem
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.utils.TextHolder
import com.topjohnwu.magisk.utils.asText
object InstallModule : DiffRvItem<InstallModule>() {
object InstallModule : RvItem(), DiffItem<InstallModule> {
override val layoutRes = R.layout.item_module_download
}
class LocalModuleRvItem(
override val item: LocalModule
) : ObservableDiffRvItem<LocalModuleRvItem>(), RvContainer<LocalModule> {
) : ObservableRvItem(), DiffItem<LocalModuleRvItem>, ItemWrapper<LocalModule> {
override val layoutRes = R.layout.item_module_md2

View File

@ -10,7 +10,7 @@ import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.base.ContentResultCallback
import com.topjohnwu.magisk.core.model.module.LocalModule
import com.topjohnwu.magisk.core.model.module.OnlineModule
import com.topjohnwu.magisk.databinding.DiffRvItemList
import com.topjohnwu.magisk.databinding.DiffObservableList
import com.topjohnwu.magisk.databinding.MergeObservableList
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.databinding.bindExtra
@ -26,7 +26,7 @@ class ModuleViewModel : AsyncLoadViewModel() {
val bottomBarBarrierIds = intArrayOf(R.id.module_update, R.id.module_remove)
private val itemsInstalled = DiffRvItemList<LocalModuleRvItem>()
private val itemsInstalled = DiffObservableList<LocalModuleRvItem>()
val items = MergeObservableList<RvItem>()
val extraBindings = bindExtra {
@ -57,11 +57,10 @@ class ModuleViewModel : AsyncLoadViewModel() {
override fun onNetworkChanged(network: Boolean) = startLoading()
private suspend fun loadInstalled() {
val installed = LocalModule.installed().map { LocalModuleRvItem(it) }
val diff = withContext(Dispatchers.Default) {
itemsInstalled.calculateDiff(installed)
withContext(Dispatchers.Default) {
val installed = LocalModule.installed().map { LocalModuleRvItem(it) }
itemsInstalled.update(installed)
}
itemsInstalled.update(installed, diff)
}
private suspend fun loadUpdateInfo() {

View File

@ -5,8 +5,9 @@ import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.model.su.SuPolicy
import com.topjohnwu.magisk.databinding.ObservableDiffRvItem
import com.topjohnwu.magisk.databinding.RvContainer
import com.topjohnwu.magisk.databinding.DiffItem
import com.topjohnwu.magisk.databinding.ItemWrapper
import com.topjohnwu.magisk.databinding.ObservableRvItem
import com.topjohnwu.magisk.databinding.set
class PolicyRvItem(
@ -16,7 +17,7 @@ class PolicyRvItem(
private val isSharedUid: Boolean,
val icon: Drawable,
val appName: String
) : ObservableDiffRvItem<PolicyRvItem>(), RvContainer<SuPolicy> {
) : ObservableRvItem(), DiffItem<PolicyRvItem>, ItemWrapper<SuPolicy> {
override val layoutRes = R.layout.item_policy_md2

View File

@ -34,9 +34,9 @@ class SuperuserViewModel(
private val itemNoData = TextItem(R.string.superuser_policy_none)
private val itemsHelpers = ObservableArrayList<TextItem>()
private val itemsPolicies = DiffRvItemList<PolicyRvItem>()
private val itemsPolicies = DiffObservableList<PolicyRvItem>()
val items = MergeObservableList<AnyDiffRvItem>()
val items = MergeObservableList<RvItem>()
.insertList(itemsHelpers)
.insertList(itemsPolicies)
val extraBindings = bindExtra {
@ -54,7 +54,7 @@ class SuperuserViewModel(
return
}
loading = true
val (policies, diff) = withContext(Dispatchers.IO) {
withContext(Dispatchers.IO) {
db.deleteOutdated()
db.delete(AppContext.applicationInfo.uid)
val policies = ArrayList<PolicyRvItem>()
@ -91,9 +91,8 @@ class SuperuserViewModel(
{ it.appName.lowercase(currentLocale) },
{ it.packageName }
))
policies to itemsPolicies.calculateDiff(policies)
itemsPolicies.update(policies)
}
itemsPolicies.update(policies, diff)
if (itemsPolicies.isNotEmpty())
itemsHelpers.clear()
else if (itemsHelpers.isEmpty())

View File

@ -22,7 +22,14 @@ import com.google.android.material.shape.MaterialShapeDrawable
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.base.BaseActivity
import com.topjohnwu.magisk.databinding.*
import com.topjohnwu.magisk.databinding.DialogMagiskBaseBinding
import com.topjohnwu.magisk.databinding.DiffItem
import com.topjohnwu.magisk.databinding.ItemWrapper
import com.topjohnwu.magisk.databinding.ObservableHost
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.databinding.bindExtra
import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.databinding.setAdapter
import com.topjohnwu.magisk.view.MagiskDialog.DialogClickListener
typealias DialogButtonClickListener = (DialogInterface) -> Unit
@ -166,7 +173,7 @@ class MagiskDialog(
class DialogItem(
override val item: CharSequence,
val position: Int
) : DiffRvItem<DialogItem>(), RvContainer<CharSequence> {
) : RvItem(), DiffItem<DialogItem>, ItemWrapper<CharSequence> {
override val layoutRes = R.layout.item_list_single_line
}

View File

@ -1,9 +1,10 @@
package com.topjohnwu.magisk.view
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.DiffRvItem
import com.topjohnwu.magisk.databinding.DiffItem
import com.topjohnwu.magisk.databinding.RvItem
sealed class TappableHeadlineItem : DiffRvItem<TappableHeadlineItem>() {
sealed class TappableHeadlineItem : RvItem(), DiffItem<TappableHeadlineItem> {
abstract val title: Int
abstract val icon: Int

View File

@ -1,10 +1,10 @@
package com.topjohnwu.magisk.view
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.DiffRvItem
import com.topjohnwu.magisk.databinding.DiffItem
import com.topjohnwu.magisk.databinding.ItemWrapper
import com.topjohnwu.magisk.databinding.RvItem
class TextItem(val text: Int) : DiffRvItem<TextItem>() {
class TextItem(override val item: Int) : RvItem(), DiffItem<TextItem>, ItemWrapper<Int> {
override val layoutRes = R.layout.item_text
override fun contentSameAs(other: TextItem) = text == other.text
}

View File

@ -25,9 +25,9 @@
<include
android:id="@+id/log_track_container"
bullet="@{item.item.action ? R.drawable.ic_check_md2 : R.drawable.ic_close_md2}"
bullet="@{item.log.action ? R.drawable.ic_check_md2 : R.drawable.ic_close_md2}"
isBottom="@{item.isBottom}"
isSelected="@{!item.item.action}"
isSelected="@{!item.log.action}"
isTop="@{item.isTop}"
layout="@layout/item_log_track_md2"
android:layout_width="wrap_content"
@ -51,7 +51,7 @@
android:id="@+id/log_app_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{item.item.appName}"
android:text="@{item.log.appName}"
android:textAppearance="@style/AppearanceFoundation.Body"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/log_date"
@ -76,7 +76,7 @@
android:id="@+id/log_app_details"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@{String.format(`%s %s`, @string/pid(item.item.fromPid), @string/target_uid(item.item.toUid))}"
android:text="@{String.format(`%s %s`, @string/pid(item.log.fromPid), @string/target_uid(item.log.toUid))}"
android:textAppearance="@style/AppearanceFoundation.Caption.Variant"
app:layout_constraintBottom_toTopOf="@id/log_command"
app:layout_constraintEnd_toEndOf="parent"
@ -89,7 +89,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="monospace"
android:text="@{item.item.command}"
android:text="@{item.log.command}"
android:textAppearance="@style/AppearanceFoundation.Caption.Variant"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"

View File

@ -15,7 +15,7 @@
android:layout_height="wrap_content"
android:gravity="center"
android:padding="@dimen/l1"
android:text="@{item.text}"
android:text="@{item.item}"
android:textAppearance="@style/AppearanceFoundation.Tiny.Variant"
tools:text="@tools:sample/lorem/random" />