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