mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-01-11 16:33:37 +00:00
Remove online section in modules fragment
This commit is contained in:
parent
f98c68a280
commit
f5c982355a
@ -232,7 +232,7 @@ dependencies {
|
||||
implementation("androidx.navigation:navigation-ui-ktx:${vNav}")
|
||||
|
||||
implementation("androidx.biometric:biometric:1.1.0")
|
||||
implementation("androidx.constraintlayout:constraintlayout:2.0.4")
|
||||
implementation("androidx.constraintlayout:constraintlayout:2.1.0")
|
||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
||||
implementation("androidx.browser:browser:1.3.0")
|
||||
implementation("androidx.preference:preference:1.1.1")
|
||||
|
@ -19,7 +19,6 @@ import com.topjohnwu.magisk.ktx.deviceProtectedContext
|
||||
import com.topjohnwu.magisk.ui.home.HomeViewModel
|
||||
import com.topjohnwu.magisk.ui.install.InstallViewModel
|
||||
import com.topjohnwu.magisk.ui.log.LogViewModel
|
||||
import com.topjohnwu.magisk.ui.module.ModuleViewModel
|
||||
import com.topjohnwu.magisk.ui.settings.SettingsViewModel
|
||||
import com.topjohnwu.magisk.ui.superuser.SuperuserViewModel
|
||||
import com.topjohnwu.magisk.ui.surequest.SuRequestViewModel
|
||||
@ -61,7 +60,6 @@ object ServiceLocator {
|
||||
return when (clz) {
|
||||
HomeViewModel::class.java -> HomeViewModel(networkService)
|
||||
LogViewModel::class.java -> LogViewModel(logRepo)
|
||||
ModuleViewModel::class.java -> ModuleViewModel(repoDB, repoUpdater)
|
||||
SettingsViewModel::class.java -> SettingsViewModel(repoDB)
|
||||
SuperuserViewModel::class.java -> SuperuserViewModel(policyDB)
|
||||
InstallViewModel::class.java -> InstallViewModel(networkService)
|
||||
|
@ -10,8 +10,6 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseUIFragment
|
||||
import com.topjohnwu.magisk.arch.ReselectionTarget
|
||||
import com.topjohnwu.magisk.arch.ViewEvent
|
||||
import com.topjohnwu.magisk.core.download.BaseDownloader
|
||||
import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding
|
||||
import com.topjohnwu.magisk.di.viewModel
|
||||
import com.topjohnwu.magisk.ktx.*
|
||||
@ -42,13 +40,10 @@ class ModuleFragment : BaseUIFragment<ModuleViewModel, FragmentModuleMd2Binding>
|
||||
super.onStart()
|
||||
setHasOptionsMenu(true)
|
||||
activity.title = resources.getString(R.string.modules)
|
||||
BaseDownloader.observeProgress(this, viewModel::onProgressUpdate)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setEndlessScroller()
|
||||
setEndlessSearch()
|
||||
|
||||
binding.moduleFilterToggle.setOnClickListener {
|
||||
isFilterVisible = true
|
||||
@ -116,13 +111,6 @@ class ModuleFragment : BaseUIFragment<ModuleViewModel, FragmentModuleMd2Binding>
|
||||
|
||||
// ---
|
||||
|
||||
override fun onEventDispatched(event: ViewEvent) = when (event) {
|
||||
is EndlessRecyclerScrollListener.ResetState -> listeners.forEach { it.resetState() }
|
||||
else -> super.onEventDispatched(event)
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.menu_module_md2, menu)
|
||||
}
|
||||
@ -137,32 +125,12 @@ class ModuleFragment : BaseUIFragment<ModuleViewModel, FragmentModuleMd2Binding>
|
||||
// ---
|
||||
|
||||
override fun onReselected() {
|
||||
binding.moduleList
|
||||
.also { it.scrollToPosition(10) }
|
||||
.let { binding.moduleList }
|
||||
.also { it.post { it.smoothScrollToPosition(0) } }
|
||||
binding.moduleList.scrollToPosition(10)
|
||||
binding.moduleList.also { it.post { it.smoothScrollToPosition(0) } }
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
override fun onPreBind(binding: FragmentModuleMd2Binding) = Unit
|
||||
|
||||
private fun setEndlessScroller() {
|
||||
val lama = binding.moduleList.layoutManager ?: return
|
||||
lama.isAutoMeasureEnabled = false
|
||||
|
||||
val listener = EndlessRecyclerScrollListener(lama, viewModel::loadRemote)
|
||||
binding.moduleList.addOnScrollListener(listener)
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
||||
private fun setEndlessSearch() {
|
||||
val lama = binding.moduleFilterInclude.moduleFilterList.layoutManager ?: return
|
||||
lama.isAutoMeasureEnabled = false
|
||||
|
||||
val listener = EndlessRecyclerScrollListener(lama, viewModel::loadMoreQuery)
|
||||
binding.moduleFilterInclude.moduleFilterList.addOnScrollListener(listener)
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,34 +39,27 @@ class SectionTitle(
|
||||
override fun contentSameAs(other: SectionTitle): Boolean = this === other
|
||||
}
|
||||
|
||||
sealed class RepoItem(val item: OnlineModule) : ObservableItem<RepoItem>() {
|
||||
class OnlineModuleRvItem(val item: OnlineModule) : ObservableItem<OnlineModuleRvItem>() {
|
||||
override val layoutRes: Int = R.layout.item_repo_md2
|
||||
|
||||
@get:Bindable
|
||||
var progress = 0
|
||||
set(value) = set(value, field, { field = it }, BR.progress)
|
||||
|
||||
abstract val isUpdate: Boolean
|
||||
var hasUpdate = false
|
||||
|
||||
override fun contentSameAs(other: RepoItem): Boolean = item == other.item
|
||||
override fun itemSameAs(other: RepoItem): Boolean = item.id == other.item.id
|
||||
override fun contentSameAs(other: OnlineModuleRvItem): Boolean = item == other.item
|
||||
override fun itemSameAs(other: OnlineModuleRvItem): Boolean = item.id == other.item.id
|
||||
|
||||
class Update(item: OnlineModule) : RepoItem(item) {
|
||||
override val isUpdate get() = true
|
||||
}
|
||||
|
||||
class Remote(item: OnlineModule) : RepoItem(item) {
|
||||
override val isUpdate get() = false
|
||||
}
|
||||
}
|
||||
|
||||
class ModuleItem(val item: LocalModule) : ObservableItem<ModuleItem>() {
|
||||
class LocalModuleRvItem(val item: LocalModule) : ObservableItem<LocalModuleRvItem>() {
|
||||
|
||||
override val layoutRes = R.layout.item_module_md2
|
||||
|
||||
@get:Bindable
|
||||
var repo: OnlineModule? = null
|
||||
set(value) = set(value, field, { field = it }, BR.repo)
|
||||
var online: OnlineModule? = null
|
||||
set(value) = set(value, field, { field = it }, BR.online)
|
||||
|
||||
@get:Bindable
|
||||
var isEnabled = item.enable
|
||||
@ -88,11 +81,10 @@ class ModuleItem(val item: LocalModule) : ObservableItem<ModuleItem>() {
|
||||
viewModel.updateActiveState()
|
||||
}
|
||||
|
||||
override fun contentSameAs(other: ModuleItem): Boolean = item.version == other.item.version
|
||||
override fun contentSameAs(other: LocalModuleRvItem): Boolean = item.version == other.item.version
|
||||
&& item.versionCode == other.item.versionCode
|
||||
&& item.description == other.item.description
|
||||
&& item.name == other.item.name
|
||||
|
||||
override fun itemSameAs(other: ModuleItem): Boolean = item.id == other.item.id
|
||||
override fun itemSameAs(other: LocalModuleRvItem): Boolean = item.id == other.item.id
|
||||
}
|
||||
|
||||
|
@ -6,12 +6,10 @@ import androidx.lifecycle.viewModelScope
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.*
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.download.Subject
|
||||
import com.topjohnwu.magisk.core.model.module.LocalModule
|
||||
import com.topjohnwu.magisk.core.tasks.RepoUpdater
|
||||
import com.topjohnwu.magisk.data.database.RepoDao
|
||||
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
||||
import com.topjohnwu.magisk.databinding.ComparableRvItem
|
||||
import com.topjohnwu.magisk.databinding.RvItem
|
||||
import com.topjohnwu.magisk.events.OpenReadmeEvent
|
||||
import com.topjohnwu.magisk.events.SelectModuleEvent
|
||||
@ -19,37 +17,16 @@ import com.topjohnwu.magisk.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.events.dialog.ModuleInstallDialog
|
||||
import com.topjohnwu.magisk.ktx.addOnListChangedCallback
|
||||
import com.topjohnwu.magisk.ktx.reboot
|
||||
import com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener
|
||||
import com.topjohnwu.magisk.utils.set
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import me.tatarka.bindingcollectionadapter2.collections.MergeObservableList
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/*
|
||||
* The repo fetching behavior should follow these rules:
|
||||
*
|
||||
* For the first time the repo list is queried in the app, it should ALWAYS fetch for
|
||||
* updates. However, this particular fetch should go through RepoUpdater.invoke(false),
|
||||
* which internally will set ETAGs when doing GET requests to GitHub's API and will
|
||||
* only update repo DB only if the GitHub API shows that something is changed remotely.
|
||||
*
|
||||
* When a user explicitly requests a full DB refresh, it should ALWAYS do a full force
|
||||
* refresh, which in code can be done with RepoUpdater.invoke(true). This will update
|
||||
* every single repo's information regardless whether GitHub's API shows if there is
|
||||
* anything changed or not.
|
||||
* */
|
||||
|
||||
class ModuleViewModel(
|
||||
private val repoDB: RepoDao,
|
||||
private val repoUpdater: RepoUpdater
|
||||
) : BaseViewModel(), Queryable {
|
||||
class ModuleViewModel : BaseViewModel(), Queryable {
|
||||
|
||||
override val queryDelay = 1000L
|
||||
private var queryJob: Job? = null
|
||||
private var remoteJob: Job? = null
|
||||
|
||||
@get:Bindable
|
||||
var isRemoteLoading = false
|
||||
@ -67,57 +44,27 @@ class ModuleViewModel(
|
||||
var searchLoading = false
|
||||
set(value) = set(value, field, { field = it }, BR.searchLoading)
|
||||
|
||||
val itemsSearch = diffListOf<RepoItem>()
|
||||
val itemSearchBinding = itemBindingOf<RepoItem> {
|
||||
val itemsSearch = diffListOf<ComparableRvItem<*>>()
|
||||
val itemSearchBinding = itemBindingOf<ComparableRvItem<*>> {
|
||||
it.bindExtra(BR.viewModel, this)
|
||||
}
|
||||
|
||||
private val installSectionList = ObservableArrayList<RvItem>()
|
||||
private val updatableSectionList = ObservableArrayList<RvItem>()
|
||||
|
||||
private val itemsInstalled = diffListOf<ModuleItem>()
|
||||
private val itemsUpdatable = diffListOf<RepoItem.Update>()
|
||||
private val itemsOnline = diffListOf<RepoItem.Remote>()
|
||||
|
||||
private val sectionUpdate = SectionTitle(
|
||||
R.string.module_section_pending,
|
||||
R.string.module_section_pending_action,
|
||||
R.drawable.ic_update_md2
|
||||
// enable with implementation of https://github.com/topjohnwu/Magisk/issues/2036
|
||||
).also { it.hasButton = false }
|
||||
|
||||
private val itemsInstalled = diffListOf<LocalModuleRvItem>()
|
||||
private val sectionInstalled = SectionTitle(
|
||||
R.string.module_installed,
|
||||
R.string.reboot,
|
||||
R.drawable.ic_restart
|
||||
).also { it.hasButton = false }
|
||||
|
||||
private val sectionOnline = SectionTitle(
|
||||
R.string.module_section_online,
|
||||
R.string.sorting_order
|
||||
).apply { updateOrderIcon() }
|
||||
|
||||
val adapter = adapterOf<RvItem>()
|
||||
val items = MergeObservableList<RvItem>()
|
||||
.also { if (Info.env.isActive) {
|
||||
it.insertItem(InstallModule)
|
||||
.insertList(updatableSectionList)
|
||||
.insertList(itemsUpdatable)
|
||||
.insertList(installSectionList)
|
||||
.insertList(itemsInstalled)
|
||||
} }
|
||||
.insertItem(sectionOnline)
|
||||
.insertList(itemsOnline)
|
||||
val itemBinding = itemBindingOf<RvItem> {
|
||||
it.bindExtra(BR.viewModel, this)
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
private var refetch = false
|
||||
|
||||
// ---
|
||||
|
||||
init {
|
||||
itemsInstalled.addOnListChangedCallback(
|
||||
onItemRangeInserted = { _, _, _ ->
|
||||
@ -129,131 +76,58 @@ class ModuleViewModel(
|
||||
installSectionList.clear()
|
||||
}
|
||||
)
|
||||
itemsUpdatable.addOnListChangedCallback(
|
||||
onItemRangeInserted = { _, _, _ ->
|
||||
if (updatableSectionList.isEmpty())
|
||||
updatableSectionList.add(sectionUpdate)
|
||||
},
|
||||
onItemRangeRemoved = { list, _, _ ->
|
||||
if (list.isEmpty())
|
||||
updatableSectionList.clear()
|
||||
}
|
||||
)
|
||||
|
||||
if (Info.env.isActive) {
|
||||
items.insertItem(InstallModule)
|
||||
.insertList(installSectionList)
|
||||
.insertList(itemsInstalled)
|
||||
}
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
fun onProgressUpdate(progress: Float, subject: Subject) {
|
||||
if (subject !is Subject.Module)
|
||||
return
|
||||
|
||||
viewModelScope.launch {
|
||||
val items = withContext(Dispatchers.Default) {
|
||||
val predicate = { it: RepoItem -> it.item.id == subject.module.id }
|
||||
itemsUpdatable.filter(predicate) +
|
||||
itemsOnline.filter(predicate) +
|
||||
itemsSearch.filter(predicate)
|
||||
}
|
||||
items.forEach { it.progress = progress.times(100).roundToInt() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun refresh(): Job {
|
||||
return viewModelScope.launch {
|
||||
state = State.LOADING
|
||||
loadInstalled()
|
||||
if (itemsOnline.isEmpty())
|
||||
loadRemote()
|
||||
state = State.LOADED
|
||||
}
|
||||
}
|
||||
|
||||
private fun SectionTitle.updateOrderIcon() {
|
||||
hasButton = true
|
||||
icon = when (Config.repoOrder) {
|
||||
Config.Value.ORDER_NAME -> R.drawable.ic_order_name
|
||||
Config.Value.ORDER_DATE -> R.drawable.ic_order_date
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun loadInstalled() {
|
||||
val installed = LocalModule.installed().map { ModuleItem(it) }
|
||||
val installed = LocalModule.installed().map { LocalModuleRvItem(it) }
|
||||
val diff = withContext(Dispatchers.Default) {
|
||||
itemsInstalled.calculateDiff(installed)
|
||||
}
|
||||
itemsInstalled.update(installed, diff)
|
||||
}
|
||||
|
||||
private suspend fun loadUpdatable() {
|
||||
val (updates, diff) = withContext(Dispatchers.IO) {
|
||||
itemsInstalled.forEach {
|
||||
launch {
|
||||
it.repo = repoDB.getModule(it.item.id)
|
||||
}
|
||||
}
|
||||
val updates = itemsInstalled
|
||||
.mapNotNull { repoDB.getUpdatableModule(it.item.id, it.item.versionCode) }
|
||||
.map { RepoItem.Update(it) }
|
||||
val diff = itemsUpdatable.calculateDiff(updates)
|
||||
return@withContext updates to diff
|
||||
}
|
||||
itemsUpdatable.update(updates, diff)
|
||||
}
|
||||
|
||||
fun loadRemote() {
|
||||
// check for existing jobs
|
||||
if (remoteJob?.isActive == true)
|
||||
return
|
||||
|
||||
if (itemsOnline.isEmpty())
|
||||
EndlessRecyclerScrollListener.ResetState().publish()
|
||||
|
||||
remoteJob = viewModelScope.launch {
|
||||
suspend fun loadRemoteDB(offset: Int) = withContext(Dispatchers.IO) {
|
||||
repoDB.getModules(offset).map { RepoItem.Remote(it) }
|
||||
}
|
||||
|
||||
isRemoteLoading = true
|
||||
val repos = if (itemsOnline.isEmpty()) {
|
||||
repoUpdater.run(refetch)
|
||||
loadUpdatable()
|
||||
loadRemoteDB(0)
|
||||
} else {
|
||||
loadRemoteDB(itemsOnline.size)
|
||||
}
|
||||
isRemoteLoading = false
|
||||
refetch = false
|
||||
queryHandler.post { itemsOnline.addAll(repos) }
|
||||
}
|
||||
}
|
||||
|
||||
fun forceRefresh() {
|
||||
itemsOnline.clear()
|
||||
itemsUpdatable.clear()
|
||||
itemsSearch.clear()
|
||||
refetch = true
|
||||
itemsInstalled.clear()
|
||||
refresh()
|
||||
submitQuery()
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
private suspend fun queryInternal(query: String, offset: Int): List<RepoItem> {
|
||||
private suspend fun queryInternal(query: String): List<ComparableRvItem<*>> {
|
||||
return if (query.isBlank()) {
|
||||
itemsSearch.clear()
|
||||
listOf()
|
||||
} else {
|
||||
withContext(Dispatchers.IO) {
|
||||
repoDB.searchModules(query, offset).map { RepoItem.Remote(it) }
|
||||
withContext(Dispatchers.Default) {
|
||||
itemsInstalled.filter {
|
||||
it.item.id.contains(query, true)
|
||||
|| it.item.name.contains(query, true)
|
||||
|| it.item.description.contains(query, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun query() {
|
||||
EndlessRecyclerScrollListener.ResetState().publish()
|
||||
queryJob = viewModelScope.launch {
|
||||
val searched = queryInternal(query, 0)
|
||||
viewModelScope.launch {
|
||||
val searched = queryInternal(query)
|
||||
val diff = withContext(Dispatchers.Default) {
|
||||
itemsSearch.calculateDiff(searched)
|
||||
}
|
||||
@ -262,59 +136,28 @@ class ModuleViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun loadMoreQuery() {
|
||||
if (queryJob?.isActive == true) return
|
||||
queryJob = viewModelScope.launch {
|
||||
val searched = queryInternal(query, itemsSearch.size)
|
||||
queryHandler.post { itemsSearch.addAll(searched) }
|
||||
}
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
fun updateActiveState() = viewModelScope.launch {
|
||||
sectionInstalled.hasButton = withContext(Dispatchers.Default) {
|
||||
itemsInstalled.any { it.isModified }
|
||||
}
|
||||
fun updateActiveState() {
|
||||
sectionInstalled.hasButton = itemsInstalled.any { it.isModified }
|
||||
}
|
||||
|
||||
fun sectionPressed(item: SectionTitle) = when (item) {
|
||||
sectionInstalled -> reboot() // TODO add reboot picker, regular reboot is not always preferred
|
||||
sectionOnline -> {
|
||||
Config.repoOrder = when (Config.repoOrder) {
|
||||
Config.Value.ORDER_NAME -> Config.Value.ORDER_DATE
|
||||
Config.Value.ORDER_DATE -> Config.Value.ORDER_NAME
|
||||
else -> Config.Value.ORDER_NAME
|
||||
}
|
||||
sectionOnline.updateOrderIcon()
|
||||
queryHandler.post {
|
||||
itemsOnline.clear()
|
||||
loadRemote()
|
||||
}
|
||||
Unit
|
||||
}
|
||||
sectionInstalled -> reboot()
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
fun downloadPressed(item: RepoItem) = if (isConnected.get()) withExternalRW {
|
||||
ModuleInstallDialog(item.item).publish()
|
||||
} else {
|
||||
SnackbarEvent(R.string.no_connection).publish()
|
||||
}
|
||||
// The following methods are not used, but kept for future integration
|
||||
|
||||
fun installPressed() = withExternalRW {
|
||||
SelectModuleEvent().publish()
|
||||
}
|
||||
fun downloadPressed(item: OnlineModule) =
|
||||
if (isConnected.get()) withExternalRW { ModuleInstallDialog(item).publish() }
|
||||
else { SnackbarEvent(R.string.no_connection).publish() }
|
||||
|
||||
fun infoPressed(item: RepoItem) =
|
||||
if (isConnected.get()) OpenReadmeEvent(item.item).publish()
|
||||
fun installPressed() = withExternalRW { SelectModuleEvent().publish() }
|
||||
|
||||
fun infoPressed(item: OnlineModule) =
|
||||
if (isConnected.get()) OpenReadmeEvent(item).publish()
|
||||
else SnackbarEvent(R.string.no_connection).publish()
|
||||
|
||||
|
||||
fun infoPressed(item: ModuleItem) {
|
||||
item.repo?.also {
|
||||
if (isConnected.get()) OpenReadmeEvent(it).publish()
|
||||
else SnackbarEvent(R.string.no_connection).publish()
|
||||
} ?: return
|
||||
}
|
||||
fun infoPressed(item: LocalModuleRvItem) { infoPressed(item.online ?: return) }
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
<variable
|
||||
name="item"
|
||||
type="com.topjohnwu.magisk.ui.module.ModuleItem" />
|
||||
type="com.topjohnwu.magisk.ui.module.LocalModuleRvItem" />
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
@ -120,7 +120,7 @@
|
||||
<ImageView
|
||||
android:id="@+id/module_info"
|
||||
style="@style/WidgetFoundation.Icon"
|
||||
gone="@{item.repo == null}"
|
||||
gone="@{item.online == null}"
|
||||
android:layout_width="wrap_content"
|
||||
android:alpha=".5"
|
||||
android:clickable="true"
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
<variable
|
||||
name="item"
|
||||
type="com.topjohnwu.magisk.ui.module.RepoItem" />
|
||||
type="com.topjohnwu.magisk.ui.module.OnlineModuleRvItem" />
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
@ -25,7 +25,6 @@
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:nextFocusRight="@id/module_info"
|
||||
android:onClick="@{() -> viewModel.downloadPressed(item)}"
|
||||
tools:layout_gravity="center"
|
||||
tools:layout_marginBottom="@dimen/l1"
|
||||
tools:layout_marginEnd="@dimen/l1">
|
||||
@ -102,7 +101,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:alpha=".5"
|
||||
android:nextFocusLeft="@id/module_card"
|
||||
android:onClick="@{() -> viewModel.infoPressed(item)}"
|
||||
android:onClick="@{() -> viewModel.infoPressed(item.item)}"
|
||||
android:paddingEnd="@dimen/l_50"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/module_download"
|
||||
app:layout_constraintEnd_toStartOf="@+id/module_download"
|
||||
@ -113,11 +112,11 @@
|
||||
android:id="@+id/module_download"
|
||||
style="@style/WidgetFoundation.Icon.Primary"
|
||||
isEnabled="@{!(item.progress == -100 || (item.progress > 0 && item.progress < 100))}"
|
||||
srcCompat="@{item.isUpdate ? R.drawable.ic_update_md2 : R.drawable.ic_download_md2}"
|
||||
srcCompat="@{item.hasUpdate ? R.drawable.ic_update_md2 : R.drawable.ic_download_md2}"
|
||||
android:layout_width="wrap_content"
|
||||
android:contentDescription="@string/download"
|
||||
android:nextFocusLeft="@id/module_info"
|
||||
android:onClick="@{() -> viewModel.downloadPressed(item)}"
|
||||
android:onClick="@{() -> viewModel.downloadPressed(item.item)}"
|
||||
android:paddingStart="@dimen/l_50"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@ -154,4 +153,3 @@
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</layout>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user