Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
268 changes: 268 additions & 0 deletions app/(tabs)/Pet-debug/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
import React from 'react';
import { ScrollView } from 'react-native';
import { YStack, XStack, Text, Button, Separator, H3, Card } from 'tamagui';
import { usePetStateContext } from '@/hooks/usePetState';
import { DiseaseType } from '@/types';
import { DISEASE_KEYS, diseaseData } from '@/constants/diseases';

export default function DebugScreen() {
const {
petState,
isLoading,
survivalDays,
updateStats,
updateMood,
updateActiveSymptom,
updateDeathRiskLevel,
killPet,
revivePet,
setBirthDate,
} = usePetStateContext();

if (isLoading) {
return (
<YStack flex={1} justifyContent="center" alignItems="center" backgroundColor="$background">
<Text>Loading...</Text>
</YStack>
);
}

// パラメータを増減
const adjustStat = (key: DiseaseType, amount: number) => {
updateStats({ [key]: amount });
};

// 全パラメータを特定値に設定
const setAllStatsTo = (value: number) => {
const updates: Partial<Record<DiseaseType, number>> = {};
DISEASE_KEYS.forEach((key) => {
const diff = value - petState.stats[key];
updates[key] = diff;
});
updateStats(updates);
};

// 生存日数を設定
const setSurvivalDays = (days: number) => {
const newBirthDate = new Date();
newBirthDate.setDate(newBirthDate.getDate() - days);
setBirthDate(newBirthDate);
};

return (
<ScrollView style={{ flex: 1, backgroundColor: '#f5f5f5' }}>
<YStack padding="$4" gap="$4" paddingTop={60}>
<H3 textAlign="center">🛠️ デバッグ画面</H3>

{/* 現在の状態表示 */}
<Card elevate bordered padding="$3">
<YStack gap="$2">
<Text fontSize="$6" fontWeight="bold">
📊 現在の状態
</Text>
<Separator />
<XStack justifyContent="space-between">
<Text>生存状態:</Text>
<Text fontWeight="bold" color={petState.isAlive ? '$green10' : '$red10'}>
{petState.isAlive ? '🌟 生存' : '💀 死亡'}
</Text>
</XStack>
<XStack justifyContent="space-between">
<Text>生存日数:</Text>
<Text fontWeight="bold">{survivalDays} 日</Text>
</XStack>
<XStack justifyContent="space-between">
<Text>危険度レベル:</Text>
<Text
fontWeight="bold"
color={
petState.deathRiskLevel === 'safe'
? '$green10'
: petState.deathRiskLevel === 'warning'
? '$yellow10'
: '$red10'
}>
{petState.deathRiskLevel}
</Text>
</XStack>
<XStack justifyContent="space-between">
<Text>機嫌:</Text>
<Text fontWeight="bold">{petState.mood}</Text>
</XStack>
<XStack justifyContent="space-between">
<Text>症状:</Text>
<Text fontWeight="bold" numberOfLines={1}>
{petState.activeSymptom?.text ?? 'なし'}
</Text>
</XStack>
</YStack>
</Card>

{/* 生存日数設定 */}
<Card elevate bordered padding="$3">
<YStack gap="$3">
<Text fontSize="$6" fontWeight="bold">
📅 生存日数設定
</Text>
<Separator />
<XStack gap="$2" flexWrap="wrap">
<Button size="$3" onPress={() => setSurvivalDays(0)}>
0日
</Button>
<Button size="$3" onPress={() => setSurvivalDays(7)}>
7日
</Button>
<Button size="$3" onPress={() => setSurvivalDays(30)}>
30日
</Button>
<Button size="$3" onPress={() => setSurvivalDays(100)}>
100日
</Button>
<Button size="$3" onPress={() => setSurvivalDays(365)}>
365日
</Button>
</XStack>
</YStack>
</Card>

{/* 健康パラメータ */}
<Card elevate bordered padding="$3">
<YStack gap="$3">
<Text fontSize="$6" fontWeight="bold">
💉 健康パラメータ
</Text>
<Separator />
{DISEASE_KEYS.map((key) => (
<YStack key={key} gap="$2">
<XStack justifyContent="space-between" alignItems="center">
<Text flex={1} fontWeight="bold">
{diseaseData[key].name}
</Text>
<Text fontWeight="bold" fontSize="$5" width={50} textAlign="right">
{petState.stats[key]}
</Text>
</XStack>
<XStack gap="$2" justifyContent="space-between">
<Button size="$2" onPress={() => adjustStat(key, -10)}>
-10
</Button>
<Button size="$2" onPress={() => adjustStat(key, -5)}>
-5
</Button>
<Button size="$2" onPress={() => adjustStat(key, -1)}>
-1
</Button>
<Button size="$2" onPress={() => adjustStat(key, 1)}>
+1
</Button>
<Button size="$2" onPress={() => adjustStat(key, 5)}>
+5
</Button>
<Button size="$2" onPress={() => adjustStat(key, 10)}>
+10
</Button>
</XStack>
</YStack>
))}
</YStack>
</Card>

{/* 状態再計算 */}
<Card elevate bordered padding="$3">
<YStack gap="$3">
<Text fontSize="$6" fontWeight="bold">
⚡ 状態を再計算
</Text>
<Separator />

<Button onPress={updateMood}>
<YStack alignItems="center">
<Text fontWeight="bold">🎭 機嫌を再計算</Text>
<Text fontSize="$2" color="$gray10">
updateMood()
</Text>
</YStack>
</Button>

<Button onPress={updateActiveSymptom}>
<YStack alignItems="center">
<Text fontWeight="bold">💬 症状を再計算</Text>
<Text fontSize="$2" color="$gray10">
updateActiveSymptom()
</Text>
</YStack>
</Button>

<Button onPress={updateDeathRiskLevel}>
<YStack alignItems="center">
<Text fontWeight="bold">⚠️ 危険度を再計算</Text>
<Text fontSize="$2" color="$gray10">
updateDeathRiskLevel()
</Text>
</YStack>
</Button>

<Separator />

<XStack gap="$2">
{petState.isAlive ? (
<Button flex={1} backgroundColor="$red10" color="white" onPress={killPet}>
<YStack alignItems="center">
<Text fontWeight="bold" color="white">
💀 ペットを死亡させる
</Text>
<Text fontSize="$2" color="white" opacity={0.7}>
killPet()
</Text>
</YStack>
</Button>
) : (
<Button flex={1} backgroundColor="$green10" color="white" onPress={revivePet}>
<YStack alignItems="center">
<Text fontWeight="bold" color="white">
🌟 ペットを復活させる
</Text>
<Text fontSize="$2" color="white" opacity={0.7}>
revivePet()
</Text>
</YStack>
</Button>
)}
</XStack>
</YStack>
</Card>

{/* パラメータ一括設定 */}
<Card elevate bordered padding="$3">
<YStack gap="$3">
<Text fontSize="$6" fontWeight="bold">
🎛️ プリセット
</Text>
<Separator />
<YStack gap="$2">
<Button size="$4" onPress={() => setAllStatsTo(0)}>
🌈 全パラメータを 0 にリセット
</Button>
<Button size="$4" onPress={() => setAllStatsTo(25)}>
💚 全パラメータを 25 に設定
</Button>
<Button size="$4" onPress={() => setAllStatsTo(50)}>
⚠️ 全パラメータを 50 に設定
</Button>
<Button size="$4" onPress={() => setAllStatsTo(75)}>
🔶 全パラメータを 75 に設定
</Button>
<Button size="$4" backgroundColor="$red10" onPress={() => setAllStatsTo(100)}>
<Text color="white" fontWeight="bold">
☠️ 全パラメータを 100 に設定(最大)
</Text>
</Button>
</YStack>
</YStack>
</Card>

<YStack height={100} />
</YStack>
</ScrollView>
);
}
10 changes: 8 additions & 2 deletions app/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Tabs } from 'expo-router';
import React from 'react';
import { useTheme } from 'tamagui';
import { Home, Footprints, ActivitySquare } from '@tamagui/lucide-icons';
import { Home, Footprints, ActivitySquare, Bug } from '@tamagui/lucide-icons';

import { HapticTab } from '@/components/haptic-tab';

Expand Down Expand Up @@ -40,7 +40,13 @@ export default function TabLayout() {
tabBarIcon: ({ color }) => <ActivitySquare size={28} color={color} />,
}}
/>
r
<Tabs.Screen
name="Pet-debug"
options={{
title: 'Debug',
tabBarIcon: ({ color }) => <Bug size={28} color={color} />,
}}
/>
</Tabs>
);
}
32 changes: 31 additions & 1 deletion app/(tabs)/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import { useWindowDimensions } from 'react-native';
import { ZStack, YStack, useTheme, Text, XStack } from 'tamagui';
import { YStack, useTheme, Text, XStack } from 'tamagui';
import Svg, { Path } from 'react-native-svg';
import LottieView from 'lottie-react-native';
import { LinearGradient } from '@tamagui/linear-gradient';
Expand All @@ -9,9 +9,21 @@ import { MaterialCommunityIcons } from '@expo/vector-icons';
import { PetSurvivalDays } from '@/components/PetSurvivalDays';
import { PetNameEditModal } from '@/components/PetName/PetNameEditModal';
import { usePetName } from '@/hooks/usePetName';
import { usePetStateContext } from '@/hooks/usePetState';
import { SpeechBubble } from '@/components/speech-bubble';
import { Modal } from '@/components/modal';
import { Symptom } from '@/types';

import BootCameraButton from '@/components/BootCameraButton';

// デフォルトの健康メッセージ
const DEFAULT_SYMPTOM: Symptom = {
id: 'healthy',
text: '今日も元気!',
tipsTitle: '健康状態',
tipsContent: 'ペットはとても元気です!この調子で健康的な食生活を続けましょう。',
};

/**
* 曲線の地面を描画するコンポーネント
* @param color
Expand All @@ -38,7 +50,12 @@ const CurveGround = ({ color, height }: { color: string; height: number }) => {
export default function WorldScreen() {
const theme = useTheme();
const { petName, updatePetName } = usePetName();
const { petState } = usePetStateContext();
const [isNameModalVisible, setIsNameModalVisible] = useState(false);
const [isTipsModalOpen, setIsTipsModalOpen] = useState(false);

// 現在の症状(activeSymptomがなければデフォルト)
const currentSymptom = petState.activeSymptom ?? DEFAULT_SYMPTOM;

const groundColor = theme.background.get();

Expand Down Expand Up @@ -126,6 +143,19 @@ export default function WorldScreen() {

<BootCameraButton />

{/* 吹き出し */}
<YStack position="absolute" top={230} left={0} right={0} alignItems="center" zIndex={15}>
<SpeechBubble symptom={currentSymptom} onPress={() => setIsTipsModalOpen(true)} />
</YStack>

{/* Tips モーダル */}
<Modal
open={isTipsModalOpen}
onOpenChange={setIsTipsModalOpen}
tipsTitle={currentSymptom.tipsTitle}
tipsContent={currentSymptom.tipsContent}
/>

<CurveGround color={groundColor} height={GROUND_HEIGHT} />
</YStack>
);
Expand Down
9 changes: 4 additions & 5 deletions components/speech-bubble.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import React from 'react';
import { YStack, Text, useTheme } from 'tamagui';
import { YStack, Text } from 'tamagui';
import { Symptom } from '@/types';

type Props = {
symptom: Symptom;
onPress?: () => void;
};

// 統一された色設定
const BUBBLE_BACKGROUND = '$color5'; // 優しいクリーム色

export const SpeechBubble: React.FC<Props> = ({ symptom }) => {
const theme = useTheme();
const backgroundColor = theme.background.val;

export const SpeechBubble: React.FC<Props> = ({ symptom, onPress }) => {
const handlePress = () => {
console.log(symptom.tipsTitle, symptom.tipsContent);
onPress?.();
};

return (
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"react-native-reanimated": "~4.1.1",
"react-native-safe-area-context": "~5.6.0",
"react-native-screens": "~4.16.0",
"react-native-svg": "^15.15.0",
"react-native-svg": "15.12.1",
"react-native-web": "~0.21.0",
"react-native-worklets": "0.5.1",
"tamagui": "^1.138.6"
Expand Down