/* * File: ImageViewer.tsx * Description: Full-screen DICOM image viewer with zoom, pan, and navigation * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. */ import React, { useState, useCallback } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, Dimensions, Image, ScrollView, StatusBar, SafeAreaView, } from 'react-native'; import { theme } from '../../../theme/theme'; import Icon from 'react-native-vector-icons/Feather'; import { API_CONFIG } from '../../../shared/utils'; // Get screen dimensions const { width: screenWidth, height: screenHeight } = Dimensions.get('window'); // ============================================================================ // INTERFACES // ============================================================================ interface ImageViewerProps { visible: boolean; images: string[]; initialIndex: number; onClose: () => void; patientName?: string; seriesInfo?: string; } // ============================================================================ // IMAGE VIEWER COMPONENT // ============================================================================ /** * ImageViewer Component * * Purpose: Full-screen DICOM image viewer with advanced viewing capabilities * * Features: * - Full-screen image display * - Image navigation (previous/next) * - Zoom and pan functionality * - Patient information display * - Series information * - Touch gestures for navigation * - Professional medical imaging interface */ const ImageViewer: React.FC = ({ visible, images, initialIndex, onClose, patientName = 'Unknown Patient', seriesInfo = 'DICOM Series', }) => { // ============================================================================ // STATE MANAGEMENT // ============================================================================ const [currentIndex, setCurrentIndex] = useState(initialIndex); const [scale, setScale] = useState(1); const [isZoomed, setIsZoomed] = useState(false); // ============================================================================ // EVENT HANDLERS // ============================================================================ /** * Handle Previous Image * * Purpose: Navigate to previous image in series */ const handlePrevious = useCallback(() => { if (currentIndex > 0) { setCurrentIndex(currentIndex - 1); setScale(1); setIsZoomed(false); } }, [currentIndex]); /** * Handle Next Image * * Purpose: Navigate to next image in series */ const handleNext = useCallback(() => { if (currentIndex < images.length - 1) { setCurrentIndex(currentIndex + 1); setScale(1); setIsZoomed(false); } }, [currentIndex, images.length]); /** * Handle Zoom In * * Purpose: Increase image zoom level */ const handleZoomIn = useCallback(() => { const newScale = Math.min(scale * 1.5, 3); setScale(newScale); setIsZoomed(newScale > 1); }, [scale]); /** * Handle Zoom Out * * Purpose: Decrease image zoom level */ const handleZoomOut = useCallback(() => { const newScale = Math.max(scale / 1.5, 0.5); setScale(newScale); setIsZoomed(newScale > 1); }, [scale]); /** * Handle Reset Zoom * * Purpose: Reset image to original size */ const handleResetZoom = useCallback(() => { setScale(1); setIsZoomed(false); }, []); /** * Handle Close * * Purpose: Close image viewer and return to previous screen */ const handleClose = useCallback(() => { setScale(1); setIsZoomed(false); setCurrentIndex(initialIndex); onClose(); }, [initialIndex, onClose]); // ============================================================================ // RENDER HELPERS // ============================================================================ /** * Render Header * * Purpose: Render image viewer header with patient info and controls */ const renderHeader = () => ( {patientName} {seriesInfo} {currentIndex + 1} of {images.length} ); /** * Render Navigation Controls * * Purpose: Render image navigation controls */ const renderNavigationControls = () => ( ); /** * Render Zoom Controls * * Purpose: Render zoom control buttons */ const renderZoomControls = () => ( {Math.round(scale * 100)}% ); // ============================================================================ // MAIN RENDER // ============================================================================ if (!visible || images.length === 0) { return null; } return ( {/* Header */} {renderHeader()} {/* Main Image Area */} {/* Navigation Controls */} {renderNavigationControls()} {/* Zoom Controls */} {renderZoomControls()} {/* Thumbnail Strip */} {images.map((image, index) => ( setCurrentIndex(index)} > {index === currentIndex && ( )} ))} ); }; // ============================================================================ // STYLES // ============================================================================ const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#000000', }, // Header Styles header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: theme.spacing.md, paddingVertical: theme.spacing.sm, backgroundColor: 'rgba(0, 0, 0, 0.8)', }, headerLeft: { flexDirection: 'row', alignItems: 'center', flex: 1, }, closeButton: { padding: theme.spacing.sm, marginRight: theme.spacing.md, }, patientInfo: { flex: 1, }, patientName: { fontSize: 16, color: theme.colors.background, fontFamily: theme.typography.fontFamily.bold, }, seriesInfo: { fontSize: 12, color: theme.colors.background, opacity: 0.8, fontFamily: theme.typography.fontFamily.regular, }, headerRight: { alignItems: 'flex-end', }, imageCounter: { fontSize: 14, color: theme.colors.background, fontFamily: theme.typography.fontFamily.medium, }, // Image Container Styles imageContainer: { flex: 1, // backgroundColor: '#000000', }, scrollView: { flex: 1, }, scrollContent: { flexGrow: 1, justifyContent: 'center', alignItems: 'center', }, image: { width: screenWidth, height: screenHeight * 0.7, }, // Navigation Controls Styles navigationControls: { position: 'absolute', top: '50%', left: 0, right: 0, flexDirection: 'row', justifyContent: 'space-between', paddingHorizontal: theme.spacing.md, transform: [{ translateY: -20 }], }, navButton: { width: 48, height: 48, borderRadius: 24, backgroundColor: 'rgba(0, 0, 0, 0.6)', justifyContent: 'center', alignItems: 'center', shadowColor: '#000000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.3, shadowRadius: 4, elevation: 4, }, navButtonDisabled: { backgroundColor: 'rgba(0, 0, 0, 0.3)', }, // Zoom Controls Styles zoomControls: { position: 'absolute', bottom: 100, right: theme.spacing.md, flexDirection: 'column', alignItems: 'center', }, zoomButton: { width: 44, height: 44, borderRadius: 22, backgroundColor: 'rgba(0, 0, 0, 0.6)', justifyContent: 'center', alignItems: 'center', marginBottom: theme.spacing.sm, shadowColor: '#000000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.3, shadowRadius: 4, elevation: 4, }, zoomText: { color: theme.colors.background, fontSize: 12, fontFamily: theme.typography.fontFamily.bold, }, // Thumbnail Strip Styles thumbnailStrip: { position: 'absolute', bottom: 0, left: 0, right: 0, backgroundColor: 'rgba(0, 0, 0, 0.8)', paddingVertical: theme.spacing.sm, }, thumbnailContent: { paddingHorizontal: theme.spacing.md, }, thumbnail: { width: 60, height: 60, borderRadius: 8, marginRight: theme.spacing.sm, position: 'relative', borderWidth: 2, borderColor: 'transparent', }, activeThumbnail: { borderColor: theme.colors.primary, }, thumbnailImage: { width: '100%', height: '100%', borderRadius: 6, }, activeIndicator: { position: 'absolute', top: -4, right: -4, width: 20, height: 20, borderRadius: 10, backgroundColor: theme.colors.primary, justifyContent: 'center', alignItems: 'center', }, }); export default ImageViewer; /* * End of File: ImageViewer.tsx * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. */