Commit 70a3dbe2 authored by Viktor De Pasquale's avatar Viktor De Pasquale

Added primitive implementation of modules screen

parent efbb3ab2
package com.topjohnwu.magisk.model.entity.recycler
import android.content.res.Resources
import android.view.View
import android.view.ViewGroup
import androidx.annotation.StringRes
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ComparableRvItem
......@@ -9,7 +11,10 @@ import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.toggle
import com.topjohnwu.magisk.model.entity.module.Module
import com.topjohnwu.magisk.model.entity.module.Repo
import com.topjohnwu.magisk.redesign.module.ModuleViewModel
import com.topjohnwu.magisk.utils.KObservableField
import com.topjohnwu.magisk.utils.rotationTo
import com.topjohnwu.magisk.utils.setRevealed
class ModuleRvItem(val item: Module) : ComparableRvItem<ModuleRvItem>() {
......@@ -72,4 +77,35 @@ class RepoRvItem(val item: Repo) : ComparableRvItem<RepoRvItem>() {
override fun contentSameAs(other: RepoRvItem): Boolean = item == other.item
override fun itemSameAs(other: RepoRvItem): Boolean = item.id == other.item.id
}
class ModuleItem(val item: Module) : ComparableRvItem<ModuleItem>() {
override val layoutRes = R.layout.item_module_md2
val isExpanded = KObservableField(false)
val isEnabled = KObservableField(item.enable)
val isModified get() = item.enable != isEnabled.value
fun toggle(viewModel: ModuleViewModel) {
isEnabled.toggle()
viewModel.moveToState(this)
}
fun toggle(view: View) {
isExpanded.toggle()
view.rotationTo(if (isExpanded.value) 225 else 180)
(view.parent as ViewGroup)
.findViewById<View>(R.id.module_expand_container)
.setRevealed(isExpanded.value)
}
override fun contentSameAs(other: ModuleItem): 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
}
\ No newline at end of file
package com.topjohnwu.magisk.redesign.module
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.model.entity.recycler.ModuleRvItem
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.model.entity.module.Module
import com.topjohnwu.magisk.model.entity.recycler.ModuleItem
import com.topjohnwu.magisk.redesign.compat.CompatViewModel
import com.topjohnwu.magisk.redesign.home.itemBindingOf
import com.topjohnwu.magisk.redesign.superuser.diffListOf
import io.reactivex.Single
class ModuleViewModel : CompatViewModel() {
val items = diffListOf<ModuleRvItem>()
val itemBinding = itemBindingOf<ModuleRvItem> {
val items = diffListOf<ModuleItem>()
val itemsPending = diffListOf<ModuleItem>()
val itemBinding = itemBindingOf<ModuleItem> {
it.bindExtra(BR.viewModel, this)
}
override fun refresh() = Single.fromCallable { Module.loadModules() }
.map { it.map { ModuleItem(it) } }
.map { it to items.calculateDiff(it) }
.subscribeK {
items.update(it.first, it.second)
items.forEach { moveToState(it) }
}
fun moveToState(item: ModuleItem) {
val isActive = items.indexOfFirst { it.itemSameAs(item) } != -1
val isPending = itemsPending.indexOfFirst { it.itemSameAs(item) } != -1
when {
isActive && isPending -> if (item.isModified) {
items.remove(item)
} else {
itemsPending.remove(item)
}
isActive && item.isModified -> {
items.remove(item)
itemsPending.add(item)
}
isPending && !item.isModified -> {
itemsPending.remove(item)
items.add(item)
}
}
}
}
\ No newline at end of file
......@@ -443,4 +443,11 @@ fun ProgressBar.setProgressAnimated(newProgress: Int) {
addUpdateListener { progress = it.animatedValue as Int }
tag = this
}.start()
}
@BindingAdapter("android:rotation")
fun View.setRotationNotAnimated(rotation: Int) {
if (animation != null) {
this.rotation = rotation.toFloat()
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?colorOnSurface"
android:pathData="M13,5V11H14.17L12,13.17L9.83,11H11V5H13M15,3H9V9H5L12,16L19,9H15V3M19,18H5V20H19V18Z"
tools:fillColor="#000" />
</vector>
\ No newline at end of file
......@@ -5,6 +5,8 @@
<data>
<import type="com.topjohnwu.magisk.R" />
<import type="com.topjohnwu.magisk.Config" />
<variable
......@@ -15,16 +17,18 @@
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:clipToPadding="false"
android:layout_height="match_parent"
android:clipToPadding="false"
android:fillViewport="true"
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}"
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l2}"
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l1}"
tools:paddingBottom="64dp"
tools:paddingTop="24dp">
<androidx.constraintlayout.widget.ConstraintLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
android:id="@+id/module_notice"
......@@ -49,17 +53,106 @@
</com.google.android.material.card.MaterialCardView>
<androidx.constraintlayout.widget.ConstraintLayout
gone="@{viewModel.itemsPending.empty}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/l1"
android:paddingEnd="@dimen/l1">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/l1"
android:layout_marginBottom="@dimen/l1"
android:text="Applied on next boot"
android:textAppearance="?appearanceTextBodyNormal"
android:textColor="?colorPrimaryTransient"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/module_reboot_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/module_reboot_button"
style="?styleButtonText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/reboot"
android:textAllCaps="false"
app:icon="@drawable/ic_restart"
app:iconPadding="@dimen/l_50"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
dividerHorizontal="@{R.drawable.divider_l1}"
dividerVertical="@{R.drawable.divider_l1}"
gone="@{viewModel.itemsPending.empty}"
itemBinding="@{viewModel.itemBinding}"
items="@{viewModel.itemsPending}"
nestedScrollingEnabled="@{false}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingStart="@dimen/l1"
android:paddingEnd="0dp"
app:layoutManager="androidx.recyclerview.widget.StaggeredGridLayoutManager"
app:spanCount="2"
tools:itemCount="1"
tools:listitem="@layout/item_module_md2" />
<androidx.appcompat.widget.AppCompatTextView
gone="@{viewModel.itemsPending.empty || viewModel.items.empty}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/l1"
android:paddingEnd="@dimen/l1"
android:text="Active"
android:textAppearance="?appearanceTextBodyNormal"
android:textColor="?colorPrimaryTransient"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/module_reboot_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
dividerHorizontal="@{R.drawable.divider_l1}"
dividerVertical="@{R.drawable.divider_l1}"
gone="@{viewModel.items.empty}"
itemBinding="@{viewModel.itemBinding}"
items="@{viewModel.items}"
nestedScrollingEnabled="@{false}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/l1"
android:clipToPadding="false"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toBottomOf="@+id/module_notice" />
android:paddingStart="@dimen/l1"
android:paddingEnd="0dp"
app:layoutManager="androidx.recyclerview.widget.StaggeredGridLayoutManager"
app:layout_constraintTop_toBottomOf="@+id/module_notice"
app:spanCount="2"
tools:itemCount="3"
tools:listitem="@layout/item_module_md2" />
<com.google.android.material.button.MaterialButton
style="?styleButtonText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="@dimen/l1"
android:text="Download more"
android:textAllCaps="false"
app:icon="@drawable/ic_download_md2" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
......
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="com.topjohnwu.magisk.Config" />
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.ModuleItem" />
<variable
name="viewModel"
type="com.topjohnwu.magisk.redesign.module.ModuleViewModel" />
</data>
<com.google.android.material.card.MaterialCardView
style="?styleCardVariant"
isEnabled="@{!Config.coreOnly}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="@{item.isEnabled() &amp;&amp; !Config.coreOnly ? 1f : .5f}"
android:onClick="@{() -> item.toggle(viewModel)}"
tools:layout_gravity="center"
tools:layout_marginBottom="@dimen/l1"
tools:layout_marginEnd="@dimen/l1">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/l1">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/module_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/l1"
android:layout_marginTop="@dimen/l1"
android:layout_marginEnd="32dp"
android:text="@{item.item.name}"
android:textAppearance="?appearanceTextBodyNormal"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/lorem" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/module_version_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/l1"
android:layout_marginEnd="@dimen/l1"
android:text="@{@string/module_version_author(item.item.version, item.item.author)}"
android:textAppearance="?appearanceTextCaptionVariant"
app:layout_constraintTop_toBottomOf="@+id/module_title"
tools:text="v1 by topjohnwu" />
<androidx.appcompat.widget.AppCompatTextView
gone="@{item.item.description.empty}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/l1"
android:layout_marginTop="@dimen/l1"
android:layout_marginEnd="@dimen/l1"
android:text="@{item.item.description}"
android:textAppearance="?appearanceTextCaptionVariant"
app:layout_constraintTop_toBottomOf="@+id/module_version_author"
tools:lines="4"
tools:text="@tools:sample/lorem/random" />
</androidx.constraintlayout.widget.ConstraintLayout>
<FrameLayout
android:id="@+id/module_expand_container"
revealFix="@{item.isExpanded}"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?colorSurfaceVariant"
android:visibility="gone">
<com.google.android.material.button.MaterialButton
style="?styleButtonError"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Remove"
android:textAllCaps="false"
app:icon="@drawable/ic_delete_md2" />
</FrameLayout>
<androidx.appcompat.widget.AppCompatImageView
style="?styleIconNormal"
isSelected="@{item.isExpanded}"
android:layout_gravity="top|end"
android:onClick="@{(v) -> item.toggle(v)}"
android:rotation="@{item.isExpanded ? 225 : 180}"
app:srcCompat="@drawable/ic_more_collapse" />
</com.google.android.material.card.MaterialCardView>
</layout>
\ No newline at end of file
......@@ -151,7 +151,7 @@
isSelected="@{item.isExpanded}"
android:layout_gravity="top|end"
android:onClick="@{(view) -> item.toggle(view)}"
android:rotation="180"
android:rotation="@{item.isExpanded ? 225 : 180}"
app:srcCompat="@drawable/ic_more_collapse" />
</com.google.android.material.card.MaterialCardView>
......
......@@ -74,6 +74,7 @@
<string name="install_start">Let\'s go</string>
<string name="module_safe_mode_message">You\'re in safe mode. None of user modules will work.\nThis message will disappear once safe mode is disabled.</string>
<string name="module_version_author">%1$s by %2$s</string>
<string name="superuser_toggle_log">Toggles logging</string>
<string name="superuser_toggle_notification">Toggles “toast” notifications</string>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment