Эх сурвалжийг харах

Update app theme preference UI

Heavily influenced by TachiyomiJ2K.
arkon 3 жил өмнө
parent
commit
6240fe1dfc

+ 8 - 5
app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseThemedActivity.kt

@@ -18,8 +18,13 @@ abstract class BaseThemedActivity : AppCompatActivity() {
 
     companion object {
         fun AppCompatActivity.applyAppTheme(preferences: PreferencesHelper) {
+            getThemeResIds(preferences.appTheme().get(), preferences.themeDarkAmoled().get())
+                .forEach { setTheme(it) }
+        }
+
+        fun getThemeResIds(appTheme: PreferenceValues.AppTheme, isAmoled: Boolean): List<Int> {
             val resIds = mutableListOf<Int>()
-            when (preferences.appTheme().get()) {
+            when (appTheme) {
                 PreferenceValues.AppTheme.MONET -> {
                     resIds += R.style.Theme_Tachiyomi_Monet
                 }
@@ -53,13 +58,11 @@ abstract class BaseThemedActivity : AppCompatActivity() {
                 }
             }
 
-            if (preferences.themeDarkAmoled().get()) {
+            if (isAmoled) {
                 resIds += R.style.ThemeOverlay_Tachiyomi_Amoled
             }
 
-            resIds.forEach {
-                setTheme(it)
-            }
+            return resIds
         }
     }
 }

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt

@@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.preference.asImmediateFlow
 import eu.kanade.tachiyomi.util.preference.defaultValue
 import eu.kanade.tachiyomi.util.preference.entriesRes
+import eu.kanade.tachiyomi.util.preference.initThenAdd
 import eu.kanade.tachiyomi.util.preference.intListPreference
 import eu.kanade.tachiyomi.util.preference.listPreference
 import eu.kanade.tachiyomi.util.preference.onChange
@@ -17,6 +18,7 @@ import eu.kanade.tachiyomi.util.preference.preferenceCategory
 import eu.kanade.tachiyomi.util.preference.switchPreference
 import eu.kanade.tachiyomi.util.preference.titleRes
 import eu.kanade.tachiyomi.util.system.isTablet
+import eu.kanade.tachiyomi.widget.preference.ThemesPreference
 import kotlinx.coroutines.flow.launchIn
 import java.util.Date
 import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
@@ -146,7 +148,7 @@ class SettingsGeneralController : SettingsController() {
 
                 summary = "%s"
             }
-            listPreference {
+            initThenAdd(ThemesPreference(context)) {
                 key = Keys.appTheme
                 titleRes = R.string.pref_app_theme
 
@@ -158,10 +160,8 @@ class SettingsGeneralController : SettingsController() {
                     }
                     it.titleResId != null && monetFilter
                 }
-                entriesRes = appThemes.map { it.titleResId!! }.toTypedArray()
-                entryValues = appThemes.map { it.name }.toTypedArray()
+                entries = appThemes
                 defaultValue = appThemes[0].name
-                summary = "%s"
 
                 onChange {
                     activity?.recreate()

+ 40 - 0
app/src/main/java/eu/kanade/tachiyomi/widget/preference/ThemesPreference.kt

@@ -0,0 +1,40 @@
+package eu.kanade.tachiyomi.widget.preference
+
+import android.content.Context
+import android.util.AttributeSet
+import androidx.preference.ListPreference
+import androidx.preference.PreferenceViewHolder
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import eu.kanade.tachiyomi.R
+import eu.kanade.tachiyomi.data.preference.PreferenceValues
+
+class ThemesPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
+    ListPreference(context, attrs),
+    ThemesPreferenceAdapter.OnItemClickListener {
+
+    private val adapter = ThemesPreferenceAdapter(this)
+
+    init {
+        layoutResource = R.layout.pref_themes_list
+    }
+
+    override fun onBindViewHolder(holder: PreferenceViewHolder) {
+        super.onBindViewHolder(holder)
+
+        val themesList = holder.findViewById(R.id.themes_list) as RecyclerView
+        themesList.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
+        themesList.adapter = adapter
+    }
+
+    override fun onItemClick(position: Int) {
+        value = entries[position].name
+        callChangeListener(value)
+    }
+
+    var entries: List<PreferenceValues.AppTheme> = emptyList()
+        set(value) {
+            field = value
+            adapter.setItems(value)
+        }
+}

+ 67 - 0
app/src/main/java/eu/kanade/tachiyomi/widget/preference/ThemesPreferenceAdapter.kt

@@ -0,0 +1,67 @@
+package eu.kanade.tachiyomi.widget.preference
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.appcompat.view.ContextThemeWrapper
+import androidx.recyclerview.widget.RecyclerView
+import eu.kanade.tachiyomi.data.preference.PreferenceValues
+import eu.kanade.tachiyomi.data.preference.PreferencesHelper
+import eu.kanade.tachiyomi.databinding.PrefThemeItemBinding
+import eu.kanade.tachiyomi.ui.base.activity.BaseThemedActivity
+import uy.kohesive.injekt.injectLazy
+
+class ThemesPreferenceAdapter(private val clickListener: OnItemClickListener) :
+    RecyclerView.Adapter<ThemesPreferenceAdapter.ThemeViewHolder>() {
+
+    private val preferences: PreferencesHelper by injectLazy()
+
+    private var themes = emptyList<PreferenceValues.AppTheme>()
+
+    private lateinit var binding: PrefThemeItemBinding
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ThemeViewHolder {
+        val themeResIds = BaseThemedActivity.getThemeResIds(themes[viewType], preferences.themeDarkAmoled().get())
+        val themedContext = themeResIds.fold(parent.context) {
+            context, themeResId -> ContextThemeWrapper(context, themeResId)
+        }
+
+        binding = PrefThemeItemBinding.inflate(LayoutInflater.from(themedContext), parent, false)
+        return ThemeViewHolder(binding.root)
+    }
+
+    override fun getItemViewType(position: Int): Int = position
+
+    override fun getItemCount(): Int = themes.size
+
+    override fun onBindViewHolder(holder: ThemesPreferenceAdapter.ThemeViewHolder, position: Int) {
+        holder.bind(themes[position])
+    }
+
+    fun setItems(themes: List<PreferenceValues.AppTheme>) {
+        this.themes = themes
+        notifyDataSetChanged()
+    }
+
+    inner class ThemeViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
+        fun bind(appTheme: PreferenceValues.AppTheme) {
+            binding.name.text = view.context.getString(appTheme.titleResId!!)
+
+            // Rounded corners
+            binding.coverContainer1.clipToOutline = true
+            binding.coverContainer2.clipToOutline = true
+
+            binding.themeCard.isChecked = preferences.appTheme().get() == appTheme
+
+            listOf(binding.root, binding.themeCard).forEach {
+                it.setOnClickListener {
+                    clickListener.onItemClick(bindingAdapterPosition)
+                }
+            }
+        }
+    }
+
+    interface OnItemClickListener {
+        fun onItemClick(position: Int)
+    }
+}

+ 6 - 0
app/src/main/res/drawable/oval.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <corners android:radius="20dp" />
+    <solid android:color="?android:attr/colorBackground" />
+</shape>

+ 187 - 0
app/src/main/res/layout/pref_theme_item.xml

@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout 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"
+    android:layout_width="110dp"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:padding="4dp">
+
+    <com.google.android.material.card.MaterialCardView
+        android:id="@+id/theme_card"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:checkable="true"
+        android:clickable="true"
+        android:focusable="true"
+        android:importantForAccessibility="no"
+        app:cardCornerRadius="@dimen/card_radius"
+        app:cardElevation="0dp">
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:layout_width="match_parent"
+            android:layout_height="176dp"
+            android:background="?android:attr/colorBackground">
+
+            <View
+                android:id="@+id/top_nav"
+                android:layout_width="0dp"
+                android:layout_height="20dp"
+                android:background="?attr/colorToolbar"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <ImageView
+                android:id="@+id/top_nav_text"
+                android:layout_width="50dp"
+                android:layout_height="10dp"
+                android:layout_marginStart="4dp"
+                android:src="@drawable/oval"
+                app:layout_constraintBottom_toBottomOf="@+id/top_nav"
+                app:layout_constraintStart_toStartOf="@+id/top_nav"
+                app:layout_constraintTop_toTopOf="@+id/top_nav"
+                app:tint="?attr/colorOnToolbar" />
+
+            <ImageView
+                android:id="@+id/heading"
+                android:layout_width="80dp"
+                android:layout_height="8dp"
+                android:layout_marginStart="4dp"
+                android:layout_marginTop="4dp"
+                android:src="@drawable/oval"
+                app:layout_constraintStart_toStartOf="@+id/top_nav"
+                app:layout_constraintTop_toBottomOf="@+id/top_nav"
+                app:tint="?attr/colorAccent" />
+
+            <FrameLayout
+                android:id="@+id/cover_container1"
+                android:layout_width="0dp"
+                android:layout_height="0dp"
+                android:layout_marginStart="4dp"
+                android:layout_marginTop="4dp"
+                android:layout_marginEnd="2dp"
+                android:background="@drawable/rounded_rectangle"
+                app:layout_constraintDimensionRatio="2:3"
+                app:layout_constraintEnd_toStartOf="@+id/cover_container2"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/heading">
+
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:alpha="0.5"
+                    android:background="?attr/colorOnSurface" />
+
+            </FrameLayout>
+
+            <View
+                android:id="@+id/cover_badge"
+                android:layout_width="8dp"
+                android:layout_height="12dp"
+                android:layout_marginStart="2dp"
+                android:layout_marginTop="2dp"
+                android:background="?attr/colorAccent"
+                app:layout_constraintStart_toStartOf="@+id/cover_container1"
+                app:layout_constraintTop_toTopOf="@+id/cover_container1" />
+
+            <FrameLayout
+                android:id="@+id/cover_container2"
+                android:layout_width="0dp"
+                android:layout_height="0dp"
+                android:layout_marginStart="2dp"
+                android:layout_marginTop="4dp"
+                android:layout_marginEnd="4dp"
+                android:background="@drawable/rounded_rectangle"
+                app:layout_constraintDimensionRatio="2:3"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toEndOf="@+id/cover_container1"
+                app:layout_constraintTop_toBottomOf="@+id/heading">
+
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:alpha="0.5"
+                    android:background="?attr/colorOnSurface" />
+
+            </FrameLayout>
+
+            <View
+                android:id="@+id/bottom_nav"
+                android:layout_width="0dp"
+                android:layout_height="20dp"
+                android:background="?attr/colorToolbar"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent" />
+
+            <ImageView
+                android:id="@+id/bottom_nav_selected_item"
+                android:layout_width="14dp"
+                android:layout_height="14dp"
+                android:src="@drawable/oval"
+                app:layout_constraintBottom_toBottomOf="@+id/bottom_nav"
+                app:layout_constraintEnd_toStartOf="@+id/bottom_nav_unselected_item1"
+                app:layout_constraintStart_toStartOf="@+id/bottom_nav"
+                app:layout_constraintTop_toTopOf="@+id/bottom_nav"
+                app:tint="?attr/colorPrimary" />
+
+            <ImageView
+                android:id="@+id/bottom_nav_unselected_item1"
+                android:layout_width="14dp"
+                android:layout_height="14dp"
+                android:src="@drawable/oval"
+                app:layout_constraintBottom_toBottomOf="@+id/bottom_nav"
+                app:layout_constraintEnd_toStartOf="@+id/bottom_nav_unselected_item2"
+                app:layout_constraintStart_toEndOf="@+id/bottom_nav_selected_item"
+                app:layout_constraintTop_toTopOf="@+id/bottom_nav"
+                app:tint="?attr/colorOnToolbar" />
+
+            <ImageView
+                android:id="@+id/bottom_nav_unselected_item2"
+                android:layout_width="14dp"
+                android:layout_height="14dp"
+                android:src="@drawable/oval"
+                app:layout_constraintBottom_toBottomOf="@+id/bottom_nav"
+                app:layout_constraintEnd_toStartOf="@+id/bottom_nav_unselected_item3"
+                app:layout_constraintStart_toEndOf="@+id/bottom_nav_unselected_item1"
+                app:layout_constraintTop_toTopOf="@+id/bottom_nav"
+                app:tint="?attr/colorOnToolbar" />
+
+            <ImageView
+                android:id="@+id/bottom_nav_unselected_item3"
+                android:layout_width="14dp"
+                android:layout_height="14dp"
+                android:src="@drawable/oval"
+                app:layout_constraintBottom_toBottomOf="@+id/bottom_nav"
+                app:layout_constraintEnd_toStartOf="@+id/bottom_nav_unselected_item4"
+                app:layout_constraintStart_toEndOf="@+id/bottom_nav_unselected_item2"
+                app:layout_constraintTop_toTopOf="@+id/bottom_nav"
+                app:tint="?attr/colorOnToolbar" />
+
+            <ImageView
+                android:id="@+id/bottom_nav_unselected_item4"
+                android:layout_width="14dp"
+                android:layout_height="14dp"
+                android:src="@drawable/oval"
+                app:layout_constraintBottom_toBottomOf="@+id/bottom_nav"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toEndOf="@+id/bottom_nav_unselected_item3"
+                app:layout_constraintTop_toTopOf="@+id/bottom_nav"
+                app:tint="?attr/colorOnToolbar" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+    </com.google.android.material.card.MaterialCardView>
+
+    <TextView
+        android:id="@+id/name"
+        android:layout_width="match_parent"
+        android:layout_height="32sp"
+        android:maxLines="2"
+        android:layout_marginTop="4dp"
+        android:textAlignment="center"
+        android:textAppearance="@style/TextAppearance.MaterialComponents.Caption"
+        tools:text="Theme Name" />
+
+</LinearLayout>

+ 26 - 0
app/src/main/res/layout/pref_themes_list.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingHorizontal="16dp"
+        android:paddingTop="4dp"
+        android:textAppearance="@style/TextAppearance.AppCompat.Menu"
+        tools:text="App theme" />
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/themes_list"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingHorizontal="16dp"
+        android:paddingVertical="8dp"
+        android:clipToPadding="false"
+        tools:listitem="@layout/pref_theme_item" />
+
+</LinearLayout>