[fix](client): paint the app background and default the theme to dark

Every screen but Login set `backgroundColor: bg` itself, so the login page and
the boot loader fell through to the platform's white surface while the text
tokens stayed light — white on light, unreadable. The palette in
`theme/tokens.ts` is fixed dark by construction, and `Uniwind.setTheme` defaulted
to light, so heroUI's own surfaces were light too. Paint the background at the
root, on the login screen and on the loader, and default the theme to dark.
This commit is contained in:
2026-10-19 09:20:42 +01:00
parent 531e9ccf15
commit ff07df7ae6
4 changed files with 12 additions and 6 deletions
+2 -1
View File
@@ -17,6 +17,7 @@ import ScannerScreen from './src/screens/ScannerScreen';
import SettingsScreen from './src/screens/SettingsScreen'; import SettingsScreen from './src/screens/SettingsScreen';
import LiveAlarmScreen from './src/screens/LiveAlarmScreen'; import LiveAlarmScreen from './src/screens/LiveAlarmScreen';
import { LoadingView } from './src/components/ui'; import { LoadingView } from './src/components/ui';
import { bg } from './src/theme/tokens';
import { navigationRef, openLiveAlarm } from './src/navigationRef'; import { navigationRef, openLiveAlarm } from './src/navigationRef';
import { getLaunchAlert } from './src/services/alarmNative'; import { getLaunchAlert } from './src/services/alarmNative';
import type { RootStackParamList } from './src/navigation'; import type { RootStackParamList } from './src/navigation';
@@ -130,7 +131,7 @@ function Root() {
function App() { function App() {
return ( return (
<GestureHandlerRootView style={{ flex: 1 }}> <GestureHandlerRootView style={{ flex: 1, backgroundColor: bg }}>
<HeroUINativeProviderRaw> <HeroUINativeProviderRaw>
<SafeAreaProvider> <SafeAreaProvider>
<ThemeProvider> <ThemeProvider>
+2 -1
View File
@@ -23,6 +23,7 @@ import {
type LucideIcon, type LucideIcon,
} from 'lucide-react-native'; } from 'lucide-react-native';
import { import {
bg,
border, border,
danger, danger,
dangerDeep, dangerDeep,
@@ -536,7 +537,7 @@ export const styles = StyleSheet.create({
paddingVertical: 48, paddingVertical: 48,
}, },
emptyAction: { marginTop: space6, alignSelf: 'stretch' }, emptyAction: { marginTop: space6, alignSelf: 'stretch' },
loading: { alignItems: 'center', justifyContent: 'center', paddingVertical: 48 }, loading: { alignItems: 'center', justifyContent: 'center', paddingVertical: 48, backgroundColor: bg },
errorBanner: { errorBanner: {
borderWidth: 1, borderWidth: 1,
borderColor: 'rgba(248,113,113,0.3)', borderColor: 'rgba(248,113,113,0.3)',
+2 -2
View File
@@ -12,7 +12,7 @@ import {
Screen, Screen,
TextInputBox, TextInputBox,
} from '../components/ui'; } from '../components/ui';
import { space4, text, textMuted, textSecondary, typeCaption, typeLabel, typeTitle } from '../theme/tokens'; import { space4, text, textMuted, textSecondary, typeCaption, typeLabel, typeTitle, bg } from '../theme/tokens';
type Mode = 'signin' | 'register'; type Mode = 'signin' | 'register';
@@ -54,7 +54,7 @@ export default function LoginScreen() {
}; };
return ( return (
<View style={{ flex: 1 }}> <View style={{ flex: 1, backgroundColor: bg }}>
{!online ? <OfflineStrip /> : null} {!online ? <OfflineStrip /> : null}
<KeyboardAvoidingView <KeyboardAvoidingView
style={{ flex: 1 }} style={{ flex: 1 }}
+6 -2
View File
@@ -18,14 +18,18 @@ interface ThemeContextValue {
const ThemeContext = createContext<ThemeContextValue | undefined>(undefined); const ThemeContext = createContext<ThemeContextValue | undefined>(undefined);
export function ThemeProvider({ children }: { children: React.ReactNode }) { export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [isDark, setIsDark] = useState(false); // The app's palette is dark by construction (`theme/tokens.ts` are fixed
// dark values); this flag only drives heroUI's own theme so its controls
// match. Defaulting to light left every heroUI surface light while the
// app's text tokens stayed light-on-light — the white-on-white login page.
const [isDark, setIsDark] = useState(true);
useEffect(() => { useEffect(() => {
let cancelled = false; let cancelled = false;
(async () => { (async () => {
try { try {
const raw = await AsyncStorage.getItem(THEME_KEY); const raw = await AsyncStorage.getItem(THEME_KEY);
const dark = raw === 'dark'; const dark = raw !== 'light';
if (!cancelled) setIsDark(dark); if (!cancelled) setIsDark(dark);
Uniwind.setTheme(dark ? 'dark' : 'light'); Uniwind.setTheme(dark ? 'dark' : 'light');
} catch { } catch {