add status
This commit is contained in:
@@ -15,6 +15,7 @@ import { SettingsModal } from '../components/SettingsModal';
|
|||||||
import { ConfirmModal, type ConfirmOption } from '../components/ConfirmModal';
|
import { ConfirmModal, type ConfirmOption } from '../components/ConfirmModal';
|
||||||
import { UploadModal } from '../components/UploadModal';
|
import { UploadModal } from '../components/UploadModal';
|
||||||
import { SyncStatusIcon } from '../components/SyncStatusIcon';
|
import { SyncStatusIcon } from '../components/SyncStatusIcon';
|
||||||
|
import { NetworkStatusBar } from '../components/NetworkStatusBar';
|
||||||
import { useSyncQueue } from '../hooks/useSyncQueue';
|
import { useSyncQueue } from '../hooks/useSyncQueue';
|
||||||
import { useUploadQueue } from '../hooks/useUploadQueue';
|
import { useUploadQueue } from '../hooks/useUploadQueue';
|
||||||
import { useAutoSync } from '../hooks/useAutoSync';
|
import { useAutoSync } from '../hooks/useAutoSync';
|
||||||
@@ -161,6 +162,7 @@ export function HomeScreen() {
|
|||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
headerRight: () => (
|
headerRight: () => (
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||||
|
<NetworkStatusBar />
|
||||||
<SyncStatusIcon
|
<SyncStatusIcon
|
||||||
isSyncing={isSyncing}
|
isSyncing={isSyncing}
|
||||||
pendingCount={pendingCount}
|
pendingCount={pendingCount}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { View, Text, StyleSheet } from 'react-native';
|
||||||
|
import { MaterialIcons } from '@expo/vector-icons';
|
||||||
|
import { useNetworkStatus } from '../hooks/useNetworkStatus';
|
||||||
|
|
||||||
|
export function NetworkStatusBar() {
|
||||||
|
const { isOnline } = useNetworkStatus();
|
||||||
|
|
||||||
|
if (isOnline) {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<View style={styles.dotOnline} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<View style={styles.offlineBadge}>
|
||||||
|
<MaterialIcons name="cloud-off" size={14} color="#fff" />
|
||||||
|
<Text style={styles.offlineText}>Offline</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
marginRight: 4,
|
||||||
|
padding: 4,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
dotOnline: {
|
||||||
|
width: 8,
|
||||||
|
height: 8,
|
||||||
|
borderRadius: 4,
|
||||||
|
backgroundColor: '#4CAF50',
|
||||||
|
},
|
||||||
|
offlineBadge: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: '#E53935',
|
||||||
|
borderRadius: 12,
|
||||||
|
paddingHorizontal: 8,
|
||||||
|
paddingVertical: 4,
|
||||||
|
gap: 4,
|
||||||
|
},
|
||||||
|
offlineText: {
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: '700',
|
||||||
|
color: '#fff',
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import { useSyncExternalStore, useRef } from 'react';
|
||||||
|
import NetInfo, { NetInfoState, NetInfoSubscription } from '@react-native-community/netinfo';
|
||||||
|
|
||||||
|
type Listener = () => void;
|
||||||
|
|
||||||
|
let state: NetInfoState | null = null;
|
||||||
|
const listeners = new Set<Listener>();
|
||||||
|
let subscription: NetInfoSubscription | null = null;
|
||||||
|
|
||||||
|
function subscribe(listener: Listener): () => void {
|
||||||
|
listeners.add(listener);
|
||||||
|
return () => { listeners.delete(listener); };
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSnapshot(): boolean {
|
||||||
|
return state?.isConnected ?? true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initIfNeeded() {
|
||||||
|
if (subscription) return;
|
||||||
|
NetInfo.fetch().then((info) => {
|
||||||
|
state = info;
|
||||||
|
listeners.forEach((l) => l());
|
||||||
|
});
|
||||||
|
subscription = NetInfo.addEventListener((info) => {
|
||||||
|
state = info;
|
||||||
|
listeners.forEach((l) => l());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NetworkStatus {
|
||||||
|
isOnline: boolean;
|
||||||
|
isWifi: boolean;
|
||||||
|
isCellular: boolean;
|
||||||
|
connectionType: string;
|
||||||
|
isInternetReachable: boolean | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useNetworkStatus(): NetworkStatus {
|
||||||
|
const mountRef = useRef(false);
|
||||||
|
if (!mountRef.current) {
|
||||||
|
initIfNeeded();
|
||||||
|
mountRef.current = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isConnected = useSyncExternalStore(subscribe, getSnapshot);
|
||||||
|
|
||||||
|
return {
|
||||||
|
isOnline: isConnected,
|
||||||
|
isWifi: state?.type === 'wifi',
|
||||||
|
isCellular: state?.type === 'cellular',
|
||||||
|
connectionType: state?.type ?? 'unknown',
|
||||||
|
isInternetReachable: state?.isInternetReachable ?? null,
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user