Skip to content

Commit

Permalink
Connect PaletteSelector
Browse files Browse the repository at this point in the history
  • Loading branch information
wyne committed Apr 17, 2024
1 parent ab9a35f commit 9c97a34
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 79 deletions.
24 changes: 24 additions & 0 deletions redux/GamesSlice.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import analytics from '@react-native-firebase/analytics';
import { PayloadAction, createAsyncThunk, createEntityAdapter, createSelector, createSlice } from '@reduxjs/toolkit';
import { getContrastRatio } from 'colorsheet';
import * as Crypto from 'expo-crypto';

import { getPalette } from '../src/ColorPalette';
import logger from '../src/Logger';

import { ScoreState, playerAdd, selectAllPlayers, selectPlayerById } from './PlayersSlice';
Expand Down Expand Up @@ -185,6 +187,28 @@ export const selectSortedPlayers = createSelector(
}
);

const selectPaletteName = (state: RootState, gameId: string) => state.games.entities[gameId]?.palette;
const selectPlayerIndex = (_: RootState, __: string, playerIndex: number) => playerIndex;

export const selectPlayerColors = createSelector(
[selectPaletteName, selectPlayerIndex],
(paletteName, playerIndex) => {
// TODO: Get player color if it exists

const palette = getPalette(paletteName || 'original');

const bg = palette[playerIndex % palette.length];

const blackContrast = getContrastRatio(bg, '#000').number;
const whiteContrast = getContrastRatio(bg, '#fff').number;

// +1 to give a slight preference to white
const fg = blackContrast >= whiteContrast + 1 ? '#000000' : '#FFFFFF';

return [bg, fg];
}
);

export const {
updateGame,
roundNext,
Expand Down
34 changes: 0 additions & 34 deletions src/ColorPalette.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { getContrastRatio } from 'colorsheet';

import { updateGame } from '../redux/GamesSlice';
import { useAppDispatch, useAppSelector } from '../redux/hooks';
import { selectPlayerById, updatePlayer } from '../redux/PlayersSlice';
import { selectCurrentGame } from '../redux/selectors';

type PaletteType = Record<string, string[]>;

Expand Down Expand Up @@ -106,23 +102,6 @@ export const getPalette = (name: string): string[] => {
return palettes[name];
};

export const getPlayerColors = (index: number): [string, string] => {
const palette = Object.keys(palettes)[0 % Object.keys(palettes).length];

// TODO: Get player color if it exists

const length = palettes[palette].length;
const bg = palettes[palette][index % length];

const blackContrast = getContrastRatio(bg, '#000').number;
const whiteContrast = getContrastRatio(bg, '#fff').number;

// +1 to give a slight preference to white
const fg = blackContrast >= whiteContrast + 1 ? '#000000' : '#FFFFFF';

return [bg, fg];
};

export const setPlayerColor = (playerId: string, color: string) => {
const dispatch = useAppDispatch();

Expand All @@ -137,16 +116,3 @@ export const setPlayerColor = (playerId: string, color: string) => {
}
}));
};

export const setGamePalette = (gameId: string, palette: string) => {
const dispatch = useAppDispatch();

const game = useAppSelector(selectCurrentGame);
if (typeof game == 'undefined') return;
dispatch(updateGame({
id: game.id,
changes: {
palette: palette,
}
}));
};
3 changes: 0 additions & 3 deletions src/components/Boards/FlexboxBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { SafeAreaView } from 'react-native-safe-area-context';

import { useAppSelector } from '../../../redux/hooks';
import { selectCurrentGame } from '../../../redux/selectors';
import { getPlayerColors } from '../../ColorPalette';
import { bottomSheetHeight } from '../../components/Sheets/GameSheet';

import FlexboxTile from './FlexboxTile';
Expand Down Expand Up @@ -97,8 +96,6 @@ const FlexboxBoard: React.FC<FlexboxBoardProps> = () => {
<FlexboxTile
key={id}
playerId={id}
color={getPlayerColors(index)[0]}
fontColor={getPlayerColors(index)[1]}
cols={cols}
rows={rows}
width={calculateTileDimensions(rows, cols).width}
Expand Down
18 changes: 9 additions & 9 deletions src/components/Boards/FlexboxTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import React from 'react';
import { DimensionValue, StyleSheet } from 'react-native';
import Animated, { Easing, FadeIn } from 'react-native-reanimated';

import { selectPlayerColors } from '../../../redux/GamesSlice';
import { useAppSelector } from '../../../redux/hooks';
import { selectInteractionType } from '../../../redux/selectors';
import { selectCurrentGame, selectInteractionType } from '../../../redux/selectors';
import { interactionComponents } from '../Interactions/InteractionComponents';
import { InteractionType } from '../Interactions/InteractionType';
import AdditionTile from '../PlayerTiles/AdditionTile/AdditionTile';
Expand All @@ -13,8 +14,6 @@ import PlayerIndexLabel from '../PlayerTiles/PlayerIndexLabel';
interface Props {
index: number;
playerId: string;
color: string;
fontColor: string;
cols: number;
rows: number;
width: number;
Expand All @@ -23,8 +22,6 @@ interface Props {

const FlexboxTile: React.FunctionComponent<Props> = ({
index,
color,
fontColor,
width,
height,
cols,
Expand All @@ -35,7 +32,10 @@ const FlexboxTile: React.FunctionComponent<Props> = ({
if (!(width > 0 && height > 0)) return null;
if (Number.isNaN(width) || Number.isNaN(height)) return null;

const currentGameId = useAppSelector(state => selectCurrentGame(state)?.id);
const playerIndexLabel = useAppSelector(state => state.settings.showPlayerIndex);
const playerColors = useAppSelector(state => selectPlayerColors(state, currentGameId || '', index || 0));
const [bg, fg] = playerColors;

const widthPerc: DimensionValue = `${(100 / cols)}%`;
const heightPerc: DimensionValue = `${(100 / rows)}%`;
Expand All @@ -50,16 +50,16 @@ const FlexboxTile: React.FunctionComponent<Props> = ({
style={[
styles.playerCard,
{
backgroundColor: color,
backgroundColor: bg,
width: widthPerc,
height: heightPerc,
borderBottomLeftRadius: playerIndexLabel ? 7 : undefined,
}]}>
<PlayerIndexLabel index={index} fontColor={fontColor} enabled={playerIndexLabel} />
<InteractionComponent index={index} fontColor={fontColor} playerId={playerId}>
<PlayerIndexLabel index={index} fontColor={fg} enabled={playerIndexLabel} />
<InteractionComponent index={index} fontColor={fg} playerId={playerId}>
<AdditionTile
playerId={playerId}
fontColor={fontColor}
fontColor={fg}
maxWidth={width}
maxHeight={height}
index={index}
Expand Down
29 changes: 21 additions & 8 deletions src/components/ColorPalettes/PaletteSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,32 @@ import React from 'react';

import { ScrollView, StyleSheet, TouchableOpacity } from 'react-native';

import { updateGame } from '../../../redux/GamesSlice';
import { useAppDispatch, useAppSelector } from '../../../redux/hooks';
import { selectCurrentGame } from '../../../redux/selectors';
import { getPalette, getPalettes } from '../../ColorPalette';

import PalettePreview from './PalettePreview';

interface Props {
// selectedPalette: ColorPalette;
// onSelect: (palette: ColorPalette) => void;
}

const MemoizedColorCircle = React.memo(PalettePreview);

const PaletteSelector: React.FunctionComponent<Props> = () => {
const PaletteSelector: React.FunctionComponent = () => {
const colorPalettes = getPalettes();
const currentGameId = useAppSelector(state => selectCurrentGame(state)?.id);
const currentPalette = useAppSelector(state => selectCurrentGame(state)?.palette);

const dispatch = useAppDispatch();

if (!currentGameId) return null;

const onSelect = (palette: string) => {
dispatch(updateGame({
id: currentGameId,
changes: {
palette: palette,
}
}));
};

return (
<ScrollView horizontal={true} contentContainerStyle={styles.container}>
Expand All @@ -24,9 +37,9 @@ const PaletteSelector: React.FunctionComponent<Props> = () => {
style={[
styles.palette,
]}
// onPress={() => onSelect(palette)}
onPress={() => onSelect(palette)}
>
<MemoizedColorCircle colors={getPalette(palette)} selected={index == 0} />
<MemoizedColorCircle colors={getPalette(palette)} selected={palette == currentPalette} />
</TouchableOpacity>
))}
</ScrollView>
Expand Down
18 changes: 10 additions & 8 deletions src/components/PlayerListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { Alert, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { Icon, ListItem } from 'react-native-elements';

import { updateGame } from '../../redux/GamesSlice';
import { selectGameById, selectPlayerColors, updateGame } from '../../redux/GamesSlice';
import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import { removePlayer, selectPlayerById } from '../../redux/PlayersSlice';
import { selectCurrentGame } from '../../redux/selectors';
import { getPlayerColors } from '../ColorPalette';

interface Props {
playerId: string;
Expand All @@ -29,10 +28,13 @@ const PlayerListItem: React.FunctionComponent<Props> = ({
navigation,
edit,
}) => {
const currentGame = useAppSelector(selectCurrentGame);
const currentGameId = useAppSelector(state => selectCurrentGame(state)?.id);
const playerIds = useAppSelector(state => selectGameById(state, currentGameId || '')?.playerIds);
const player = useAppSelector(state => selectPlayerById(state, playerId));
const playerColors = useAppSelector(state => selectPlayerColors(state, currentGameId || '', index || 0));

if (typeof currentGame == 'undefined') return null;
if (currentGameId == '' || currentGameId === undefined) return null;
if (playerIds === undefined) return null;
if (typeof index == 'undefined') return null;

const dispatch = useAppDispatch();
Expand Down Expand Up @@ -60,16 +62,16 @@ const PlayerListItem: React.FunctionComponent<Props> = ({
removePlayerHandler();

await analytics().logEvent('remove_player', {
game_id: currentGame.id,
game_id: currentGameId,
player_index: index,
});
};

const removePlayerHandler = () => {
dispatch(updateGame({
id: currentGame.id,
id: currentGameId,
changes: {
playerIds: currentGame.playerIds.filter((id) => id != playerId),
playerIds: playerIds.filter((id) => id != playerId),
}
}));
dispatch(removePlayer(playerId));
Expand Down Expand Up @@ -104,7 +106,7 @@ const PlayerListItem: React.FunctionComponent<Props> = ({

<View style={[
styles.colorBadge,
{ backgroundColor: getPlayerColors(index)[0] }
{ backgroundColor: playerColors[0] }
]} />

<Text style={[styles.input]}>
Expand Down
37 changes: 20 additions & 17 deletions src/components/ScoreLog/PlayerNameColumn.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
import React from 'react';

import { createSelector } from '@reduxjs/toolkit';
import { StyleSheet, Text, View } from 'react-native';
import { Icon } from 'react-native-elements/dist/icons/Icon';

import { selectPlayerColors } from '../../../redux/GamesSlice';
import { useAppSelector } from '../../../redux/hooks';
import { selectPlayerById } from '../../../redux/PlayersSlice';
import { selectCurrentGame } from '../../../redux/selectors';
import { RootState } from '../../../redux/store';
import { getPlayerColors } from '../../ColorPalette';
import { systemBlue } from '../../constants';

const selectPlayerEntities = (state: RootState) => state.players.entities;
interface CellProps {
index: number;
playerId: string;
}

const selectPlayerIds = (_: RootState, playerIds: string[]) => playerIds;
const PlayerNameCell: React.FunctionComponent<CellProps> = ({ index, playerId }) => {
const currentGameId = useAppSelector(state => selectCurrentGame(state)?.id);
const playerColors = useAppSelector(state => selectPlayerColors(state, currentGameId || '', index || 0));
const playerName = useAppSelector(state => selectPlayerById(state, playerId)?.playerName);

const selectPlayerNamesByIds = createSelector(
[selectPlayerEntities, selectPlayerIds],
(players, playerIds) => playerIds.map(id => players[id]?.playerName)
);
return (
<View key={index} style={{ paddingLeft: 5, borderLeftWidth: 5, borderColor: playerColors[0] }}>
<Text key={index} style={{ color: 'white', maxWidth: 100, fontSize: 20, }}
numberOfLines={1}
>{playerName}</Text>
</View>
);
};

const PlayerNameColumn: React.FunctionComponent = () => {
const playerIds = useAppSelector(state => selectCurrentGame(state)?.playerIds) || [];
const playerNames = useAppSelector(state => selectPlayerNamesByIds(state, playerIds));


return (
<View style={{ paddingVertical: 10 }}>
Expand All @@ -33,12 +40,8 @@ const PlayerNameColumn: React.FunctionComponent = () => {
size={19}
color='white' />
</Text>
{playerNames.map((name, index) => (
<View key={index} style={{ paddingLeft: 5, borderLeftWidth: 5, borderColor: getPlayerColors(index)[0] }}>
<Text key={index} style={{ color: 'white', maxWidth: 100, fontSize: 20, }}
numberOfLines={1}
>{name}</Text>
</View>
{playerIds.map((playerId, index) => (
<PlayerNameCell key={index} index={index} playerId={playerId} />
))}
</View>
);
Expand Down

0 comments on commit 9c97a34

Please sign in to comment.