Skip to content

Commit

Permalink
[feature] Support change theme
Browse files Browse the repository at this point in the history
  • Loading branch information
SkyD666 committed Apr 4, 2024
1 parent ba46ce8 commit e8b7d36
Show file tree
Hide file tree
Showing 50 changed files with 1,348 additions and 84 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ android {
minSdk = 24
targetSdk = 34
versionCode = 10
versionName = "1.1-alpha08"
versionName = "1.1-beta01"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AniVu"
android:theme="@style/Theme.AniVu.Pink"
tools:targetApi="31">
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
Expand Down
5 changes: 3 additions & 2 deletions app/src/main/java/com/skyd/anivu/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.skyd.anivu
import android.app.Application
import android.content.Context
import com.google.android.material.color.DynamicColors
import com.skyd.anivu.model.preference.appearance.ThemePreference
import com.skyd.anivu.model.worker.deletearticle.listenerDeleteArticleFrequency
import com.skyd.anivu.model.worker.rsssync.listenerRssSyncFrequency
import com.skyd.anivu.util.CrashHandler
Expand All @@ -18,8 +19,8 @@ class App : Application() {

CrashHandler.init(this)

DynamicColors.applyToActivitiesIfAvailable(this)

// DynamicColors.applyToActivitiesIfAvailable(this)
// setTheme(ThemePreference.toResId(this))
listenerRssSyncFrequency(this)
listenerDeleteArticleFrequency(this)
}
Expand Down
10 changes: 8 additions & 2 deletions app/src/main/java/com/skyd/anivu/base/BaseActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.viewbinding.ViewBinding
import com.skyd.anivu.model.preference.appearance.ThemePreference

abstract class BaseActivity<T : ViewBinding> : AppCompatActivity() {
protected lateinit var binding: T
Expand All @@ -14,9 +15,10 @@ abstract class BaseActivity<T : ViewBinding> : AppCompatActivity() {
enableEdgeToEdge()
super.onCreate(savedInstanceState)

binding = getViewBinding()

initTheme()
beforeSetContentView()

binding = getViewBinding()
setContentView(binding.root)

binding.initView()
Expand All @@ -25,4 +27,8 @@ abstract class BaseActivity<T : ViewBinding> : AppCompatActivity() {
protected open fun T.initView() {}

protected open fun beforeSetContentView() {}

private fun initTheme() {
setTheme(ThemePreference.toResId(this))
}
}
6 changes: 6 additions & 0 deletions app/src/main/java/com/skyd/anivu/ext/AnimationExt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.skyd.anivu.ext

import android.view.animation.Animation

val Animation.isRunning: Boolean
get() = hasStarted() && !hasEnded()
10 changes: 0 additions & 10 deletions app/src/main/java/com/skyd/anivu/ext/ContextExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ import android.content.ContextWrapper
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.content.res.TypedArray
import android.graphics.Point
import android.os.Build
import android.util.TypedValue
import androidx.core.content.ContextCompat

val Context.activity: Activity
Expand Down Expand Up @@ -51,14 +49,6 @@ fun Context.screenWidth(includeVirtualKey: Boolean): Int {
return outPoint.x
}

fun Context.getAttrColor(attr: Int): Int {
val typedValue = TypedValue()
val typedArray: TypedArray = obtainStyledAttributes(typedValue.data, intArrayOf(attr))
val color = typedArray.getColor(0, 0)
typedArray.recycle()
return color
}

fun Context.getAppVersionName(): String {
var appVersionName = ""
try {
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/java/com/skyd/anivu/ext/NumberExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,6 @@ val Int.sp: Int
Resources.getSystem().displayMetrics
).toInt()

fun Float.toPercentage(): String = "%.2f%%".format(this * 100)
fun Float.toPercentage(): String = "%.2f%%".format(this * 100)

fun Float.toDegrees(): Float = (this * 180 / Math.PI).toFloat()
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.skyd.anivu.model.preference.appearance

import android.content.Context
import android.os.Build
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.stringPreferencesKey
import com.skyd.anivu.R
import com.skyd.anivu.base.BasePreference
import com.skyd.anivu.ext.dataStore
import com.skyd.anivu.ext.getOrDefault
import com.skyd.anivu.ext.put
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

object ThemePreference : BasePreference<String> {
private const val THEME = "theme"

const val DYNAMIC = "Dynamic"
const val PINK = "Pink"
const val GREEN = "Green"
const val BLUE = "Blue"
const val YELLOW = "Yellow"
const val PURPLE = "Purple"

val values: Array<String>
get() {
val v = arrayOf(PINK, GREEN, BLUE, YELLOW, PURPLE)
return if (supportDynamicTheme()) arrayOf(DYNAMIC, *v) else v
}

override val default = if (supportDynamicTheme()) DYNAMIC else PINK

val key = stringPreferencesKey(THEME)

fun put(
context: Context,
scope: CoroutineScope,
value: String,
onSuccess: (() -> Unit)? = null,
) {
scope.launch(Dispatchers.IO) {
context.dataStore.put(key, value)
withContext(Dispatchers.Main) {
onSuccess?.invoke()
}
}
}

override fun fromPreferences(preferences: Preferences): String = preferences[key] ?: default

private fun supportDynamicTheme(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S

fun toDisplayName(
context: Context,
value: String = context.dataStore.getOrDefault(this),
): String = when (value) {
DYNAMIC -> context.getString(R.string.theme_dynamic)
PINK -> context.getString(R.string.theme_pink)
GREEN -> context.getString(R.string.theme_green)
BLUE -> context.getString(R.string.theme_blue)
YELLOW -> context.getString(R.string.theme_yellow)
PURPLE -> context.getString(R.string.theme_purple)
else -> context.getString(R.string.unknown)
}

fun toResId(
context: Context,
value: String = context.dataStore.getOrDefault(this),
): Int = when (value) {
DYNAMIC -> R.style.Theme_AniVu_Dynamic
PINK -> R.style.Theme_AniVu_Pink
GREEN -> R.style.Theme_AniVu_Green
BLUE -> R.style.Theme_AniVu_Blue
YELLOW -> R.style.Theme_AniVu_Yellow
PURPLE -> R.style.Theme_AniVu_Purple
else -> R.style.Theme_AniVu_Pink
}
}
35 changes: 20 additions & 15 deletions app/src/main/java/com/skyd/anivu/ui/fragment/more/MoreFragment.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package com.skyd.anivu.ui.fragment.more

import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.content.res.AppCompatResources
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.color.MaterialColors
import com.skyd.anivu.R
import com.skyd.anivu.base.BaseFragment
import com.skyd.anivu.databinding.FragmentMoreBinding
import com.skyd.anivu.ext.addInsetsByPadding
import com.skyd.anivu.ext.findMainNavController
import com.skyd.anivu.ext.getAttrColor
import com.skyd.anivu.model.bean.MoreBean
import com.skyd.anivu.ui.adapter.decoration.AniVuItemDecoration
import com.skyd.anivu.ui.adapter.variety.AniSpanSize
Expand All @@ -22,23 +21,17 @@ import dagger.hilt.android.AndroidEntryPoint
class MoreFragment : BaseFragment<FragmentMoreBinding>() {
override val transitionProvider = nullTransitionProvider

private val adapter = VarietyAdapter(mutableListOf())

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

adapter.apply {
dataList += getMoreBeanList()
override fun FragmentMoreBinding.initView() {
val adapter = VarietyAdapter(mutableListOf()).apply {
dataList = getMoreBeanList()
addProxy(More1Proxy(onClick = {
val data = dataList[it]
if (data is MoreBean) {
findMainNavController().navigate(data.navigateId)
}
}))
}
}

override fun FragmentMoreBinding.initView() {
rvMoreFragment.layoutManager = GridLayoutManager(
requireContext(),
AniSpanSize.MAX_SPAN_SIZE
Expand All @@ -61,24 +54,36 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>() {
icon = AppCompatResources.getDrawable(
requireContext(), R.drawable.ic_settings_24
)!!,
iconTint = requireContext().getAttrColor(com.google.android.material.R.attr.colorOnPrimary),
iconTint = MaterialColors.getColor(
requireView(),
com.google.android.material.R.attr.colorOnPrimary
),
navigateId = R.id.action_to_settings_fragment,
background = AppCompatResources.getDrawable(
requireContext(), R.drawable.shape_curly_corner
)!!,
backgroundTint = requireContext().getAttrColor(com.google.android.material.R.attr.colorPrimary),
backgroundTint = MaterialColors.getColor(
requireView(),
com.google.android.material.R.attr.colorPrimary
),
),
MoreBean(
title = getString(R.string.about_fragment_name),
icon = AppCompatResources.getDrawable(
requireContext(), R.drawable.ic_info_24
)!!,
iconTint = requireContext().getAttrColor(com.google.android.material.R.attr.colorOnSecondary),
iconTint = MaterialColors.getColor(
requireView(),
com.google.android.material.R.attr.colorOnSecondary
),
navigateId = R.id.action_to_about_fragment,
background = AppCompatResources.getDrawable(
requireContext(), R.drawable.shape_clover
)!!,
backgroundTint = requireContext().getAttrColor(com.google.android.material.R.attr.colorSecondary),
backgroundTint = MaterialColors.getColor(
requireView(),
com.google.android.material.R.attr.colorSecondary
),
),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ class SettingsFragment : BasePreferenceFragmentCompat() {
rootKey: String?,
screen: PreferenceScreen
) {
Preference(this).apply {
key = "appearance"
title = getString(R.string.appearance_fragment_name)
summary = getString(R.string.appearance_fragment_description)
setIcon(R.drawable.ic_palette_24)
setOnPreferenceClickListener {
findMainNavController().navigate(R.id.action_to_appearance_fragment)
true
}
screen.addPreference(this)
}

Preference(this).apply {
key = "rssConfig"
title = getString(R.string.rss_config_fragment_name)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.skyd.anivu.ui.fragment.settings.appearance

import android.content.Context
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import androidx.preference.DropDownPreference
import androidx.preference.ListPreference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceScreen
import com.skyd.anivu.R
import com.skyd.anivu.base.BasePreferenceFragmentCompat
import com.skyd.anivu.ext.dataStore
import com.skyd.anivu.ext.getOrDefault
import com.skyd.anivu.model.preference.appearance.ThemePreference
import dagger.hilt.android.AndroidEntryPoint


@AndroidEntryPoint
class AppearanceFragment : BasePreferenceFragmentCompat() {
override val title by lazy { resources.getString(R.string.appearance_fragment_name) }
override fun Context.onAddPreferences(
savedInstanceState: Bundle?,
rootKey: String?,
screen: PreferenceScreen
) {
val themeCategory = PreferenceCategory(this).apply {
key = "themeCategory"
title = getString(R.string.appearance_fragment_theme_category)
screen.addPreference(this)
}

DropDownPreference(this).apply {
key = "theme"
title = getString(R.string.appearance_fragment_theme)
summaryProvider = ListPreference.SimpleSummaryProvider.getInstance()
value = context.dataStore.getOrDefault(ThemePreference)
entries = ThemePreference.values.map {
ThemePreference.toDisplayName(context, it)
}.toTypedArray()
entryValues = ThemePreference.values
setOnPreferenceChangeListener { _, newValue ->
ThemePreference.put(
requireContext(), lifecycleScope, newValue as String,
) {
requireActivity().recreate()
}
true
}
themeCategory.addPreference(this)
}
}
}
Loading

0 comments on commit e8b7d36

Please sign in to comment.