feat: implement main application structure with UI and layout management
- Added main application logic in `src/ui/app.rs` to handle state and modal dialogs. - Created module structure for UI components in `src/ui/mod.rs`. - Implemented column configuration screen in `src/ui/screens/configuracao_colunas.rs`. - Developed file import screen in `src/ui/screens/import.rs` for CSV and XLSX files. - Added layout management screen in `src/ui/screens/layouts.rs` for saving and importing layouts. - Created result display screen in `src/ui/screens/resultado.rs` to show analysis results. - Introduced modular organization for screens in `src/ui/screens/mod.rs`.
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
use crate::domain::errors::{ErroArquivo, ResumoAvisos};
|
||||
use encoding_rs::WINDOWS_1252;
|
||||
use std::path::Path;
|
||||
|
||||
const LIMITE_BYTES: u64 = 50 * 1024 * 1024;
|
||||
|
||||
/// Resultado da leitura de um arquivo CSV.
|
||||
pub struct ResultadoCsv {
|
||||
/// Linhas de dados (já sem o cabeçalho), cada linha é um vetor de strings.
|
||||
pub linhas: Vec<Vec<String>>,
|
||||
/// Avisos coletados durante a leitura.
|
||||
pub avisos: ResumoAvisos,
|
||||
}
|
||||
|
||||
/// Lê um arquivo CSV e retorna as linhas de dados (sem o cabeçalho).
|
||||
///
|
||||
/// # Parâmetros
|
||||
/// - `caminho`: caminho do arquivo
|
||||
/// - `delimitador`: caractere delimitador (`,`, `;` ou `\t`)
|
||||
/// - `encoding`: "utf-8" ou "windows-1252"
|
||||
/// - `linha_cabecalho`: número da linha do cabeçalho (base 1). 0 = sem cabeçalho.
|
||||
pub fn ler_csv(
|
||||
caminho: &Path,
|
||||
delimitador: u8,
|
||||
encoding: &str,
|
||||
linha_cabecalho: usize,
|
||||
) -> Result<ResultadoCsv, ErroArquivo> {
|
||||
// Verificar tamanho
|
||||
let metadata = std::fs::metadata(caminho)
|
||||
.map_err(|e| ErroArquivo::ErroLeitura(e.to_string()))?;
|
||||
if metadata.len() > LIMITE_BYTES {
|
||||
return Err(ErroArquivo::TamanhoExcedido(metadata.len()));
|
||||
}
|
||||
|
||||
// Ler conteúdo bruto
|
||||
let bytes = std::fs::read(caminho)
|
||||
.map_err(|e| ErroArquivo::ErroLeitura(e.to_string()))?;
|
||||
|
||||
// Decodificar encoding
|
||||
let conteudo = match encoding.to_lowercase().as_str() {
|
||||
"windows-1252" | "latin-1" | "iso-8859-1" => {
|
||||
let (decoded, _, _) = WINDOWS_1252.decode(&bytes);
|
||||
decoded.into_owned()
|
||||
}
|
||||
_ => {
|
||||
String::from_utf8(bytes)
|
||||
.map_err(|e| ErroArquivo::ErroLeitura(format!("Encoding inválido: {}", e)))?
|
||||
}
|
||||
};
|
||||
|
||||
let mut avisos = ResumoAvisos::default();
|
||||
let mut linhas_dados: Vec<Vec<String>> = Vec::new();
|
||||
let mut numero_linha_arquivo: usize = 0;
|
||||
|
||||
let mut reader = csv::ReaderBuilder::new()
|
||||
.delimiter(delimitador)
|
||||
.has_headers(false)
|
||||
.flexible(true)
|
||||
.from_reader(conteudo.as_bytes());
|
||||
|
||||
for resultado in reader.records() {
|
||||
numero_linha_arquivo += 1;
|
||||
|
||||
// Pular linhas antes ou na linha do cabeçalho
|
||||
if linha_cabecalho > 0 && numero_linha_arquivo <= linha_cabecalho {
|
||||
continue;
|
||||
}
|
||||
|
||||
match resultado {
|
||||
Ok(record) => {
|
||||
let campos: Vec<String> = record.iter().map(|s| s.to_string()).collect();
|
||||
|
||||
// Ignorar linhas completamente em branco
|
||||
if campos.iter().all(|s| s.trim().is_empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
linhas_dados.push(campos);
|
||||
}
|
||||
Err(_) => {
|
||||
avisos.linhas_malformadas += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ResultadoCsv {
|
||||
linhas: linhas_dados,
|
||||
avisos,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user