More homescreen UI improvements

This commit is contained in:
topjohnwu 2020-08-09 06:52:02 -07:00
parent 15b1215972
commit 24f6024383
8 changed files with 134 additions and 190 deletions

View File

@ -0,0 +1,84 @@
package com.topjohnwu.magisk.model.entity
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.databinding.RvItem
sealed class DeveloperItem {
abstract val items: List<IconLink>
abstract val name: Int
object Main : DeveloperItem() {
override val items =
listOf(
IconLink.Twitter.Main,
IconLink.Patreon,
IconLink.PayPal.Main,
IconLink.Github
)
override val name get() = R.string.topjohnwu
}
object App : DeveloperItem() {
override val items =
listOf<IconLink>(
IconLink.Twitter.App,
IconLink.PayPal.App
)
override val name get() = R.string.diareuse
}
}
private interface Dev {
val name: String
}
private interface MainDev: Dev {
override val name get() = "topjohnwu"
}
private interface AppDev: Dev {
override val name get() = "diareuse"
}
sealed class IconLink : RvItem() {
abstract val icon: Int
abstract val title: Int
abstract val link: String
override val layoutRes get() = R.layout.item_icon_link
sealed class PayPal : IconLink(), Dev {
override val icon get() = R.drawable.ic_paypal
override val title get() = R.string.paypal
override val link get() = "https://paypal.me/$name"
object App : PayPal(), AppDev
object Main : PayPal(), MainDev
}
object Patreon : IconLink() {
override val icon get() = R.drawable.ic_patreon
override val title get() = R.string.patreon
override val link get() = Const.Url.PATREON_URL
}
sealed class Twitter : IconLink(), Dev {
override val icon get() = R.drawable.ic_twitter
override val title get() = R.string.twitter
override val link get() = "https://twitter.com/$name"
object App : Twitter(), AppDev
object Main : Twitter(), MainDev
}
object Github : IconLink() {
override val icon get() = R.drawable.ic_github
override val title get() = R.string.home_item_source
override val link get() = Const.Url.SOURCE_CODE_URL
}
}

View File

@ -1,116 +0,0 @@
package com.topjohnwu.magisk.model.entity.recycler
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.databinding.ComparableRvItem
sealed class HomeItem : ComparableRvItem<HomeItem>() {
abstract val icon: Int
abstract val title: Int
abstract val link: String
override val layoutRes = R.layout.item_developer_link
override fun contentSameAs(other: HomeItem) = itemSameAs(other)
override fun itemSameAs(other: HomeItem) = this == other
override fun equals(other: Any?): Boolean {
if (other !is HomeItem) return false
return icon == other.icon && title == other.title && link == other.link
}
override fun hashCode() =
icon.hashCode() + title.hashCode() + link.hashCode() + layoutRes.hashCode()
// region Children
sealed class PayPal : HomeItem() {
override val icon = R.drawable.ic_paypal
override val title = R.string.paypal
override val link = "https://paypal.me/%s"
// region Children
object App : PayPal() {
override val link = super.link.format("diareuse")
}
object Mainline : PayPal() {
override val link = super.link.format("topjohnwu")
}
// endregion
}
object Patreon : HomeItem() {
override val icon = R.drawable.ic_patreon
override val title = R.string.patreon
override val link = Const.Url.PATREON_URL
}
sealed class Twitter : HomeItem() {
override val icon = R.drawable.ic_twitter
override val title = R.string.twitter
override val link = "https://twitter.com/%s"
// region Children
object App : Twitter() {
override val link = super.link.format("diareuse")
}
object Mainline : Twitter() {
override val link = super.link.format("topjohnwu")
}
// endregion
}
object Github : HomeItem() {
override val icon = R.drawable.ic_github
override val title = R.string.home_item_source
override val link = Const.Url.SOURCE_CODE_URL
}
object Xda : HomeItem() {
override val icon = R.drawable.ic_xda
override val title = R.string.xda
override val link = Const.Url.XDA_THREAD
}
// endregion
}
sealed class DeveloperItem : ComparableRvItem<DeveloperItem>() {
abstract val items: List<HomeItem>
abstract val name: Int
override val layoutRes = R.layout.item_developer
override fun contentSameAs(other: DeveloperItem) = itemSameAs(other)
override fun itemSameAs(other: DeveloperItem) = this == other
override fun equals(other: Any?): Boolean {
if (other !is DeveloperItem) return false
return name == other.name && items == other.items
}
override fun hashCode() = name.hashCode() + items.hashCode() + layoutRes.hashCode()
//region Children
object Mainline : DeveloperItem() {
override val items =
listOf(HomeItem.PayPal.Mainline, HomeItem.Patreon, HomeItem.Twitter.Mainline)
override val name = R.string.topjohnwu
}
object App : DeveloperItem() {
override val items =
listOf(HomeItem.PayPal.App, HomeItem.Twitter.App)
override val name = R.string.diareuse
}
object Project : DeveloperItem() {
override val items =
listOf(HomeItem.Github, HomeItem.Xda)
override val name = R.string.home_links_project
}
//endregion
}

View File

@ -2,6 +2,7 @@ package com.topjohnwu.magisk.ui.base
import androidx.databinding.ViewDataBinding import androidx.databinding.ViewDataBinding
import com.topjohnwu.magisk.databinding.ComparableRvItem import com.topjohnwu.magisk.databinding.ComparableRvItem
import com.topjohnwu.magisk.databinding.RvItem
import com.topjohnwu.magisk.utils.DiffObservableList import com.topjohnwu.magisk.utils.DiffObservableList
import com.topjohnwu.magisk.utils.FilterableDiffObservableList import com.topjohnwu.magisk.utils.FilterableDiffObservableList
import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter
@ -39,7 +40,7 @@ fun <T : ComparableRvItem<*>> adapterOf() = object : BindingRecyclerViewAdapter<
} }
} }
inline fun <T : ComparableRvItem<*>> itemBindingOf( inline fun <T : RvItem> itemBindingOf(
crossinline body: (ItemBinding<*>) -> Unit = {} crossinline body: (ItemBinding<*>) -> Unit = {}
) = OnItemBind<T> { itemBinding, _, item -> ) = OnItemBind<T> { itemBinding, _, item ->
item.bind(itemBinding) item.bind(itemBinding)

View File

@ -15,9 +15,8 @@ import com.topjohnwu.magisk.data.repository.MagiskRepository
import com.topjohnwu.magisk.ktx.await import com.topjohnwu.magisk.ktx.await
import com.topjohnwu.magisk.ktx.packageName import com.topjohnwu.magisk.ktx.packageName
import com.topjohnwu.magisk.ktx.res import com.topjohnwu.magisk.ktx.res
import com.topjohnwu.magisk.model.entity.IconLink
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Manager import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Manager
import com.topjohnwu.magisk.model.entity.recycler.DeveloperItem
import com.topjohnwu.magisk.model.entity.recycler.HomeItem
import com.topjohnwu.magisk.model.events.ActivityExecutor import com.topjohnwu.magisk.model.events.ActivityExecutor
import com.topjohnwu.magisk.model.events.OpenInappLinkEvent import com.topjohnwu.magisk.model.events.OpenInappLinkEvent
import com.topjohnwu.magisk.model.events.ViewEvent import com.topjohnwu.magisk.model.events.ViewEvent
@ -77,11 +76,7 @@ class HomeViewModel(
val showUninstall get() = val showUninstall get() =
Info.env.magiskVersionCode > 0 && stateMagisk != MagiskState.LOADING && isConnected.get() Info.env.magiskVersionCode > 0 && stateMagisk != MagiskState.LOADING && isConnected.get()
val items = listOf(DeveloperItem.Mainline, DeveloperItem.App, DeveloperItem.Project) val itemBinding = itemBindingOf<IconLink> {
val itemBinding = itemBindingOf<HomeItem> {
it.bindExtra(BR.viewModel, this)
}
val itemDeveloperBinding = itemBindingOf<DeveloperItem> {
it.bindExtra(BR.viewModel, this) it.bindExtra(BR.viewModel, this)
} }

View File

@ -6,11 +6,11 @@ import android.graphics.drawable.Drawable
import android.view.ContextThemeWrapper import android.view.ContextThemeWrapper
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView
import android.widget.PopupMenu import android.widget.PopupMenu
import android.widget.ProgressBar import android.widget.ProgressBar
import android.widget.TextView import android.widget.TextView
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.appcompat.widget.AppCompatImageView
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.databinding.BindingAdapter import androidx.databinding.BindingAdapter
@ -33,7 +33,7 @@ fun setOnNavigationClickedListener(view: Toolbar, listener: View.OnClickListener
} }
@BindingAdapter("srcCompat") @BindingAdapter("srcCompat")
fun setImageResource(view: AppCompatImageView, @DrawableRes resId: Int) { fun setImageResource(view: ImageView, @DrawableRes resId: Int) {
view.setImageResource(resId) view.setImageResource(resId)
} }

View File

@ -9,6 +9,8 @@
<import type="com.topjohnwu.magisk.ui.home.MagiskState" /> <import type="com.topjohnwu.magisk.ui.home.MagiskState" />
<import type="com.topjohnwu.magisk.model.entity.DeveloperItem"/>
<variable <variable
name="viewModel" name="viewModel"
type="com.topjohnwu.magisk.ui.home.HomeViewModel" /> type="com.topjohnwu.magisk.ui.home.HomeViewModel" />
@ -166,23 +168,21 @@
android:text="@string/home_support_content" android:text="@string/home_support_content"
android:textAppearance="@style/AppearanceFoundation.Caption.Variant" /> android:textAppearance="@style/AppearanceFoundation.Caption.Variant" />
<androidx.recyclerview.widget.RecyclerView <include
dividerHorizontal="@{@drawable/divider_l1}" layout="@layout/item_developer"
dividerVertical="@{@drawable/divider_l1}" android:layout_width="wrap_content"
itemBinding="@{viewModel.itemDeveloperBinding}"
items="@{viewModel.items}"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/l1" android:layout_marginTop="@dimen/l_50"
android:clipToPadding="false" viewModel="@{viewModel}"
android:nestedScrollingEnabled="false" item="@{DeveloperItem.Main.INSTANCE}" />
android:orientation="horizontal"
android:overScrollMode="ifContentScrolls" <include
android:paddingStart="@dimen/l1" layout="@layout/item_developer"
app:layoutManager="androidx.recyclerview.widget.StaggeredGridLayoutManager" android:layout_width="wrap_content"
app:spanCount="2" android:layout_height="wrap_content"
tools:itemCount="3" android:layout_marginTop="@dimen/l_50"
tools:listitem="@layout/item_developer" /> viewModel="@{viewModel}"
item="@{DeveloperItem.App.INSTANCE}" />
</LinearLayout> </LinearLayout>

View File

@ -7,7 +7,7 @@
<variable <variable
name="item" name="item"
type="com.topjohnwu.magisk.model.entity.recycler.DeveloperItem" /> type="com.topjohnwu.magisk.model.entity.DeveloperItem" />
<variable <variable
name="viewModel" name="viewModel"
@ -15,55 +15,35 @@
</data> </data>
<androidx.constraintlayout.widget.ConstraintLayout <LinearLayout
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:layout_gravity="center|start"> android:orientation="vertical"
android:padding="@dimen/l1" >
<com.google.android.material.card.MaterialCardView <TextView
style="@style/WidgetFoundation.Card.Primary"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constrainedWidth="true" android:text="@{item.name}"
app:layout_constraintBottom_toBottomOf="parent" android:textAppearance="@style/AppearanceFoundation.Caption"
app:layout_constraintEnd_toEndOf="parent" android:textStyle="bold"
app:layout_constraintHorizontal_bias="0" tools:text="\@topjohnwu" />
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout <androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent" itemBinding="@{viewModel.itemBinding}"
android:layout_height="wrap_content" items="@{item.items}"
android:orientation="vertical" nestedScrollingEnabled="@{false}"
android:padding="@dimen/l1"> android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:fadingEdgeLength="@dimen/l1"
android:orientation="horizontal"
android:paddingTop="@dimen/l_50"
android:requiresFadingEdge="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="3"
tools:listitem="@layout/item_icon_link" />
<androidx.appcompat.widget.AppCompatTextView </LinearLayout>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{item.name}"
android:textAppearance="@style/AppearanceFoundation.Caption.OnPrimary"
android:textStyle="bold"
tools:text="\@topjohnwu" />
<androidx.recyclerview.widget.RecyclerView
itemBinding="@{viewModel.itemBinding}"
items="@{item.items}"
nestedScrollingEnabled="@{false}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:fadingEdgeLength="@dimen/l1"
android:orientation="horizontal"
android:paddingTop="@dimen/l_50"
android:requiresFadingEdge="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="3"
tools:listitem="@layout/item_developer_link" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout> </layout>

View File

@ -7,7 +7,7 @@
<variable <variable
name="item" name="item"
type="com.topjohnwu.magisk.model.entity.recycler.HomeItem" /> type="com.topjohnwu.magisk.model.entity.IconLink" />
<variable <variable
name="viewModel" name="viewModel"
@ -24,12 +24,12 @@
android:padding="@dimen/l_50" android:padding="@dimen/l_50"
tools:layout_gravity="center"> tools:layout_gravity="center">
<androidx.appcompat.widget.AppCompatImageView <ImageView
android:id="@+id/developer_link" android:id="@+id/developer_link"
style="@style/WidgetFoundation.Image.Small" style="@style/WidgetFoundation.Image.Small"
android:layout_gravity="center" android:layout_gravity="center"
app:srcCompat="@{item.icon}" app:srcCompat="@{item.icon}"
app:tint="?colorOnPrimary" app:tint="?colorOnSurface"
tools:srcCompat="@drawable/ic_paypal" /> tools:srcCompat="@drawable/ic_paypal" />
</FrameLayout> </FrameLayout>