Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Unreleased

- Adds a Portable Chrome Nova theme matching the Polaris dim Moonlight-grey early-2000s silver palette, including settings/theme-picker entries and restrained Compose library surfaces.

## 1.1.3 - 2026-06-12

Nova 1.1.3 is the public APK publishing patch for the 1.1.2 confidence build. It preserves the same handheld Library, Command Center, NovaHUD, Insert-key, stale-session recovery, input, crash, and dependency hardening work from 1.1.2, while bumping the Android package version so GitHub Releases / Obtainium installs can update cleanly.
Expand Down
19 changes: 17 additions & 2 deletions app/src/main/java/com/papi/nova/ui/NovaThemeManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ object NovaThemeManager {
const val THEME_POLARIS = "polaris"
const val THEME_OLED = "oled"
const val THEME_MIAMI = "miami"
const val THEME_PORTABLE_CHROME = "portable_chrome"
const val THEME_HIGH_CONTRAST = "high_contrast"
const val THEME_MATERIAL_YOU = "material_you"

Expand All @@ -34,6 +35,8 @@ object NovaThemeManager {
theme == THEME_OLED -> activity.setTheme(R.style.AppTheme_OLED)
theme == THEME_MIAMI && isSettings -> activity.setTheme(R.style.SettingsTheme_Miami)
theme == THEME_MIAMI -> activity.setTheme(R.style.AppTheme_Miami)
theme == THEME_PORTABLE_CHROME && isSettings -> activity.setTheme(R.style.SettingsTheme_PortableChrome)
theme == THEME_PORTABLE_CHROME -> activity.setTheme(R.style.AppTheme_PortableChrome)
theme == THEME_HIGH_CONTRAST && isSettings -> activity.setTheme(R.style.SettingsTheme_HighContrast)
theme == THEME_HIGH_CONTRAST -> activity.setTheme(R.style.AppTheme_HighContrast)
theme == THEME_MATERIAL_YOU && isSettings -> activity.setTheme(R.style.SettingsTheme_MaterialYou)
Expand Down Expand Up @@ -70,7 +73,7 @@ object NovaThemeManager {

private fun normalizeTheme(theme: String?): String {
return when (theme) {
THEME_POLARIS, THEME_OLED, THEME_MIAMI, THEME_HIGH_CONTRAST, THEME_MATERIAL_YOU -> theme
THEME_POLARIS, THEME_OLED, THEME_MIAMI, THEME_PORTABLE_CHROME, THEME_HIGH_CONTRAST, THEME_MATERIAL_YOU -> theme
else -> THEME_POLARIS
}
}
Expand All @@ -86,14 +89,16 @@ object NovaThemeManager {

fun isOled(context: Context): Boolean = getTheme(context) == THEME_OLED
fun isMiami(context: Context): Boolean = getTheme(context) == THEME_MIAMI
fun isPortableChrome(context: Context): Boolean = getTheme(context) == THEME_PORTABLE_CHROME
fun isHighContrast(context: Context): Boolean = getTheme(context) == THEME_HIGH_CONTRAST
fun isMaterialYou(context: Context): Boolean = getTheme(context) == THEME_MATERIAL_YOU

fun cycleTheme(context: Context): String {
val next = when (getTheme(context)) {
THEME_POLARIS -> THEME_OLED
THEME_OLED -> THEME_MIAMI
THEME_MIAMI -> THEME_HIGH_CONTRAST
THEME_MIAMI -> THEME_PORTABLE_CHROME
THEME_PORTABLE_CHROME -> THEME_HIGH_CONTRAST
THEME_HIGH_CONTRAST -> if (isMaterialYouAvailable()) THEME_MATERIAL_YOU else THEME_POLARIS
THEME_MATERIAL_YOU -> THEME_POLARIS
else -> THEME_POLARIS
Expand All @@ -106,6 +111,7 @@ object NovaThemeManager {
return when (theme) {
THEME_OLED -> context.getString(R.string.nova_theme_oled_label)
THEME_MIAMI -> context.getString(R.string.nova_theme_miami_label)
THEME_PORTABLE_CHROME -> context.getString(R.string.nova_theme_portable_chrome_label)
THEME_HIGH_CONTRAST -> context.getString(R.string.nova_theme_high_contrast_label)
THEME_MATERIAL_YOU -> context.getString(R.string.nova_theme_material_you_label)
else -> context.getString(R.string.nova_theme_polaris_label)
Expand All @@ -130,6 +136,7 @@ object NovaThemeManager {
return when {
isOled(context) -> Color.BLACK
isMiami(context) -> ContextCompat.getColor(context, R.color.nova_miami_bg_window)
isPortableChrome(context) -> ContextCompat.getColor(context, R.color.nova_portable_bg_window)
isHighContrast(context) -> ContextCompat.getColor(context, R.color.nova_hc_bg_window)
isMaterialYou(context) && isMaterialYouAvailable() ->
resolveThemeColor(context, android.R.attr.colorBackground, ContextCompat.getColor(context, R.color.nova_bg_window))
Expand Down Expand Up @@ -160,6 +167,7 @@ object NovaThemeManager {
return when {
isOled(context) -> ContextCompat.getColor(context, R.color.nova_oled_bg_card)
isMiami(context) -> ContextCompat.getColor(context, R.color.nova_miami_bg_card)
isPortableChrome(context) -> ContextCompat.getColor(context, R.color.nova_portable_bg_card)
isHighContrast(context) -> ContextCompat.getColor(context, R.color.nova_hc_bg_card)
isMaterialYou(context) && isMaterialYouAvailable() ->
resolveThemeColor(context, com.google.android.material.R.attr.colorSurface, ContextCompat.getColor(context, R.color.nova_bg_card))
Expand All @@ -172,6 +180,7 @@ object NovaThemeManager {
return when {
isOled(context) -> ContextCompat.getColor(context, R.color.nova_oled_dialog_bg)
isMiami(context) -> ContextCompat.getColor(context, R.color.nova_miami_dialog_bg)
isPortableChrome(context) -> ContextCompat.getColor(context, R.color.nova_portable_dialog_bg)
isHighContrast(context) -> ContextCompat.getColor(context, R.color.nova_hc_dialog_bg)
isMaterialYou(context) && isMaterialYouAvailable() ->
resolveThemeColor(context, com.google.android.material.R.attr.colorSurface, ContextCompat.getColor(context, R.color.nova_dialog_bg))
Expand All @@ -196,6 +205,7 @@ object NovaThemeManager {
return when {
isOled(context) -> ContextCompat.getColor(context, R.color.nova_oled_accent)
isMiami(context) -> ContextCompat.getColor(context, R.color.nova_miami_accent)
isPortableChrome(context) -> ContextCompat.getColor(context, R.color.nova_portable_accent)
isHighContrast(context) -> ContextCompat.getColor(context, R.color.nova_hc_accent)
else -> ContextCompat.getColor(context, R.color.nova_accent)
}
Expand All @@ -206,6 +216,7 @@ object NovaThemeManager {
return when {
isOled(context) -> ContextCompat.getColor(context, R.color.nova_oled_accent_surface)
isMiami(context) -> ContextCompat.getColor(context, R.color.nova_miami_accent_surface)
isPortableChrome(context) -> ContextCompat.getColor(context, R.color.nova_portable_accent_surface)
isHighContrast(context) -> ContextCompat.getColor(context, R.color.nova_hc_accent_surface)
else -> ContextCompat.getColor(context, R.color.nova_accent_surface)
}
Expand All @@ -216,6 +227,7 @@ object NovaThemeManager {
return when {
isOled(context) -> ContextCompat.getColor(context, R.color.nova_oled_divider)
isMiami(context) -> ContextCompat.getColor(context, R.color.nova_miami_divider)
isPortableChrome(context) -> ContextCompat.getColor(context, R.color.nova_portable_divider)
isHighContrast(context) -> ContextCompat.getColor(context, R.color.nova_hc_divider)
isMaterialYou(context) && isMaterialYouAvailable() ->
resolveThemeColor(context, com.google.android.material.R.attr.colorOutline, ContextCompat.getColor(context, R.color.nova_divider))
Expand All @@ -228,6 +240,7 @@ object NovaThemeManager {
return when {
isOled(context) -> ContextCompat.getColor(context, R.color.nova_oled_text_primary)
isMiami(context) -> ContextCompat.getColor(context, R.color.nova_miami_text_primary)
isPortableChrome(context) -> ContextCompat.getColor(context, R.color.nova_portable_text_primary)
isHighContrast(context) -> ContextCompat.getColor(context, R.color.nova_hc_text_primary)
isMaterialYou(context) && isMaterialYouAvailable() ->
resolveThemeColor(context, android.R.attr.textColorPrimary, ContextCompat.getColor(context, R.color.nova_text_primary))
Expand All @@ -240,6 +253,7 @@ object NovaThemeManager {
return when {
isOled(context) -> ContextCompat.getColor(context, R.color.nova_oled_text_secondary)
isMiami(context) -> ContextCompat.getColor(context, R.color.nova_miami_text_secondary)
isPortableChrome(context) -> ContextCompat.getColor(context, R.color.nova_portable_text_secondary)
isHighContrast(context) -> ContextCompat.getColor(context, R.color.nova_hc_text_secondary)
isMaterialYou(context) && isMaterialYouAvailable() ->
resolveThemeColor(context, android.R.attr.textColorSecondary, ContextCompat.getColor(context, R.color.nova_text_secondary))
Expand All @@ -252,6 +266,7 @@ object NovaThemeManager {
return when {
isOled(context) -> ContextCompat.getColor(context, R.color.nova_oled_text_muted)
isMiami(context) -> ContextCompat.getColor(context, R.color.nova_miami_text_muted)
isPortableChrome(context) -> ContextCompat.getColor(context, R.color.nova_portable_text_muted)
isHighContrast(context) -> ContextCompat.getColor(context, R.color.nova_hc_text_muted)
isMaterialYou(context) && isMaterialYouAvailable() ->
resolveThemeColor(context, android.R.attr.textColorSecondary, ContextCompat.getColor(context, R.color.nova_text_muted))
Expand Down
19 changes: 18 additions & 1 deletion app/src/main/java/com/papi/nova/ui/compose/NovaComposeTheme.kt
Original file line number Diff line number Diff line change
Expand Up @@ -77,66 +77,76 @@ val LocalNovaLibrarySurfaces = staticCompositionLocalOf {
fun NovaComposeColors.librarySurfaces(theme: String): NovaLibrarySurfaces {
val isOled = theme == NovaThemeManager.THEME_OLED
val isMiami = theme == NovaThemeManager.THEME_MIAMI
val isPortableChrome = theme == NovaThemeManager.THEME_PORTABLE_CHROME
val isHighContrast = theme == NovaThemeManager.THEME_HIGH_CONTRAST
val isMaterialYou = theme == NovaThemeManager.THEME_MATERIAL_YOU
return NovaLibrarySurfaces(
backgroundScrim = when {
isOled -> Color.Transparent
isMiami -> window.copy(alpha = 0.60f)
isPortableChrome -> Color.Black.copy(alpha = 0.20f)
isHighContrast -> Color.Black.copy(alpha = 0.72f)
isMaterialYou -> window.copy(alpha = 0.28f)
else -> window.copy(alpha = 0.56f)
},
panel = when {
isOled -> dialog.copy(alpha = 0.88f)
isMiami -> dialog.copy(alpha = 0.82f)
isPortableChrome -> dialog.copy(alpha = 0.90f)
isHighContrast -> dialog.copy(alpha = 0.96f)
isMaterialYou -> card.copy(alpha = 0.76f)
else -> dialog.copy(alpha = 0.64f)
},
panelBorder = when {
isOled -> divider.copy(alpha = 0.78f)
isMiami -> accent.copy(alpha = 0.18f)
isPortableChrome -> divider.copy(alpha = 0.62f)
isHighContrast -> divider.copy(alpha = 0.92f)
isMaterialYou -> divider.copy(alpha = 0.46f)
else -> divider.copy(alpha = 0.44f)
},
tile = when {
isOled -> card.copy(alpha = 0.90f)
isMiami -> card.copy(alpha = 0.82f)
isPortableChrome -> card.copy(alpha = 0.88f)
isHighContrast -> card.copy(alpha = 0.98f)
isMaterialYou -> card.copy(alpha = 0.78f)
else -> card.copy(alpha = 0.74f)
},
tileBorder = when {
isOled -> divider.copy(alpha = 0.78f)
isMiami -> divider.copy(alpha = 0.58f)
isPortableChrome -> divider.copy(alpha = 0.62f)
isHighContrast -> divider.copy(alpha = 0.90f)
else -> divider.copy(alpha = 0.50f)
},
control = when {
isOled -> card.copy(alpha = 0.78f)
isMiami -> card.copy(alpha = 0.76f)
isPortableChrome -> card.copy(alpha = 0.84f)
isHighContrast -> card.copy(alpha = 1f)
isMaterialYou -> card.copy(alpha = 0.70f)
else -> card.copy(alpha = 0.72f)
},
selectedControl = accent.copy(alpha = when {
isHighContrast -> 0.34f
isMiami -> 0.22f
isPortableChrome -> 0.20f
isOled -> 0.22f
else -> 0.18f
}),
focusRing = accent,
focusHalo = accent.copy(alpha = when {
isHighContrast -> 0.36f
isMiami -> 0.28f
isPortableChrome -> 0.20f
isOled -> 0.24f
else -> 0.18f
}),
mediaPlaceholder = when {
isOled -> Color(0xFF08080C)
isMiami -> Color(0xFF2C1734)
isPortableChrome -> Color(0xFFB8C1CC)
isHighContrast -> Color(0xFF111827)
isMaterialYou -> card.copy(alpha = 1f)
else -> divider.copy(alpha = 1f)
Expand All @@ -152,19 +162,22 @@ fun NovaComposeColors.librarySurfaces(theme: String): NovaLibrarySurfaces {
focusedArtworkAlpha = when {
isOled -> 0.10f
isMiami -> 0.26f
isPortableChrome -> 0.16f
isMaterialYou -> 0.18f
else -> 0.24f
},
focusedArtworkScrim = Color.Black.copy(alpha = when {
isOled -> 0.82f
isMiami -> 0.76f
isPortableChrome -> 0.64f
else -> 0.72f
}),
particlesEnabled = !isOled,
particleAlpha = when {
isOled -> 0f
isHighContrast -> 0.28f
isMiami -> 0.68f
isPortableChrome -> 0.32f
isMaterialYou -> 0.42f
else -> 1f
}
Expand All @@ -190,7 +203,11 @@ fun NovaComposeTheme(content: @Composable () -> Unit) {
onAccent = Color(
ContextCompat.getColor(
context,
if (theme == NovaThemeManager.THEME_MIAMI) R.color.nova_miami_void else R.color.nova_ice
when (theme) {
NovaThemeManager.THEME_MIAMI -> R.color.nova_miami_void
NovaThemeManager.THEME_PORTABLE_CHROME -> R.color.nova_portable_on_accent
else -> R.color.nova_ice
}
)
)
)
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/values-v31/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,10 @@
<item name="android:windowSplashScreenBackground">@color/nova_miami_bg_window</item>
<item name="android:windowSplashScreenIconBackgroundColor">@color/nova_miami_bg_window</item>
</style>
<style name="AppTheme.PortableChrome">
<item name="android:colorBackground">@color/nova_portable_bg_window</item>
<item name="android:windowBackground">@color/nova_portable_bg_window</item>
<item name="android:windowSplashScreenBackground">@color/nova_portable_bg_window</item>
<item name="android:windowSplashScreenIconBackgroundColor">@color/nova_portable_bg_window</item>
</style>
</resources>
2 changes: 2 additions & 0 deletions app/src/main/res/values/arrays.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
<item>Polaris Aurora</item>
<item>Console OLED</item>
<item>Miami Nebula</item>
<item>Portable Chrome</item>
<item>High Contrast</item>
<item>Material You</item>
</string-array>
<string-array name="nova_theme_values">
<item>polaris</item>
<item>oled</item>
<item>miami</item>
<item>portable_chrome</item>
<item>high_contrast</item>
<item>material_you</item>
</string-array>
Expand Down
26 changes: 26 additions & 0 deletions app/src/main/res/values/colors_nova.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,32 @@
<color name="nova_miami_accent_glow">#73FF5CAB</color>
<color name="nova_miami_ripple">#22FF5CAB</color>

<!-- Portable Chrome - Moonlight-grey early-2000s silver with restrained status accents. -->
<color name="nova_portable_void">#FF98A6B5</color>
<color name="nova_portable_deep">#FFB8C1CC</color>
<color name="nova_portable_twilight">#FFA7B2BE</color>
<color name="nova_portable_storm">#FF7F8C9A</color>
<color name="nova_portable_silver">#FFD6DDE5</color>
<color name="nova_portable_ice">#FFEAF0F5</color>
<color name="nova_portable_bg_primary">#FFB8C1CC</color>
<color name="nova_portable_bg_window">#FFB8C1CC</color>
<color name="nova_portable_bg_card">#E6D6DDE5</color>
<color name="nova_portable_bg_elevated">#FFE0E6EC</color>
<color name="nova_portable_bg_input">#FFC8D1DC</color>
<color name="nova_portable_dialog_bg">#FFD6DDE5</color>
<color name="nova_portable_context_bg">#FFC7D1DD</color>
<color name="nova_portable_divider">#FF7F8C9A</color>
<color name="nova_portable_text_primary">#FF25313D</color>
<color name="nova_portable_text_secondary">#FF4F5D6B</color>
<color name="nova_portable_text_muted">#FF667584</color>
<color name="nova_portable_accent">#FF557395</color>
<color name="nova_portable_accent_surface">#22557395</color>
<color name="nova_portable_accent_glow">#33557395</color>
<color name="nova_portable_ripple">#22557395</color>
<color name="nova_portable_success">#FF315B45</color>
<color name="nova_portable_streaming">#FF315B45</color>
<color name="nova_portable_online">#FF557395</color>
<color name="nova_portable_on_accent">#FFFFFFFF</color>
<!-- High Contrast — brighter copy, firm outlines, and blue focus for readability. -->
<color name="nova_hc_bg_primary">#FF05070c</color>
<color name="nova_hc_bg_card">#F00f172a</color>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
<string name="nova_theme_polaris_label">Polaris Aurora</string>
<string name="nova_theme_oled_label">Console OLED</string>
<string name="nova_theme_miami_label">Miami Nebula</string>
<string name="nova_theme_portable_chrome_label">Portable Chrome</string>
<string name="nova_theme_high_contrast_label">High Contrast</string>
<string name="nova_theme_material_you_label">Material You</string>
<string name="pcview_quick_library">Open Nova Library</string>
Expand Down
Loading
Loading