global darkmode hook usage; use style abstractions; remove ui wrapper causing issues

This commit is contained in:
David Westgate 2025-03-17 23:10:31 -07:00
parent 68a91a32ad
commit e720e2e010
17 changed files with 268 additions and 279 deletions

View File

@ -1,9 +1,11 @@
import i18n from "@/i18n/i18n"; import i18n from "@/i18n/i18n";
import { COLORS } from "@/styles/styles";
import AppContext, { IAppContext } from "@/util/context"; import AppContext, { IAppContext } from "@/util/context";
import { MaterialIcons } from "@expo/vector-icons"; import { MaterialIcons } from "@expo/vector-icons";
import { Stack } from "expo-router"; import { Stack } from "expo-router";
import React, { useMemo, useState } from "react"; import React, { useMemo, useState } from "react";
import { I18nextProvider, useTranslation } from "react-i18next"; import { I18nextProvider, useTranslation } from "react-i18next";
import { useColorScheme } from "react-native";
const RootLayout: React.FC = () => { const RootLayout: React.FC = () => {
const [showSettings, setShowSettings] = useState<boolean>(false); const [showSettings, setShowSettings] = useState<boolean>(false);
@ -17,20 +19,36 @@ const RootLayout: React.FC = () => {
[showSettings] [showSettings]
); );
const colorScheme = useColorScheme();
const darkMode = useMemo(() => colorScheme === "dark", [colorScheme]);
const colors = useMemo(
() => (darkMode ? COLORS.DARK : COLORS.LIGHT),
[darkMode]
);
return ( return (
<AppContext.Provider value={ctx}> <AppContext.Provider value={ctx}>
<I18nextProvider i18n={i18n}> <I18nextProvider i18n={i18n}>
<Stack <Stack
screenOptions={{ screenOptions={{
contentStyle: {
backgroundColor: colors.BACKGROUND,
},
headerShown: true, headerShown: true,
title: t("poker_chips_helper"), title: t("poker_chips_helper"),
navigationBarColor: colors.PRIMARY,
headerRight: () => ( headerRight: () => (
<MaterialIcons <MaterialIcons
name="settings" name="settings"
onPress={() => setShowSettings(!showSettings)} onPress={() => setShowSettings(!showSettings)}
size={30} size={30}
color={colors.TEXT}
/> />
), ),
headerStyle: {
backgroundColor: colors.PRIMARY,
},
headerTintColor: colors.TEXT,
statusBarBackgroundColor: "grey",
}} }}
/> />
</I18nextProvider> </I18nextProvider>

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect, useContext, useMemo } from "react"; import React, { useState, useEffect, useContext, useMemo } from "react";
import { ScrollView, Alert } from "react-native"; import { ScrollView, Alert, useColorScheme, Appearance } from "react-native";
import Button from "@/containers/Button"; import Button from "@/containers/Button";
import PlayerSelector from "@/components/PlayerSelector"; import PlayerSelector from "@/components/PlayerSelector";
import BuyInSelector from "@/components/BuyInSelector"; import BuyInSelector from "@/components/BuyInSelector";
@ -12,12 +12,11 @@ import {
savePersistentState, savePersistentState,
loadPersistentState, loadPersistentState,
} from "@/util/PersistentState"; } from "@/util/PersistentState";
import styles from "@/styles/styles"; import styles, { COLORS } from "@/styles/styles";
import Section from "@/containers/Section"; import Section from "@/containers/Section";
import AppContext from "@/util/context"; import AppContext from "@/util/context";
import { Picker } from "@react-native-picker/picker"; import { Picker } from "@react-native-picker/picker";
import i18n from "@/i18n/i18n"; import i18n from "@/i18n/i18n";
import PokerAppUi from "@/containers/PokerAppUi";
const IndexScreen: React.FC = () => { const IndexScreen: React.FC = () => {
const [playerCount, setPlayerCount] = useState(2); const [playerCount, setPlayerCount] = useState(2);
@ -26,8 +25,12 @@ const IndexScreen: React.FC = () => {
const [totalChipsCount, setTotalChipsCount] = useState<number[]>([]); const [totalChipsCount, setTotalChipsCount] = useState<number[]>([]);
const [selectedCurrency, setSelectedCurrency] = useState<string>("$"); const [selectedCurrency, setSelectedCurrency] = useState<string>("$");
const [selectedLanguage, setSelectedLanguage] = useState<string>("en"); const [selectedLanguage, setSelectedLanguage] = useState<string>("en");
const [lightGrayMode, setLightGrayMode] = useState<boolean>(false); const colorScheme = useColorScheme();
const darkMode = useMemo(() => colorScheme === "dark", [colorScheme]);
const colors = useMemo(
() => (darkMode ? COLORS.DARK : COLORS.LIGHT),
[darkMode]
);
const context = useContext(AppContext); const context = useContext(AppContext);
const isSettingsVisible = useMemo(() => context.showSettings, [context]); const isSettingsVisible = useMemo(() => context.showSettings, [context]);
@ -87,14 +90,12 @@ const IndexScreen: React.FC = () => {
}; };
return ( return (
<PokerAppUi darkMode={lightGrayMode}>
<ScrollView <ScrollView
/*style={styles.scrollView} style={styles.scrollView}
contentContainerStyle={styles.scrollViewContent}*/ contentContainerStyle={styles.scrollViewContent}
style={{ flex: 1 }}
contentContainerStyle={{ paddingHorizontal: 15, paddingBottom: 30 }}
> >
{isSettingsVisible && ( {isSettingsVisible && (
<>
<Section <Section
title={i18n.t("appearance")} title={i18n.t("appearance")}
iconName={"brightness-4"} iconName={"brightness-4"}
@ -102,17 +103,16 @@ const IndexScreen: React.FC = () => {
> >
<Button <Button
title={ title={
lightGrayMode darkMode
? i18n.t("switch_to_light_mode") ? i18n.t("switch_to_light_mode")
: i18n.t("switch_to_gray_mode") : i18n.t("switch_to_dark_mode")
}
onPress={() =>
Appearance.setColorScheme(darkMode ? "light" : "dark")
} }
onPress={() => setLightGrayMode(!lightGrayMode)}
darkMode={lightGrayMode}
/> />
</Section> </Section>
)}
{isSettingsVisible && (
<Section <Section
title={i18n.t("select_language")} title={i18n.t("select_language")}
iconName={"language"} iconName={"language"}
@ -121,15 +121,28 @@ const IndexScreen: React.FC = () => {
<Picker <Picker
selectedValue={selectedLanguage} selectedValue={selectedLanguage}
onValueChange={handleLanguageChange} onValueChange={handleLanguageChange}
style={styles.picker} style={[styles.picker, { color: colors.TEXT }]}
dropdownIconColor={colors.TEXT}
> >
<Picker.Item label={i18n.t("english")} value="en" /> <Picker.Item
<Picker.Item label={i18n.t("spanish")} value="es" /> label={i18n.t("english")}
value="en"
style={{
color: colors.TEXT,
backgroundColor: colors.PRIMARY,
}}
/>
<Picker.Item
label={i18n.t("spanish")}
value="es"
style={{
color: colors.TEXT,
backgroundColor: colors.PRIMARY,
}}
/>
</Picker> </Picker>
</Section> </Section>
)}
{isSettingsVisible && (
<Section <Section
title={i18n.t("select_currency")} title={i18n.t("select_currency")}
iconName={"attach-money"} iconName={"attach-money"}
@ -140,6 +153,7 @@ const IndexScreen: React.FC = () => {
setSelectedCurrency={setSelectedCurrency} setSelectedCurrency={setSelectedCurrency}
/> />
</Section> </Section>
</>
)} )}
<Section <Section
@ -151,7 +165,6 @@ const IndexScreen: React.FC = () => {
<PlayerSelector <PlayerSelector
playerCount={playerCount} playerCount={playerCount}
setPlayerCount={setPlayerCount} setPlayerCount={setPlayerCount}
darkMode={lightGrayMode}
/> />
</Section> </Section>
@ -162,7 +175,6 @@ const IndexScreen: React.FC = () => {
<BuyInSelector <BuyInSelector
selectedCurrency={selectedCurrency} selectedCurrency={selectedCurrency}
setBuyInAmount={setBuyInAmount} setBuyInAmount={setBuyInAmount}
darkMode={lightGrayMode}
/> />
</Section> </Section>
@ -176,7 +188,6 @@ const IndexScreen: React.FC = () => {
setTotalChipsCount(chipCountArray); setTotalChipsCount(chipCountArray);
setNumberOfChips(chipCountArray.length); setNumberOfChips(chipCountArray.length);
}} }}
darkMode={lightGrayMode}
/> />
</Section> </Section>
@ -191,7 +202,6 @@ const IndexScreen: React.FC = () => {
setTotalChipsCount={setTotalChipsCount} setTotalChipsCount={setTotalChipsCount}
numberOfChips={numberOfChips} numberOfChips={numberOfChips}
setNumberOfChips={setNumberOfChips} setNumberOfChips={setNumberOfChips}
darkMode={lightGrayMode}
/> />
</Section> </Section>
@ -217,28 +227,23 @@ const IndexScreen: React.FC = () => {
title={i18n.t("save_slot_1")} title={i18n.t("save_slot_1")}
onPress={() => handleSave("SLOT1")} onPress={() => handleSave("SLOT1")}
disabled={buyInAmount === null} disabled={buyInAmount === null}
darkMode={lightGrayMode}
/> />
<Button <Button
title={i18n.t("save_slot_2")} title={i18n.t("save_slot_2")}
onPress={() => handleSave("SLOT2")} onPress={() => handleSave("SLOT2")}
disabled={buyInAmount === null} disabled={buyInAmount === null}
darkMode={lightGrayMode}
/> />
<Button <Button
title={i18n.t("load_slot_1")} title={i18n.t("load_slot_1")}
onPress={() => handleLoad("SLOT1")} onPress={() => handleLoad("SLOT1")}
darkMode={lightGrayMode}
/> />
<Button <Button
title={i18n.t("load_slot_2")} title={i18n.t("load_slot_2")}
onPress={() => handleLoad("SLOT2")} onPress={() => handleLoad("SLOT2")}
darkMode={lightGrayMode}
/> />
</> </>
</Section> </Section>
</ScrollView> </ScrollView>
</PokerAppUi>
); );
}; };

View File

@ -1,5 +1,5 @@
import React, { useState } from "react"; import React, { useMemo, useState } from "react";
import { View, Text, TextInput } from "react-native"; import { View, Text, TextInput, useColorScheme } from "react-native";
import styles, { COLORS } from "@/styles/styles"; import styles, { COLORS } from "@/styles/styles";
import Button from "@/containers/Button"; import Button from "@/containers/Button";
import i18n from "@/i18n/i18n"; import i18n from "@/i18n/i18n";
@ -7,7 +7,6 @@ import i18n from "@/i18n/i18n";
interface BuyInSelectorProps { interface BuyInSelectorProps {
setBuyInAmount: React.Dispatch<React.SetStateAction<number>>; setBuyInAmount: React.Dispatch<React.SetStateAction<number>>;
selectedCurrency: string; selectedCurrency: string;
darkMode: boolean;
} }
const defaultBuyInOptions = [10, 25, 50]; const defaultBuyInOptions = [10, 25, 50];
@ -23,10 +22,15 @@ const parseRoundClamp = (num: string): number => {
const BuyInSelector: React.FC<BuyInSelectorProps> = ({ const BuyInSelector: React.FC<BuyInSelectorProps> = ({
setBuyInAmount, setBuyInAmount,
selectedCurrency, selectedCurrency,
darkMode,
}) => { }) => {
const [customAmount, setCustomAmount] = useState(""); const [customAmount, setCustomAmount] = useState("");
const [buyInAmount, setBuyInAmountState] = useState<number | null>(null); const [buyInAmount, setBuyInAmountState] = useState<number | null>(null);
const colorScheme = useColorScheme();
const darkMode = useMemo(() => colorScheme === "dark", [colorScheme]);
const colors = useMemo(
() => (darkMode ? COLORS.DARK : COLORS.LIGHT),
[darkMode]
);
const handleCustomAmountChange = (value: string) => { const handleCustomAmountChange = (value: string) => {
const numericValue = parseRoundClamp(value); const numericValue = parseRoundClamp(value);
@ -55,13 +59,13 @@ const BuyInSelector: React.FC<BuyInSelectorProps> = ({
key={amount} key={amount}
onPress={() => handleBuyInSelection(amount)} onPress={() => handleBuyInSelection(amount)}
title={`${selectedCurrency} ${amount}`} title={`${selectedCurrency} ${amount}`}
darkMode={darkMode}
/> />
))} ))}
</View> </View>
<TextInput <TextInput
style={styles.input} style={[styles.input, { color: colors.TEXT }]}
placeholderTextColor={colors.TEXT}
value={customAmount} value={customAmount}
maxLength={3} maxLength={3}
onChangeText={handleCustomAmountChange} onChangeText={handleCustomAmountChange}
@ -69,7 +73,7 @@ const BuyInSelector: React.FC<BuyInSelectorProps> = ({
keyboardType="numeric" keyboardType="numeric"
/> />
<Text style={styles.h2}> <Text style={[styles.h2, { color: colors.TEXT }]}>
{`${i18n.t("selected_buy_in")} `} {`${i18n.t("selected_buy_in")} `}
{buyInAmount !== null {buyInAmount !== null
? `${selectedCurrency} ${buyInAmount}` ? `${selectedCurrency} ${buyInAmount}`

View File

@ -6,10 +6,8 @@ import i18n from "@/i18n/i18n";
const ChipDetection = ({ const ChipDetection = ({
updateChipCount, updateChipCount,
darkMode,
}: { }: {
updateChipCount: (chipData: Record<string, number>) => void; updateChipCount: (chipData: Record<string, number>) => void;
darkMode: boolean;
}) => { }) => {
const [imageUri, setImageUri] = useState<string | null>(null); const [imageUri, setImageUri] = useState<string | null>(null);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@ -135,16 +133,8 @@ const ChipDetection = ({
marginBottom: 10, marginBottom: 10,
}} }}
> >
<Button <Button title={i18n.t("pick_an_image")} onPress={pickImage} />
title={i18n.t("pick_an_image")} <Button title={i18n.t("take_a_photo")} onPress={takePhoto} />
onPress={pickImage}
darkMode={darkMode}
/>
<Button
title={i18n.t("take_a_photo")}
onPress={takePhoto}
darkMode={darkMode}
/>
</View> </View>
{imageUri && ( {imageUri && (

View File

@ -21,13 +21,11 @@ const ChipInputModal = ({
setShowModal, setShowModal,
totalChipsCount, totalChipsCount,
update, update,
darkMode,
}: { }: {
showModal: [boolean, ColorValue]; showModal: [boolean, ColorValue];
setShowModal: React.Dispatch<React.SetStateAction<[boolean, ColorValue]>>; setShowModal: React.Dispatch<React.SetStateAction<[boolean, ColorValue]>>;
totalChipsCount: number[]; totalChipsCount: number[];
update: Function; update: Function;
darkMode: boolean;
}) => { }) => {
const color: ColorValue = useMemo(() => showModal[1], [showModal]); const color: ColorValue = useMemo(() => showModal[1], [showModal]);
const colorIdx = useMemo(() => colors.indexOf(color), [color]); const colorIdx = useMemo(() => colors.indexOf(color), [color]);
@ -77,7 +75,6 @@ const ChipInputModal = ({
update(showModal[1], Number.isNaN(value) ? 0 : value); update(showModal[1], Number.isNaN(value) ? 0 : value);
setShowModal([false, color]); setShowModal([false, color]);
}} }}
darkMode={darkMode}
/> />
</Modal> </Modal>
); );
@ -119,13 +116,11 @@ const ChipsSelector = ({
totalChipsCount, totalChipsCount,
setTotalChipsCount, setTotalChipsCount,
setNumberOfChips, setNumberOfChips,
darkMode,
}: { }: {
numberOfChips: number; numberOfChips: number;
totalChipsCount: number[]; totalChipsCount: number[];
setTotalChipsCount: React.Dispatch<React.SetStateAction<number[]>>; setTotalChipsCount: React.Dispatch<React.SetStateAction<number[]>>;
setNumberOfChips: React.Dispatch<React.SetStateAction<number>>; setNumberOfChips: React.Dispatch<React.SetStateAction<number>>;
darkMode: boolean;
}) => { }) => {
const [showModal, setShowModal] = useState<[boolean, ColorValue]>([ const [showModal, setShowModal] = useState<[boolean, ColorValue]>([
false, false,
@ -172,7 +167,6 @@ const ChipsSelector = ({
setNumberOfChips(Math.max(1, numberOfChips - 1)); setNumberOfChips(Math.max(1, numberOfChips - 1));
}} }}
disabled={numberOfChips === 1} disabled={numberOfChips === 1}
darkMode={darkMode}
/> />
<View style={[styles.container, { flexDirection: "row" }]}> <View style={[styles.container, { flexDirection: "row" }]}>
{colorsUsed.map((color) => { {colorsUsed.map((color) => {
@ -193,7 +187,6 @@ const ChipsSelector = ({
setNumberOfChips(Math.min(5, numberOfChips + 1)); setNumberOfChips(Math.min(5, numberOfChips + 1));
}} }}
disabled={numberOfChips === 5} disabled={numberOfChips === 5}
darkMode={darkMode}
/> />
<ChipInputModal <ChipInputModal
@ -201,7 +194,6 @@ const ChipsSelector = ({
setShowModal={setShowModal} setShowModal={setShowModal}
totalChipsCount={totalChipsCount} totalChipsCount={totalChipsCount}
update={update} update={update}
darkMode={darkMode}
/> />
</> </>
); );

View File

@ -1,7 +1,8 @@
import React from "react"; import React, { useMemo } from "react";
import { Picker } from "@react-native-picker/picker"; import { Picker } from "@react-native-picker/picker";
import styles from "@/styles/styles"; import styles, { COLORS } from "@/styles/styles";
import i18n from "@/i18n/i18n"; import i18n from "@/i18n/i18n";
import { useColorScheme } from "react-native";
interface CurrencySelectorProps { interface CurrencySelectorProps {
selectedCurrency: string; selectedCurrency: string;
@ -12,18 +13,53 @@ const CurrencySelector: React.FC<CurrencySelectorProps> = ({
selectedCurrency, selectedCurrency,
setSelectedCurrency, setSelectedCurrency,
}) => { }) => {
const colorScheme = useColorScheme();
const darkMode = useMemo(() => colorScheme === "dark", [colorScheme]);
const colors = useMemo(
() => (darkMode ? COLORS.DARK : COLORS.LIGHT),
[darkMode]
);
return ( return (
<> <>
<Picker <Picker
selectedValue={selectedCurrency} selectedValue={selectedCurrency}
onValueChange={(itemValue) => setSelectedCurrency(itemValue)} onValueChange={(itemValue) => setSelectedCurrency(itemValue)}
style={styles.picker} style={[styles.picker, { color: colors.TEXT }]}
dropdownIconColor={colors.TEXT}
testID="currency-picker" // ✅ Add testID here testID="currency-picker" // ✅ Add testID here
> >
<Picker.Item label={i18n.t("usd")} value="$" /> <Picker.Item
<Picker.Item label={i18n.t("euro")} value="€" /> label={i18n.t("usd")}
<Picker.Item label={i18n.t("pound")} value="£" /> value="$"
<Picker.Item label={i18n.t("inr")} value="₹" /> style={{
color: colors.TEXT,
backgroundColor: colors.PRIMARY,
}}
/>
<Picker.Item
label={i18n.t("euro")}
value="€"
style={{
color: colors.TEXT,
backgroundColor: colors.PRIMARY,
}}
/>
<Picker.Item
label={i18n.t("pound")}
value="£"
style={{
color: colors.TEXT,
backgroundColor: colors.PRIMARY,
}}
/>
<Picker.Item
label={i18n.t("inr")}
value="₹"
style={{
color: colors.TEXT,
backgroundColor: colors.PRIMARY,
}}
/>
</Picker> </Picker>
</> </>
); );

View File

@ -1,12 +1,11 @@
import React from "react"; import React, { useMemo } from "react";
import { View, Text } from "react-native"; import { View, Text, useColorScheme } from "react-native";
import Button from "@/containers/Button"; import Button from "@/containers/Button";
import styles from "@/styles/styles"; import styles, { COLORS } from "@/styles/styles";
interface PlayerSelectorProps { interface PlayerSelectorProps {
playerCount: number; playerCount: number;
setPlayerCount: React.Dispatch<React.SetStateAction<number>>; setPlayerCount: React.Dispatch<React.SetStateAction<number>>;
darkMode: boolean;
} }
const MIN = 2; const MIN = 2;
@ -15,7 +14,6 @@ const MAX = 8;
const PlayerSelector: React.FC<PlayerSelectorProps> = ({ const PlayerSelector: React.FC<PlayerSelectorProps> = ({
playerCount, playerCount,
setPlayerCount, setPlayerCount,
darkMode,
}) => { }) => {
const increasePlayers = () => { const increasePlayers = () => {
if (playerCount < MAX) setPlayerCount(playerCount + 1); if (playerCount < MAX) setPlayerCount(playerCount + 1);
@ -24,21 +22,25 @@ const PlayerSelector: React.FC<PlayerSelectorProps> = ({
const decreasePlayers = () => { const decreasePlayers = () => {
if (playerCount > MIN) setPlayerCount(playerCount - 1); if (playerCount > MIN) setPlayerCount(playerCount - 1);
}; };
const colorScheme = useColorScheme();
const darkMode = useMemo(() => colorScheme === "dark", [colorScheme]);
const colors = useMemo(
() => (darkMode ? COLORS.DARK : COLORS.LIGHT),
[darkMode]
);
return ( return (
<View style={{ flexDirection: "row", alignItems: "center" }}> <View style={{ flexDirection: "row", alignItems: "center", gap: 10 }}>
<Button <Button
title="-" title="-"
onPress={decreasePlayers} onPress={decreasePlayers}
disabled={playerCount <= MIN} disabled={playerCount <= MIN}
darkMode={darkMode}
/> />
<Text style={styles.h1}>{playerCount}</Text> <Text style={[styles.h1, { color: colors.TEXT }]}>{playerCount}</Text>
<Button <Button
title="+" title="+"
onPress={increasePlayers} onPress={increasePlayers}
disabled={playerCount >= MAX} disabled={playerCount >= MAX}
darkMode={darkMode}
/> />
</View> </View>
); );

View File

@ -19,7 +19,6 @@ describe("BuyInSelector Component", () => {
<BuyInSelector <BuyInSelector
setBuyInAmount={setBuyInAmount} setBuyInAmount={setBuyInAmount}
selectedCurrency={selectedCurrency} selectedCurrency={selectedCurrency}
darkMode={false}
/> />
); );
return { return {

View File

@ -45,7 +45,7 @@ describe("ChipDetection", () => {
it("renders correctly", () => { it("renders correctly", () => {
const { getByText } = render( const { getByText } = render(
<ChipDetection updateChipCount={mockUpdateChipCount} darkMode={false} /> <ChipDetection updateChipCount={mockUpdateChipCount} />
); );
expect(getByText(/pick an image/i)).toBeTruthy(); expect(getByText(/pick an image/i)).toBeTruthy();
@ -59,7 +59,7 @@ describe("ChipDetection", () => {
}); });
const { getByText } = render( const { getByText } = render(
<ChipDetection updateChipCount={mockUpdateChipCount} darkMode={false} /> <ChipDetection updateChipCount={mockUpdateChipCount} />
); );
fireEvent.press(getByText(/pick an image/i)); fireEvent.press(getByText(/pick an image/i));
@ -78,7 +78,7 @@ describe("ChipDetection", () => {
}); });
const { getByText } = render( const { getByText } = render(
<ChipDetection updateChipCount={mockUpdateChipCount} darkMode={false} /> <ChipDetection updateChipCount={mockUpdateChipCount} />
); );
fireEvent.press(getByText(/take a photo/i)); fireEvent.press(getByText(/take a photo/i));
@ -99,7 +99,7 @@ describe("ChipDetection", () => {
}); });
const { getByText } = render( const { getByText } = render(
<ChipDetection updateChipCount={mockUpdateChipCount} darkMode={false} /> <ChipDetection updateChipCount={mockUpdateChipCount} />
); );
fireEvent.press(getByText(/take a photo/i)); fireEvent.press(getByText(/take a photo/i));
@ -126,7 +126,7 @@ describe("ChipDetection", () => {
); );
const { getByText } = render( const { getByText } = render(
<ChipDetection updateChipCount={mockUpdateChipCount} darkMode={false} /> <ChipDetection updateChipCount={mockUpdateChipCount} />
); );
fireEvent.press(getByText(/pick an image/i)); fireEvent.press(getByText(/pick an image/i));
@ -159,7 +159,7 @@ describe("ChipDetection", () => {
); );
const { getByText } = render( const { getByText } = render(
<ChipDetection updateChipCount={mockUpdateChipCount} darkMode={false} /> <ChipDetection updateChipCount={mockUpdateChipCount} />
); );
fireEvent.press(getByText(/pick an image/i)); fireEvent.press(getByText(/pick an image/i));

View File

@ -28,7 +28,6 @@ const rend = () =>
totalChipsCount={TOTAL_CHIPS_COUNT} totalChipsCount={TOTAL_CHIPS_COUNT}
setTotalChipsCount={mocktTotalChipsCount} setTotalChipsCount={mocktTotalChipsCount}
setNumberOfChips={mockSetNumberOfChips} setNumberOfChips={mockSetNumberOfChips}
darkMode={false}
/> />
); );

View File

@ -6,11 +6,7 @@ describe("PlayerSelector Component", () => {
it("renders the initial player count and buttons correctly", () => { it("renders the initial player count and buttons correctly", () => {
const setPlayerCount = jest.fn(); const setPlayerCount = jest.fn();
const { getByText, getByRole } = render( const { getByText, getByRole } = render(
<PlayerSelector <PlayerSelector playerCount={4} setPlayerCount={setPlayerCount} />
playerCount={4}
setPlayerCount={setPlayerCount}
darkMode={false}
/>
); );
expect(getByText("4")).toBeTruthy(); expect(getByText("4")).toBeTruthy();
@ -21,11 +17,7 @@ describe("PlayerSelector Component", () => {
it('increases player count when "+" button is pressed', () => { it('increases player count when "+" button is pressed', () => {
const setPlayerCount = jest.fn(); const setPlayerCount = jest.fn();
const { getByRole } = render( const { getByRole } = render(
<PlayerSelector <PlayerSelector playerCount={4} setPlayerCount={setPlayerCount} />
playerCount={4}
setPlayerCount={setPlayerCount}
darkMode={false}
/>
); );
fireEvent.press(getByRole("button", { name: "+" })); fireEvent.press(getByRole("button", { name: "+" }));
@ -35,11 +27,7 @@ describe("PlayerSelector Component", () => {
it('decreases player count when "-" button is pressed', () => { it('decreases player count when "-" button is pressed', () => {
const setPlayerCount = jest.fn(); const setPlayerCount = jest.fn();
const { getByRole } = render( const { getByRole } = render(
<PlayerSelector <PlayerSelector playerCount={4} setPlayerCount={setPlayerCount} />
playerCount={4}
setPlayerCount={setPlayerCount}
darkMode={false}
/>
); );
fireEvent.press(getByRole("button", { name: "-" })); fireEvent.press(getByRole("button", { name: "-" }));
@ -49,11 +37,7 @@ describe("PlayerSelector Component", () => {
it("does not increase player count beyond 8", () => { it("does not increase player count beyond 8", () => {
const setPlayerCount = jest.fn(); const setPlayerCount = jest.fn();
const { getByRole } = render( const { getByRole } = render(
<PlayerSelector <PlayerSelector playerCount={8} setPlayerCount={setPlayerCount} />
playerCount={8}
setPlayerCount={setPlayerCount}
darkMode={false}
/>
); );
fireEvent.press(getByRole("button", { name: "+" })); fireEvent.press(getByRole("button", { name: "+" }));
@ -63,11 +47,7 @@ describe("PlayerSelector Component", () => {
it("does not decrease player count below 2", () => { it("does not decrease player count below 2", () => {
const setPlayerCount = jest.fn(); const setPlayerCount = jest.fn();
const { getByRole } = render( const { getByRole } = render(
<PlayerSelector <PlayerSelector playerCount={2} setPlayerCount={setPlayerCount} />
playerCount={2}
setPlayerCount={setPlayerCount}
darkMode={false}
/>
); );
fireEvent.press(getByRole("button", { name: "-" })); fireEvent.press(getByRole("button", { name: "-" }));

View File

@ -1,19 +1,25 @@
import React from "react"; import { COLORS } from "@/styles/styles";
import { Text, TouchableOpacity, StyleSheet } from "react-native"; import React, { useMemo } from "react";
import {
Text,
TouchableOpacity,
StyleSheet,
useColorScheme,
} from "react-native";
interface ButtonProps { interface ButtonProps {
title: string; title: string;
onPress: () => void; onPress: () => void;
disabled?: boolean; disabled?: boolean;
darkMode: boolean;
} }
const Button: React.FC<ButtonProps> = ({ const Button: React.FC<ButtonProps> = ({ title, onPress, disabled }) => {
title, const colorScheme = useColorScheme();
onPress, const darkMode = useMemo(() => colorScheme === "dark", [colorScheme]);
disabled, const colors = useMemo(
darkMode, () => (darkMode ? COLORS.DARK : COLORS.LIGHT),
}) => { [darkMode]
);
return ( return (
<TouchableOpacity <TouchableOpacity
onPress={onPress} onPress={onPress}
@ -21,18 +27,11 @@ const Button: React.FC<ButtonProps> = ({
accessibilityRole="button" accessibilityRole="button"
style={[ style={[
styles.button, styles.button,
darkMode ? styles.darkButton : styles.lightButton, { backgroundColor: colors.PRIMARY },
disabled && styles.disabled, disabled && styles.disabled,
]} ]}
> >
<Text <Text style={[styles.buttonText, { color: colors.TEXT }]}>{title}</Text>
style={[
styles.buttonText,
darkMode ? styles.darkText : styles.lightText,
]}
>
{title}
</Text>
</TouchableOpacity> </TouchableOpacity>
); );
}; };

View File

@ -1,52 +0,0 @@
import React, { ReactNode } from "react";
import {
SafeAreaView,
StatusBar,
View,
StyleSheet,
Dimensions,
} from "react-native";
interface PokerAppUiProps {
children: ReactNode;
darkMode?: boolean;
}
const PokerAppUi: React.FC<PokerAppUiProps> = ({
children,
darkMode = false,
}) => {
const screenHeight = Dimensions.get("window").height;
return (
<SafeAreaView
style={[styles.safeArea, darkMode ? styles.lightGray : styles.light]}
>
<StatusBar barStyle={"dark-content"} />
<View style={[styles.container, { minHeight: screenHeight }]}>
{children}
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
safeArea: {
flex: 1,
},
container: {
flex: 1,
width: "100%",
padding: 16,
justifyContent: "flex-start",
alignItems: "center",
},
light: {
backgroundColor: "#F5F5F5",
},
lightGray: {
backgroundColor: "#D3D3D3",
},
});
export default PokerAppUi;

View File

@ -1,7 +1,7 @@
import { View, Text, StyleSheet } from "react-native"; import { View, Text, StyleSheet, useColorScheme } from "react-native";
import React from "react"; import React, { useMemo } from "react";
import { MaterialIcons } from "@expo/vector-icons"; import { MaterialIcons } from "@expo/vector-icons";
import globalStyles from "@/styles/styles"; import globalStyles, { COLORS } from "@/styles/styles";
const titleCase = (input: string) => const titleCase = (input: string) =>
input input
@ -23,6 +23,12 @@ const Section = ({
orientation?: "row" | "column"; orientation?: "row" | "column";
contentStyle?: object; contentStyle?: object;
}) => { }) => {
const colorScheme = useColorScheme();
const darkMode = useMemo(() => colorScheme === "dark", [colorScheme]);
const colors = useMemo(
() => (darkMode ? COLORS.DARK : COLORS.LIGHT),
[darkMode]
);
return ( return (
<View style={styles.container}> <View style={styles.container}>
<View style={styles.header}> <View style={styles.header}>
@ -30,9 +36,11 @@ const Section = ({
style={styles.icon} style={styles.icon}
name={iconName} name={iconName}
size={30} size={30}
color={"black"} color={colors.TEXT}
/> />
<Text style={styles.title}>{titleCase(title)}</Text> <Text style={[styles.title, { color: colors.TEXT }]}>
{titleCase(title)}
</Text>
</View> </View>
<View <View
style={{ style={{

View File

@ -48,7 +48,7 @@
"please_select_valid_buyin": "Please select a valid buy-in amount", "please_select_valid_buyin": "Please select a valid buy-in amount",
"chip_value_warn": "Be advised that the value of the distributed chips does not equal the buy-in for these inputs.\n\nHowever, results shown are fair to all players", "chip_value_warn": "Be advised that the value of the distributed chips does not equal the buy-in for these inputs.\n\nHowever, results shown are fair to all players",
"appearance": "Appearance", "appearance": "Appearance",
"switch_to_gray_mode": "Switch to Gray Mode", "switch_to_dark_mode": "Switch to Dark Mode",
"switch_to_light_mode": "Switch to Light Mode" "switch_to_light_mode": "Switch to Light Mode"
} }
} }

View File

@ -49,7 +49,7 @@
"please_select_valid_buyin": "Por favor seleccione una cantidad de buy-in válida", "please_select_valid_buyin": "Por favor seleccione una cantidad de buy-in válida",
"chip_value_warn": "Tenga en cuenta que el valor de las fichas distribuidas no es igual al buy-in para estas entradas.\n\nSin embargo, los resultados que se muestran son justos para todos los jugadores.", "chip_value_warn": "Tenga en cuenta que el valor de las fichas distribuidas no es igual al buy-in para estas entradas.\n\nSin embargo, los resultados que se muestran son justos para todos los jugadores.",
"appearance": "Apariencia", "appearance": "Apariencia",
"switch_to_gray_mode": "Cambiar a Modo Gris", "switch_to_dark_mode": "Cambiar a Modo Oscuro",
"switch_to_light_mode": "Cambiar a Modo Claro" "switch_to_light_mode": "Cambiar a Modo Claro"
} }
} }

View File

@ -1,16 +1,23 @@
import { StyleSheet } from "react-native"; import { StyleSheet } from "react-native";
export const COLORS = { export const COLORS = {
PRIMARY: "#007bff",
SECONDARY: "#6c757d",
SUCCESS: "#28a745",
DANGER: "#dc3545",
WARNING: "#c79c28", WARNING: "#c79c28",
LIGHT: {
TEXT: "black",
PRIMARY: "lightgrey",
SECONDARY: "azure",
BACKGROUND: "ghostwhite",
DISABLED: "gray",
},
DARK: {
TEXT: "white",
PRIMARY: "black",
SECONDARY: "teal",
BACKGROUND: "dimgrey",
DISABLED: "gray",
},
}; };
const lightStyles = StyleSheet.create({});
const darkStyles = StyleSheet.create({});
const GlobalStyles = StyleSheet.create({ const GlobalStyles = StyleSheet.create({
scrollView: {}, scrollView: {},
scrollViewContent: { scrollViewContent: {
@ -51,9 +58,11 @@ const GlobalStyles = StyleSheet.create({
textShadowRadius: 10, textShadowRadius: 10,
}, },
picker: { picker: {
height: 50, borderRadius: 10,
height: 55,
width: 150, width: 150,
}, },
pickerItem: {},
}); });
export default GlobalStyles; export default GlobalStyles;