From 03e24a338abcae7a9a80cc35d16298a8e88eb1e8 Mon Sep 17 00:00:00 2001 From: Justin Wyne <1986068+wyne@users.noreply.github.com> Date: Wed, 17 Apr 2024 20:58:04 -0700 Subject: [PATCH 1/3] Haptics on round change --- src/components/Headers/GameHeader.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/components/Headers/GameHeader.tsx b/src/components/Headers/GameHeader.tsx index 39df1c90..b3f960ca 100644 --- a/src/components/Headers/GameHeader.tsx +++ b/src/components/Headers/GameHeader.tsx @@ -3,11 +3,12 @@ import React from 'react'; import analytics from '@react-native-firebase/analytics'; import { ParamListBase } from '@react-navigation/native'; import { NativeStackNavigationProp } from '@react-navigation/native-stack'; -import { Text, StyleSheet, TouchableOpacity } from 'react-native'; +import * as Haptics from 'expo-haptics'; +import { StyleSheet, Text, TouchableOpacity } from 'react-native'; import { Button } from 'react-native-elements'; import { Icon } from 'react-native-elements/dist/icons/Icon'; -import { roundNext, roundPrevious , selectGameById } from '../../../redux/GamesSlice'; +import { roundNext, roundPrevious, selectGameById } from '../../../redux/GamesSlice'; import { useAppDispatch, useAppSelector } from '../../../redux/hooks'; import { systemBlue } from '../../constants'; import AddendButton from '../Buttons/AddendButton'; @@ -83,20 +84,26 @@ const GameHeader: React.FunctionComponent = ({ navigation }) => { const nextRoundHandler = async () => { if (isLastRound && currentGame.locked) return; + Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); + dispatch(roundNext(currentGame.id)); - await analytics().logEvent('round_change', { + analytics().logEvent('round_change', { game_id: currentGameId, source: 'next button', + round: roundCurrent, }); }; const prevRoundHandler = async () => { if (isFirstRound) return; + Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); + dispatch(roundPrevious(currentGame.id)); - await analytics().logEvent('round_change', { + analytics().logEvent('round_change', { game_id: currentGameId, source: 'previous button', + round: roundCurrent, }); }; From 627269a242f9c21e7610d3405d89ab17d7623d7e Mon Sep 17 00:00:00 2001 From: Justin Wyne <1986068+wyne@users.noreply.github.com> Date: Wed, 17 Apr 2024 21:20:11 -0700 Subject: [PATCH 2/3] Show a + plus icon on next round if it's the last one --- src/components/Headers/GameHeader.tsx | 28 ++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/components/Headers/GameHeader.tsx b/src/components/Headers/GameHeader.tsx index b3f960ca..4a25cd3c 100644 --- a/src/components/Headers/GameHeader.tsx +++ b/src/components/Headers/GameHeader.tsx @@ -39,9 +39,10 @@ const PrevRoundButton: React.FunctionComponent = ({ prevRo interface NextRoundButtonProps { nextRoundHandler: () => void; visible: boolean; + showPlus?: boolean; } -const NextRoundButton: React.FunctionComponent = ({ nextRoundHandler, visible }) => { +const NextRoundButton: React.FunctionComponent = ({ nextRoundHandler, visible, showPlus = false }) => { return ( @@ -51,6 +52,19 @@ const NextRoundButton: React.FunctionComponent = ({ nextRo color={systemBlue} style={{ opacity: visible ? 0 : 1 }} /> + {showPlus && + + } ); }; @@ -84,7 +98,12 @@ const GameHeader: React.FunctionComponent = ({ navigation }) => { const nextRoundHandler = async () => { if (isLastRound && currentGame.locked) return; - Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); + if (isLastRound) { + // Stronger haptics if creating a new round + Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); + } else { + Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); + } dispatch(roundNext(currentGame.id)); analytics().logEvent('round_change', { @@ -116,7 +135,10 @@ const GameHeader: React.FunctionComponent = ({ navigation }) => { headerCenter={<> Round {roundCurrent + 1} - + } headerRight={!currentGame.locked && } /> From b36b305018c719cf399a4f5bae89a1e69110c937 Mon Sep 17 00:00:00 2001 From: Justin Wyne <1986068+wyne@users.noreply.github.com> Date: Wed, 17 Apr 2024 21:47:09 -0700 Subject: [PATCH 3/3] Fix game settings page navigation on first create --- src/Navigation.tsx | 2 +- src/components/Buttons/CheckButton.test.tsx | 4 ++-- src/components/Buttons/CheckButton.tsx | 9 ++++----- src/components/Buttons/NewGameButton.tsx | 2 +- src/components/Headers/SettingsHeader.tsx | 2 +- src/components/PopupMenu/AbstractPopupMenu.tsx | 2 +- src/screens/SettingsScreen.tsx | 2 +- 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Navigation.tsx b/src/Navigation.tsx index e31078f8..333cf680 100644 --- a/src/Navigation.tsx +++ b/src/Navigation.tsx @@ -31,7 +31,7 @@ export type RootStackParamList = { List: undefined; Game: undefined; Settings: { - reason?: string; + source?: string; }; AppInfo: undefined; Share: undefined; diff --git a/src/components/Buttons/CheckButton.test.tsx b/src/components/Buttons/CheckButton.test.tsx index 48e8946c..93f0d9dd 100644 --- a/src/components/Buttons/CheckButton.test.tsx +++ b/src/components/Buttons/CheckButton.test.tsx @@ -9,7 +9,7 @@ describe('CheckButton', () => { const navigation = useNavigationMock(); it.skip('should navigate to Game screen when pressed', async () => { - const { getByRole } = render(); + const { getByRole } = render(); const button = getByRole('button'); await waitFor(() => { fireEvent.press(button); @@ -18,7 +18,7 @@ describe('CheckButton', () => { }); it.skip('should navigate back a screen when pressed', async () => { - const { getByRole } = render(); + const { getByRole } = render(); const button = getByRole('button'); await waitFor(() => { fireEvent.press(button); diff --git a/src/components/Buttons/CheckButton.tsx b/src/components/Buttons/CheckButton.tsx index b41c3d64..1dc66100 100644 --- a/src/components/Buttons/CheckButton.tsx +++ b/src/components/Buttons/CheckButton.tsx @@ -11,7 +11,7 @@ import HeaderButton from './HeaderButton'; type RouteParams = { Settings: { - reason?: string; + source?: string; }; }; interface Props { @@ -24,11 +24,10 @@ const CheckButton: React.FunctionComponent = ({ navigation, route }) => { return ( { await analytics().logEvent('save_game'); - if (route?.params?.reason === 'new_game') { - navigation.navigate('Game'); + if (route?.params?.source === 'list_screen') { + navigation.navigate('List'); } else { - //TODO: when the game is first created, this will go back instead of to game screen - navigation.goBack(); + navigation.navigate('Game'); } }}> Done diff --git a/src/components/Buttons/NewGameButton.tsx b/src/components/Buttons/NewGameButton.tsx index 84019b11..1aae589f 100644 --- a/src/components/Buttons/NewGameButton.tsx +++ b/src/components/Buttons/NewGameButton.tsx @@ -35,7 +35,7 @@ const NewGameButton: React.FunctionComponent = ({ navigation }) => { }) ).then(() => { setTimeout(() => { - navigation.navigate('Settings', { reason: 'new_game' }); + navigation.navigate('Settings', { source: 'new_game' }); }, 500); }); }; diff --git a/src/components/Headers/SettingsHeader.tsx b/src/components/Headers/SettingsHeader.tsx index 507a18ea..fa5f65a8 100644 --- a/src/components/Headers/SettingsHeader.tsx +++ b/src/components/Headers/SettingsHeader.tsx @@ -10,7 +10,7 @@ import CustomHeader from './CustomHeader'; type RouteParams = { Settings: { - reason?: string; + source?: string; }; }; diff --git a/src/components/PopupMenu/AbstractPopupMenu.tsx b/src/components/PopupMenu/AbstractPopupMenu.tsx index f8e54ff8..7d7279cb 100644 --- a/src/components/PopupMenu/AbstractPopupMenu.tsx +++ b/src/components/PopupMenu/AbstractPopupMenu.tsx @@ -47,7 +47,7 @@ const AbstractPopupMenu: React.FC = (props) => { */ const editGameHandler = async () => { props.setCurrentGameCallback(); - props.navigation.navigate('Settings', { reason: 'edit_game' }); + props.navigation.navigate('Settings', { source: 'list_screen' }); await analytics().logEvent('menu_edit', { round_count: roundTotal, diff --git a/src/screens/SettingsScreen.tsx b/src/screens/SettingsScreen.tsx index 633ed20c..67ece1b0 100644 --- a/src/screens/SettingsScreen.tsx +++ b/src/screens/SettingsScreen.tsx @@ -20,7 +20,7 @@ import logger from '../Logger'; type RouteParams = { Settings: { - reason?: string; + source?: string; }; };