Procházet zdrojové kódy

新增选择图片创建主题颜色功能

HapeLee před 1 rokem
rodič
revize
45c953024f

+ 31 - 3
app/src/main/java/io/legato/kazusa/App.kt

@@ -7,7 +7,9 @@ import android.app.NotificationManager
 import android.content.Context
 import android.content.Context
 import android.content.pm.ApplicationInfo
 import android.content.pm.ApplicationInfo
 import android.content.res.Configuration
 import android.content.res.Configuration
+import android.graphics.BitmapFactory
 import android.os.Build
 import android.os.Build
+import androidx.core.graphics.scale
 import com.github.liuyueyi.quick.transfer.constants.TransType
 import com.github.liuyueyi.quick.transfer.constants.TransType
 import com.google.android.material.color.DynamicColors
 import com.google.android.material.color.DynamicColors
 import com.google.android.material.color.DynamicColorsOptions
 import com.google.android.material.color.DynamicColorsOptions
@@ -59,6 +61,7 @@ import kotlinx.coroutines.launch
 import org.chromium.base.ThreadUtils
 import org.chromium.base.ThreadUtils
 import splitties.init.appCtx
 import splitties.init.appCtx
 import splitties.systemservices.notificationManager
 import splitties.systemservices.notificationManager
+import java.io.File
 import java.net.URL
 import java.net.URL
 import java.util.concurrent.TimeUnit
 import java.util.concurrent.TimeUnit
 import java.util.logging.Level
 import java.util.logging.Level
@@ -72,9 +75,34 @@ class App : Application() {
         if (getPrefString("app_theme", "0") == "11") {
         if (getPrefString("app_theme", "0") == "11") {
             if (AppConfig.customMode == "accent")
             if (AppConfig.customMode == "accent")
                 setTheme(R.style.ThemeOverlay_WhiteBackground)
                 setTheme(R.style.ThemeOverlay_WhiteBackground)
-            DynamicColors.applyToActivitiesIfAvailable(this, DynamicColorsOptions.Builder()
-                .setContentBasedSource(this.primaryColor)
-                .build())
+
+            val colorImagePath = getPrefString(PreferKey.colorImage)
+            if (!colorImagePath.isNullOrBlank()) {
+                val file = File(colorImagePath)
+                if (file.exists()) {
+                    val bitmap = BitmapFactory.decodeFile(file.absolutePath)
+                    if (bitmap != null) {
+                        val colorAccuracy = true
+                        val targetWidth = if (colorAccuracy) (bitmap.width / 4).coerceAtMost(256) else 16
+                        val targetHeight = if (colorAccuracy) (bitmap.height / 4).coerceAtMost(256) else 16
+                        val scaledBitmap = bitmap.scale(targetWidth, targetHeight, false)
+
+                        val options = DynamicColorsOptions.Builder()
+                            .setContentBasedSource(scaledBitmap)
+                            .build()
+
+                        DynamicColors.applyToActivitiesIfAvailable(this, options)
+                        bitmap.recycle()
+                    }
+                }
+            }else{
+                DynamicColors.applyToActivitiesIfAvailable(
+                    this,
+                    DynamicColorsOptions.Builder()
+                        .setContentBasedSource(this.primaryColor)
+                        .build()
+                )
+            }
         }
         }
 
 
         super.onCreate()
         super.onCreate()

+ 32 - 3
app/src/main/java/io/legato/kazusa/base/BaseActivity.kt

@@ -3,6 +3,7 @@ package io.legato.kazusa.base
 import android.annotation.SuppressLint
 import android.annotation.SuppressLint
 import android.content.Context
 import android.content.Context
 import android.content.res.Configuration
 import android.content.res.Configuration
+import android.graphics.BitmapFactory
 import android.graphics.Color
 import android.graphics.Color
 import android.os.Build
 import android.os.Build
 import android.os.Bundle
 import android.os.Bundle
@@ -14,6 +15,7 @@ import android.view.View
 import androidx.activity.enableEdgeToEdge
 import androidx.activity.enableEdgeToEdge
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.app.AppCompatActivity
 import androidx.core.graphics.drawable.toDrawable
 import androidx.core.graphics.drawable.toDrawable
+import androidx.core.graphics.scale
 import androidx.core.view.WindowCompat
 import androidx.core.view.WindowCompat
 import androidx.viewbinding.ViewBinding
 import androidx.viewbinding.ViewBinding
 import com.google.android.material.appbar.AppBarLayout
 import com.google.android.material.appbar.AppBarLayout
@@ -22,6 +24,7 @@ import com.google.android.material.color.DynamicColorsOptions
 import io.legato.kazusa.R
 import io.legato.kazusa.R
 import io.legato.kazusa.constant.AppLog
 import io.legato.kazusa.constant.AppLog
 import io.legato.kazusa.constant.EventBus
 import io.legato.kazusa.constant.EventBus
+import io.legato.kazusa.constant.PreferKey
 import io.legato.kazusa.constant.Theme
 import io.legato.kazusa.constant.Theme
 import io.legato.kazusa.help.config.AppConfig
 import io.legato.kazusa.help.config.AppConfig
 import io.legato.kazusa.help.config.ThemeConfig
 import io.legato.kazusa.help.config.ThemeConfig
@@ -38,6 +41,7 @@ import io.legato.kazusa.utils.fullScreen
 import io.legato.kazusa.utils.setNavigationBarColorAuto
 import io.legato.kazusa.utils.setNavigationBarColorAuto
 import io.legato.kazusa.utils.setStatusBarColorAuto
 import io.legato.kazusa.utils.setStatusBarColorAuto
 import io.legato.kazusa.utils.themeColor
 import io.legato.kazusa.utils.themeColor
+import java.io.File
 
 
 
 
 abstract class BaseActivity<VB : ViewBinding>(
 abstract class BaseActivity<VB : ViewBinding>(
@@ -169,11 +173,36 @@ abstract class BaseActivity<VB : ViewBinding>(
             "11" -> {
             "11" -> {
                 if (AppConfig.customMode == "accent")
                 if (AppConfig.customMode == "accent")
                     setTheme(R.style.ThemeOverlay_WhiteBackground)
                     setTheme(R.style.ThemeOverlay_WhiteBackground)
-                DynamicColors.applyToActivitiesIfAvailable(application, DynamicColorsOptions.Builder()
-                    .setContentBasedSource(application.primaryColor)
-                    .build())
 
 
+                val colorImagePath = getPrefString(PreferKey.colorImage)
+                if (!colorImagePath.isNullOrBlank()) {
+                    val file = File(colorImagePath)
+                    if (file.exists()) {
+                        val bitmap = BitmapFactory.decodeFile(file.absolutePath)
+                        if (bitmap != null) {
+                            val colorAccuracy = true
+                            val targetWidth = if (colorAccuracy) (bitmap.width / 4).coerceAtMost(256) else 16
+                            val targetHeight = if (colorAccuracy) (bitmap.height / 4).coerceAtMost(256) else 16
+                            val scaledBitmap = bitmap.scale(targetWidth, targetHeight, false)
+
+                            val options = DynamicColorsOptions.Builder()
+                                .setContentBasedSource(scaledBitmap)
+                                .build()
+
+                            DynamicColors.applyToActivitiesIfAvailable(application, options)
+                            bitmap.recycle()
+                        }
+                    }
+                }else{
+                    DynamicColors.applyToActivitiesIfAvailable(
+                        application,
+                        DynamicColorsOptions.Builder()
+                            .setContentBasedSource(application.primaryColor)
+                            .build()
+                    )
+                }
             }
             }
+
             "12" -> setTheme(R.style.AppTheme_Transparent)
             "12" -> setTheme(R.style.AppTheme_Transparent)
         }
         }
 
 

+ 2 - 0
app/src/main/java/io/legato/kazusa/constant/PreferKey.kt

@@ -205,4 +205,6 @@ object PreferKey {
     const val pureBlack = "pure_black"
     const val pureBlack = "pure_black"
     const val labelVisibilityMode = "labelVisibilityMode"
     const val labelVisibilityMode = "labelVisibilityMode"
     const val menuAlpha = "menuAlpha"
     const val menuAlpha = "menuAlpha"
+
+    const val colorImage = "colorImage"
 }
 }

+ 53 - 0
app/src/main/java/io/legato/kazusa/lib/prefs/ImagePreviewPreference.kt

@@ -0,0 +1,53 @@
+package io.legato.kazusa.lib.prefs
+
+import android.content.Context
+import android.graphics.BitmapFactory
+import android.net.Uri
+import android.util.AttributeSet
+import android.view.View
+import android.widget.ImageView
+import androidx.preference.PreferenceViewHolder
+import io.legato.kazusa.R
+import java.io.File
+
+class ImagePreviewPreference(context: Context, attrs: AttributeSet) : Preference(context, attrs) {
+
+    private var preview: ImageView? = null
+
+    init {
+        layoutResource = R.layout.view_preference
+        widgetLayoutResource = R.layout.view_icon
+    }
+
+    override fun onBindViewHolder(holder: PreferenceViewHolder) {
+        super.onBindViewHolder(holder)
+        val v = Preference.bindView<ImageView>(
+            context, holder, icon, title, summary,
+            widgetLayoutResource,
+            R.id.preview,
+            50,
+            50
+        )
+
+        preview = v
+        updatePreview()
+    }
+
+    fun updatePreview() {
+        val path = sharedPreferences?.getString(key, null)
+        val view = preview ?: return
+
+        if (!path.isNullOrBlank()) {
+            val file = File(path)
+            if (file.exists()) {
+                val bitmap = BitmapFactory.decodeFile(path)
+                view.setImageBitmap(bitmap)
+                view.visibility = View.VISIBLE
+                return
+            }
+        }
+
+        view.setImageDrawable(null)
+        view.visibility = View.GONE
+    }
+}

+ 75 - 31
app/src/main/java/io/legato/kazusa/ui/config/ThemeConfigFragment.kt

@@ -58,10 +58,12 @@ class ThemeConfigFragment : PreferenceFragmentCompat(),
     SharedPreferences.OnSharedPreferenceChangeListener
     SharedPreferences.OnSharedPreferenceChangeListener
     //MenuProvider
     //MenuProvider
     {
     {
+        private val requestCodeBgLight = 121
+        private val requestCodeBgDark = 122
 
 
-    private val requestCodeBgLight = 121
-    private val requestCodeBgDark = 122
-    private val selectImage = registerForActivityResult(SelectImageContract()) {
+        private val requestCodeColorImage = 123
+
+        private val selectImage = registerForActivityResult(SelectImageContract()) {
         it.uri?.let { uri ->
         it.uri?.let { uri ->
             when (it.requestCode) {
             when (it.requestCode) {
                 requestCodeBgLight -> setBgFromUri(uri, PreferKey.bgImage) {
                 requestCodeBgLight -> setBgFromUri(uri, PreferKey.bgImage) {
@@ -71,6 +73,10 @@ class ThemeConfigFragment : PreferenceFragmentCompat(),
                 requestCodeBgDark -> setBgFromUri(uri, PreferKey.bgImageN) {
                 requestCodeBgDark -> setBgFromUri(uri, PreferKey.bgImageN) {
                     upTheme(true)
                     upTheme(true)
                 }
                 }
+
+                requestCodeColorImage -> setBgFromUri(uri, PreferKey.colorImage) {
+                    upPreferenceSummary(PreferKey.colorImage, getPrefString(PreferKey.colorImage))
+                }
             }
             }
         }
         }
     }
     }
@@ -78,8 +84,6 @@ class ThemeConfigFragment : PreferenceFragmentCompat(),
     override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
     override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
         addPreferencesFromResource(R.xml.pref_config_theme)
         addPreferencesFromResource(R.xml.pref_config_theme)
 
 
-        upPreferenceSummary(PreferKey.bgImage, getPrefString(PreferKey.bgImage))
-        upPreferenceSummary(PreferKey.bgImageN, getPrefString(PreferKey.bgImageN))
         upPreferenceSummary(PreferKey.fontScale)
         upPreferenceSummary(PreferKey.fontScale)
 
 
         findPreference<ColorPreference>(PreferKey.cBackground)?.let {
         findPreference<ColorPreference>(PreferKey.cBackground)?.let {
@@ -129,6 +133,18 @@ class ThemeConfigFragment : PreferenceFragmentCompat(),
             customMode?.isVisible = newValue == "11"
             customMode?.isVisible = newValue == "11"
             true
             true
         }
         }
+
+        val hasColorImage = !getPrefString(PreferKey.colorImage).isNullOrBlank()
+        colorPrimary?.isEnabled = !hasColorImage
+        if (hasColorImage)
+        {
+            upPreferenceSummary("colorPrimary", getString(R.string.seed_photo_alart))
+            upPreferenceSummary(PreferKey.colorImage, getString(R.string.click_to_delete))
+        }
+        if (!getPrefString(PreferKey.bgImage).isNullOrBlank())
+            upPreferenceSummary(PreferKey.bgImage, getString(R.string.click_to_delete))
+        if (!getPrefString(PreferKey.bgImageN).isNullOrBlank())
+            upPreferenceSummary(PreferKey.bgImageN, getString(R.string.click_to_delete))
     }
     }
 
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -200,6 +216,11 @@ class ThemeConfigFragment : PreferenceFragmentCompat(),
                 //recreateActivities()
                 //recreateActivities()
             }
             }
 
 
+            PreferKey.colorImage ->
+                Handler(Looper.getMainLooper()).postDelayed({
+                    requireContext().restart()
+                }, 100)
+
             PreferKey.bgImage,
             PreferKey.bgImage,
             PreferKey.bgImageN -> {
             PreferKey.bgImageN -> {
                 upPreferenceSummary(key, getPrefString(key))
                 upPreferenceSummary(key, getPrefString(key))
@@ -232,6 +253,8 @@ class ThemeConfigFragment : PreferenceFragmentCompat(),
 
 
             PreferKey.bgImage -> selectBgAction(false)
             PreferKey.bgImage -> selectBgAction(false)
             PreferKey.bgImageN -> selectBgAction(true)
             PreferKey.bgImageN -> selectBgAction(true)
+            "colorImage" -> selectBgAction(null)
+
             "themeList" -> ThemeListDialog().show(childFragmentManager, "themeList")
             "themeList" -> ThemeListDialog().show(childFragmentManager, "themeList")
             "saveDayTheme",
             "saveDayTheme",
             "saveNightTheme" -> alertSaveTheme(key)
             "saveNightTheme" -> alertSaveTheme(key)
@@ -267,39 +290,60 @@ class ThemeConfigFragment : PreferenceFragmentCompat(),
         }
         }
     }
     }
 
 
-    private fun selectBgAction(isNight: Boolean) {
-        val bgKey = if (isNight) PreferKey.bgImageN else PreferKey.bgImage
-        val blurringKey = if (isNight) PreferKey.bgImageNBlurring else PreferKey.bgImageBlurring
-        val actions = arrayListOf(
-            getString(R.string.background_image_blurring),
-            getString(R.string.select_image)
-        )
-        if (!getPrefString(bgKey).isNullOrEmpty()) {
-            actions.add(getString(R.string.delete))
-        }
-        context?.selector(items = actions) { _, i ->
-            when (i) {
-                0 -> alertImageBlurring(blurringKey) {
-                    upTheme(isNight)
-                }
+        private fun selectBgAction(isNight: Boolean?) {
+            val bgKey = when (isNight) {
+                true -> PreferKey.bgImageN
+                false -> PreferKey.bgImage
+                null -> PreferKey.colorImage
+            }
+            val blurringKey = when (isNight) {
+                true -> PreferKey.bgImageNBlurring
+                false -> PreferKey.bgImageBlurring
+                else -> null
+            }
+
+            val actions = mutableListOf<String>()
 
 
-                1 -> {
-                    if (isNight) {
-                        selectImage.launch(requestCodeBgDark)
-                    } else {
-                        selectImage.launch(requestCodeBgLight)
+            if (isNight != null) {
+                actions.add(getString(R.string.background_image_blurring))
+            }
+
+            actions.add(getString(R.string.select_image))
+
+            if (!getPrefString(bgKey).isNullOrEmpty()) {
+                actions.add(getString(R.string.delete))
+            }
+
+            context?.selector(items = actions) { _, i ->
+                when {
+                    isNight != null && i == 0 -> {
+                        alertImageBlurring(blurringKey!!) {
+                            upTheme(isNight)
+                        }
                     }
                     }
-                }
 
 
-                2 -> {
-                    removePref(bgKey)
-                    upTheme(isNight)
+                    (isNight == null && i == 0) || (isNight != null && i == 1) -> {
+                        when (isNight) {
+                            true -> selectImage.launch(requestCodeBgDark)
+                            false -> selectImage.launch(requestCodeBgLight)
+                            null -> selectImage.launch(requestCodeColorImage)
+                        }
+                    }
+
+                    (isNight == null && i == 1) || (isNight != null && i == 2) -> {
+                        removePref(bgKey)
+                        if (isNight != null) {
+                            upTheme(isNight)
+                        } else {
+                            upPreferenceSummary(PreferKey.colorImage, getPrefString(PreferKey.colorImage))
+                        }
+                    }
                 }
                 }
             }
             }
         }
         }
-    }
 
 
-    private fun alertImageBlurring(preferKey: String, success: () -> Unit) {
+
+        private fun alertImageBlurring(preferKey: String, success: () -> Unit) {
         alert(R.string.background_image_blurring) {
         alert(R.string.background_image_blurring) {
             val alertBinding = DialogImageBlurringBinding.inflate(layoutInflater).apply {
             val alertBinding = DialogImageBlurringBinding.inflate(layoutInflater).apply {
                 getPrefInt(preferKey, 0).let {
                 getPrefInt(preferKey, 0).let {

+ 11 - 3
app/src/main/res/layout/view_icon.xml

@@ -1,5 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="utf-8"?>
-<ImageView android:id="@+id/preview"
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="48dp"
     android:layout_width="48dp"
-    android:layout_height="48dp" />
+    android:layout_height="48dp"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:cardBackgroundColor="@android:color/transparent"
+    app:strokeWidth="0dp">
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/preview"
+        android:scaleType="centerCrop"/>
+</com.google.android.material.card.MaterialCardView>

+ 4 - 1
app/src/main/res/values-zh/strings.xml

@@ -1270,7 +1270,7 @@
     <string name="dark_mode">深色</string>
     <string name="dark_mode">深色</string>
     <string name="pure_black">纯黑深色模式</string>
     <string name="pure_black">纯黑深色模式</string>
     <string name="transparent_theme_alarm">透明主题请于设置背景图片后设置</string>
     <string name="transparent_theme_alarm">透明主题请于设置背景图片后设置</string>
-    <string name="seed_color_summary">使用种子颜色创建主题</string>
+    <string name="seed_color_summary">使用种子颜色生成主题颜色</string>
     <string name="seed_color">种子色</string>
     <string name="seed_color">种子色</string>
     <string name="custom_mode">自定义模式</string>
     <string name="custom_mode">自定义模式</string>
     <string name="be_swiped">仍可滑动切换页面</string>
     <string name="be_swiped">仍可滑动切换页面</string>
@@ -1293,4 +1293,7 @@
     <string name="add_as_new_book">新增书籍到书架</string>
     <string name="add_as_new_book">新增书籍到书架</string>
     <string name="quick_add_to_shelf">快速添加到书架</string>
     <string name="quick_add_to_shelf">快速添加到书架</string>
     <string name="book_added_to_shelf">书籍已添加到书架</string>
     <string name="book_added_to_shelf">书籍已添加到书架</string>
+    <string name="seed_photo_summary">使用图片生成主题颜色</string>
+    <string name="seed_photo_alart">若需使用种子颜色,请取消种子图片选择</string>
+    <string name="click_to_delete">点击以删除或更改</string>
 </resources>
 </resources>

+ 3 - 0
app/src/main/res/values/strings.xml

@@ -1294,4 +1294,7 @@
     <string name="add_as_new_book">新增书籍到书架</string>
     <string name="add_as_new_book">新增书籍到书架</string>
     <string name="quick_add_to_shelf">快速添加到书架</string>
     <string name="quick_add_to_shelf">快速添加到书架</string>
     <string name="book_added_to_shelf">书籍已添加到书架</string>
     <string name="book_added_to_shelf">书籍已添加到书架</string>
+    <string name="seed_photo_summary">使用图片生成主题颜色</string>
+    <string name="seed_photo_alart">若需使用种子颜色,请取消种子图片选择</string>
+    <string name="click_to_delete">Click to delete or change</string>
 </resources>
 </resources>

+ 7 - 2
app/src/main/res/xml/pref_config_theme.xml

@@ -37,6 +37,11 @@
             app:cpv_dialogType="preset"
             app:cpv_dialogType="preset"
             app:iconSpaceReserved="false" />
             app:iconSpaceReserved="false" />
 
 
+        <io.legato.kazusa.lib.prefs.ImagePreviewPreference
+            android:key="colorImage"
+            android:title="种子图片"
+            android:summary="@string/seed_photo_summary"/>
+
         <io.legato.kazusa.lib.prefs.NameListPreference
         <io.legato.kazusa.lib.prefs.NameListPreference
             android:defaultValue="global"
             android:defaultValue="global"
             android:key="customMode"
             android:key="customMode"
@@ -131,11 +136,11 @@
         app:iconSpaceReserved="false"
         app:iconSpaceReserved="false"
         app:layout="@layout/view_preference_category">
         app:layout="@layout/view_preference_category">
 
 
-        <io.legato.kazusa.lib.prefs.Preference
+        <io.legato.kazusa.lib.prefs.ImagePreviewPreference
             android:key="backgroundImage"
             android:key="backgroundImage"
             android:title="@string/light_mode" />
             android:title="@string/light_mode" />
 
 
-        <io.legato.kazusa.lib.prefs.Preference
+        <io.legato.kazusa.lib.prefs.ImagePreviewPreference
             android:key="backgroundImageNight"
             android:key="backgroundImageNight"
             android:title="@string/dark_mode" />
             android:title="@string/dark_mode" />