# Project export: Guardian Angel

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 11.0
- Tagline: Guardian Angel, always by your side.
- Devpost: https://devpost.com/software/guardian-angel-op49t2
- GitHub: https://github.com/ArianaJohnson/cal-hacks-2024
- Result: winner (Google: Most impactful app)
- Team: 4 GitHub contributor(s) — Theodore (41 commits), chanelle (17 commits), Sean Wang (6 commits), Ariana Johnson (4 commits)

## Devpost submission (written by the team)

### Inspiration

Guardian Angel was born from the need for reliable emergency assistance in an unpredictable world. Our experiences with the elderly, such as our grandparents, who may fall when we’re not around, and the challenges we may face in vulnerable situations motivated us to create a tool that automatically reaches out for help when it’s needed most. We aimed to empower individuals to feel safe and secure, knowing that assistance is just a call away, even in their most vulnerable moments.

### What it does

Core to Guardian Angel, our life-saving Emergency Reporter AI speech app, is an LLM and text-to-speech pipeline that provides real-time, situation-critical responses to 911 dispatchers. The app automatically detects distress signals—such as falls or other emergencies—and contacts dispatch services on behalf of the user, relaying essential information like patient biometric data, medical history, current state, and location. By integrating these features, Guardian Angel enhances efficiency and improves success in time-sensitive situations where rapid, accurate responses are crucial.

### How we built it

We developed Guardian Angel using React Native with Expo, leveraging Python and TypeScript for enhanced code quality. The backend is powered by FastAPI, allowing for efficient data handling. We integrated AI technologies, including Google Gemini for voice transcription and Deepgram for audio processing, which enhances our app’s ability to communicate effectively with dispatch services.

### Challenges we ran into

Our team faced several challenges during development, including difficulties with database integration and frontend design. Many team members were new to React Native, leading to styling and compatibility issues. Additionally, figuring out how to implement functions in the API for text-to-speech and speech-to-text during phone calls required significant troubleshooting.

### Accomplishments we're proud of

We are proud of several milestones achieved during this project. First, we successfully integrated a unique aesthetic into our UI by incorporating hand-drawn elements, which sets our app apart and creates a friendly, approachable user experience. Additionally, we reached a significant milestone in audio processing by effectively transcribing audio input using the Gemini model, allowing us to capture user commands accurately, and converting the transcribed text back to voice with Deepgram for seamless communication with dispatch. We’re also excited to share that our members have only built websites, making the experience of crafting an app and witnessing the fruits of our labor even more rewarding. It’s been exciting to acquire and apply new tools throughout this project, diving into various aspects of transforming our idea into a scalable application—from designing and learning UI/UX to implementing the React Native framework, emulating iOS and Android devices for testing compatibility, and establishing communication between the frontend and backend/database.

### What we learned

Through this hackathon, our team learned the importance of effective collaboration, utilizing a “divide and conquer” approach while keeping each other updated on our progress. We gained hands-on experience in mobile app development, transitioning from our previous focus on web development, and explored new tools and technologies essential for creating a scalable application.

### What's next

Looking ahead, we plan to enhance Guardian Angel by integrating features such as smartwatch compatibility for monitoring vital signs like heart rate and improving fall detection accuracy. We aim to refine our GPS location services for better tracking and continue optimizing our AI speech models for enhanced performance. Additionally, we’re exploring the potential for spatial awareness and microphone access to record surroundings during emergencies, further improving our response capabilities.

## README (from the GitHub repository)

# Guardian Angel 🚨 (2024 Cal-Hacks)
## AI-Powered Emergency Reporter & Real-Time Speech Assistant

Guardian Angel is a life-saving emergency reporting application designed to assist 911 dispatchers during time-critical situations. When a user is unable to communicate, Guardian Angel automatically detects distress signals—such as falls or medical emergencies—and speaks on the user’s behalf using an AI-driven speech and language pipeline.

The system delivers accurate, structured, and context-aware emergency information in real time, improving response efficiency and outcomes when seconds matter.

---

## What Guardian Angel Does

Guardian Angel acts as an intelligent intermediary between the user and emergency dispatch services.

It:
- Detects emergency situations automatically or via manual trigger
- Captures and processes live audio
- Uses an LLM to understand the situation
- Generates clear, dispatcher-ready speech
- Relays critical data such as:
  - Biometric readings
  - Medical history
  - Current physical state
  - Real-time location

---

## System Overview
guardian-angel/
│
├── mobile/ # React Native + Expo app
│ ├── app/
│ ├── components/
│ └── ...
│
├── backend/ # FastAPI backend
│ ├── main.py
│ ├── requirements.txt
│ └── ...

---

## Tech Stack

### Frontend
- React Native
- Expo
- TypeScript

### Backend
- FastAPI (Python)
- REST-based architecture

### AI & Audio
- Google Gemini for transcription and LLM reasoning
- Deepgram for audio processing and speech synthesis

---


---

## How to Run Guardian Angel Locally

### Prerequisites

You will need:
- Node.js (v18 or higher)
- Python (v3.10 or higher)
- Expo CLI
- Git

---

### Step 1 — Clone the Repository

```bash
git clone https://github.com/your-org/guardian-angel.git
cd guardian-angel

cd mobile
npm install

Create a .env file in the mobile/ directory:

EXPO_PUBLIC_API_URL=http://localhost:8000


Start the Expo development server:

npx expo start


Run the app using:

iOS Simulator

Android Emulator

Physical device via Expo Go

Step 3 — Backend Setup (FastAPI)
cd backend
python -m venv venv
source venv/bin/activate        # macOS/Linux
venv\Scripts\activate          # Windows
pip install -r requirements.txt


Create a .env file in the backend/ directory:

GEMINI_API_KEY=your_gemini_api_key
DEEPGRAM_API_KEY=your_deepgram_api_key


Start the backend server:

uvicorn main:app --reload

The API will be available at:

http://localhost:8000




## Detected evidence (automated analysis)

Indexed codebase: 30 recognized source files, 50 KB.
- FastAPI (technology) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- TypeScript (language) — detected in the code
- Google Gemini (technology) — claimed on Devpost, not found in the code
- Node.js (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (41 of 41)

```
.gitignore
.idea/.gitignore
.idea/cal-hacks-2024.iml
.idea/misc.xml
.idea/modules.xml
.idea/vcs.xml
fastapi-backend/app.py
fastapi-backend/deepgram_prompter.py
fastapi-backend/deprecated_gemini_prompter.py
fastapi-backend/gemini_fastapi.py
fastapi-backend/maps_fastapi.py
fastapi-backend/models.py
package.json
react-native-frontend/app/.gitignore
react-native-frontend/app/app.json
react-native-frontend/app/app/_layout.tsx
react-native-frontend/app/app/(tabs)/_layout.tsx
react-native-frontend/app/app/(tabs)/emergency-response.tsx
react-native-frontend/app/app/(tabs)/index.tsx
react-native-frontend/app/app/(tabs)/ip_str.tsx
react-native-frontend/app/app/(tabs)/user-information.tsx
react-native-frontend/app/app/+html.tsx
react-native-frontend/app/app/+not-found.tsx
react-native-frontend/app/app/modal.tsx
react-native-frontend/app/babel.config.js
react-native-frontend/app/components/__tests__/StyledText-test.js
react-native-frontend/app/components/EditScreenInfo.tsx
react-native-frontend/app/components/ExternalLink.tsx
react-native-frontend/app/components/StyledText.tsx
react-native-frontend/app/components/Themed.tsx
react-native-frontend/app/components/useClientOnlyValue.ts
react-native-frontend/app/components/useClientOnlyValue.web.ts
react-native-frontend/app/components/useColorScheme.ts
react-native-frontend/app/components/useColorScheme.web.ts
react-native-frontend/app/constants/Colors.ts
react-native-frontend/app/npm
react-native-frontend/app/npx
react-native-frontend/app/package.json
react-native-frontend/app/tsconfig.json
README.md
requirements.txt
```

### Dependencies

- package.json: @expo-google-fonts/newsreader@^0.2.3, expo-font@^12.0.10, react-native-gesture-handler@^2.20.0
- react-native-frontend/app/package.json: @babel/core@^7.20.0, @expo/ngrok@^4.1.3, @expo/vector-icons@^14.0.2, @react-navigation/native@^6.0.2, @types/react@~18.2.45, axios@^1.7.7, expo@~51.0.28, expo-av@^14.0.7, expo-font@~12.0.9, expo-linking@~6.3.1, expo-permissions@^14.4.0, expo-router@~3.5.23, expo-sensors@~13.0.9, expo-splash-screen@~0.27.5, expo-status-bar@~1.12.1, expo-system-ui@~3.0.7, expo-web-browser@~13.0.3, jest@^29.2.1, jest-expo@~51.0.3, react@18.2.0, react-dom@18.2.0, react-native@0.74.5, react-native-permissions@^5.0.1, react-native-reanimated@~3.10.1, react-native-safe-area-context@4.10.5, react-native-screens@3.31.1, react-native-web@~0.19.10, react-test-renderer@18.2.0, typescript@~5.3.3
- requirements.txt: fastapi@>=0.1.0rc1, google-generativeai@>=0.1.0rc1

### Recent commits (newest first)

- Revise title in README.md
- Update README.md
- Update README.md
- Update README.md
- Update README.md
- fix
- Merge pull request #12 from ArianaJohnson/adad
- Merge branch 'main' into adad
- da
- d
- Merge remote-tracking branch 'origin/main'
- Pipline
- Added pipline
- Index file integration
- edit
- Merge pull request #11 from ArianaJohnson/bruh
- Merge branch 'main' of https://github.com/ArianaJohnson/cal-hacks-2024
- install packages for accelerometer
- tab bar
- Merge pull request #10 from ArianaJohnson/steve

## Key source files (fetched from GitHub, selected and truncated for size)

### requirements.txt

```
google-generativeai>=0.1.0rc1
fastapi>=0.1.0rc1

```

### package.json

```
{
  "dependencies": {
    "@expo-google-fonts/newsreader": "^0.2.3",
    "expo-font": "^12.0.10",
    "react-native-gesture-handler": "^2.20.0"
  }
}

```

### react-native-frontend/app/package.json

```
{
  "name": "app",
  "main": "expo-router/entry",
  "version": "1.0.0",
  "scripts": {
    "start": "expo start --tunnel",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "test": "jest --watchAll"
  },
  "jest": {
    "preset": "jest-expo"
  },
  "dependencies": {
    "@expo/ngrok": "^4.1.3",
    "@expo/vector-icons": "^14.0.2",
    "@react-navigation/native": "^6.0.2",
    "axios": "^1.7.7",
    "expo": "~51.0.28",
    "expo-av": "^14.0.7",
    "expo-font": "~12.0.9",
    "expo-linking": "~6.3.1",
    "expo-permissions": "^14.4.0",
    "expo-router": "~3.5.23",
    "expo-splash-screen": "~0.27.5",
    "expo-status-bar": "~1.12.1",
    "expo-system-ui": "~3.0.7",
    "expo-web-browser": "~13.0.3",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-native": "0.74.5",
    "react-native-permissions": "^5.0.1",
    "react-native-reanimated": "~3.10.1",
    "react-native-safe-area-context": "4.10.5",
    "react-native-screens": "3.31.1",
    "react-native-web": "~0.19.10",
    "expo-sensors": "~13.0.9"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "@types/react": "~18.2.45",
    "jest": "^29.2.1",
    "jest-expo": "~51.0.3",
    "react-test-renderer": "18.2.0",
    "typescript": "~5.3.3"
  },
  "private": true
}

```

### fastapi-backend/app.py

```python
from fastapi import FastAPI, HTTPException
from typing import List, Optional
from uuid import uuid4, UUID
import psycopg2
from psycopg2 import sql, Error
from models import *

# adding the components we made
from maps_fastapi import router as maps_router
from gemini_fastapi import router as gemini_router
from deepgram_prompter import router as deepgram_router
app = FastAPI()
# include the apis defined for gemini in another py
app.include_router(gemini_router)
app.include_router(deepgram_router)




app = FastAPI()
# include the apis defined for gemini in another py
app.include_router(gemini_router)
app.include_router(maps_router)

# Database connection settings
DB_CONFIG = {
    "host": "your_postgres_host",
    "database": "medical_info_db",
    "user": "your_username",
    "password": "your_password",
}

# Helper function to get a database connection
def get_db_connection():
    return psycopg2.connect(**DB_CONFIG)

@app.post("/patients/", response_model=Patient)
async def create_patient(patient: Patient):
    query = """
    INSERT INTO patients (id, name, age, emergency_contact, medical_conditions, allergies, medications)
    VALUES (%s, %s, %s, %s, %s, %s, %s)
    RETURNING id
    """
    params = (
        str(uuid4()),  # Generate new UUID
        patient.name,
        patient.age,
        f"{patient.emergency_contact.name};{patient.emergency_contact.phone}",
        ', '.join(patient.medical_info.medical_conditions),
        ', '.join(patient.medical_info.allergies) if patient.medical_info.allergies else None,
        ', '.join(patient.medical_info.medications) if patient.medical_info.medications else None
    )

    try:
        with get_db_connection() as conn:
            with conn.cursor() as cursor:
                cursor.execute(query, params)
                patient.id = params[0]  # Assign generated UUID
                conn.commit()
                return patient
    except Error as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/patients/{patient_id}", response_model=Patient)
async def get_patient(patient_id: UUID):
    query = "SELECT * FROM patients WHERE id = %s"
    try:
        with get_db_connection() as conn:
            with conn.cursor() as cursor:
                cursor.execute(query, (str(patient_id),))
                row = cursor.fetchone()
                if row is None:
                    raise HTTPException(status_code=404, detail="Patient not found")
                return Patient(
                    id=row[0],
                    name=row[1],
                    age=row[2],
                    emergency_contact=EmergencyContact(*row[3].split(';')),
                    medical_info=MedicalInfo(
                        medical_conditions=row[4].split(', '),
                        allergies=row[5].split(', ') if row[5] else None,
                        medications=row[6].split(', ') if row[6] else None
                    )
                )
    except Error as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/patients/", response_model=List[Patient])
async def get_all_patients():
    query = "SELECT * FROM patients"
    try:
        with get_db_connection() as conn:
            with conn.cursor() as cursor:
                cursor.execute(query)
                rows = cursor.fetchall()
                return [
                    Patient(
                        id=row[0],
                        name=row[1],
                        age=row[2],
                        emergency_contact=EmergencyContact(*row[3].split(';')),
                        medical_info=MedicalInfo(
                            medical_conditions=row[4].split(', '),
                            allergies=row[5].split(', ') if row[5] else None,
                            medications=row[6].split(', ') if row[6] else None
                        )
                    ) for row in rows
                ]
    except Error as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.put("/patients/{patient_id}", response_model=Patient)
async def update_patient(patient_id: UUID, updated_patient: Patient):
    query = """
    UPDATE patients
    SET name = %s, age = %s, emergency_contact = %s, medical_conditions = %s,
        allergies = %s, medications = %s
    WHERE id = %s
    """
    params = (
        updated_patient.name,
        updated_patient.age,
        f"{updated_patient.emergency_contact.name};{updated_patient.emergency_contact.phone}",
        ', '.join(updated_patient.medical_info.medical_conditions),
        ', '.join(updated_patient.medical_info.allergies) if updated_patient.medical_info.allergies else None,
        ', '.join(updated_patient.medical_info.medications) if updated_patient.medical_info.medications else None,
        str(patient_id)
    )
    try:
        with get_db_connection() as conn:
            with conn.cursor() as cursor:
                cursor.execute(query, params)
                conn.commit()
                if cursor.rowcount == 0:
                    raise HTTPException(status_code=404, detail="Patient not found")
                return updated_patient
    except Error as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.delete("/patients/{patient_id}", response_model=dict)
async def delete_patient(patient_id: UUID):
    query = "DELETE FROM patients WHERE id = %s"
    try:
        with get_db_connection() as conn:
            with conn.cursor() as cursor:
                cursor.execute(query, (str(patient_id),))
                conn.commit()
                if cursor.rowcount == 0:
                    raise HTTPException(status_code=404, detail="Patient not found")
                return {"message": "Patient deleted successfully"}
    except Error as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.post("/dispatch/", response_model=dict)
async def dispatch_request(dispatch: DispatchRequest):
    # Logic to handle the dispatch
    print(f"Dispat
[truncated — 309 more characters]
```

### react-native-frontend/app/app/_layout.tsx

```typescript
import FontAwesome from '@expo/vector-icons/FontAwesome';
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
import { useFonts } from 'expo-font';
import { Stack } from 'expo-router';
import * as SplashScreen from 'expo-splash-screen';
import { useEffect } from 'react';
import 'react-native-reanimated';

import { useColorScheme } from '@/components/useColorScheme';

export {
  // Catch any errors thrown by the Layout component.
  ErrorBoundary,
} from 'expo-router';

export const unstable_settings = {
  // Ensure that reloading on `/modal` keeps a back button present.
  initialRouteName: '(tabs)',
};

// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();

export default function RootLayout() {
  const [loaded, error] = useFonts({
    NewsReader: require('../assets/fonts/NewsReader.ttf'),
    ...FontAwesome.font,
  });

  // Expo Router uses Error Boundaries to catch errors in the navigation tree.
  useEffect(() => {
    if (error) throw error;
  }, [error]);

  useEffect(() => {
    if (loaded) {
      SplashScreen.hideAsync();
    }
  }, [loaded]);

  if (!loaded) {
    return null;
  }

  return <RootLayoutNav />;
}

function RootLayoutNav() {
  const colorScheme = useColorScheme();

  return (
    <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
      <Stack>
        <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
        <Stack.Screen name="modal" options={{ presentation: 'modal' }} />
      </Stack>
    </ThemeProvider>
  );
}

```

### react-native-frontend/app/app/(tabs)/_layout.tsx

```typescript
import React from 'react';
import FontAwesome from '@expo/vector-icons/FontAwesome';
import { Link, Tabs } from 'expo-router';
import { Pressable } from 'react-native';

import Colors from '@/constants/Colors';
import { useColorScheme } from '@/components/useColorScheme';
import { useClientOnlyValue } from '@/components/useClientOnlyValue';

// You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/
function TabBarIcon(props: {
  name: React.ComponentProps<typeof FontAwesome>['name'];
  color: string;
}) {
  return <FontAwesome size={28} style={{ marginBottom: -3 }} {...props} />;
}

export default function TabLayout() {
  const colorScheme = useColorScheme();

  return (
    <Tabs
      screenOptions={{
        tabBarActiveTintColor: 'black',
        tabBarStyle: { backgroundColor: '#E6F7FF' },
        // Disable the static render of the header on web
        // to prevent a hydration error in React Navigation v6.
        headerShown: useClientOnlyValue(false, true),
      }}>
      <Tabs.Screen
        name="index"
        options={{
          title: 'home',
          tabBarIcon: ({ color }) => <TabBarIcon name="home" color={color} />,
          
          headerRight: () => (
            <Link href="/modal" asChild>
              <Pressable>
                {({ pressed }) => (
                  <FontAwesome
                    name="info-circle"
                    size={25}
                    color={Colors[colorScheme ?? 'light'].text}
                    style={{ marginRight: 15, opacity: pressed ? 0.5 : 1 }}
                  />
                )}
              </Pressable>
            </Link>
          ),
        }}
      />
      <Tabs.Screen
        name="user-information"
        options={{
          title: 'User Information',
          tabBarIcon: ({ color }) => <TabBarIcon name="gears" color={color} />,
        }}
      />
    </Tabs>
  );
}

```

### react-native-frontend/app/app/(tabs)/index.tsx

```typescript
import React, { useState, useRef, useEffect } from 'react';
import { View, Text, Pressable, StyleSheet, Alert, PanResponder, Animated, Image } from 'react-native';
import Colors from '@/constants/Colors';
import { useColorScheme } from '@/components/useColorScheme';
import { useNavigation } from '@react-navigation/native';
import * as Permissions from "expo-permissions";
import { Audio } from 'expo-av';
import axios from 'axios';


export default function TabOneScreen() {
  const colorScheme = useColorScheme();
  const permission = await requestMicrophonePermission();
  const [isCalling, setIsCalling] = useState(false);
  const slideValue = useRef(new Animated.Value(0)).current; // Create a ref for animated value
  const [timer, setTimer] = useState(5);
  const buttonWidth = 250; // Width of the emergency button
  const navigation = useNavigation();

// Get the navigation object



  const panResponder = useRef(
    PanResponder.create({
      onMoveShouldSetPanResponder: (_, gestureState) => {
        return gestureState.dx > 20; // Start sliding when dragged right more than 20 pixels
      },
      onPanResponderMove: (_, gestureState) => {
        // Update the animated value based on gesture movement
        const newValue = Math.min(buttonWidth, gestureState.dx); // Limit sliding to button width
        slideValue.setValue(newValue); // Set the value of the animated variable
      },
      onPanResponderRelease: async () => {
        // Slide is sufficient to cancel
        if (slideValue.__getValue() >= buttonWidth / 2) {
          Alert.alert('Call Cancelled', 'The emergency call has been cancelled.');
          setIsCalling(false);
          slideValue.setValue(0); // Reset slide position
        } else {
          // If not sufficiently slid, reset the position
          slideValue.setValue(0);
        }
      },
    })
  ).current;


    const handleEmergencyPress = async () => {
    await requestMicrophonePermission();
    const { status } = await Permissions.askAsync(Permissions.AUDIO_RECORDING);
    if (status !== 'granted') {
      Alert.alert('Microphone Permission', 'Sorry, we need microphone permissions to make this work!');
    }
  }


  async function startRecording() {
    try {
      const { recording } = await Audio.Recording.createAsync({
        android: {
          extension: '.wav',
          outputFormat: Audio.RecordingOptionsAndroid.OutputFormat.DEFAULT,
          encoding: Audio.RecordingOptionsAndroid.Encoding.PCM_16BIT,
          sampleRate: 16000,
          numberOfChannels: 1,
        },
      });
      setRecording(recording);
      return true;
    } catch (error) {
      console.error('Failed to start recording', error);
      return false;
    }
  }

  async function stopRecording() {
    if (recording) {
      await recording.stopAndUnloadAsync();
      const uri = recording.getURI();
      console.log('Recording stopped and stored at', uri);
      await sendAudioToDispatch(xuri);
      setRecording(null);
    }
  }

  async function sendAudioToDispatch(uri: string | null) {
    if (!uri) {
      console.error('No URI provided for audio');
      return;
    }

    const formData = new FormData();

    formData.append('audio', {
      uri,
      name: 'audio.wav',
      type: 'audio/wav',
    } as any); // Cast to any if TypeScript is giving an error

    try {
      const response = await axios.post('http://10.42.159.255:8000/dispatch/', formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
      });

      if (response.status === 200) {
        Alert.alert('Success', 'Your audio has been sent to emergency services.');
      } else {
        console.error('Failed to dispatch audio', response.data);
        Alert.alert('Error', 'Failed to send audio to emergency services.');
      }
    } catch (error) {
      console.error('Error sending audio to API', error);
      Alert.alert('Error', 'An error occurred while sending audio.');
    }
  }
    return (
    <View style={[styles.container, { backgroundColor: Colors[colorScheme].background }]}>
      <Image
        source={require('./guardian_angels_bear.png')}  // Path to the local image
        style={styles.image}
      />
      <Text style={[styles.appName, { color: Colors[colorScheme].text }]}>guardian angel</Text>

      <View
        style={[styles.emergencyButtonContainer, { backgroundColor: Colors[colorScheme].tint }]}
        {...panResponder.panHandlers}
      >
        <Animated.View
          style={[
            styles.emergencyButton,
            { transform: [{ translateX: slideValue }] }, // Apply slide value to the button's x position
          ]}
        >
          <Pressable onPress={handleEmergencyPress}>
            <Text style={styles.buttonText}>Emergency Call</Text>
          </Pressable>
        </Animated.View>
      </View>

      {isCalling && (
        <View>
          <Text style={[styles.timerText, { color: Colors[colorScheme].text }]}>
            Calling in {timer}...
          </Text>
          <Text style={[styles.cancelText, { color: Colors[colorScheme].text }]}>
            Slide to Cancel
          </Text>
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  panicImage: {
    width: 200,
    height: 200,
    resizeMode: 'contain',
  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  appName: {
    fontSize: 28,
    fontWeight: 'bold',
    marginBottom: 40,
  },
  emergencyButtonContainer: {
    width: 250,
    height: 60,
    borderRadius: 10,
    overflow: 'hidden', // Ensures that the button doesn't overflow the container
    position: 'relative', // Allows for absolute positioning of the button
    justifyContent: 'center',
  },
  emergencyButton: {
    width: '100%',
    height: '100%',
    justifyContent: 'center',
    alignItems: 'center',
    borderRadius: 10,
    backgroundColor: 'blue', // Change the color if needed
  },
  buttonText: {
    fontSiz
[truncated — 211 more characters]
```

### .idea/vcs.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="VcsDirectoryMappings">
    <mapping directory="" vcs="Git" />
  </component>
</project>
```

### .idea/modules.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ProjectModuleManager">
    <modules>
      <module fileurl="file://$PROJECT_DIR$/.idea/cal-hacks-2024.iml" filepath="$PROJECT_DIR$/.idea/cal-hacks-2024.iml" />
    </modules>
  </component>
</project>
```

### .idea/misc.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="Black">
    <option name="sdkName" value="Python 3.11 (cal-hacks-2024)" />
  </component>
  <component name="ProjectRootManager" version="2" languageLevel="JDK_20" default="true" project-jdk-name="20" project-jdk-type="JavaSDK">
    <output url="file://$PROJECT_DIR$/out" />
  </component>
</project>
```

[22 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]