import React, { useState } from 'react'; import { View, Text, TouchableOpacity, StyleSheet, Alert, } from 'react-native'; import { useLocalSearchParams, useRouter } from 'expo-router'; import { Ionicons } from '@expo/vector-icons'; import { SafeAreaView } from 'react-native-safe-area-context'; import * as FileSystem from 'expo-file-system/legacy'; import * as Sharing from 'expo-sharing'; import { useFilamentStore } from '@store/filamentStore'; import { usePresetStore } from '@store/presetStore'; import { calcFilamentPercentage } from '@domain/Filament'; import { colors, typography, spacing, radius } from '@shared/theme'; import { formatWeight } from '@shared/utils/filament'; import { Button } from '@presentation/components/ui/Button'; import { httpClient } from '@adapters/remote/httpClient'; type LabelSize = '50x30' | '62x29' | '38x25'; const LABEL_SIZES: { id: LabelSize; label: string; sub: string }[] = [ { id: '50x30', label: '50 × 30', sub: 'Padrão' }, { id: '62x29', label: '62 × 29', sub: 'Brother DK' }, { id: '38x25', label: '38 × 25', sub: 'Dymo 11354' }, ]; type ContentOption = 'color' | 'name' | 'material_brand' | 'net_weight' | 'print_temp' | 'qrcode'; const CONTENT_OPTIONS: { id: ContentOption; label: string }[] = [ { id: 'color', label: 'Cor visual' }, { id: 'name', label: 'Nome' }, { id: 'material_brand', label: 'Material · Marca' }, { id: 'net_weight', label: 'Peso líquido' }, { id: 'print_temp', label: 'Temp. impressão' }, { id: 'qrcode', label: 'QR Code' }, ]; /** * Tela de Exportar Etiqueta — 1FZ-0 */ export default function LabelScreen(): React.ReactElement { const { id } = useLocalSearchParams<{ id: string }>(); const router = useRouter(); const { filaments } = useFilamentStore(); const { presets } = usePresetStore(); const filament = filaments.find((f) => f.id === id); const preset = filament ? presets.find((p) => p.id === filament.spoolPresetId) : undefined; const [selectedSize, setSelectedSize] = useState('50x30'); const [selectedFormat, setSelectedFormat] = useState<'pdf' | 'svg'>('pdf'); const [enabledContent, setEnabledContent] = useState>( new Set(['color', 'name', 'material_brand', 'net_weight', 'print_temp', 'qrcode']), ); if (!filament) { return ( Filamento não encontrado ); } const pct = calcFilamentPercentage(filament); function toggleContent(opt: ContentOption): void { setEnabledContent((prev) => { const next = new Set(prev); if (next.has(opt)) next.delete(opt); else next.add(opt); return next; }); } async function handleExport(): Promise { const [widthStr, heightStr] = selectedSize.split('x'); const width_mm = Number(widthStr); const height_mm = Number(heightStr); const isPdf = selectedFormat === 'pdf'; const fields = Array.from(enabledContent).join(','); try { if (isPdf) { const response = await httpClient.get( `/filaments/${id}/label.pdf`, { params: { width_mm, height_mm, fields }, responseType: 'arraybuffer' }, ); const base64 = btoa( String.fromCharCode(...new Uint8Array(response.data)), ); const fileUri = `${FileSystem.cacheDirectory}meowspool-label-${id}.pdf`; await FileSystem.writeAsStringAsync(fileUri, base64, { encoding: FileSystem.EncodingType.Base64, }); if (await Sharing.isAvailableAsync()) { await Sharing.shareAsync(fileUri, { mimeType: 'application/pdf', UTI: 'com.adobe.pdf' }); } else { Alert.alert('Compartilhamento indisponível', 'Este dispositivo não suporta compartilhamento de arquivos.'); } } else { const response = await httpClient.get( `/filaments/${id}/label.svg`, { params: { width_mm, height_mm, fields }, responseType: 'text' }, ); const fileUri = `${FileSystem.cacheDirectory}meowspool-label-${id}.svg`; await FileSystem.writeAsStringAsync(fileUri, response.data, { encoding: 'utf8' }); if (await Sharing.isAvailableAsync()) { await Sharing.shareAsync(fileUri, { mimeType: 'image/svg+xml', UTI: 'public.svg-image' }); } else { Alert.alert('Compartilhamento indisponível', 'Este dispositivo não suporta compartilhamento de arquivos.'); } } } catch (err) { Alert.alert('Erro', String(err)); } } const sizeLabel = LABEL_SIZES.find((s) => s.id === selectedSize); return ( {/* Header */} router.back()}> Exportar Etiqueta {/* Label Preview */} PREVIEW DA ETIQUETA {filament.brand}{filament.model ? ` ${filament.model}` : ''} {filament.brand} · {filament.material} · {filament.colorHex} DISPONÍVEL {formatWeight(filament.netWeightG)} {filament.tempHotendC && ( HOTEND {filament.tempHotendC}°C )} {filament.tempBedC && ( MESA {filament.tempBedC}°C )} {/* QR placeholder */} {' '} {sizeLabel?.label} mm ({sizeLabel?.sub}) {/* Tamanho */} TAMANHO {LABEL_SIZES.map((s) => ( setSelectedSize(s.id)} style={[styles.sizeChip, selectedSize === s.id && styles.sizeChipActive]} > {s.label} {s.sub} ))} {/* Conteúdo */} CONTEÚDO DA ETIQUETA {CONTENT_OPTIONS.map((opt) => { const active = enabledContent.has(opt.id); return ( toggleContent(opt.id)} style={[styles.contentChip, active && styles.contentChipActive]} > {active && } {opt.label} ); })} {/* CTA */} {(['pdf', 'svg'] as const).map((fmt) => ( setSelectedFormat(fmt)} style={[styles.formatChip, selectedFormat === fmt && styles.formatChipActive]} > {fmt.toUpperCase()} ))}