diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 96db681..43c614b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -13,6 +13,42 @@ plugins { alias(libs.plugins.kotlin.serialization) alias(libs.plugins.ksp) alias(libs.plugins.nav.safeargs.kotlin) + alias(libs.plugins.naterialthemebuilder) +} + +materialThemeBuilder { + themes { + for ((name, color) in listOf( + "Red" to "F44336", + "Pink" to "E91E63", + "Purple" to "9C27B0", + "DeepPurple" to "673AB7", + "Indigo" to "3F51B5", + "Blue" to "2196F3", + "LightBlue" to "03A9F4", + "Cyan" to "00BCD4", + "Teal" to "009688", + "Green" to "4FAF50", + "LightGreen" to "8BC3A4", + "Lime" to "CDDC39", + "Yellow" to "FFEB3B", + "Amber" to "FFC107", + "Orange" to "FF9800", + "DeepOrange" to "FF5722", + "Brown" to "795548", + "BlueGrey" to "607D8F", + "Sakura" to "FF9CA8" + )) { + create("Material$name") { + lightThemeFormat = "ThemeOverlay.Light.%s" + darkThemeFormat = "ThemeOverlay.Dark.%s" + primaryColor = "#$color" + } + } + } + // Add Material Design 3 color tokens (such as palettePrimary100) in generated theme + // rikka.material >= 2.0.0 provides such attributes + generatePalette = false } val appPackageName: String by rootProject.extra @@ -55,9 +91,14 @@ afterEvaluate { val translatorJson = JSONObject(translatorsMap).toJSONString() val srcDir = android.sourceSets["main"].assets.srcDirs.first() - logger.lifecycle("Src dir: $srcDir") + logger.lifecycle("Asset dir: $srcDir") if (!srcDir.exists()) srcDir.mkdirs() File(srcDir, "translators.json").writeText(translatorJson) + } else { + val srcDir = android.sourceSets["main"].assets.srcDirs.first() + logger.lifecycle("Asset dir: $srcDir") + if (!srcDir.exists()) srcDir.mkdirs() + File(srcDir, "translators.json").writeText("{}") } } diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt index d6029c8..63d1ebf 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/fragment/SettingsFragment.kt @@ -7,6 +7,7 @@ import android.text.TextUtils import android.view.View import android.view.WindowInsets import androidx.appcompat.app.AppCompatDelegate +import androidx.core.net.toUri import androidx.fragment.app.Fragment import androidx.preference.ListPreference import androidx.preference.Preference @@ -14,8 +15,10 @@ import androidx.preference.PreferenceDataStore import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreferenceCompat import by.kirich1409.viewbindingdelegate.viewBinding +import com.google.android.material.color.DynamicColors import com.google.android.material.dialog.MaterialAlertDialogBuilder import icu.nullptr.hidemyapplist.common.CommonUtils +import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.hmaApp import icu.nullptr.hidemyapplist.service.ConfigManager import icu.nullptr.hidemyapplist.service.PrefManager @@ -236,6 +239,32 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen } } + findPreference("translation")?.let { + it.summary = getString(R.string.settings_translate_summary, getString(R.string.app_name)) + it.setOnPreferenceClickListener { + startActivity(Intent(Intent.ACTION_VIEW, Constants.TRANSLATE_URL.toUri())) + true + } + } + + findPreference("followSystemAccent")?.also { + it.isVisible = DynamicColors.isDynamicColorAvailable() + + it.setOnPreferenceChangeListener { _, _ -> + activity?.recreate() + true + } + } + + findPreference("themeColor")?.also { + if (!DynamicColors.isDynamicColorAvailable()) it.dependency = null + + it.setOnPreferenceChangeListener { _, _ -> + activity?.recreate() + true + } + } + findPreference("darkTheme")?.setOnPreferenceChangeListener { _, newValue -> val newMode = (newValue as String).toInt() if (PrefManager.darkTheme != newMode) { @@ -252,11 +281,6 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen configureDataIsolation() - findPreference("bypassRiskyPackageWarning")?.setOnPreferenceChangeListener { _, newValue -> - activity?.recreate() - true - } - findPreference("stopSystemService")?.setOnPreferenceClickListener { if (ServiceClient.serviceVersion != 0) { MaterialAlertDialogBuilder(requireContext()) diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/ThemeUtils.kt b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/ThemeUtils.kt index 302d9b4..56b49a5 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/ThemeUtils.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/ui/util/ThemeUtils.kt @@ -9,13 +9,60 @@ import androidx.annotation.ColorInt import androidx.annotation.ColorRes import androidx.annotation.StyleRes import androidx.fragment.app.Fragment +import com.google.android.material.color.DynamicColors import icu.nullptr.hidemyapplist.service.PrefManager import org.frknkrc44.hma_oss.R object ThemeUtils { + private val colorThemeMap = mapOf( + "SAKURA" to R.style.ThemeOverlay_Light_MaterialSakura, + "MATERIAL_RED" to R.style.ThemeOverlay_Light_MaterialRed, + "MATERIAL_PINK" to R.style.ThemeOverlay_Light_MaterialPink, + "MATERIAL_PURPLE" to R.style.ThemeOverlay_Light_MaterialPurple, + "MATERIAL_DEEP_PURPLE" to R.style.ThemeOverlay_Light_MaterialDeepPurple, + "MATERIAL_INDIGO" to R.style.ThemeOverlay_Light_MaterialIndigo, + "MATERIAL_BLUE" to R.style.ThemeOverlay_Light_MaterialBlue, + "MATERIAL_LIGHT_BLUE" to R.style.ThemeOverlay_Light_MaterialLightBlue, + "MATERIAL_CYAN" to R.style.ThemeOverlay_Light_MaterialCyan, + "MATERIAL_TEAL" to R.style.ThemeOverlay_Light_MaterialTeal, + "MATERIAL_GREEN" to R.style.ThemeOverlay_Light_MaterialGreen, + "MATERIAL_LIGHT_GREEN" to R.style.ThemeOverlay_Light_MaterialLightGreen, + "MATERIAL_LIME" to R.style.ThemeOverlay_Light_MaterialLime, + "MATERIAL_YELLOW" to R.style.ThemeOverlay_Light_MaterialYellow, + "MATERIAL_AMBER" to R.style.ThemeOverlay_Light_MaterialAmber, + "MATERIAL_ORANGE" to R.style.ThemeOverlay_Light_MaterialOrange, + "MATERIAL_DEEP_ORANGE" to R.style.ThemeOverlay_Light_MaterialDeepOrange, + "MATERIAL_BROWN" to R.style.ThemeOverlay_Light_MaterialBrown, + "MATERIAL_BLUE_GREY" to R.style.ThemeOverlay_Light_MaterialBlueGrey + ) + + private val darkColorThemeMap = mapOf( + "SAKURA" to R.style.ThemeOverlay_Dark_MaterialSakura, + "MATERIAL_RED" to R.style.ThemeOverlay_Dark_MaterialRed, + "MATERIAL_PINK" to R.style.ThemeOverlay_Dark_MaterialPink, + "MATERIAL_PURPLE" to R.style.ThemeOverlay_Dark_MaterialPurple, + "MATERIAL_DEEP_PURPLE" to R.style.ThemeOverlay_Dark_MaterialDeepPurple, + "MATERIAL_INDIGO" to R.style.ThemeOverlay_Dark_MaterialIndigo, + "MATERIAL_BLUE" to R.style.ThemeOverlay_Dark_MaterialBlue, + "MATERIAL_LIGHT_BLUE" to R.style.ThemeOverlay_Dark_MaterialLightBlue, + "MATERIAL_CYAN" to R.style.ThemeOverlay_Dark_MaterialCyan, + "MATERIAL_TEAL" to R.style.ThemeOverlay_Dark_MaterialTeal, + "MATERIAL_GREEN" to R.style.ThemeOverlay_Dark_MaterialGreen, + "MATERIAL_LIGHT_GREEN" to R.style.ThemeOverlay_Dark_MaterialLightGreen, + "MATERIAL_LIME" to R.style.ThemeOverlay_Dark_MaterialLime, + "MATERIAL_YELLOW" to R.style.ThemeOverlay_Dark_MaterialYellow, + "MATERIAL_AMBER" to R.style.ThemeOverlay_Dark_MaterialAmber, + "MATERIAL_ORANGE" to R.style.ThemeOverlay_Dark_MaterialOrange, + "MATERIAL_DEEP_ORANGE" to R.style.ThemeOverlay_Dark_MaterialDeepOrange, + "MATERIAL_BROWN" to R.style.ThemeOverlay_Dark_MaterialBrown, + "MATERIAL_BLUE_GREY" to R.style.ThemeOverlay_Dark_MaterialBlueGrey + ) + private const val THEME_DEFAULT = "DEFAULT" private const val THEME_BLACK = "BLACK" + val isSystemAccent get() = DynamicColors.isDynamicColorAvailable() && PrefManager.followSystemAccent + fun isNightMode(context: Context) = (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES fun isUsingBlackTheme(context: Context) = PrefManager.blackDarkTheme && isNightMode(context) @@ -31,6 +78,17 @@ object ThemeUtils { R.style.ThemeOverlay_Black else R.style.ThemeOverlay } + val colorTheme get() = if (isSystemAccent) "SYSTEM" else PrefManager.themeColor + + @StyleRes + fun getColorThemeStyleRes(context: Context): Int { + return if (isNightMode(context)) { + darkColorThemeMap[colorTheme] ?: R.style.ThemeOverlay_Dark_MaterialBlue + } else { + colorThemeMap[colorTheme] ?: R.style.ThemeOverlay_Light_MaterialBlue + } + } + /** * Retrieve a color from the current [android.content.res.Resources.Theme]. */ diff --git a/app/src/main/java/icu/nullptr/hidemyapplist/util/ConfigUtils.kt b/app/src/main/java/icu/nullptr/hidemyapplist/util/ConfigUtils.kt index e6b07c3..4fe3317 100644 --- a/app/src/main/java/icu/nullptr/hidemyapplist/util/ConfigUtils.kt +++ b/app/src/main/java/icu/nullptr/hidemyapplist/util/ConfigUtils.kt @@ -1,14 +1,17 @@ package icu.nullptr.hidemyapplist.util +import android.content.res.Resources import icu.nullptr.hidemyapplist.service.PrefManager import java.util.Locale class ConfigUtils private constructor() { companion object { + fun getSystemLocale(): Locale = Resources.getSystem().configuration.getLocales().get(0) + fun getLocale(): Locale { val tag = PrefManager.locale - return if (tag == "SYSTEM") Locale.getDefault() + return if (tag == "SYSTEM") getSystemLocale() else Locale.forLanguageTag(tag) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/activity/AboutActivity.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/activity/AboutActivity.kt index bb9244f..31aac66 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/activity/AboutActivity.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/activity/AboutActivity.kt @@ -1,24 +1,16 @@ package org.frknkrc44.hma_oss.ui.activity -import android.content.Context import android.content.Intent import android.content.res.ColorStateList -import android.content.res.Resources import android.os.Build import android.os.Bundle import android.view.View import android.view.WindowInsets import android.widget.LinearLayout -import androidx.activity.enableEdgeToEdge import androidx.annotation.DrawableRes -import androidx.appcompat.app.AppCompatActivity import androidx.core.net.toUri import com.bumptech.glide.Glide -import com.google.android.material.color.DynamicColors -import icu.nullptr.hidemyapplist.hmaApp -import icu.nullptr.hidemyapplist.ui.util.ThemeUtils import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.homeItemBackgroundColor -import icu.nullptr.hidemyapplist.util.ConfigUtils.Companion.getLocale import org.frknkrc44.hma_oss.R import org.frknkrc44.hma_oss.common.BuildConfig import org.frknkrc44.hma_oss.databinding.ActivityAboutBinding @@ -26,7 +18,7 @@ import org.frknkrc44.hma_oss.databinding.ActivityAboutListItemBinding import org.json.JSONObject @Suppress("deprecation") -class AboutActivity : AppCompatActivity() { +class AboutActivity : BaseActivity() { private lateinit var binding: ActivityAboutBinding override fun onCreate(savedInstanceState: Bundle?) { @@ -34,10 +26,6 @@ class AboutActivity : AppCompatActivity() { binding = ActivityAboutBinding.inflate(layoutInflater) setContentView(binding.root) - DynamicColors.applyToActivityIfAvailable(this) - - enableEdgeToEdge() - binding.root.setOnApplyWindowInsetsListener { v, insets -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { val barInsets = insets.getInsets(WindowInsets.Type.systemBars()) @@ -72,7 +60,11 @@ class AboutActivity : AppCompatActivity() { backgroundTintList = tint } - appIcon.setImageResource(R.mipmap.ic_launcher_round) + Glide.with(this@AboutActivity) + .load(R.mipmap.ic_launcher_round) + .circleCrop() + .into(appIcon) + appName.setText(R.string.app_name) appVersion.text = BuildConfig.APP_VERSION_NAME @@ -127,14 +119,10 @@ class AboutActivity : AppCompatActivity() { val newLayout = ActivityAboutListItemBinding.inflate(layoutInflater) setOnClickUrl(newLayout.root, url) - newLayout.aboutPersonIcon.setImageResource(avatarResId) - - with(newLayout.aboutPersonIcon) { - shapeAppearanceModel = shapeAppearanceModel - .toBuilder() - .setAllCornerSizes { 48.0f } - .build() - } + Glide.with(this) + .load(avatarResId) + .circleCrop() + .into(newLayout.aboutPersonIcon) newLayout.text1.text = name newLayout.text2.text = desc @@ -146,15 +134,9 @@ class AboutActivity : AppCompatActivity() { Glide.with(this) .load(avatarUrl) .placeholder(R.drawable.outline_info_24) + .circleCrop() .into(newLayout.aboutPersonIcon) - with(newLayout.aboutPersonIcon) { - shapeAppearanceModel = shapeAppearanceModel - .toBuilder() - .setAllCornerSizes { 48.0f } - .build() - } - newLayout.text1.text = name newLayout.text2.visibility = View.GONE layout.addView(newLayout.root) @@ -167,20 +149,4 @@ class AboutActivity : AppCompatActivity() { startActivity(intent) } } - - override fun onApplyThemeResource(theme: Resources.Theme, resid: Int, first: Boolean) { - super.onApplyThemeResource(theme, resid, first) - theme.applyStyle(ThemeUtils.getNightThemeStyleRes(this), true) - } - - override fun attachBaseContext(newBase: Context?) { - super.attachBaseContext(getLocaleAppliedContext(newBase)) - } - - fun getLocaleAppliedContext(context: Context?): Context? { - val config = hmaApp.resources.configuration - config.setLocale(getLocale()) - - return context?.createConfigurationContext(config) - } } \ No newline at end of file diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/activity/BaseActivity.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/activity/BaseActivity.kt new file mode 100644 index 0000000..1375a2d --- /dev/null +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/activity/BaseActivity.kt @@ -0,0 +1,48 @@ +package org.frknkrc44.hma_oss.ui.activity + +import android.content.Context +import android.content.res.Resources +import android.os.Bundle +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.color.DynamicColors +import com.google.android.material.color.DynamicColorsOptions +import icu.nullptr.hidemyapplist.hmaApp +import icu.nullptr.hidemyapplist.ui.util.ThemeUtils +import icu.nullptr.hidemyapplist.util.ConfigUtils.Companion.getLocale + +open class BaseActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + enableEdgeToEdge() + + DynamicColors.applyToActivityIfAvailable( + this, + DynamicColorsOptions.Builder().also { + if (!ThemeUtils.isSystemAccent) + it.setThemeOverlay(ThemeUtils.getColorThemeStyleRes(this)) + }.build() + ) + } + + override fun onApplyThemeResource(theme: Resources.Theme, resid: Int, first: Boolean) { + super.onApplyThemeResource(theme, resid, first) + if (!DynamicColors.isDynamicColorAvailable()) { + theme.applyStyle(ThemeUtils.getColorThemeStyleRes(this), true) + } + + theme.applyStyle(ThemeUtils.getNightThemeStyleRes(this), true) + } + + override fun attachBaseContext(newBase: Context?) { + super.attachBaseContext(getLocaleAppliedContext(newBase)) + } + + fun getLocaleAppliedContext(context: Context?): Context? { + val config = hmaApp.resources.configuration + config.setLocale(getLocale()) + + return context?.createConfigurationContext(config) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/frknkrc44/hma_oss/ui/activity/MainActivity.kt b/app/src/main/java/org/frknkrc44/hma_oss/ui/activity/MainActivity.kt index 957e35b..621a95f 100644 --- a/app/src/main/java/org/frknkrc44/hma_oss/ui/activity/MainActivity.kt +++ b/app/src/main/java/org/frknkrc44/hma_oss/ui/activity/MainActivity.kt @@ -1,48 +1,20 @@ package org.frknkrc44.hma_oss.ui.activity -import android.content.Context -import android.content.res.Resources import android.os.Bundle -import androidx.activity.enableEdgeToEdge -import androidx.appcompat.app.AppCompatActivity import androidx.navigation.findNavController -import com.google.android.material.color.DynamicColors -import icu.nullptr.hidemyapplist.hmaApp -import icu.nullptr.hidemyapplist.ui.util.ThemeUtils -import icu.nullptr.hidemyapplist.util.ConfigUtils.Companion.getLocale import org.frknkrc44.hma_oss.R import org.frknkrc44.hma_oss.databinding.ActivityMainBinding -class MainActivity : AppCompatActivity() { +class MainActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - enableEdgeToEdge() - val binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) - - DynamicColors.applyToActivityIfAvailable(this) - } - - override fun onApplyThemeResource(theme: Resources.Theme, resid: Int, first: Boolean) { - super.onApplyThemeResource(theme, resid, first) - theme.applyStyle(ThemeUtils.getNightThemeStyleRes(this), true) } override fun onSupportNavigateUp(): Boolean { val navController = this.findNavController(R.id.nav_host_fragment) return navController.navigateUp() || super.onSupportNavigateUp() } - - override fun attachBaseContext(newBase: Context?) { - super.attachBaseContext(getLocaleAppliedContext(newBase)) - } - - fun getLocaleAppliedContext(context: Context?): Context? { - val config = hmaApp.resources.configuration - config.setLocale(getLocale()) - - return context?.createConfigurationContext(config) - } } \ No newline at end of file diff --git a/app/src/main/res/drawable/about_content_bg.xml b/app/src/main/res/drawable/about_content_bg.xml index 5eba749..81dc93c 100644 --- a/app/src/main/res/drawable/about_content_bg.xml +++ b/app/src/main/res/drawable/about_content_bg.xml @@ -3,9 +3,5 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> - + diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index ab814fe..c396671 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -37,6 +37,8 @@ @@ -51,6 +53,8 @@ diff --git a/app/src/main/res/layout/activity_about_header.xml b/app/src/main/res/layout/activity_about_header.xml index 438d74a..33f4485 100644 --- a/app/src/main/res/layout/activity_about_header.xml +++ b/app/src/main/res/layout/activity_about_header.xml @@ -74,14 +74,14 @@ diff --git a/app/src/main/res/layout/activity_about_list_item.xml b/app/src/main/res/layout/activity_about_list_item.xml index ff8d0f2..7c33c2b 100644 --- a/app/src/main/res/layout/activity_about_list_item.xml +++ b/app/src/main/res/layout/activity_about_list_item.xml @@ -7,10 +7,11 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - + android:layout_height="48dp" + android:importantForAccessibility="no" /> diff --git a/app/src/main/res/layout/activity_about_text_section.xml b/app/src/main/res/layout/activity_about_text_section.xml index 1fbd32e..1a125da 100644 --- a/app/src/main/res/layout/activity_about_text_section.xml +++ b/app/src/main/res/layout/activity_about_text_section.xml @@ -6,6 +6,8 @@ diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 6915f4d..0f4b38c 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -74,8 +74,7 @@ diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index af421f8..9430a45 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -32,11 +32,6 @@ -