iOS server-rendered home widgets can't follow light/dark mode (`theme` param is always "light")
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 35/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- ios, react-native, swift, typescript
- Área
- backend-api-design, mobile
Línea de trabajo
Start with ios/shared/WidgetServer/VoltraWidgetAppearance.swift and VoltraWidgetServerFetcher.swift:84 to understand how the theme parameter is set, then read ios/target/VoltraHomeWidget.swift:107,289 for entry parsing and rendering. Compare the suggested payload-variant and dynamic-color approaches before choosing a direction; done means server-rendered and app-pushed widgets render correctly in both appearances and respond to appearance changes, with tests covering selection and fallback behavior.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
What happens
A server-rendered home screen widget (serverUpdate on a widget with no entry) stays in its light colors when the device is in dark mode. It also doesn't change when the user switches appearance, until something renders the payload again.
Reproduced on 2.2.0. The code involved is unchanged in 2.3.2.
Repro
- Configure a home screen widget with
serverUpdatepointing at an endpoint that returnsrenderWidgetToString(variants)and picks its colors from thethemequery param. - Put the device (or simulator) in dark mode and add the widget.
- The server receives
theme=lighton every timeline fetch, so the widget renders light. - Switch the device appearance either way. The widget keeps whatever colors were in the last payload.
Cause
There are two separate problems.
1. The theme sent with server requests isn't the system appearance. VoltraWidgetAppearance.currentTheme() (ios/shared/WidgetServer/VoltraWidgetAppearance.swift:9) reads UITraitCollection.current.userInterfaceStyle. It runs inside the timeline provider's fetch (VoltraWidgetServerFetcher.swift:84), which isn't drawing anything, so there is no meaningful current trait collection. In our testing it came back "light" while the system was dark. A TimelineProvider can't know the appearance at all: WidgetKit asks for the timeline once and draws the same entry in both light and dark.
2. Payloads can only describe one appearance. Colors are serialized as fixed strings (JSColorParser.parse has no light/dark color), and VoltraHomeWidgetEntry holds a single rootNode that VoltraHomeWidgetView draws without reading @Environment(\.colorScheme) (ios/target/VoltraHomeWidget.swift:107, :289). So even with a correct theme, a payload rendered for one appearance is wrong as soon as the user switches. Fixing that means re-rendering from the app or waiting for the next server refresh.
Dynamic Widgets solve this through env.colorScheme. #319 covers light/dark colors for Android Dynamic Widgets and scopes server-rendered payloads out. Server-rendered and app-pushed (updateWidget) widgets on iOS have no equivalent.
Suggested fix
Some options, roughly smallest first:
- A. Per-appearance variants in the payload. Allow optional
<family>@light/<family>@darkkeys next to the existing family keys. The provider parses them, andVoltraHomeWidgetViewpicks one with@Environment(\.colorScheme), falling back to the plain family key. Older clients ignore unknown keys, so the payload stays backward compatible.renderWidgetToJsonalready accepts arbitrary root names, so both variants share one stylesheet. We run this as a local patch (about 60 lines, all inVoltraHomeWidget.swift) and can open a PR if this direction works for you. - B. Light/dark color pairs in color values, e.g.
{ light: '#FFFFFF', dark: '#1C1C1E' }, resolved when drawing through a dynamicUIColor. This makes payloads smaller and covers every widget kind, and it matches what #319 proposes for Android. - C. Either way, make
themereliable or document it. If the appearance can't be known while fetching, it may be better to dropthemeor mark it as best-effort. That would tell server authors to send both appearances (A or B) instead of trusting it.
Workaround
Until then, we render both appearances and let the widget pick one with the local patch from option A. On the server we ignore theme and read the appearance the app last reported from a custom credential header (setWidgetServerCredentials({ headers })). Unpatched builds fall back to that.
Environment
@use-voltra/ios-client2.2.0 (VoltraWidgetAppearance/VoltraHomeWidgetchecked in 2.3.2)- Xcode 27, iOS 26.5 and iOS 27 simulators
- Expo SDK 58, server-rendered widget with
serverUpdate, app also pushing withupdateWidget
- Lenguaje dominante
- TypeScript
- Estrellas
- 844
- Forks
- 46
- Merge medio
- 21 h 11 min
- PR fusionados (30 d)
- 14
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de callstackincubator/voltra
-
platform:iOS
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
callstackincubator/voltra#340 · 1 comentario · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
refactor-scout
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
callstackincubator/voltra#308 ·
Los mantenedores suelen responder en 1 día
-
refactor-scout
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
callstackincubator/voltra#307 ·
Los mantenedores suelen responder en 1 día
-
bug platform:Android Widget
Dificultad 3/5 Medio día Aptitud para principiantes 55/100
callstackincubator/voltra#345 ·
Los mantenedores suelen responder en 1 día
-
enhancement platform:Android platform:iOS
Dificultad 5/5 Más de una semana Aptitud para principiantes 8/100
callstackincubator/voltra#343 ·
Los mantenedores suelen responder en 1 día
Todos los issues de callstackincubator/voltra
Issues similares
-
level/task type/bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
wazuh/wazuh-dashboard-plugins#9508 ·
Los mantenedores suelen responder en 1 día
-
Testnet EOL page links Zonescan mainnetPosiblemente ocupada @napelvs la tomó hoy. Abierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 76/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Azure-Samples/azure-search-openai-demo#3249 ·
Los mantenedores suelen responder en 1 día
-
[Docs] docs/architecture.mermaid leaves out 21 of the 51 src/ directoriesPosiblemente ocupada @uyg7x la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
Los mantenedores suelen responder en 1 día
-
enhancement status:needs-triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
dongdongbh/Mindwtr#1438 ·
Los mantenedores suelen responder en 1 día