diff --git a/Cargo.lock b/Cargo.lock index 7896b33..488d503 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -857,6 +857,7 @@ dependencies = [ "egui", "encoding_rs", "genpdf", + "image", "regex", "rfd", "rusqlite", @@ -865,6 +866,7 @@ dependencies = [ "serde", "serde_json", "thiserror 2.0.18", + "winres", ] [[package]] @@ -3922,6 +3924,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml_datetime" version = "0.7.5+spec-1.1.0" @@ -5007,6 +5018,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winres" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" +dependencies = [ + "toml", +] + [[package]] name = "wit-bindgen" version = "0.51.0" diff --git a/Cargo.toml b/Cargo.toml index be86072..73cf4d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,7 @@ dirs = "5" thiserror = "2" regex = "1" rfd = "0.15" +image = { version = "0.25", default-features = false, features = ["ico"] } + +[build-dependencies] +winres = "0.1" diff --git a/FEATURES_BACKLOG.md b/FEATURES_BACKLOG.md index 108c9e9..b35d4ab 100644 --- a/FEATURES_BACKLOG.md +++ b/FEATURES_BACKLOG.md @@ -84,7 +84,7 @@ Verificar se já existe no codigo, pois na tela de configuração do Layout ele --- -### F-05 — Recarregar Arquivo Sem Reconfigurar (Sim bem necessario) +### F-05 — Recarregar Arquivo Sem Reconfigurar (Implementado) **Problema:** Quando o usuário corrige o arquivo fonte e quer re-verificar, precisa navegar todo o fluxo novamente (selecionar arquivo → configurar colunas → analisar). diff --git a/SUGESTOES_UI.md b/SUGESTOES_UI.md deleted file mode 100644 index ddf7232..0000000 --- a/SUGESTOES_UI.md +++ /dev/null @@ -1,113 +0,0 @@ -# Sugestões de Melhoria — Fluxo da Interface - -**Data:** 02/03/2026 - ---- - -## 1. Indicador de progresso das etapas - -O fluxo possui 3–4 passos bem definidos (`Importando → ConfigurandoColunas → ExibindoResultado`), mas não há nenhum indicador visual de onde o usuário está. - -**Sugestão:** Adicionar um breadcrumb simples no topo de todas as telas: - -``` -① Arquivo ② Colunas ③ Resultado -``` - -O passo atual ficaria destacado. Isso orienta o usuário sobre o que falta sem exigir nenhuma regra de negócio adicional. - ---- - -## 2. Unificar importação e configuração de colunas em um único painel - -Atualmente o caminho é: -1. Selecionar arquivo → clicar **"▶ Configurar Colunas"** -2. Configurar colunas → clicar **"▶ Importar e Analisar"** - -São 3 ações separadas para chegar à análise. - -**Sugestão:** Mover as configurações CSV/XLSX para a mesma tela de importação como uma seção expansível ("Configurações avançadas"), deixando o botão principal como **"▶ Importar e Analisar"** direto. - ---- - -## 3. Pré-visualização das primeiras linhas do arquivo - -Após selecionar o arquivo, o usuário precisa alternar entre a aplicação e a planilha para descobrir quais índices correspondem a cada campo. - -**Sugestão:** Exibir as primeiras 3–5 linhas do arquivo em uma tabela simples logo após a seleção, para que o usuário identifique visualmente o índice de cada coluna sem sair do app. - ---- - -## 4. Confirmação ao clicar em "Nova Análise" - -O botão **"< Nova Análise"** em `resultado.rs` executa `app.notas_importadas.clear()` imediatamente, sem nenhum modal de confirmação. Um clique acidental descarta o resultado atual sem aviso. - -**Sugestão:** Exibir modal de confirmação com a mensagem: -> "Deseja iniciar uma nova análise? O resultado atual será descartado." - -Botões: **Confirmar** | **Cancelar** - ---- - -## 5. Reorganizar seções do resultado - -A ordem atual das seções em `resultado.rs` é: - -``` -Totais → Faltantes → Duplicatas -``` - -O objetivo principal do software é detectar faltantes e duplicatas; os totais são informação complementar. - -**Sugestão:** Inverter para: - -``` -Faltantes → Duplicatas → Totais -``` - -Isso coloca a informação mais relevante no topo da tela. - ---- - -## 6. Seletor de layout também na tela de configuração de colunas - -O dropdown de layouts está disponível apenas em `import.rs`. O usuário frequentemente percebe que precisa de um layout diferente **depois** de visitar a tela de configuração e ver os campos. - -**Sugestão:** Duplicar o seletor de layout no topo de `configuracao_colunas.rs`, evitando que o usuário volte à tela anterior só para trocar o layout. - ---- - -## 7. Botão "Salvar como layout..." na tela de configuração - -Para salvar um layout atualmente o usuário precisa navegar para `GerenciandoLayouts`. Esse desvio quebra o fluxo principal. - -**Sugestão:** Adicionar um botão **"💾 Salvar como layout..."** diretamente em `configuracao_colunas.rs` que abre um modal simples pedindo apenas o nome do layout. Internamente, chama o mesmo use case `salvar_layout`. - ---- - -## 8. Feedback visual durante a análise - -A transição `ConfigurandoColunas → ExibindoResultado` pode demorar com arquivos grandes (até 100k registros, conforme RNF03). Atualmente o app não exibe nenhum sinal enquanto processa, parecendo travado. - -**Sugestão:** Adicionar o estado `Analisando` no `EstadoApp` (já previsto no IMPLEMENTACAO.md mas não implementado) e exibir uma mensagem simples tipo: - -``` -⏳ Analisando... aguarde. -``` - -Mesmo sem progresso percentual, já elimina a percepção de travamento. - ---- - -## Resumo de Impacto - -| # | Sugestão | Impacto UX | Esforço estimado | -|---|----------|------------|-----------------| -| 1 | Breadcrumb de etapas | Médio | Baixo | -| 2 | Unificar importação + configuração | Alto | Médio | -| 3 | Pré-visualização do arquivo | Alto | Médio | -| 4 | Confirmação em "Nova Análise" | Baixo | Baixo | -| 5 | Reordenar seções do resultado | Médio | Baixo | -| 6 | Seletor de layout em configuração | Médio | Baixo | -| 7 | Salvar layout na tela de configuração | Médio | Baixo | -| 8 | Feedback durante análise | Alto | Baixo | diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..09015d5 --- /dev/null +++ b/build.rs @@ -0,0 +1,7 @@ +fn main() { + if std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" { + let mut res = winres::WindowsResource::new(); + res.set_icon("icon.ico"); + res.compile().unwrap(); + } +} diff --git a/icon.ico b/icon.ico new file mode 100644 index 0000000..b17af15 Binary files /dev/null and b/icon.ico differ diff --git a/src/application/usecases/executar_analise.rs b/src/application/usecases/executar_analise.rs index 919ea62..4b8afb3 100644 --- a/src/application/usecases/executar_analise.rs +++ b/src/application/usecases/executar_analise.rs @@ -6,7 +6,7 @@ use crate::domain::{ }, services::{ detector_duplicidade::duplicidades_por_serie, - detector_sequencia::{LIMITE_FALTANTES, calcular_intervalo, detectar_faltantes}, + detector_sequencia::{calcular_intervalo, detectar_faltantes, LIMITE_FALTANTES}, }, }; use rust_decimal::Decimal; @@ -107,7 +107,13 @@ mod tests { } fn nota_com_tipo(numero: u64, serie: &str, tipo: &str) -> Nota { - Nota::new(numero, serie.to_string(), Some(tipo.to_string()), None, None) + Nota::new( + numero, + serie.to_string(), + Some(tipo.to_string()), + None, + None, + ) } #[test] diff --git a/src/domain/entities/mod.rs b/src/domain/entities/mod.rs index 5f5e86e..52ca926 100644 --- a/src/domain/entities/mod.rs +++ b/src/domain/entities/mod.rs @@ -1,5 +1,5 @@ +pub mod chave_serie; pub mod layout; pub mod nota; pub mod resultado_analise; pub mod serie; -pub mod chave_serie; diff --git a/src/domain/services/detector_duplicidade.rs b/src/domain/services/detector_duplicidade.rs index f82035e..078740d 100644 --- a/src/domain/services/detector_duplicidade.rs +++ b/src/domain/services/detector_duplicidade.rs @@ -50,7 +50,13 @@ mod tests { } fn nota_com_tipo(numero: u64, serie: &str, tipo: &str) -> Nota { - Nota::new(numero, serie.to_string(), Some(tipo.to_string()), None, None) + Nota::new( + numero, + serie.to_string(), + Some(tipo.to_string()), + None, + None, + ) } #[test] @@ -84,16 +90,25 @@ mod tests { #[test] fn mesmo_numero_serie_tipos_diferentes_nao_e_duplicata() { - let notas = vec![nota_com_tipo(1, "001", "NFE"), nota_com_tipo(1, "001", "NFCE")]; + let notas = vec![ + nota_com_tipo(1, "001", "NFE"), + nota_com_tipo(1, "001", "NFCE"), + ]; let dup = detectar_duplicidades(¬as); assert!(dup.is_empty()); } #[test] fn mesmo_numero_serie_tipo_igual_e_duplicata() { - let notas = vec![nota_com_tipo(1, "001", "NFE"), nota_com_tipo(1, "001", "NFE")]; + let notas = vec![ + nota_com_tipo(1, "001", "NFE"), + nota_com_tipo(1, "001", "NFE"), + ]; let dup = detectar_duplicidades(¬as); - assert_eq!(dup.get(&(1, "001".to_string(), Some("NFE".to_string()))), Some(&2)); + assert_eq!( + dup.get(&(1, "001".to_string(), Some("NFE".to_string()))), + Some(&2) + ); } #[test] diff --git a/src/infrastructure/csv_reader.rs b/src/infrastructure/csv_reader.rs index 25fb5a6..901934b 100644 --- a/src/infrastructure/csv_reader.rs +++ b/src/infrastructure/csv_reader.rs @@ -26,15 +26,14 @@ pub fn ler_csv( linha_cabecalho: usize, ) -> Result { // Verificar tamanho - let metadata = std::fs::metadata(caminho) - .map_err(|e| ErroArquivo::ErroLeitura(e.to_string()))?; + 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()))?; + let bytes = std::fs::read(caminho).map_err(|e| ErroArquivo::ErroLeitura(e.to_string()))?; // Decodificar encoding let conteudo = match encoding.to_lowercase().as_str() { @@ -42,10 +41,8 @@ pub fn ler_csv( let (decoded, _, _) = WINDOWS_1252.decode(&bytes); decoded.into_owned() } - _ => { - String::from_utf8(bytes) - .map_err(|e| ErroArquivo::ErroLeitura(format!("Encoding inválido: {}", e)))? - } + _ => String::from_utf8(bytes) + .map_err(|e| ErroArquivo::ErroLeitura(format!("Encoding inválido: {}", e)))?, }; let mut avisos = ResumoAvisos::default(); @@ -97,8 +94,7 @@ pub fn preview_csv( encoding: &str, n: usize, ) -> Result>, ErroArquivo> { - let bytes = std::fs::read(caminho) - .map_err(|e| ErroArquivo::ErroLeitura(e.to_string()))?; + let bytes = std::fs::read(caminho).map_err(|e| ErroArquivo::ErroLeitura(e.to_string()))?; let conteudo = match encoding.to_lowercase().as_str() { "windows-1252" | "latin-1" | "iso-8859-1" => { diff --git a/src/infrastructure/pdf_generator.rs b/src/infrastructure/pdf_generator.rs index fa8de1b..070127a 100644 --- a/src/infrastructure/pdf_generator.rs +++ b/src/infrastructure/pdf_generator.rs @@ -11,10 +11,8 @@ use std::path::Path; // Fontes embutidas no binário em tempo de compilação. // Liberation Sans (~402 KB cada) substitui Arial do sistema (~993 KB cada), // eliminando dependência de fonte externa e reduzindo o tamanho dos PDFs gerados. -const FONT_REGULAR: &[u8] = - include_bytes!("../../assets/fonts/LiberationSans-Regular.ttf"); -const FONT_BOLD: &[u8] = - include_bytes!("../../assets/fonts/LiberationSans-Bold.ttf"); +const FONT_REGULAR: &[u8] = include_bytes!("../../assets/fonts/LiberationSans-Regular.ttf"); +const FONT_BOLD: &[u8] = include_bytes!("../../assets/fonts/LiberationSans-Bold.ttf"); /// Metadados do relatório. pub struct MetadadosRelatorio { @@ -56,12 +54,10 @@ impl PdfGenerator for GenpdfGenerator { doc.set_page_decorator(decorator); // Título - doc.push( - Paragraph::new("").styled_string( - "Relatório de Análise de Notas Fiscais", - style::Style::new().bold().with_font_size(16), - ), - ); + doc.push(Paragraph::new("").styled_string( + "Relatório de Análise de Notas Fiscais", + style::Style::new().bold().with_font_size(16), + )); doc.push(Break::new(1)); // Metadados @@ -81,7 +77,8 @@ impl PdfGenerator for GenpdfGenerator { // Totais doc.push( - Paragraph::new("").styled_string("Totais", style::Style::new().bold().with_font_size(14)), + Paragraph::new("") + .styled_string("Totais", style::Style::new().bold().with_font_size(14)), ); doc.push(Paragraph::new(format!( "Total Geral: R$ {}", @@ -102,9 +99,10 @@ impl PdfGenerator for GenpdfGenerator { doc.push(Break::new(1)); // Notas Faltantes - doc.push( - Paragraph::new("").styled_string("Notas Faltantes por Série", style::Style::new().bold().with_font_size(14)), - ); + doc.push(Paragraph::new("").styled_string( + "Notas Faltantes por Série", + style::Style::new().bold().with_font_size(14), + )); // Use faltantes keys for this section (may differ from soma keys if no values) let mut chaves_faltantes: Vec<&ChaveSerie> = resultado.faltantes_por_serie.keys().collect(); @@ -114,7 +112,10 @@ impl PdfGenerator for GenpdfGenerator { let faltantes = match resultado.faltantes_por_serie.get(*chave) { Some(f) if !f.is_empty() => f, _ => { - doc.push(Paragraph::new(format!(" Série {}: nenhuma faltante", chave.label()))); + doc.push(Paragraph::new(format!( + " Série {}: nenhuma faltante", + chave.label() + ))); continue; } }; @@ -131,9 +132,10 @@ impl PdfGenerator for GenpdfGenerator { doc.push(Break::new(1)); // Duplicatas - doc.push( - Paragraph::new("").styled_string("Duplicatas por Série", style::Style::new().bold().with_font_size(14)), - ); + doc.push(Paragraph::new("").styled_string( + "Duplicatas por Série", + style::Style::new().bold().with_font_size(14), + )); let mut chaves_dup: Vec<&ChaveSerie> = resultado.duplicadas_por_serie.keys().collect(); chaves_dup.sort(); @@ -142,7 +144,10 @@ impl PdfGenerator for GenpdfGenerator { let duplicatas = match resultado.duplicadas_por_serie.get(*chave) { Some(d) if !d.is_empty() => d, _ => { - doc.push(Paragraph::new(format!(" Série {}: nenhuma duplicata", chave.label()))); + doc.push(Paragraph::new(format!( + " Série {}: nenhuma duplicata", + chave.label() + ))); continue; } }; @@ -155,7 +160,9 @@ impl PdfGenerator for GenpdfGenerator { for (numero, count) in duplicatas { doc.push(Paragraph::new(format!( " NF {} / Série {} — {} ocorrências", - numero, chave.label(), count + numero, + chave.label(), + count ))); } } diff --git a/src/infrastructure/sqlite/layout_repository.rs b/src/infrastructure/sqlite/layout_repository.rs index ae1d7d1..00c6569 100644 --- a/src/infrastructure/sqlite/layout_repository.rs +++ b/src/infrastructure/sqlite/layout_repository.rs @@ -125,15 +125,9 @@ pub fn listar(conn: &Connection) -> Result> { linha_cabecalho: row.get::<_, i64>(5)? as usize, indice_numero: row.get::<_, i64>(6)? as usize, indice_serie: row.get::<_, i64>(7)? as usize, - indice_valor: row - .get::<_, Option>(8)? - .map(|v| v as usize), - indice_data: row - .get::<_, Option>(9)? - .map(|v| v as usize), - indice_documento_tipo: row - .get::<_, Option>(15)? - .map(|v| v as usize), + indice_valor: row.get::<_, Option>(8)?.map(|v| v as usize), + indice_data: row.get::<_, Option>(9)?.map(|v| v as usize), + indice_documento_tipo: row.get::<_, Option>(15)?.map(|v| v as usize), }, }) } else { diff --git a/src/infrastructure/sqlite/migrations.rs b/src/infrastructure/sqlite/migrations.rs index 4510dd9..bf7353a 100644 --- a/src/infrastructure/sqlite/migrations.rs +++ b/src/infrastructure/sqlite/migrations.rs @@ -14,11 +14,9 @@ pub fn aplicar_migrations(conn: &Connection) -> Result<()> { )?; let versao_atual: i64 = conn - .query_row( - "SELECT versao FROM schema_version LIMIT 1;", - [], - |row| row.get(0), - ) + .query_row("SELECT versao FROM schema_version LIMIT 1;", [], |row| { + row.get(0) + }) .unwrap_or(0); if versao_atual < 1 { @@ -32,9 +30,15 @@ pub fn aplicar_migrations(conn: &Connection) -> Result<()> { } if versao_atual == 0 { - conn.execute("INSERT INTO schema_version (versao) VALUES (?1);", [VERSAO_SCHEMA_ATUAL])?; + conn.execute( + "INSERT INTO schema_version (versao) VALUES (?1);", + [VERSAO_SCHEMA_ATUAL], + )?; } else if versao_atual < VERSAO_SCHEMA_ATUAL { - conn.execute("UPDATE schema_version SET versao = ?1;", [VERSAO_SCHEMA_ATUAL])?; + conn.execute( + "UPDATE schema_version SET versao = ?1;", + [VERSAO_SCHEMA_ATUAL], + )?; } Ok(()) diff --git a/src/infrastructure/xlsx_reader.rs b/src/infrastructure/xlsx_reader.rs index 61ab97c..869d631 100644 --- a/src/infrastructure/xlsx_reader.rs +++ b/src/infrastructure/xlsx_reader.rs @@ -24,8 +24,8 @@ pub struct ResultadoXlsx { pub fn listar_abas(caminho: &Path) -> Result, ErroArquivo> { verificar_tamanho(caminho)?; - let workbook = open_workbook_auto(caminho) - .map_err(|e| ErroArquivo::Corrompido(e.to_string()))?; + let workbook = + open_workbook_auto(caminho).map_err(|e| ErroArquivo::Corrompido(e.to_string()))?; Ok(workbook.sheet_names().to_vec()) } @@ -45,8 +45,8 @@ pub fn ler_xlsx( ) -> Result { verificar_tamanho(caminho)?; - let mut workbook = open_workbook_auto(caminho) - .map_err(|e| ErroArquivo::Corrompido(e.to_string()))?; + let mut workbook = + open_workbook_auto(caminho).map_err(|e| ErroArquivo::Corrompido(e.to_string()))?; let range: calamine::Range = workbook .worksheet_range(nome_aba) @@ -99,14 +99,11 @@ pub fn ler_xlsx( /// Retorna as primeiras 5 linhas de uma aba XLSX, a partir da linha 1. /// Usado exclusivamente para pré-visualização na UI. -pub fn preview_xlsx( - caminho: &Path, - nome_aba: &str, -) -> Result>, ErroArquivo> { +pub fn preview_xlsx(caminho: &Path, nome_aba: &str) -> Result>, ErroArquivo> { verificar_tamanho(caminho)?; - let mut workbook = open_workbook_auto(caminho) - .map_err(|e| ErroArquivo::Corrompido(e.to_string()))?; + let mut workbook = + open_workbook_auto(caminho).map_err(|e| ErroArquivo::Corrompido(e.to_string()))?; let range: calamine::Range = workbook .worksheet_range(nome_aba) @@ -182,8 +179,8 @@ pub fn parsear_letra_linha(s: &str) -> Option { } fn verificar_tamanho(caminho: &Path) -> Result<(), ErroArquivo> { - let metadata = std::fs::metadata(caminho) - .map_err(|e| ErroArquivo::ErroLeitura(e.to_string()))?; + 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())); } diff --git a/src/main.rs b/src/main.rs index d7aa8b5..96d2ed8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + mod application; mod domain; mod infrastructure; @@ -5,15 +7,32 @@ mod ui; use ui::app::App; +fn load_icon() -> Option { + let bytes = include_bytes!("../icon.ico"); + let img = image::load_from_memory(bytes).ok()?.into_rgba8(); + let (width, height) = img.dimensions(); + Some(egui::viewport::IconData { + rgba: img.into_raw(), + width, + height, + }) +} + fn main() -> eframe::Result { + let mut viewport = egui::ViewportBuilder::default() + .with_title("Comparador de Notas") + .with_inner_size([1024.0, 768.0]) + .with_min_inner_size([800.0, 600.0]); + + if let Some(icon) = load_icon() { + viewport = viewport.with_icon(std::sync::Arc::new(icon)); + } + let native_options = eframe::NativeOptions { - viewport: egui::ViewportBuilder::default() - .with_title("Comparador de Notas") - .with_inner_size([1024.0, 768.0]) - .with_min_inner_size([800.0, 600.0]), + viewport, ..Default::default() }; - + eframe::run_native( "Comparador de Notas", native_options, diff --git a/src/ui/screens/configuracao_colunas.rs b/src/ui/screens/configuracao_colunas.rs index a69fee5..c563715 100644 --- a/src/ui/screens/configuracao_colunas.rs +++ b/src/ui/screens/configuracao_colunas.rs @@ -1,7 +1,7 @@ -use crate::application::usecases::importar_arquivo::{importar_csv, importar_xlsx}; use crate::application::usecases::executar_analise::{ expandir_analise, pre_analisar, series_com_intervalo_excessivo, }; +use crate::application::usecases::importar_arquivo::{importar_csv, importar_xlsx}; use crate::domain::entities::layout::{Layout, TipoArquivo}; use crate::ui::app::{App, EstadoApp, ResultadoPendente}; use egui::{Context, Ui}; @@ -169,7 +169,8 @@ fn renderizar_csv(ui: &mut Ui, app: &mut App) { app.layout_csv_atual.delimitador as u8, &app.layout_csv_atual.encoding.clone(), 5, - ).ok(); + ) + .ok(); } } }); diff --git a/src/ui/screens/layouts.rs b/src/ui/screens/layouts.rs index a8cbc88..69413a5 100644 --- a/src/ui/screens/layouts.rs +++ b/src/ui/screens/layouts.rs @@ -239,10 +239,7 @@ fn importar_json(app: &mut App, conteudo: &str) { ); } _ => { - app.exibir_erro(format!( - "Conflito de nome: layout '{}' já existe.", - nome - )); + app.exibir_erro(format!("Conflito de nome: layout '{}' já existe.", nome)); } } } diff --git a/src/ui/screens/mod.rs b/src/ui/screens/mod.rs index b292dc8..6647f5b 100644 --- a/src/ui/screens/mod.rs +++ b/src/ui/screens/mod.rs @@ -26,12 +26,9 @@ pub fn renderizar_tabela_preview(ui: &mut egui::Ui, linhas: &[Vec]) { } ui.label( - egui::RichText::new(format!( - "Pré-visualização ({} linha(s))", - linhas.len() - )) - .small() - .weak(), + egui::RichText::new(format!("Pré-visualização ({} linha(s))", linhas.len())) + .small() + .weak(), ); ui.add_space(2.0); @@ -69,4 +66,4 @@ pub fn renderizar_tabela_preview(ui: &mut egui::Ui, linhas: &[Vec]) { } }); }); -} \ No newline at end of file +}