update
This commit is contained in:
@@ -5,12 +5,15 @@ import {
|
||||
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';
|
||||
|
||||
@@ -44,6 +47,7 @@ export default function LabelScreen(): React.ReactElement {
|
||||
const preset = filament ? presets.find((p) => p.id === filament.spoolPresetId) : undefined;
|
||||
|
||||
const [selectedSize, setSelectedSize] = useState<LabelSize>('50x30');
|
||||
const [selectedFormat, setSelectedFormat] = useState<'pdf' | 'svg'>('pdf');
|
||||
const [enabledContent, setEnabledContent] = useState<Set<ContentOption>>(
|
||||
new Set(['color', 'name', 'material_brand', 'net_weight', 'print_temp', 'qrcode']),
|
||||
);
|
||||
@@ -68,9 +72,47 @@ export default function LabelScreen(): React.ReactElement {
|
||||
});
|
||||
}
|
||||
|
||||
function handleExport(): void {
|
||||
// TODO: Generate SVG and share via expo-sharing
|
||||
Alert.alert('Exportar SVG', 'Funcionalidade de exportação SVG será implementada na integração com o backend.');
|
||||
async function handleExport(): Promise<void> {
|
||||
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<ArrayBuffer>(
|
||||
`/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<string>(
|
||||
`/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);
|
||||
@@ -174,8 +216,21 @@ export default function LabelScreen(): React.ReactElement {
|
||||
|
||||
{/* CTA */}
|
||||
<View style={styles.footer}>
|
||||
<View style={styles.formatRow}>
|
||||
{(['pdf', 'svg'] as const).map((fmt) => (
|
||||
<TouchableOpacity
|
||||
key={fmt}
|
||||
onPress={() => setSelectedFormat(fmt)}
|
||||
style={[styles.formatChip, selectedFormat === fmt && styles.formatChipActive]}
|
||||
>
|
||||
<Text style={[styles.formatChipText, selectedFormat === fmt && styles.formatChipTextActive]}>
|
||||
{fmt.toUpperCase()}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
<Button
|
||||
label="Exportar SVG"
|
||||
label={`Exportar ${selectedFormat.toUpperCase()}`}
|
||||
leftIcon={<Ionicons name="download-outline" size={18} color={colors.bgBase} />}
|
||||
onPress={handleExport}
|
||||
/>
|
||||
@@ -300,8 +355,27 @@ const styles = StyleSheet.create({
|
||||
contentChipTextActive: { color: colors.accent },
|
||||
footer: {
|
||||
padding: spacing[5],
|
||||
gap: spacing[3],
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: colors.border,
|
||||
backgroundColor: colors.bgBase,
|
||||
},
|
||||
formatRow: { flexDirection: 'row', gap: spacing[2] },
|
||||
formatChip: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
paddingVertical: spacing[2],
|
||||
borderRadius: radius.lg,
|
||||
backgroundColor: colors.bgSurface,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.border,
|
||||
},
|
||||
formatChipActive: { borderColor: colors.accent, backgroundColor: colors.accentMuted },
|
||||
formatChipText: {
|
||||
fontFamily: typography.fontFamily.ui,
|
||||
fontSize: typography.fontSize.sm,
|
||||
fontWeight: typography.fontWeight.semibold,
|
||||
color: colors.textSecondary,
|
||||
},
|
||||
formatChipTextActive: { color: colors.accent },
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user