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
425 changes: 46 additions & 379 deletions pawsense/App.js

Large diffs are not rendered by default.

6 changes: 1 addition & 5 deletions pawsense/AppStyles.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
// styles.js
import { StyleSheet, Dimensions } from 'react-native';

const { width, height } = Dimensions.get('window');


const styles = StyleSheet.create({
container: {
flex: 1,
Expand Down Expand Up @@ -497,7 +493,7 @@ const styles = StyleSheet.create({
borderRadius: 8,
paddingHorizontal: 16,
paddingVertical: 8,
minWidth: (width - 64) / 2 - 4,
minWidth: (Dimensions.get('window').width - 64) / 2 - 4,
alignItems: 'center',
},
commandButtonText: {
Expand Down
62 changes: 62 additions & 0 deletions pawsense/components/Behavior.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { ScrollView, Text, View } from "react-native";
import { Card, Badge } from "./components";
import styles from "../AppStyles";

export default (getBehaviorEmoji, currentBehavior, currentEmotion, predictions) => (
<ScrollView style={styles.tabContent} showsVerticalScrollIndicator={false}>
<Card>
<Text style={styles.cardTitle}>Current Behavior</Text>
<View style={styles.behaviorDisplay}>
<Text style={styles.behaviorEmoji}>{getBehaviorEmoji(currentBehavior)}</Text>
<Text style={styles.behaviorName}>{currentBehavior}</Text>
<Text style={styles.behaviorConfidence}>Confidence: 94%</Text>
<Badge
text={currentEmotion}
style={[styles.currentEmotionBadge, { backgroundColor: '#F3E8FF' }]}
textStyle={{ color: '#7C3AED' }}
/>
</View>
</Card>

<Card>
<Text style={{ fontSize: 20, fontWeight: 'bold', marginBottom: 10 }}>
Activity Predictions
</Text>
{predictions.length > 0 ? (
[...predictions] // create a shallow copy to avoid mutating state directly
.sort((a, b) => {
// extract minutes from timeInfo like "in 123 minutes"
const aMinutes = parseInt(a.timeInfo.match(/in (\d+) minutes/)[1], 10);
const bMinutes = parseInt(b.timeInfo.match(/in (\d+) minutes/)[1], 10);
return aMinutes - bMinutes;
})
.map((pred, idx) => {
const [hour, minute] = pred.time.split(':');

const minutesMatch = pred.timeInfo.match(/in (\d+) minutes/);
let timeInfoFormatted = pred.timeInfo;
if (minutesMatch) {
const totalMinutes = parseInt(minutesMatch[1], 10);
if (totalMinutes >= 60) {
const hrs = Math.floor(totalMinutes / 60);
const mins = totalMinutes % 60;
timeInfoFormatted = `in ${hrs} hour${hrs > 1 ? 's' : ''} ${mins} minute${mins !== 1 ? 's' : ''}`;
}
}

return (
<View
key={idx}
style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 8 }}
>
<Text style={{ flex: 1, fontWeight: '600' }}>{pred.label}</Text>
<Badge text={`${hour}:${minute} (${timeInfoFormatted})`} />
</View>
);
})
) : (
<Text>Loading predictions...</Text>
)}
</Card>
</ScrollView>
);
61 changes: 61 additions & 0 deletions pawsense/components/Dashboard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { ScrollView, Text, View } from "react-native";
import styles from "../AppStyles.js";
import { Card, Badge, ProgressBar } from "./components.jsx";

export default (healthData, clientData, currentEmotion) => (
<ScrollView style={styles.tabContent} showsVerticalScrollIndicator={false}>
<Card style={styles.statusCard}>
<Text style={styles.cardTitle}>Current Status</Text>
<View style={styles.statusGrid}>
<View style={[styles.statusItem, { backgroundColor: '#EFF6FF' }]}>
<Text style={[styles.statusValue, { color: '#2563EB' }]}>{clientData.heart_rate}</Text>
<Text style={[styles.statusLabel, { color: '#2563EB' }]}>BPM</Text>
</View>
<View style={[styles.statusItem, { backgroundColor: '#F0FDF4' }]}>
<Text style={[styles.statusValue, { color: '#16A34A' }]}>{clientData.temperature}°F</Text>
<Text style={[styles.statusLabel, { color: '#16A34A' }]}>Temperature</Text>
</View>
</View>
<View style={styles.activityContainer}>
<Text style={styles.activityLabel}>Activity Level</Text>
<Badge text={`${healthData.activity}%`} style={styles.activityBadge} />
</View>
<ProgressBar progress={healthData.activity} color="#3B82F6" />
</Card>

<Card style={styles.behaviorCard}>
<Text style={styles.cardTitle}>Behavior & Emotion</Text>
<View style={styles.behaviorContent}>
<View style={styles.behaviorInfo}>
<Text style={styles.behaviorText}>{clientData.activity}</Text>
<Text style={styles.behaviorSubtext}>Current Activity</Text>
</View>
<Badge
text={currentEmotion}
style={[styles.emotionBadge, { backgroundColor: '#F3E8FF' }]}
textStyle={{ color: '#7C3AED' }}
/>
</View>
<Text style={styles.timestamp}>
Last updated: {new Date().toLocaleTimeString()}
</Text>
</Card>

<Card style={styles.locationCard}>
<Text style={styles.cardTitle}>Location</Text>
<View style={styles.locationContent}>
<View style={styles.locationInfo}>
<Text style={styles.locationName}>{clientData.context}</Text>
<Text style={styles.locationCoords}>
{clientData.latitude}, {clientData.longitude}
</Text>
</View>
<Badge
text="Safe Zone"
style={[styles.safeBadge, { backgroundColor: '#DCFCE7', borderColor: '#16A34A' }]}
textStyle={{ color: '#16A34A' }}
/>
</View>
</Card>
</ScrollView>
);
63 changes: 63 additions & 0 deletions pawsense/components/Health.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// @ts-check
import { ScrollView, Text, View } from "react-native";
import { Card, ProgressBar } from "./components";
import styles from "../AppStyles";
import { Ionicons } from "@expo/vector-icons";

export default (clientData) => (
<ScrollView style={styles.tabContent} showsVerticalScrollIndicator={false}>
<Card>
<Text style={styles.cardTitle}>Vital Signs</Text>
<View style={styles.vitalSignsGrid}>
<View style={[styles.vitalSignCard, { backgroundColor: '#FEF2F2' }]}>
<View style={styles.vitalSignHeader}>
<Ionicons name="heart" size={16} color="#EF4444" />
<Text style={styles.vitalSignLabel}>Heart Rate</Text>
</View>
<Text style={[styles.vitalSignValue, { color: '#EF4444' }]}>{clientData.heart_rate}</Text>
<Text style={[styles.vitalSignUnit, { color: '#EF4444' }]}>BPM (Normal)</Text>
</View>
<View style={[styles.vitalSignCard, { backgroundColor: '#FFF7ED' }]}>
<View style={styles.vitalSignHeader}>
<Ionicons name="thermometer" size={16} color="#F97316" />
<Text style={styles.vitalSignLabel}>Temperature</Text>
</View>
<Text style={[styles.vitalSignValue, { color: '#F97316' }]}>{clientData.temperature}°F</Text>
<Text style={[styles.vitalSignUnit, { color: '#F97316' }]}>Normal Range</Text>
</View>
</View>
</Card>

<Card>
<Text style={styles.cardTitle}>Daily Activity</Text>
<View style={styles.activityMetric}>
<View style={styles.metricHeader}>
<Text style={styles.metricLabel}>Steps Today</Text>
<Text style={styles.metricValue}>{clientData.steps}</Text>
</View>
<ProgressBar progress={(clientData.steps / 15000) * 100} color="#10B981" />
<Text style={styles.metricGoal}>Goal: 15,000 steps</Text>
</View>
<View style={styles.activityMetric}>
<View style={styles.metricHeader}>
<Text style={styles.metricLabel}>Calories Burned</Text>
<Text style={styles.metricValue}>{clientData.calories}</Text>
</View>
<ProgressBar progress={(clientData.calories / 600) * 100} color="#F59E0B" />
<Text style={styles.metricGoal}>Goal: 600 calories</Text>
</View>
</Card>

<Card>
<Text style={styles.cardTitle}>Health Alerts</Text>
<View style={styles.healthAlert}>
<Text style={[styles.healthAlertTitle, { color: 'red', fontWeight: 'bold' }]}>
⚠️ Health Alert!
</Text>
<Text style={styles.healthAlertText}>
Max has missed his medicine dose today.
</Text>
</View>
</Card>
</ScrollView>
);
55 changes: 55 additions & 0 deletions pawsense/components/Location.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { ScrollView, Text, View } from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { Card, Badge } from "./components";
import styles from "../AppStyles";

export default (clientData, locations) => (
<ScrollView style={styles.tabContent} showsVerticalScrollIndicator={false}>
<Card>
<Text style={styles.cardTitle}>Live Location</Text>
<View style={styles.mapPlaceholder}>
<Ionicons name="location" size={48} color="#EF4444" />
<Text style={styles.mapLocationName}>{clientData.context}</Text>
<Text style={styles.mapLocationCoords}>
{clientData.latitude}, {clientData.longitude}
</Text>
<Badge
text="In Safe Zone"
style={[styles.mapBadge, { backgroundColor: '#DCFCE7' }]}
textStyle={{ color: '#16A34A' }}
/>
</View>
<View style={styles.locationDetails}>
<View style={styles.locationDetailRow}>
<Text style={styles.locationDetailLabel}>Distance from Home</Text>
<Text style={styles.locationDetailValue}>0.3 miles</Text>
</View>
<View style={styles.locationDetailRow}>
<Text style={styles.locationDetailLabel}>Last Movement</Text>
<Text style={styles.locationDetailValue}>2 minutes ago</Text>
</View>
</View>
</Card>

<Card>
<Text style={styles.cardTitle}>Recent Locations</Text>
{locations.map((location, index) => (
<View key={index} style={styles.locationHistoryItem}>
<View style={styles.locationHistoryInfo}>
<Ionicons name="location-outline" size={16} color="#6B7280" />
<View style={styles.locationHistoryText}>
<Text style={styles.locationHistoryName}>{location.name}</Text>
<Text style={styles.locationHistoryTime}>
{Math.floor(Math.random() * 60)} min ago
</Text>
</View>
</View>
<Badge
text={`${Math.floor(Math.random() * 30) + 5} min`}
style={styles.durationBadge}
/>
</View>
))}
</Card>
</ScrollView>
);
70 changes: 70 additions & 0 deletions pawsense/components/Translator.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { ScrollView, Text, View, TouchableOpacity, TextInput } from "react-native";
import { Ionicons } from "@expo/vector-icons";
import styles from "../AppStyles";
import { Card, Badge } from "./components";

export default (translatorInput, setTranslatorInput, handleTranslate, translatorOutput, recentBarks) => (
<ScrollView style={styles.tabContent} showsVerticalScrollIndicator={false}>
<Card>
<Text style={styles.cardTitle}>Two-Way Translator</Text>
<View style={styles.translatorInput}>
<Text style={styles.inputLabel}>Speak to Max:</Text>
<View style={styles.inputContainer}>
<TextInput
style={styles.textInput}
value={translatorInput}
onChangeText={setTranslatorInput}
placeholder="Type your message..."
placeholderTextColor="#9CA3AF"
/>
<TouchableOpacity
style={styles.sendButton}
onPress={handleTranslate}
>
<Ionicons name="send" size={20} color="#FFFFFF" />
</TouchableOpacity>
</View>
</View>
{translatorOutput && (
<View style={styles.translatorResponse}>
<Text style={styles.responseLabel}>Max's Response:</Text>
<Text style={styles.responseText}>{translatorOutput}</Text>
</View>
)}
</Card>

<Card>
<Text style={styles.cardTitle}>Recent Bark Translations</Text>
{recentBarks.map((bark, index) => (
<View key={index} style={styles.barkTranslation}>
<View style={styles.barkHeader}>
<Text style={styles.barkText}>{bark.translation}</Text>
<Badge
text={`${bark.confidence}%`}
style={styles.confidenceBadge}
/>
</View>
<Text style={styles.barkTime}>{bark.time}</Text>
</View>
))}
</Card>

<Card>
<Text style={styles.cardTitle}>Quick Commands</Text>
<View style={styles.quickCommands}>
{['Sit', 'Stay', 'Come', 'Good Boy'].map((command) => (
<TouchableOpacity
key={command}
style={styles.commandButton}
onPress={() => {
setTranslatorInput(command);
handleTranslate();
}}
>
<Text style={styles.commandButtonText}>{command}</Text>
</TouchableOpacity>
))}
</View>
</Card>
</ScrollView>
);
40 changes: 40 additions & 0 deletions pawsense/components/components.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { View, Text, TouchableOpacity } from "react-native";
import { Ionicons } from "@expo/vector-icons";
import styles from "../AppStyles";

export const Card = ({ children, style }) => (
<View style={[styles.card, style]}>
{children}
</View>
);

export const Badge = ({ text, style, textStyle }) => (
<View style={[styles.badge, style]}>
<Text style={[styles.badgeText, textStyle]}>{text}</Text>
</View>
);

export const ProgressBar = ({ progress, color = '#3B82F6', height = 8 }) => (
<View style={[styles.progressContainer, { height }]}>
<View
style={[
styles.progressBar,
{ width: `${progress}%`, backgroundColor: color, height }
]}
/>
</View>
);

export const TabButton = ({ icon, isActive, onPress, label }) => (
<TouchableOpacity
style={[styles.tabButton, isActive && styles.tabButtonActive]}
onPress={onPress}
>
<Ionicons
name={icon}
size={20}
color={isActive ? '#FFFFFF' : '#6B7280'}
/>
{label && <Text style={[styles.tabLabel, isActive && styles.tabLabelActive]}>{label}</Text>}
</TouchableOpacity>
);