diff --git a/app/src/main/java/io/nekohasekai/sagernet/ktx/Utils.kt b/app/src/main/java/io/nekohasekai/sagernet/ktx/Utils.kt index 3e176c8ed..8c43f98b8 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ktx/Utils.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ktx/Utils.kt @@ -11,6 +11,7 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.content.res.Resources +import android.graphics.Color import android.os.Build import android.system.Os import android.system.OsConstants @@ -284,9 +285,22 @@ fun Context.getColour(@ColorRes colorRes: Int): Int { } fun Context.getColorAttr(@AttrRes resId: Int): Int { - return ContextCompat.getColor(this, TypedValue().also { - theme.resolveAttribute(resId, it, true) - }.resourceId) + val tv = TypedValue() + // resolveRefs = true follows ?attr chains (e.g. statusConnectingColor -> colorOnPrimary). + // The result is either a color-resource reference (resourceId != 0) or a literal color + // value (resourceId == 0); ContextCompat.getColor(0) would throw on the latter. + theme.resolveAttribute(resId, tv, true) + if (tv.resourceId != 0) { + return ContextCompat.getColor(this, tv.resourceId) + } + // No backing resource: the attr resolved directly to a literal value. Use it only + // when it is actually a color (e.g. ?attr/colorOnPrimary defined as a literal); + // otherwise fall back to a safe default rather than returning a garbage int. + return if (tv.type in TypedValue.TYPE_FIRST_COLOR_INT..TypedValue.TYPE_LAST_COLOR_INT) { + tv.data + } else { + Color.TRANSPARENT + } } val isExpert: Boolean by lazy { BuildConfig.DEBUG || DataStore.isExpert } diff --git a/app/src/main/java/io/nekohasekai/sagernet/widget/StatsBar.kt b/app/src/main/java/io/nekohasekai/sagernet/widget/StatsBar.kt index 821670db2..7cddcfc46 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/widget/StatsBar.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/widget/StatsBar.kt @@ -109,11 +109,13 @@ class StatsBar @JvmOverloads constructor( private fun setStatusColorByState(state: BaseService.State) { // Connected = statusConnectedColor (green), Stopped/Stopping = statusStoppedColor - // (red — "Shutting down…" reads as red), Connecting/other = colorOnPrimary. + // (red — "Shutting down…" reads as red), Connecting = statusConnectingColor (Dracula + // yellow; colorOnPrimary elsewhere), other = colorOnPrimary. // Non-Dracula themes default these attrs to colorOnPrimary, so no change. val attr = when (state) { BaseService.State.Connected -> R.attr.statusConnectedColor BaseService.State.Stopped, BaseService.State.Stopping -> R.attr.statusStoppedColor + BaseService.State.Connecting -> R.attr.statusConnectingColor else -> com.google.android.material.R.attr.colorOnPrimary } statusText.setTextColor(context.getColorAttr(attr)) diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index ff5dc33b4..e146ce488 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -32,6 +32,7 @@ @color/color_dracula_yellow @color/color_dracula_green @color/color_dracula_red + @color/color_dracula_yellow @color/color_dracula_red @color/color_dracula_cyan @color/color_dracula_cyan @@ -57,6 +58,7 @@ @color/color_dracula_yellow @color/color_dracula_green @color/color_dracula_red + @color/color_dracula_yellow @color/color_dracula_red @color/color_dracula_cyan @color/color_dracula_cyan diff --git a/app/src/main/res/values-v26/themes.xml b/app/src/main/res/values-v26/themes.xml index 6b1efb0c9..58a704e87 100644 --- a/app/src/main/res/values-v26/themes.xml +++ b/app/src/main/res/values-v26/themes.xml @@ -10,6 +10,7 @@ ?android:attr/textColorPrimary ?attr/colorOnPrimary ?attr/colorOnPrimary + ?attr/colorOnPrimary @color/material_red_500 ?attr/colorOnPrimary ?attr/colorOnPrimary diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index bda8ff5b5..f01246e2b 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -19,6 +19,9 @@ Dracula themes are unchanged; Dracula tints connected=green, stopped=red. --> + + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 021a3934a..f0e4e8c83 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -9,6 +9,7 @@ ?android:attr/textColorPrimary ?attr/colorOnPrimary ?attr/colorOnPrimary + ?attr/colorOnPrimary @color/material_red_500 ?attr/colorOnPrimary ?attr/colorOnPrimary @@ -81,6 +82,7 @@ ?android:attr/textColorPrimary ?attr/colorOnPrimary ?attr/colorOnPrimary + ?attr/colorOnPrimary @color/material_red_500 ?attr/colorOnPrimary ?attr/colorOnPrimary @@ -642,6 +644,7 @@ @color/color_dracula_yellow @color/color_dracula_green @color/color_dracula_red + @color/color_dracula_yellow @color/color_dracula_red @color/color_dracula_cyan @color/color_dracula_cyan @@ -689,6 +692,7 @@ @color/color_dracula_yellow @color/color_dracula_green @color/color_dracula_red + @color/color_dracula_yellow @color/color_dracula_red @color/color_dracula_cyan @color/color_dracula_cyan