refactor: consistent theme with dark/light theme possibility

main
Torpenn 2025-04-08 21:44:56 +02:00
parent 459571979b
commit 14f1c50215
No known key found for this signature in database
GPG Key ID: 56C8A89C974E3ED2
11 changed files with 84 additions and 47 deletions

View File

@ -113,7 +113,7 @@ const Title = styled(Text)(({ theme }) => ({
textAlign: 'center', textAlign: 'center',
fontSize: 40, fontSize: 40,
fontWeight: 'bold', fontWeight: 'bold',
color: theme.colors.black color: theme.colors.fixed.black
})); }));
const Container = styled.View({ const Container = styled.View({
@ -135,7 +135,5 @@ const CustomText = styled(Text)(({ theme }) => ({
fontSize: 20, fontSize: 20,
fontWeight: 'bold', fontWeight: 'bold',
textAlign: 'center', textAlign: 'center',
color: theme.colors.white color: theme.colors.fixed.white
})) }))

View File

@ -102,6 +102,15 @@ export default function Timer() {
); );
}; };
const handleReset = () => {
setCurrentRep(1);
setIsWorkPhase(true);
setTimeLeft(workTime);
setIsRunning(false);
setIsFinish(false);
cancelNotification();
};
const nextRep = () => { const nextRep = () => {
if (currentRep < reps) { if (currentRep < reps) {
if (isWorkPhase) { if (isWorkPhase) {
@ -152,7 +161,7 @@ export default function Timer() {
return ( return (
<Container bgColor={renderBgColor()}> <Container bgColor={renderBgColor()}>
{isFinish && <FinishContent handleStart={handleStart} />} {isFinish && <FinishContent handleStart={handleStart} handleReset={handleReset} />}
{!isFinish && ( {!isFinish && (
<TimerContent <TimerContent
@ -164,6 +173,7 @@ export default function Timer() {
isRunning={isRunning} isRunning={isRunning}
nextRep={nextRep} nextRep={nextRep}
previousRep={previousRep} previousRep={previousRep}
handleReset={handleReset}
handleStop={handleStop} handleStop={handleStop}
handleContine={handleContine} handleContine={handleContine}
/> />
@ -177,6 +187,6 @@ const Container = styled(View)<{ bgColor: TimerBgColor }>(
flex: 1, flex: 1,
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center",
backgroundColor: theme.colors[bgColor], backgroundColor: theme.colors.fixed[bgColor],
}), }),
); );

View File

@ -1,6 +1,6 @@
import FontAwesome from '@expo/vector-icons/FontAwesome'; import FontAwesome from '@expo/vector-icons/FontAwesome';
import { ThemeProvider } from '@emotion/react'; import { ThemeProvider } from '@emotion/react';
import { theme } from '@/app/shared/theme/index'; import { useThemeColors } from '@/app/shared/theme/index';
import { useFonts } from 'expo-font'; import { useFonts } from 'expo-font';
import { Stack } from 'expo-router'; import { Stack } from 'expo-router';
import * as SplashScreen from 'expo-splash-screen'; import * as SplashScreen from 'expo-splash-screen';
@ -47,9 +47,11 @@ export default function RootLayout() {
} }
function RootLayoutNav() { function RootLayoutNav() {
const dynamicTheme = useThemeColors();
return ( return (
<LanguageProvider> <LanguageProvider>
<ThemeProvider theme={theme}> <ThemeProvider theme={dynamicTheme}>
<Stack> <Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} /> <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="Timer" options={{ headerShown: false }} /> <Stack.Screen name="Timer" options={{ headerShown: false }} />

View File

@ -1,7 +0,0 @@
export const colors = {
black: '#000000',
white: '#FFFFFF',
red: '#FF4141',
green: '#3AC26E',
grey: '#F9F9F9',
} as const;

View File

@ -1,14 +1,22 @@
import { colors } from './colors'; import Colors from '@/constants/Colors';
import { layout } from './layout'; import { layout } from './layout';
import { useColorScheme } from 'react-native';
export const theme = { export const theme = {
colors, colors: Colors,
layout layout
}; };
export const useThemeColors = () => {
const colorScheme = useColorScheme() ?? 'light';
return {
...theme,
};
};
declare module '@emotion/react' { declare module '@emotion/react' {
export interface Theme { export interface Theme {
colors: typeof colors; colors: typeof Colors;
layout: typeof layout; layout: typeof layout;
} }
} }

View File

@ -69,9 +69,9 @@ const Container = styled.TouchableOpacity<{
disabled: boolean; disabled: boolean;
secondary: boolean; secondary: boolean;
}>(({ theme, bgColor, secondary }) => ({ }>(({ theme, bgColor, secondary }) => ({
backgroundColor: theme.colors[bgColor], backgroundColor: theme.colors.fixed[bgColor],
borderWidth: secondary ? 1 : 0, borderWidth: secondary ? 1 : 0,
borderColor: theme.colors[bgColor], borderColor: theme.colors.fixed[bgColor],
borderRadius: 6, borderRadius: 6,
height: theme.layout.gridUnit * 12, height: theme.layout.gridUnit * 12,
justifyContent: 'center', justifyContent: 'center',
@ -81,13 +81,13 @@ const Container = styled.TouchableOpacity<{
})); }));
const Label = styled(Text)<{ color: LabelColor }>(({ theme, color }) => ({ const Label = styled(Text)<{ color: LabelColor }>(({ theme, color }) => ({
color: theme.colors[color], color: theme.colors.fixed[color],
fontSize: 16, fontSize: 16,
fontWeight: 'semibold', fontWeight: 'semibold',
})); }));
const SecondaryLabel = styled(Text)<{ bgColor: ButtonColor }>(({ theme, bgColor }) => ({ const SecondaryLabel = styled(Text)<{ bgColor: ButtonColor }>(({ theme, bgColor }) => ({
color: theme.colors[bgColor], color: theme.colors.fixed[bgColor],
fontWeight: 'semibold', fontWeight: 'semibold',
})); }));
@ -97,4 +97,3 @@ const IconContainer = styled.View(({ theme }) => ({
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
})); }));

View File

@ -43,7 +43,7 @@ const Container = styled.View<{
width: '100%', width: '100%',
borderRadius: 10, borderRadius: 10,
overflow: 'hidden', overflow: 'hidden',
backgroundColor: theme.colors[bgColor] backgroundColor: theme.colors.fixed[bgColor]
})); }));
export default Card; export default Card;

View File

@ -42,6 +42,5 @@ const CustomText = styled(Text)(({ theme }) => ({
fontSize: 20, fontSize: 20,
fontWeight: 'bold', fontWeight: 'bold',
textAlign: 'center', textAlign: 'center',
color: theme.colors.white color: theme.colors.fixed.white
})) }))

View File

@ -9,15 +9,22 @@ import { i18n } from '@/app/i18n/i18n';
type FinishContentProps = { type FinishContentProps = {
handleStart: () => void; handleStart: () => void;
handleReset: () => void;
}; };
const t = i18n.scoped('timer.finishContent'); const t = i18n.scoped('timer.finishContent');
export default function FinishContent({ export default function FinishContent({
handleStart handleStart,
handleReset
}: FinishContentProps) { }: FinishContentProps) {
const router = useRouter(); const router = useRouter();
const handleBackClick = () => {
router.push('/');
handleReset();
};
return ( return (
<> <>
<Time>{t('finish')}</Time> <Time>{t('finish')}</Time>
@ -29,7 +36,7 @@ export default function FinishContent({
<HorizontalSpacer widthUnits={3} /> <HorizontalSpacer widthUnits={3} />
<Button label={i18n.t('back')} onPress={() => router.push('/')} /> <Button label={i18n.t('back')} onPress={handleBackClick} />
</Row> </Row>
</> </>
); );
@ -43,5 +50,5 @@ const Row = styled(View)(() => ({
const Time = styled(Text)(({ theme }) => ({ const Time = styled(Text)(({ theme }) => ({
fontSize: 70, fontSize: 70,
fontWeight: 'bold', fontWeight: 'bold',
color: theme.colors.white color: theme.colors.fixed.white
})); }));

View File

@ -19,6 +19,7 @@ interface TimerContentProps {
nextRep: () => void; nextRep: () => void;
previousRep: () => void; previousRep: () => void;
bgColor: TimerBgColor; bgColor: TimerBgColor;
handleReset: () => void;
} }
const t = i18n.scoped('timer.timerContent'); const t = i18n.scoped('timer.timerContent');
@ -31,12 +32,18 @@ export default function TimerContent({
isRunning, isRunning,
handleStop, handleStop,
handleContine, handleContine,
handleReset,
nextRep, nextRep,
previousRep, previousRep,
bgColor, bgColor,
}: TimerContentProps ) { }: TimerContentProps ) {
const router = useRouter(); const router = useRouter();
const handleBackClick = () => {
router.push('/');
handleReset();
};
return ( return (
<> <>
<Title>{isWorkPhase ? t('fight') : t('rest')}</Title> <Title>{isWorkPhase ? t('fight') : t('rest')}</Title>
@ -71,13 +78,13 @@ export default function TimerContent({
<VerticalSpacer heightUnits={4} /> <VerticalSpacer heightUnits={4} />
<Button label={i18n.t('back')} onPress={() => router.push('/')} /> <Button label={i18n.t('back')} onPress={handleBackClick} />
</> </>
); );
} }
const ButtonContainer = styled(View)<{ bgColor: TimerBgColor }>(({ theme, bgColor }) => ({ const ButtonContainer = styled(View)<{ bgColor: TimerBgColor }>(({ theme, bgColor }) => ({
backgroundColor: theme.colors[bgColor], backgroundColor: theme.colors.fixed[bgColor],
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'space-between', justifyContent: 'space-between',
})); }));
@ -85,17 +92,17 @@ const ButtonContainer = styled(View)<{ bgColor: TimerBgColor }>(({ theme, bgColo
const Title = styled(Text)(({ theme }) => ({ const Title = styled(Text)(({ theme }) => ({
fontSize: 50, fontSize: 50,
fontWeight: 'bold', fontWeight: 'bold',
color: theme.colors.white color: theme.colors.fixed.white
})); }));
const Time = styled(Text)(({ theme }) => ({ const Time = styled(Text)(({ theme }) => ({
fontSize: 100, fontSize: 100,
fontWeight: 'bold', fontWeight: 'bold',
color: theme.colors.white color: theme.colors.fixed.white
})); }));
const Reps = styled(Text)(({ theme }) => ({ const Reps = styled(Text)(({ theme }) => ({
fontSize: 30, fontSize: 30,
fontWeight: 'bold', fontWeight: 'bold',
color: theme.colors.white color: theme.colors.fixed.white
})); }));

View File

@ -1,19 +1,33 @@
const tintColorLight = '#2f95dc'; const baseColors = {
const tintColorDark = '#fff'; black: '#000000',
white: '#FFFFFF',
red: '#FF4141',
green: '#3AC26E',
grey: '#F9F9F9',
} as const;
export default { export default {
fixed: {
...baseColors,
},
// LightTheme
light: { light: {
text: '#000', primary: '#007AFF',
background: '#fff', secondary: '#5856D6',
tint: tintColorLight, error: baseColors.red,
tabIconDefault: '#ccc', success: baseColors.green,
tabIconSelected: tintColorLight, background: baseColors.white,
surface: '#F2F2F7',
text: baseColors.black,
}, },
// DarkTheme
dark: { dark: {
text: '#fff', primary: '#0A84FF',
background: '#000', secondary: '#5E5CE6',
tint: tintColorDark, error: '#FF453A',
tabIconDefault: '#ccc', success: '#32D74B',
tabIconSelected: tintColorDark, background: baseColors.black,
surface: '#1C1C1E',
text: baseColors.white,
}, },
}; } as const;