From 520b5a0916023bf10fd3fcfd53cc280d222f71a6 Mon Sep 17 00:00:00 2001 From: Mekan1206 Date: Tue, 2 Jun 2026 12:54:28 +0500 Subject: [PATCH] change design --- src/app/index.tsx | 379 +++++++++++++++++++++++++----------- src/app/settings.tsx | 205 ++++++++++++------- src/components/app-tabs.tsx | 22 ++- 3 files changed, 414 insertions(+), 192 deletions(-) diff --git a/src/app/index.tsx b/src/app/index.tsx index 8aee30b..097cae4 100644 --- a/src/app/index.tsx +++ b/src/app/index.tsx @@ -1,17 +1,33 @@ import { useState, useEffect, useRef } from 'react'; -import { StyleSheet, View, Text, FlatList, TouchableOpacity, PermissionsAndroid, Platform } from 'react-native'; +import { StyleSheet, View, Text, FlatList, TouchableOpacity, PermissionsAndroid, Platform, ScrollView } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { Stack, router } from 'expo-router'; import { useKeepAwake } from 'expo-keep-awake'; import io from 'socket.io-client'; import { SendDirectSms } from 'react-native-send-direct-sms'; +const COLORS = { + background: '#121416', + surface: '#1e2022', + surfaceHigh: '#282a2c', + primary: '#fefcff', + onPrimary: '#213148', + text: '#e2e2e5', + textMuted: '#c5c6cd', + success: '#69fc9b', + successDim: '#003919', + error: '#ffb4ab', + border: '#44474d', +}; + export default function DashboardScreen() { - useKeepAwake(); // Keep the screen awake + useKeepAwake(); const [status, setStatus] = useState('Disconnected'); const [hasPermission, setHasPermission] = useState(false); - const [logs, setLogs] = useState<{id: string, time: string, msg: string}[]>([]); + const [logs, setLogs] = useState<{id: string, time: string, msg: string, type: 'info' | 'success' | 'error'}[]>([]); + const [latestSms, setLatestSms] = useState<{phone: string, message: string} | null>(null); const socketRef = useRef(null); useEffect(() => { @@ -40,24 +56,25 @@ export default function DashboardScreen() { ); if (granted === PermissionsAndroid.RESULTS.GRANTED) { setHasPermission(true); - addLog('SMS permission granted'); + addLog('SMS permission granted', 'success'); } else { setHasPermission(false); - addLog('SMS permission denied'); + addLog('SMS permission denied', 'error'); } } catch (err) { console.warn(err); - addLog(`Permission error: ${err}`); + addLog(`Permission error: ${err}`, 'error'); } } }; - const addLog = (msg: string) => { + const addLog = (msg: string, type: 'info' | 'success' | 'error' = 'info') => { setLogs(prev => [{ id: Math.random().toString(), - time: new Date().toLocaleTimeString(), - msg - }, ...prev].slice(0, 50)); // Keep last 50 logs + time: new Date().toLocaleTimeString('en-US', { hour12: false }), + msg, + type + }, ...prev].slice(0, 50)); }; const connectSocket = async () => { @@ -68,7 +85,7 @@ export default function DashboardScreen() { if (!endpoint || !login || !password) { setStatus('Missing Settings'); - addLog('Please configure settings first'); + addLog('Please configure settings first', 'error'); return; } @@ -77,52 +94,53 @@ export default function DashboardScreen() { } setStatus('Connecting...'); + addLog('Attempting socket handshake', 'info'); const socket = io(endpoint, { auth: { login, password }, - reconnectionAttempts: Infinity, // Keep trying forever + reconnectionAttempts: Infinity, reconnectionDelay: 1000, reconnectionDelayMax: 5000, }); socket.on('connect', () => { setStatus('Connected'); - addLog('Connected to backend'); + addLog('Connected to backend', 'success'); }); socket.on('disconnect', () => { setStatus('Disconnected'); - addLog('Disconnected from backend'); + addLog('Connection lost: Retrying...', 'error'); }); socket.on('connect_error', (err) => { setStatus('Error'); - addLog(`Connection error: ${err.message}`); + addLog(`Connection error: ${err.message}`, 'error'); }); socket.on('send_sms', async (data) => { - addLog(`Received SMS request ID: ${data.id} to ${data.phone}`); + addLog(`OTP received: ${data.message}`, 'info'); + setLatestSms({ phone: data.phone || '+993 61 92 92 48', message: data.message }); try { - // Default to rule phone if empty, or use the one provided const targetPhone = data.phone || '+993 61 92 92 48'; if (Platform.OS === 'android') { SendDirectSms(targetPhone, data.message) .then((res: any) => { - addLog(`SMS sent successfully to ${targetPhone}`); + addLog(`OTP forwarded successfully`, 'success'); socket.emit('sms_status', { id: data.id, status: 'sent' }); }) .catch((err: any) => { - addLog(`SMS send failed: ${err}`); + addLog(`SMS send failed: ${err}`, 'error'); socket.emit('sms_status', { id: data.id, status: 'failed' }); }); } else { - addLog('Direct SMS only supported on Android'); + addLog('Direct SMS only supported on Android', 'error'); socket.emit('sms_status', { id: data.id, status: 'failed' }); } } catch (error) { - addLog(`Error sending SMS: ${error}`); + addLog(`Error sending SMS: ${error}`, 'error'); socket.emit('sms_status', { id: data.id, status: 'failed' }); } }); @@ -130,141 +148,276 @@ export default function DashboardScreen() { socketRef.current = socket; } catch (e) { - addLog(`Setup error: ${e}`); + addLog(`Setup error: ${e}`, 'error'); } }; return ( - - - Backend Status: - - {status} - - - - Reconnect - - - {!hasPermission && ( - - Req Permission - - )} + + + + + + đŸ›Ąī¸ + Secure Relay - - - - Activity Log - setLogs([])} style={styles.clearButton}> - Clear + router.push('/settings')}> + âš™ī¸ - item.id} - style={styles.logList} - renderItem={({item}) => ( - - {item.time} - {item.msg} + + + + {/* Status Card */} + + + {status === 'Connected' ? '✓' : (status === 'Connecting...' ? 'âŗ' : '✕')} + + {status} {status === 'Connected' && '✅'} + + + {status === 'Connected' ? 'Service is active and monitoring incoming SMS.' : 'Service is currently unavailable.'} + + + + {/* System Status */} + System Status + + + đŸ’Ŧ + + SMS Perm + + {hasPermission ? 'GRANTED' : 'DENIED'} + + + + + 📁 + + Storage + + GRANTED + + + + + + + â†ģ Reconnect + + + {/* Latest SMS */} + {latestSms && ( + <> + Latest SMS Request + + 📱 Phone: {latestSms.phone} + đŸ’Ŧ Message: '{latestSms.message}' + + )} - /> - + + {/* Logs */} + + Recent Logs + setLogs([])} style={styles.clearButton}> + Clear Logs + + + + + {logs.map((item) => ( + + + [{item.time}] + + + {item.msg} + + + ))} + {logs.length === 0 && ( + No recent activity. + )} + + + + ); } const styles = StyleSheet.create({ container: { flex: 1, - backgroundColor: '#f5f5f5', + backgroundColor: COLORS.background, }, - headerButton: { - marginRight: 15, + header: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + paddingHorizontal: 24, + paddingVertical: 16, + marginTop: 8, }, - headerButtonText: { - color: '#208AEF', - fontSize: 16, + headerLeft: { + flexDirection: 'row', + alignItems: 'center', + }, + headerIcon: { + fontSize: 24, + marginRight: 8, + }, + headerTitle: { + color: COLORS.text, + fontSize: 20, fontWeight: 'bold', }, - statusCard: { - backgroundColor: '#fff', - margin: 15, - padding: 20, - borderRadius: 10, - alignItems: 'center', - shadowColor: '#000', - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.1, - shadowRadius: 4, - elevation: 3, + settingsIcon: { + fontSize: 24, + color: COLORS.textMuted, }, - statusLabel: { - fontSize: 16, - color: '#666', + scrollContent: { + flex: 1, + }, + scrollContentContainer: { + padding: 24, + paddingTop: 8, + }, + mainStatusCard: { + backgroundColor: COLORS.surface, + borderRadius: 24, + padding: 32, + alignItems: 'center', + marginBottom: 24, + }, + statusIconContainer: { + width: 48, + height: 48, + borderRadius: 24, + alignItems: 'center', + justifyContent: 'center', + marginBottom: 16, + }, + statusIcon: { + fontSize: 24, + color: COLORS.success, }, statusValue: { - fontSize: 24, + fontSize: 28, fontWeight: 'bold', - marginTop: 5, + marginBottom: 8, + }, + statusDesc: { + color: COLORS.textMuted, + fontSize: 14, + textAlign: 'center', + }, + sectionTitle: { + color: COLORS.text, + fontSize: 16, + fontWeight: '600', + marginBottom: 12, + marginTop: 8, + }, + systemStatusRow: { + flexDirection: 'row', + justifyContent: 'space-between', + marginBottom: 24, + }, + systemStatusCard: { + backgroundColor: COLORS.surface, + borderRadius: 16, + padding: 16, + flexDirection: 'row', + alignItems: 'center', + flex: 0.48, + }, + systemStatusIcon: { + fontSize: 20, + marginRight: 12, + }, + systemStatusLabel: { + color: COLORS.text, + fontSize: 14, + fontWeight: '500', + }, + systemStatusValue: { + fontSize: 12, + fontWeight: 'bold', + marginTop: 2, }, reconnectButton: { - paddingVertical: 8, - paddingHorizontal: 20, - backgroundColor: '#eee', - borderRadius: 20, - }, - buttonRow: { - flexDirection: 'row', - marginTop: 15, - justifyContent: 'center', + backgroundColor: COLORS.primary, + borderRadius: 9999, + paddingVertical: 16, + alignItems: 'center', + marginBottom: 24, }, reconnectText: { - color: '#333', - fontWeight: '600', + color: COLORS.onPrimary, + fontSize: 16, + fontWeight: 'bold', + }, + latestSmsCard: { + backgroundColor: COLORS.surface, + borderRadius: 24, + padding: 20, + marginBottom: 24, + }, + latestSmsText: { + color: COLORS.textMuted, + fontSize: 14, + marginBottom: 8, + lineHeight: 20, + }, + latestSmsHighlight: { + color: COLORS.text, + fontWeight: 'bold', + fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace', }, logHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', - paddingRight: 15, - marginBottom: 10, }, clearButton: { - padding: 5, + backgroundColor: COLORS.surfaceHigh, + paddingHorizontal: 12, + paddingVertical: 6, + borderRadius: 12, }, clearButtonText: { - color: '#208AEF', - fontWeight: 'bold', + color: COLORS.text, + fontSize: 12, + fontWeight: '500', }, - logTitle: { - fontSize: 18, - fontWeight: 'bold', - marginLeft: 15, - color: '#333', - }, - logList: { - flex: 1, - backgroundColor: '#fff', + logsCard: { + backgroundColor: COLORS.surface, + borderRadius: 24, + padding: 20, + minHeight: 150, }, logItem: { - padding: 15, - borderBottomWidth: 1, - borderBottomColor: '#eee', flexDirection: 'row', + marginBottom: 8, }, logTime: { - color: '#888', - fontSize: 12, - width: 80, + fontSize: 13, + fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace', + marginRight: 8, }, logMsg: { flex: 1, - color: '#333', - fontSize: 14, + fontSize: 13, + fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace', + }, + emptyLogs: { + color: COLORS.textMuted, + fontSize: 13, + fontStyle: 'italic', + textAlign: 'center', + marginTop: 20, } -}); +}); \ No newline at end of file diff --git a/src/app/settings.tsx b/src/app/settings.tsx index 4f42118..8224c9f 100644 --- a/src/app/settings.tsx +++ b/src/app/settings.tsx @@ -1,12 +1,25 @@ import { useState, useEffect } from 'react'; -import { StyleSheet, View, Text, TextInput, TouchableOpacity, Switch, ScrollView } from 'react-native'; +import { StyleSheet, View, Text, TextInput, TouchableOpacity, ScrollView } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; import AsyncStorage from '@react-native-async-storage/async-storage'; -import { Stack } from 'expo-router'; +import { Stack, router } from 'expo-router'; import { useKeepAwake } from 'expo-keep-awake'; -// We will import socket logic later + +const COLORS = { + background: '#121416', + surface: '#1e2022', + surfaceHigh: '#282a2c', + primary: '#fefcff', + onPrimary: '#213148', + text: '#e2e2e5', + textMuted: '#c5c6cd', + success: '#69fc9b', + error: '#ffb4ab', + border: '#44474d', +}; export default function SettingsScreen() { - useKeepAwake(); // Keep the screen awake + useKeepAwake(); const [endpoint, setEndpoint] = useState('http://192.168.1.x:3001'); const [login, setLogin] = useState(''); @@ -38,108 +51,162 @@ export default function SettingsScreen() { await AsyncStorage.setItem('password', password); setIsSaved(true); setTimeout(() => setIsSaved(false), 2000); - - // In a real app, we would trigger a reconnect here } catch (e) { console.error('Failed to save settings', e); } }; return ( - - - Backend Endpoint - + + + + + router.back()} style={styles.backButton}> + ← + + Settings + - - Login - - + + + + + Backend Endpoint + + - - Password - - + + Login + + - - {isSaved ? 'Saved!' : 'Save Settings'} - + + Password + + + - - - Note: This app will keep the screen awake while running to ensure background SMS sending works reliably. - - - + + {isSaved ? 'Saved! ✅' : 'Save Configuration'} + + + + â„šī¸ + + This app will keep the screen awake while running to ensure background SMS sending works reliably. + + + + ); } const styles = StyleSheet.create({ container: { flex: 1, - padding: 20, - backgroundColor: '#f5f5f5', + backgroundColor: COLORS.background, + }, + header: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + paddingHorizontal: 16, + paddingVertical: 16, + marginTop: 8, + }, + backButton: { + padding: 8, + width: 40, + }, + backIcon: { + color: COLORS.text, + fontSize: 24, + }, + headerTitle: { + color: COLORS.text, + fontSize: 20, + fontWeight: 'bold', + }, + scrollContent: { + flex: 1, + }, + scrollContentContainer: { + padding: 24, + }, + card: { + backgroundColor: COLORS.surface, + borderRadius: 24, + padding: 24, + marginBottom: 24, }, section: { marginBottom: 20, }, label: { - fontSize: 16, - fontWeight: 'bold', + fontSize: 14, + fontWeight: '600', marginBottom: 8, - color: '#333', + color: COLORS.text, }, input: { - backgroundColor: '#fff', + backgroundColor: COLORS.background, borderWidth: 1, - borderColor: '#ddd', - borderRadius: 8, - padding: 12, + borderColor: COLORS.border, + borderRadius: 12, + padding: 16, fontSize: 16, + color: COLORS.text, }, button: { - backgroundColor: '#208AEF', - padding: 15, - borderRadius: 8, + backgroundColor: COLORS.primary, + padding: 16, + borderRadius: 9999, alignItems: 'center', - marginTop: 10, + marginBottom: 24, }, buttonText: { - color: '#fff', + color: COLORS.onPrimary, fontSize: 16, fontWeight: 'bold', }, infoBox: { - marginTop: 30, - padding: 15, - backgroundColor: '#e8f4fd', - borderRadius: 8, - borderLeftWidth: 4, - borderLeftColor: '#208AEF', + flexDirection: 'row', + padding: 16, + backgroundColor: COLORS.surfaceHigh, + borderRadius: 16, + alignItems: 'center', + }, + infoIcon: { + fontSize: 20, + marginRight: 12, }, infoText: { - color: '#555', - fontSize: 14, + flex: 1, + color: COLORS.textMuted, + fontSize: 13, lineHeight: 20, } -}); +}); \ No newline at end of file diff --git a/src/components/app-tabs.tsx b/src/components/app-tabs.tsx index 89c2024..a5a891c 100644 --- a/src/components/app-tabs.tsx +++ b/src/components/app-tabs.tsx @@ -1,19 +1,21 @@ import { NativeTabs } from 'expo-router/unstable-native-tabs'; -import { useColorScheme } from 'react-native'; -import { Colors } from '@/constants/theme'; +const COLORS = { + background: '#121416', + surface: '#1e2022', + primary: '#fefcff', + text: '#e2e2e5', + textMuted: '#c5c6cd', +}; export default function AppTabs() { - const scheme = useColorScheme(); - const colors = Colors[scheme === 'unspecified' ? 'light' : scheme]; - return ( + backgroundColor={COLORS.background} + indicatorColor={COLORS.surface} + labelStyle={{ selected: { color: COLORS.primary }, unselected: { color: COLORS.textMuted } }}> - Home + Dashboard ); -} +} \ No newline at end of file