diff --git a/src/application/usecases/executar_analise.rs b/src/application/usecases/executar_analise.rs index 37efeee..9fb5ee8 100644 --- a/src/application/usecases/executar_analise.rs +++ b/src/application/usecases/executar_analise.rs @@ -1,11 +1,11 @@ use crate::domain::{ entities::{ nota::Nota, - resultado_analise::{IntervaloSerie, ResultadoAnalise, ResultadoPreAnalise}, + resultado_analise::{ResultadoAnalise, ResultadoPreAnalise}, }, services::{ detector_duplicidade::duplicidades_por_serie, - detector_sequencia::{calcular_intervalo, detectar_faltantes, LIMITE_FALTANTES}, + detector_sequencia::{LIMITE_FALTANTES, calcular_intervalo, detectar_faltantes}, }, }; use rust_decimal::Decimal; @@ -55,9 +55,7 @@ pub fn pre_analisar(notas: &[Nota]) -> ResultadoPreAnalise { /// Verifica se alguma série excede o limite de faltantes. /// Retorna lista de séries que precisam de confirmação. -pub fn series_com_intervalo_excessivo( - pre: &ResultadoPreAnalise, -) -> Vec<(String, u64)> { +pub fn series_com_intervalo_excessivo(pre: &ResultadoPreAnalise) -> Vec<(String, u64)> { pre.intervalos_por_serie .iter() .filter(|(_, iv)| iv.excede_limite(LIMITE_FALTANTES)) @@ -89,19 +87,18 @@ pub fn expandir_analise(pre: ResultadoPreAnalise, notas: &[Nota]) -> ResultadoAn } } -/// Executa análise completa sem verificar limites (use case simplificado). -/// Útil quando o caller já confirmou ou sabe que não há intervalos excessivos. -pub fn executar_analise(notas: &[Nota]) -> ResultadoAnalise { - let pre = pre_analisar(notas); - expandir_analise(pre, notas) -} - #[cfg(test)] mod tests { use super::*; use crate::domain::entities::nota::Nota; use rust_decimal_macros::dec; + /// Executa análise completa sem verificar limites (atalho para testes). + fn executar_analise(notas: &[Nota]) -> ResultadoAnalise { + let pre = pre_analisar(notas); + expandir_analise(pre, notas) + } + fn nota(numero: u64, serie: &str, valor: Option) -> Nota { Nota::new(numero, serie.to_string(), valor, None) } @@ -133,10 +130,7 @@ mod tests { #[test] fn pre_analise_detecta_intervalo_excessivo() { - let notas = vec![ - nota(1, "001", None), - nota(20_000, "001", None), - ]; + let notas = vec![nota(1, "001", None), nota(20_000, "001", None)]; let pre = pre_analisar(¬as); let excessivos = series_com_intervalo_excessivo(&pre); assert_eq!(excessivos.len(), 1); diff --git a/src/application/usecases/importar_arquivo.rs b/src/application/usecases/importar_arquivo.rs index 63414c4..def8fed 100644 --- a/src/application/usecases/importar_arquivo.rs +++ b/src/application/usecases/importar_arquivo.rs @@ -1,4 +1,4 @@ -use crate::domain::entities::layout::{Layout, LayoutCsv, LayoutXlsx}; +use crate::domain::entities::layout::{LayoutCsv, LayoutXlsx}; use crate::domain::entities::nota::Nota; use crate::domain::entities::serie::validar_serie; use crate::domain::errors::{ErroArquivo, ResumoAvisos}; @@ -24,7 +24,10 @@ pub fn listar_abas_xlsx(caminho: &Path) -> Result { } /// Importa um arquivo CSV e retorna as notas válidas + avisos consolidados. -pub fn importar_csv(caminho: &Path, config: &LayoutCsv) -> Result { +pub fn importar_csv( + caminho: &Path, + config: &LayoutCsv, +) -> Result { let resultado = csv_reader::ler_csv( caminho, config.delimitador as u8, @@ -46,17 +49,21 @@ pub fn importar_csv(caminho: &Path, config: &LayoutCsv) -> Result Result { +pub fn importar_xlsx( + caminho: &Path, + config: &LayoutXlsx, +) -> Result { // Determinar linha de início a partir de qualquer campo mapeado let linha_inicio = { - let coord_num = xlsx_reader::parsear_letra_linha(&config.pos_numero) - .ok_or_else(|| ErroArquivo::ErroLeitura(format!( - "Posição de Numero inválida: '{}'", config.pos_numero - )))?; - let coord_ser = xlsx_reader::parsear_letra_linha(&config.pos_serie) - .ok_or_else(|| ErroArquivo::ErroLeitura(format!( - "Posição de Serie inválida: '{}'", config.pos_serie - )))?; + let coord_num = xlsx_reader::parsear_letra_linha(&config.pos_numero).ok_or_else(|| { + ErroArquivo::ErroLeitura(format!( + "Posição de Numero inválida: '{}'", + config.pos_numero + )) + })?; + let coord_ser = xlsx_reader::parsear_letra_linha(&config.pos_serie).ok_or_else(|| { + ErroArquivo::ErroLeitura(format!("Posição de Serie inválida: '{}'", config.pos_serie)) + })?; coord_num.linha.min(coord_ser.linha) }; @@ -113,7 +120,9 @@ fn mapear_linhas_para_notas( Some(s) if !s.trim().is_empty() => s.trim().to_string(), _ => { avisos.numeros_invalidos += 1; - avisos.detalhes.push(format!("Linha {}: campo Numero ausente", linha_num)); + avisos + .detalhes + .push(format!("Linha {}: campo Numero ausente", linha_num)); continue; } }; @@ -123,7 +132,9 @@ fn mapear_linhas_para_notas( Ok(n) => n, Err(msg) => { avisos.numeros_invalidos += 1; - avisos.detalhes.push(format!("Linha {}: {}", linha_num, msg)); + avisos + .detalhes + .push(format!("Linha {}: {}", linha_num, msg)); continue; } }; @@ -133,7 +144,9 @@ fn mapear_linhas_para_notas( Some(s) => s.trim().to_string(), None => { avisos.series_invalidas += 1; - avisos.detalhes.push(format!("Linha {}: campo Serie ausente", linha_num)); + avisos + .detalhes + .push(format!("Linha {}: campo Serie ausente", linha_num)); continue; } }; diff --git a/src/application/usecases/layouts.rs b/src/application/usecases/layouts.rs index f55c21a..db231c1 100644 --- a/src/application/usecases/layouts.rs +++ b/src/application/usecases/layouts.rs @@ -2,7 +2,7 @@ use crate::domain::{ entities::layout::{Layout, LayoutJson}, errors::ErroLayout, }; -use crate::infrastructure::sqlite::{layout_repository, migrations}; +use crate::infrastructure::sqlite::layout_repository; use rusqlite::Connection; /// Salva um layout no banco de dados. @@ -14,12 +14,10 @@ pub fn salvar_layout(conn: &Connection, layout: &Layout) -> Result } if let Some(id) = layout.id() { - layout_repository::atualizar(conn, layout) - .map_err(|e| e.to_string())?; + layout_repository::atualizar(conn, layout).map_err(|e| e.to_string())?; Ok(id) } else { - layout_repository::salvar(conn, layout) - .map_err(|e| e.to_string()) + layout_repository::salvar(conn, layout).map_err(|e| e.to_string()) } } @@ -28,11 +26,6 @@ pub fn listar_layouts(conn: &Connection) -> Result, String> { layout_repository::listar(conn).map_err(|e| e.to_string()) } -/// Carrega um layout pelo id. -pub fn carregar_layout(conn: &Connection, id: i64) -> Result, String> { - layout_repository::buscar_por_id(conn, id).map_err(|e| e.to_string()) -} - /// Exclui um layout pelo id. pub fn excluir_layout(conn: &Connection, id: i64) -> Result<(), String> { layout_repository::excluir(conn, id).map_err(|e| e.to_string()) @@ -61,8 +54,8 @@ pub fn importar_layout_json( novo_nome: Option<&str>, ) -> Result { // Deserializar - let json_repr: LayoutJson = serde_json::from_str(json) - .map_err(|e| ErroLayout::JsonMalformado(e.to_string()))?; + let json_repr: LayoutJson = + serde_json::from_str(json).map_err(|e| ErroLayout::JsonMalformado(e.to_string()))?; let mut layout = Layout::try_from(json_repr)?; @@ -105,6 +98,5 @@ pub fn importar_layout_json( } // Inserir novo - layout_repository::salvar(conn, &layout) - .map_err(|e| ErroLayout::JsonMalformado(e.to_string())) + layout_repository::salvar(conn, &layout).map_err(|e| ErroLayout::JsonMalformado(e.to_string())) } diff --git a/src/domain/errors.rs b/src/domain/errors.rs index 1b42960..a10a98a 100644 --- a/src/domain/errors.rs +++ b/src/domain/errors.rs @@ -1,13 +1,5 @@ use thiserror::Error; -#[derive(Debug, Error, Clone)] -pub enum ErroNumero { - #[error("Número zero não é válido para uma nota fiscal")] - Zero, - #[error("Valor não numérico: '{0}'")] - NaoNumerico(String), -} - #[derive(Debug, Error, Clone)] pub enum ErroSerie { #[error("Série inválida: '{0}' (deve conter de 1 a 3 dígitos numéricos)")] @@ -40,52 +32,10 @@ pub enum ErroArquivo { TamanhoExcedido(u64), #[error("Arquivo corrompido ou ilegível: {0}")] Corrompido(String), - #[error("Formato não suportado: {0}")] - FormatoNaoSuportado(String), #[error("Erro de leitura: {0}")] ErroLeitura(String), } -#[derive(Debug, Error)] -pub enum ErroAnalise { - #[error("Intervalo de faltantes muito grande para a série '{serie}': {intervalo} registros")] - IntervaloMuitoGrande { serie: String, intervalo: u64 }, - #[error("Campo obrigatório não mapeado: {0}")] - CampoObrigatorioNaoMapeado(String), - #[error("Índice de coluna inválido: campo '{campo}', índice {indice}")] - IndiceInvalido { campo: String, indice: usize }, - #[error("Dois campos mapeados para o mesmo índice: {0}")] - IndicesDuplicados(String), -} - -/// Aviso coletado durante a importação, para ser exibido de forma consolidada ao usuário. -#[derive(Debug, Clone)] -pub struct AvisoImportacao { - pub categoria: CategoriaAviso, - pub mensagem: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum CategoriaAviso { - LinhaMalformada, - NumeroInvalido, - SerieInvalida, - ValorInvalido, - RegistroDescartado, -} - -impl std::fmt::Display for CategoriaAviso { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - CategoriaAviso::LinhaMalformada => write!(f, "Linhas malformadas"), - CategoriaAviso::NumeroInvalido => write!(f, "Valores de Numero inválidos"), - CategoriaAviso::SerieInvalida => write!(f, "Registros com Série inválida"), - CategoriaAviso::ValorInvalido => write!(f, "Valores monetários inválidos"), - CategoriaAviso::RegistroDescartado => write!(f, "Registros descartados"), - } - } -} - /// Resumo consolidado de avisos para exibição em um único modal. #[derive(Debug, Default, Clone)] pub struct ResumoAvisos { diff --git a/src/infrastructure/pdf_generator.rs b/src/infrastructure/pdf_generator.rs index 54c46db..d47578c 100644 --- a/src/infrastructure/pdf_generator.rs +++ b/src/infrastructure/pdf_generator.rs @@ -3,7 +3,7 @@ use crate::domain::services::parser_monetario::formatar_valor_br; use chrono::{DateTime, Local}; use genpdf::{ elements::{Break, Paragraph}, - fonts, style, Document, Element, SimplePageDecorator, + fonts, style, Document, SimplePageDecorator, }; use std::path::Path; diff --git a/src/infrastructure/sqlite/connection.rs b/src/infrastructure/sqlite/connection.rs index 452d1ff..1cf9562 100644 --- a/src/infrastructure/sqlite/connection.rs +++ b/src/infrastructure/sqlite/connection.rs @@ -1,8 +1,6 @@ use rusqlite::Connection; use std::path::{Path, PathBuf}; -const LIMITE_50MB: u64 = 50 * 1024 * 1024; - /// Determina o caminho do banco de dados conforme o sistema operacional. pub fn caminho_banco() -> PathBuf { let config_dir = dirs::config_dir().unwrap_or_else(|| PathBuf::from(".")); @@ -33,7 +31,7 @@ pub fn abrir_banco_no_caminho(caminho: &Path) -> Result<(Connection, bool), Stri // Testar se o banco funciona com uma query simples match conn.execute_batch("SELECT 1;") { Ok(_) => return Ok((conn, false)), - Err(e) => { + Err(_e) => { // Banco corrompido drop(conn); let bak = caminho.with_extension("db.bak"); diff --git a/src/infrastructure/sqlite/layout_repository.rs b/src/infrastructure/sqlite/layout_repository.rs index d260e2c..385aae5 100644 --- a/src/infrastructure/sqlite/layout_repository.rs +++ b/src/infrastructure/sqlite/layout_repository.rs @@ -145,55 +145,6 @@ pub fn listar(conn: &Connection) -> Result> { layouts } -/// Busca um layout pelo id. -pub fn buscar_por_id(conn: &Connection, id: i64) -> Result> { - let mut stmt = conn.prepare( - "SELECT id, nome, tipo, - delimitador, encoding, linha_cabecalho, - indice_numero, indice_serie, indice_valor, indice_data, - aba, pos_numero, pos_serie, pos_valor, pos_data - FROM layouts WHERE id = ?1", - )?; - - let mut results = stmt.query_map([id], |row| { - let id: i64 = row.get(0)?; - let nome: String = row.get(1)?; - let tipo: String = row.get(2)?; - - if tipo == "csv" { - let delim_str: String = row.get(3)?; - let delimitador = delim_str.chars().next().unwrap_or(';'); - Ok(Layout::Csv { - id: Some(id), - nome, - config: LayoutCsv { - delimitador, - encoding: row.get(4)?, - 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), - }, - }) - } else { - Ok(Layout::Xlsx { - id: Some(id), - nome, - config: LayoutXlsx { - aba: row.get(10)?, - pos_numero: row.get(11)?, - pos_serie: row.get(12)?, - pos_valor: row.get(13)?, - pos_data: row.get(14)?, - }, - }) - } - })?; - - results.next().transpose() -} - /// Remove um layout pelo id. pub fn excluir(conn: &Connection, id: i64) -> Result<()> { conn.execute("DELETE FROM layouts WHERE id = ?1", [id])?; diff --git a/src/infrastructure/sqlite/migrations.rs b/src/infrastructure/sqlite/migrations.rs index 0ba9e6d..4ac6eec 100644 --- a/src/infrastructure/sqlite/migrations.rs +++ b/src/infrastructure/sqlite/migrations.rs @@ -21,12 +21,12 @@ pub fn aplicar_migrations(conn: &Connection) -> Result<()> { ) .unwrap_or(0); - if versao_atual < 1 { + if versao_atual < VERSAO_SCHEMA_ATUAL { migration_v1(conn)?; if versao_atual == 0 { - conn.execute("INSERT INTO schema_version (versao) VALUES (?1);", [1])?; + conn.execute("INSERT INTO schema_version (versao) VALUES (?1);", [VERSAO_SCHEMA_ATUAL])?; } else { - conn.execute("UPDATE schema_version SET versao = ?1;", [1])?; + conn.execute("UPDATE schema_version SET versao = ?1;", [VERSAO_SCHEMA_ATUAL])?; } } diff --git a/src/infrastructure/xlsx_reader.rs b/src/infrastructure/xlsx_reader.rs index eeb039f..61ab97c 100644 --- a/src/infrastructure/xlsx_reader.rs +++ b/src/infrastructure/xlsx_reader.rs @@ -52,7 +52,7 @@ pub fn ler_xlsx( .worksheet_range(nome_aba) .map_err(|e| ErroArquivo::Corrompido(e.to_string()))?; - let mut avisos = ResumoAvisos::default(); + let avisos = ResumoAvisos::default(); let mut linhas: Vec> = Vec::new(); let linha_inicio_base0 = (linha_inicio.saturating_sub(1)) as usize; diff --git a/src/ui/app.rs b/src/ui/app.rs index 20f3e26..e9a127c 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -1,10 +1,6 @@ use crate::application::usecases::{ executar_analise::{expandir_analise, pre_analisar, series_com_intervalo_excessivo}, - importar_arquivo::{importar_csv, importar_xlsx, listar_abas_xlsx, ResultadoImportacao}, - layouts::{ - carregar_layout, excluir_layout, exportar_layout_json, importar_layout_json, - listar_layouts, salvar_layout, - }, + layouts::{excluir_layout, listar_layouts, salvar_layout}, }; use crate::domain::{ entities::{ @@ -14,10 +10,7 @@ use crate::domain::{ }, errors::ResumoAvisos, }; -use crate::infrastructure::{ - pdf_generator::GenpdfGenerator, - sqlite::{connection::abrir_banco, migrations::aplicar_migrations}, -}; +use crate::infrastructure::sqlite::{connection::abrir_banco, migrations::aplicar_migrations}; use egui::Context; use rusqlite::Connection; use std::path::PathBuf; @@ -34,10 +27,7 @@ pub enum EstadoApp { /// Resultado pronto para exibição. ExibindoResultado(ResultadoAnalise), /// Aguardando confirmação do usuário para expandir faltantes. - ConfirmandoIntervalo { - pre: ResultadoPreAnalise, - series_excessivas: Vec<(String, u64)>, - }, + ConfirmandoIntervalo { pre: ResultadoPreAnalise }, /// Gerenciamento de layouts. GerenciandoLayouts, /// Análise em execução em background (thread separada). @@ -72,6 +62,7 @@ pub enum TipoModal { pub enum AcaoModal { ConfirmarExpansaoFaltantes, ConfirmarExclusaoLayout(i64), + #[allow(dead_code)] SobrescreverLayout, ConfirmarNovaAnalise, /// Salvar a configuração atual como novo layout, usando modal.input_texto como nome. @@ -396,12 +387,20 @@ impl App { /// Processa o resultado recebido do canal de análise em background. pub fn processar_resultado_pendente(&mut self, resultado: ResultadoPendente) { match resultado { - ResultadoPendente::Concluido { resultado, avisos, notas } => { + ResultadoPendente::Concluido { + resultado, + avisos, + notas, + } => { if let Some(n) = notas { self.notas_importadas = n; } if let Some(av) = &avisos { - self.avisos_importacao = if av.tem_avisos() { Some(av.clone()) } else { None }; + self.avisos_importacao = if av.tem_avisos() { + Some(av.clone()) + } else { + None + }; } self.estado = EstadoApp::ExibindoResultado(resultado); if let Some(av) = &self.avisos_importacao.clone() { @@ -418,18 +417,22 @@ impl App { notas, } => { self.notas_importadas = notas; - self.avisos_importacao = if avisos.tem_avisos() { Some(avisos) } else { None }; + self.avisos_importacao = if avisos.tem_avisos() { + Some(avisos) + } else { + None + }; let msg = series_excessivas .iter() .map(|(serie, count)| { - format!("Série {}: intervalo de {} faltantes detectado", serie, count) + format!( + "Série {}: intervalo de {} faltantes detectado", + serie, count + ) }) .collect::>() .join("\n"); - self.estado = EstadoApp::ConfirmandoIntervalo { - pre, - series_excessivas, - }; + self.estado = EstadoApp::ConfirmandoIntervalo { pre }; self.exibir_confirmacao( "Intervalo muito grande", format!( @@ -464,16 +467,16 @@ impl App { let msg = excessivos .iter() .map(|(serie, count)| { - format!("Série {}: intervalo de {} faltantes detectado", serie, count) + format!( + "Série {}: intervalo de {} faltantes detectado", + serie, count + ) }) .collect::>() .join("\n"); let acao = AcaoModal::ConfirmarExpansaoFaltantes; - self.estado = EstadoApp::ConfirmandoIntervalo { - pre, - series_excessivas: excessivos, - }; + self.estado = EstadoApp::ConfirmandoIntervalo { pre }; self.exibir_confirmacao( "Intervalo muito grande", format!( @@ -502,7 +505,8 @@ impl App { egui::TopBottomPanel::top("breadcrumb").show(ctx, |ui| { ui.add_space(4.0); ui.horizontal(|ui| { - for (i, label) in ["① Arquivo", "② Colunas", "③ Resultado"].iter().enumerate() { + for (i, label) in ["① Arquivo", "② Colunas", "③ Resultado"].iter().enumerate() + { let n = i + 1; let texto = egui::RichText::new(*label); if n == passo_ativo { @@ -552,25 +556,23 @@ impl eframe::App for App { let tela_id = self.tela_atual(); // Renderizar a tela atual - egui::CentralPanel::default().show(ctx, |ui| { - match tela_id { - 0 => crate::ui::screens::import::renderizar(ui, ctx, self), - 1 => crate::ui::screens::import::renderizar_selecao_aba(ui, ctx, self), - 2 => crate::ui::screens::configuracao_colunas::renderizar(ui, ctx, self), - 3 => crate::ui::screens::resultado::renderizar(ui, ctx, self), - 4 => crate::ui::screens::configuracao_colunas::renderizar(ui, ctx, self), - 5 => crate::ui::screens::layouts::renderizar(ui, ctx, self), - 6 => { - ui.centered_and_justified(|ui| { - ui.label( - egui::RichText::new("⏳ Analisando... aguarde.") - .size(22.0) - .strong(), - ); - }); - } - _ => {} + egui::CentralPanel::default().show(ctx, |ui| match tela_id { + 0 => crate::ui::screens::import::renderizar(ui, ctx, self), + 1 => crate::ui::screens::import::renderizar_selecao_aba(ui, ctx, self), + 2 => crate::ui::screens::configuracao_colunas::renderizar(ui, ctx, self), + 3 => crate::ui::screens::resultado::renderizar(ui, ctx, self), + 4 => crate::ui::screens::configuracao_colunas::renderizar(ui, ctx, self), + 5 => crate::ui::screens::layouts::renderizar(ui, ctx, self), + 6 => { + ui.centered_and_justified(|ui| { + ui.label( + egui::RichText::new("⏳ Analisando... aguarde.") + .size(22.0) + .strong(), + ); + }); } + _ => {} }); } } diff --git a/src/ui/screens/configuracao_colunas.rs b/src/ui/screens/configuracao_colunas.rs index d56a8e8..2dfd229 100644 --- a/src/ui/screens/configuracao_colunas.rs +++ b/src/ui/screens/configuracao_colunas.rs @@ -100,6 +100,16 @@ pub fn renderizar(ui: &mut Ui, ctx: &Context, app: &mut App) { } }); + if valido && !app.notas_importadas.is_empty() { + if ui + .button("🔄 Reanalisar") + .on_hover_text("Reanalisa as notas já importadas sem reimportar o arquivo") + .clicked() + { + app.executar_analise(); + } + } + if ui.button("💾 Salvar como layout...").clicked() { app.exibir_modal_salvar_layout(); } diff --git a/src/ui/screens/import.rs b/src/ui/screens/import.rs index 09f36e5..725d40d 100644 --- a/src/ui/screens/import.rs +++ b/src/ui/screens/import.rs @@ -1,6 +1,4 @@ -use crate::application::usecases::importar_arquivo::{ - importar_csv, importar_xlsx, listar_abas_xlsx, -}; +use crate::application::usecases::importar_arquivo::listar_abas_xlsx; use crate::domain::entities::layout::TipoArquivo; use crate::ui::app::{App, EstadoApp}; use egui::{Context, Ui}; diff --git a/src/ui/screens/layouts.rs b/src/ui/screens/layouts.rs index 776fdfe..916bde8 100644 --- a/src/ui/screens/layouts.rs +++ b/src/ui/screens/layouts.rs @@ -1,7 +1,7 @@ use crate::application::usecases::layouts::{ exportar_layout_json, importar_layout_json, salvar_layout, }; -use crate::domain::entities::layout::{Layout, LayoutCsv, LayoutXlsx, TipoArquivo}; +use crate::domain::entities::layout::{Layout, TipoArquivo}; use crate::domain::errors::ErroLayout; use crate::ui::app::{AcaoModal, App, EstadoApp}; use egui::{Context, Ui}; @@ -83,7 +83,7 @@ pub fn renderizar(ui: &mut Ui, ctx: &Context, app: &mut App) { fn renderizar_secao_layouts( ui: &mut Ui, - ctx: &Context, + _ctx: &Context, app: &mut App, titulo: &str, layouts: &[Layout], diff --git a/src/ui/screens/resultado.rs b/src/ui/screens/resultado.rs index 652ec3d..cf38135 100644 --- a/src/ui/screens/resultado.rs +++ b/src/ui/screens/resultado.rs @@ -10,7 +10,7 @@ use egui::{Context, Ui}; const OPCOES_PAGINA: &[usize] = &[50, 100, 200, 1000]; /// Renderiza a tela de resultados. -pub fn renderizar(ui: &mut Ui, ctx: &Context, app: &mut App) { +pub fn renderizar(ui: &mut Ui, _ctx: &Context, app: &mut App) { // Extrair resultado do estado (sem mover) let resultado = match &app.estado { EstadoApp::ExibindoResultado(r) => r.clone(),