Skip to content

Commit 064b954

Browse files
feat: Add profile screen and various improvements
- Add new Profile screen with user information display - Add Google Sign Out and Revoke Access functionality - Add permissions layout for better organization - Add TypeScript types for react-native-console-view - Add misc utilities for time formatting - Add Gradle wrapper files for Android builds - Update tab layout to include Profile tab - Remove deprecated cellular and location components - Improve debug screen and login functionality - Update various permission demos - Update dependencies in package.json
1 parent 45b4793 commit 064b954

26 files changed

+2130
-511
lines changed

app/(tabs)/_layout.tsx

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import FontAwesome from '@expo/vector-icons/FontAwesome';
2-
import { Link, Tabs } from 'expo-router';
2+
import { Tabs, usePathname, useRouter } from 'expo-router';
33

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

99
export default function TabLayout() {
10+
const pathname = usePathname();
11+
const router = useRouter();
12+
1013
return (
1114
<Tabs
1215
screenOptions={{
@@ -38,10 +41,10 @@ export default function TabLayout() {
3841
}}
3942
/>
4043
<Tabs.Screen
41-
name="cellular"
44+
name="profile"
4245
options={{
43-
title: 'Cellular',
44-
tabBarIcon: ({ color }: { color: string }) => <TabBarIcon name="phone" color={color} />,
46+
title: 'Profile',
47+
tabBarIcon: ({ color }: { color: string }) => <TabBarIcon name="user" color={color} />,
4548
}}
4649
/>
4750
<Tabs.Screen
@@ -50,6 +53,20 @@ export default function TabLayout() {
5053
title: 'Permissions',
5154
tabBarIcon: ({ color }: { color: string }) => <TabBarIcon name="shield" color={color} />,
5255
}}
56+
listeners={{
57+
tabPress: (e: { preventDefault: () => void }) => {
58+
// If already on a permissions sub-page (not the index), navigate to permissions index
59+
const isOnPermissionsSubPage = pathname.startsWith('/permissions/') && pathname !== '/permissions';
60+
const isOnPermissionsIndex = pathname === '/permissions' || pathname === '/(tabs)/permissions';
61+
62+
if (isOnPermissionsSubPage || isOnPermissionsIndex) {
63+
// Prevent default tab behavior
64+
e.preventDefault();
65+
// Navigate to permissions index, replacing the current route to reset the stack
66+
router.replace('/(tabs)/permissions');
67+
}
68+
},
69+
}}
5370
/>
5471
</Tabs>
5572
);

app/(tabs)/cellular.tsx

Lines changed: 0 additions & 37 deletions
This file was deleted.

app/(tabs)/index.tsx

Lines changed: 2 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,11 @@
1-
import { View, Text, Button, ActivityIndicator, StyleSheet, Image, ScrollView } from 'react-native';
2-
import MapView, { Marker } from 'react-native-maps';
1+
import { View, Button, StyleSheet, Image, ScrollView } from 'react-native';
32
import { Link } from 'expo-router';
4-
import { useLocation } from '@/hooks/useLocation';
53
import LogViewer from '@/components/LogViewer';
64
import BatteryInfo from '@/components/BatteryInfo';
7-
import { triggerLocalSampleNotification } from '@/utils/notifications.utils';
8-
import { usePushNotifications } from '@/hooks/usePushNotifications';
95
import CustomHeader from '@/components/CustomHeader';
10-
import { simulateAsyncGlobalError, triggerNativeTestException } from '@/services/errorHandler.service';
116
import * as Sentry from '@sentry/react-native';
127

13-
export default function LocationComponent() {
14-
const { fcmToken } = usePushNotifications();
15-
const { location, address, error, loading, fetchLocation } = useLocation(fcmToken);
16-
17-
const textColor = '#ffffff';
18-
8+
export default function HomeScreen() {
199
return (
2010
<View style={{ flex: 1, backgroundColor: '#000' }}>
2111
<CustomHeader title="Home" showModalButton={true} />
@@ -28,64 +18,6 @@ export default function LocationComponent() {
2818
{/* Battery information */}
2919
<BatteryInfo />
3020

31-
{/* Location / Map */}
32-
{loading ? (
33-
<ActivityIndicator size="large" color="#007AFF" />
34-
) : error ? (
35-
<Text style={[styles.text, { color: textColor }]}>{error}</Text>
36-
) : location && address ? (
37-
<>
38-
<Text style={[styles.text, { color: textColor }]}>
39-
Address: {address.name}, {address.city}, {address.region}, {address.country}
40-
</Text>
41-
<Text style={[styles.text, { color: textColor }]}>
42-
{location.coords.latitude} - {location.coords.longitude}
43-
</Text>
44-
45-
<View style={styles.mapContainer}>
46-
<MapView
47-
style={styles.map}
48-
region={
49-
location
50-
? {
51-
latitude: location.coords.latitude,
52-
longitude: location.coords.longitude,
53-
latitudeDelta: 0.01,
54-
longitudeDelta: 0.01,
55-
}
56-
: {
57-
latitude: 37.7749, // Default to San Francisco
58-
longitude: -122.4194,
59-
latitudeDelta: 0.05,
60-
longitudeDelta: 0.05,
61-
}
62-
}
63-
showsUserLocation={true}
64-
loadingEnabled={true}
65-
>
66-
{location && (
67-
<Marker
68-
coordinate={{
69-
latitude: location.coords.latitude,
70-
longitude: location.coords.longitude,
71-
}}
72-
title="You are here"
73-
/>
74-
)}
75-
</MapView>
76-
</View>
77-
</>
78-
) : (
79-
<Text style={[styles.text, { color: textColor }]}>Waiting for location...</Text>
80-
)}
81-
82-
<Button title="Get Location" onPress={fetchLocation} />
83-
<Button title="Trigger Sample Notification" onPress={triggerLocalSampleNotification} />
84-
<View style={{ height: 12 }} />
85-
<Button title="JS Crash Test (async)" onPress={() => simulateAsyncGlobalError('Manual JS async crash test')} />
86-
<View style={{ height: 8 }} />
87-
<Button color="#d9534f" title="Native Crash Test" onPress={triggerNativeTestException} />
88-
8921
{/* Link to Login page */}
9022
<View style={{ marginTop: 12 }}>
9123
<Link href="/login" asChild>
@@ -108,11 +40,6 @@ const styles = StyleSheet.create({
10840
width: '90%',
10941
alignItems: 'center',
11042
},
111-
text: {
112-
fontSize: 16,
113-
marginVertical: 8,
114-
textAlign: 'center',
115-
},
11643
batteryContainer: {
11744
borderRadius: 8,
11845
padding: 10,
@@ -124,17 +51,6 @@ const styles = StyleSheet.create({
12451
fontSize: 16,
12552
marginBottom: 4,
12653
},
127-
mapContainer: {
128-
width: '100%',
129-
height: 300,
130-
marginTop: 16,
131-
borderRadius: 10,
132-
overflow: 'hidden',
133-
},
134-
map: {
135-
width: '100%',
136-
height: '100%',
137-
},
13854
});
13955

14056
const imgStyles = StyleSheet.create({

app/(tabs)/permissions/_layout.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Stack } from 'expo-router';
2+
3+
export default function PermissionsLayout() {
4+
return (
5+
<Stack
6+
screenOptions={{
7+
headerShown: false,
8+
}}
9+
/>
10+
);
11+
}

app/(tabs)/permissions/index.tsx

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1-
import { Link } from 'expo-router';
1+
import { useRouter } from 'expo-router';
22
import React from 'react';
33
import { View, Text, StyleSheet, ScrollView, Pressable } from 'react-native';
4+
import FontAwesome from '@expo/vector-icons/FontAwesome';
45
import CustomHeader from '@/components/CustomHeader';
56

6-
const routes = [
7-
{ href: '/permissions/location', title: 'Location (foreground/background)' },
8-
{ href: '/permissions/camera-mic', title: 'Camera & Microphone' },
9-
{ href: '/permissions/notifications', title: 'Notifications' },
10-
{ href: '/permissions/media-storage', title: 'Media Library' },
11-
{ href: '/permissions/storage', title: 'Storage & File Access' },
12-
{ href: '/permissions/telephony-sms', title: 'Telephony & SMS' },
13-
{ href: '/permissions/connectivity', title: 'Bluetooth & Nearby' },
7+
const routes: Array<{ href: string; title: string; icon: string; color: string }> = [
8+
{ href: '/permissions/location', title: 'Location (foreground/background)', icon: '📍', color: '#4CAF50' },
9+
{ href: '/permissions/camera-mic', title: 'Camera & Microphone', icon: '📷', color: '#E91E63' },
10+
{ href: '/permissions/notifications', title: 'Notifications', icon: '🔔', color: '#FF9800' },
11+
{ href: '/permissions/media-storage', title: 'Media Library', icon: '🖼️', color: '#9C27B0' },
12+
{ href: '/permissions/storage', title: 'Storage & File Access', icon: '📁', color: '#00BCD4' },
13+
{ href: '/permissions/telephony-sms', title: 'Telephony & SMS', icon: '📱', color: '#F44336' },
14+
{ href: '/permissions/connectivity', title: 'Bluetooth & Nearby', icon: '📶', color: '#3F51B5' },
1415
];
1516

1617
export default function PermissionsHub() {
18+
const router = useRouter();
19+
1720
return (
1821
<View style={styles.container}>
1922
<CustomHeader title="Permissions Hub" />
@@ -24,12 +27,14 @@ export default function PermissionsHub() {
2427
</Text>
2528
{routes.map((route) => (
2629
<View style={styles.card} key={route.href}>
27-
<Text style={styles.cardTitle}>{route.title}</Text>
28-
<Link href={route.href} asChild>
29-
<Pressable style={styles.button}>
30-
<Text style={styles.buttonText}>Open demo</Text>
31-
</Pressable>
32-
</Link>
30+
<Text style={styles.cardTitle}>{route.icon} {route.title}</Text>
31+
<Pressable
32+
style={[styles.button, { backgroundColor: route.color }]}
33+
onPress={() => router.push(route.href as any)}
34+
>
35+
<Text style={styles.buttonText}>Open demo</Text>
36+
<FontAwesome name="chevron-right" size={12} color="#fff" style={styles.buttonArrow} />
37+
</Pressable>
3338
</View>
3439
))}
3540
</ScrollView>
@@ -53,8 +58,12 @@ const styles = StyleSheet.create({
5358
button: {
5459
backgroundColor: '#1e88e5',
5560
paddingVertical: 10,
61+
paddingHorizontal: 16,
5662
borderRadius: 8,
63+
flexDirection: 'row',
5764
alignItems: 'center',
65+
justifyContent: 'center',
5866
},
59-
buttonText: { color: '#fff', fontWeight: '600' },
67+
buttonText: { color: '#fff', fontWeight: '600', fontSize: 14 },
68+
buttonArrow: { marginLeft: 8, marginTop: 2 },
6069
});

0 commit comments

Comments
 (0)