import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity, ActivityIndicator } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { BLEConnectionState } from '@/services/ble/types';
import {
AppColors,
BorderRadius,
FontSizes,
FontWeights,
Spacing,
} from '@/constants/theme';
interface ConnectionStatusIndicatorProps {
connectionState: BLEConnectionState;
isReconnecting?: boolean;
reconnectAttempts?: number;
maxAttempts?: number;
onReconnect?: () => void;
onCancel?: () => void;
compact?: boolean;
}
/**
* Visual indicator for BLE connection status with reconnect controls
*/
export function ConnectionStatusIndicator({
connectionState,
isReconnecting = false,
reconnectAttempts = 0,
maxAttempts = 3,
onReconnect,
onCancel,
compact = false,
}: ConnectionStatusIndicatorProps) {
const getStatusConfig = () => {
if (isReconnecting) {
return {
icon: 'sync' as const,
color: AppColors.warning,
bgColor: AppColors.warningLight,
label: `Reconnecting... (${reconnectAttempts}/${maxAttempts})`,
showSpinner: true,
};
}
switch (connectionState) {
case BLEConnectionState.READY:
return {
icon: 'bluetooth' as const,
color: AppColors.success,
bgColor: AppColors.successLight,
label: 'Connected',
showSpinner: false,
};
case BLEConnectionState.CONNECTING:
case BLEConnectionState.DISCOVERING:
return {
icon: 'bluetooth' as const,
color: AppColors.primary,
bgColor: AppColors.primaryLighter,
label: 'Connecting...',
showSpinner: true,
};
case BLEConnectionState.DISCONNECTING:
return {
icon: 'bluetooth' as const,
color: AppColors.textMuted,
bgColor: AppColors.background,
label: 'Disconnecting...',
showSpinner: true,
};
case BLEConnectionState.ERROR:
return {
icon: 'warning' as const,
color: AppColors.error,
bgColor: AppColors.errorLight,
label: 'Connection Error',
showSpinner: false,
};
case BLEConnectionState.DISCONNECTED:
default:
return {
icon: 'bluetooth-outline' as const,
color: AppColors.textMuted,
bgColor: AppColors.background,
label: 'Not Connected',
showSpinner: false,
};
}
};
const config = getStatusConfig();
if (compact) {
return (
{config.showSpinner ? (
) : (
)}
{config.label}
);
}
return (
{config.showSpinner ? (
) : (
)}
{config.label}
{isReconnecting && (
Attempting to restore connection...
)}
{/* Action buttons */}
{(connectionState === BLEConnectionState.ERROR ||
connectionState === BLEConnectionState.DISCONNECTED) &&
!isReconnecting &&
onReconnect && (
Reconnect
)}
{isReconnecting && onCancel && (
Cancel
)}
);
}
const styles = StyleSheet.create({
container: {
borderRadius: BorderRadius.lg,
padding: Spacing.md,
},
compactContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: Spacing.xs,
paddingHorizontal: Spacing.sm,
paddingVertical: Spacing.xs,
borderRadius: BorderRadius.md,
},
compactLabel: {
fontSize: FontSizes.xs,
fontWeight: FontWeights.medium,
},
statusRow: {
flexDirection: 'row',
alignItems: 'center',
gap: Spacing.md,
},
iconContainer: {
width: 32,
height: 32,
justifyContent: 'center',
alignItems: 'center',
},
textContainer: {
flex: 1,
},
label: {
fontSize: FontSizes.base,
fontWeight: FontWeights.semibold,
},
sublabel: {
fontSize: FontSizes.sm,
color: AppColors.textMuted,
marginTop: 2,
},
actionButton: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
gap: Spacing.xs,
marginTop: Spacing.md,
paddingVertical: Spacing.sm,
paddingHorizontal: Spacing.md,
borderRadius: BorderRadius.md,
borderWidth: 1,
borderColor: AppColors.primary,
},
actionButtonText: {
fontSize: FontSizes.sm,
fontWeight: FontWeights.medium,
color: AppColors.primary,
},
cancelButton: {
borderColor: AppColors.error,
},
cancelButtonText: {
color: AppColors.error,
},
});
export default ConnectionStatusIndicator;