diff --git a/docs/icon-system.md b/docs/icon-system.md new file mode 100644 index 0000000..249ce6e --- /dev/null +++ b/docs/icon-system.md @@ -0,0 +1,106 @@ +# Sistema de Ícones — CyberCore Signer + +Este documento estabelece as especificações de design, gramática visual, convenções de código e diretrizes de renderização do sistema de ícones do **CyberCore Signer**. + +--- + +## 1. Gramática Visual e Grid Base + +O sistema de ícones do CyberCore Signer foi projetado para oferecer clareza, consistência corporativa e alta fidelidade tanto no **Modo Claro** quanto no **Modo Escuro**, além de suporte a telas com alta densidade de pixels (HiDPI / Retina). + +| Parâmetro | Especificação | Descrição | +| :--- | :--- | :--- | +| **ViewBox Canônico** | `0 0 24 24` | Todos os ícones são desenhados em um canvas quadrado padronizado de 24×24 pixels. | +| **Safe Area** | `2px` em todas as bordas | Os grafismos principais ficam contidos na área útil de `20×20px` (coordenadas de `2` a `22`). | +| **Stroke (Espessura)** | `1.75px` a `2.0px` | Traços consistentes entre todos os glifos vetoriais, proporcionando peso uniforme. | +| **Cantos e Terminações** | `round` | `stroke-linecap="round"` e `stroke-linejoin="round"` para um visual moderno e suave. | +| **Texto Embutido** | **Nenhum** (`Proibido`) | Ícones não devem incorporar elementos ``. Toda semântica é transmitida por formas puras e labels da interface. | + +--- + +## 2. Paleta de Cores e Tintas Semânticas + +Os ícones utilizam `currentColor` como tinta principal, permitindo repintura dinâmica e herança das cores dos tokens do tema ativo: + +| Papel | Token / Cor Modo Claro | Token / Cor Modo Escuro | Uso | +| :--- | :--- | :--- | :--- | +| **Tinta Principal (`currentColor`)** | `#1E293B` (`-fx-color-text`) | `#F1F5F9` (`-fx-color-text`) | Linhas de contorno, silhuetas e glifos primários. | +| **Acento Primário** | `#0288D1` (`-fx-color-primary`) | `#38BDF8` (`-fx-color-primary`) | Elementos de destaque, dobras de documentos, escudos. | +| **Sucesso** | `#10B981` (`-fx-color-success`) | `#34D399` (`-fx-color-success`) | Confirmações, validações concluídas (`check`, `validate`). | +| **Alerta / Atenção** | `#F59E0B` (`-fx-color-warning`) | `#FBBF24` (`-fx-color-warning`) | Avisos de validade próxima, selos e certificações (`seal`). | +| **Erro / Perigo** | `#EF4444` (`-fx-color-error`) | `#F87171` (`-fx-color-error`) | Ações destrutivas, falhas de assinatura (`error`, `exit`). | +| **Atenuado / Muted** | `#64748B` (`-fx-color-text-muted`) | `#94A3B8` (`-fx-color-text-muted`) | Guias internas, linhas secundárias, fechar (`close`). | + +--- + +## 3. Escala de Tamanhos Padronizados + +Para manter a consistência da interface, os ícones devem ser consumidos exclusivamente através dos 5 tamanhos canônicos definidos na fachada `Icons`: + +``` + 16px 20px 24px 32px 40px + [ Micro ] [ Pequeno ] [ Padrão ] [ Médio ] [ Grande ] +``` + +- **`SIZE_16` (16×16 px):** Badges de status de certificado, botões auxiliares pequenos de janelas de diálogo (ex.: fechar, atualizar). +- **`SIZE_20` (20×20 px):** Menus secundários, botões de ação secundária, itens compactos em listas. +- **`SIZE_24` (24×24 px):** Tamanho padrão de componentes, botões de barra lateral do Hub, campos com ícone prefixado. +- **`SIZE_32` (32×32 px):** Cabeçalhos de diálogos de aprovação CCSP, títulos de assistentes. +- **`SIZE_40` (40×40 px):** Cartões e botões do painel principal (Hub de Ações Rápidas). + +--- + +## 4. Catálogo dos Ícones Vetoriais + +| Arquivo SVG | Glifo / Nome | Propósito e Uso na Aplicação | +| :--- | :--- | :--- | +| `pdf.svg` | `Icons.pdf()` | Assinatura de documentos PDF e fluxos PAdES. | +| `xml.svg` | `Icons.xml()` | Assinatura de documentos XML e notas fiscais (XMLDSig). | +| `file.svg` | `Icons.file()` | Assinatura de arquivos e digests genéricos. | +| `attached.svg` | `Icons.attached()` | Assinatura atachada / envelopada (CAdES Attached). | +| `batch.svg` | `Icons.batch()` | Assinatura de múltiplos documentos em lote. | +| `co-sign.svg` | `Icons.coSign()` | Adição de co-assinatura em documento já assinado. | +| `timestamp.svg` | `Icons.timestamp()` | Aplicação de carimbo do tempo (TSA). | +| `ltv.svg` | `Icons.ltv()` | Assinatura com validação de longo prazo (LTV). | +| `validate.svg` | `Icons.validate()` | Validador de integridade e assinaturas digitais. | +| `validate-timestamp.svg` | `Icons.validateTimestamp()` | Validador específico de carimbos de tempo. | +| `seal.svg` | `Icons.seal()` | Gerenciamento e aplicação de selos visuais. | +| `seal-icp-brasil.svg` | `Icons.sealIcpBrasil()` | Selo vetorial oficial padrão ICP-Brasil. | +| `cert.svg` | `Icons.certificates()` | Gerenciamento e seleção de certificados A1 e A3. | +| `shield.svg` | `Icons.shield()` | Segurança, proteção e integridade do agente. | +| `settings.svg` | `Icons.settings()` | Painel de configurações e preferências locais. | +| `logs.svg` | `Icons.logs()` | Visualizador de registros de auditoria e logs locais. | +| `tutorial.svg` | `Icons.tutorial()` | Guia interativo e tutorial de primeiros passos. | +| `about.svg` | `Icons.about()` | Diálogo sobre o CyberCore Signer, versão e licença. | +| `exit.svg` | `Icons.exit()` | Confirmação e encerramento do agente desktop. | +| `refresh.svg` | `Icons.refresh()` | Atualizar lista de certificados e recarregar dados. | +| `sun.svg` | `Icons.sun()` | Alternador para Modo Claro. | +| `moon.svg` | `Icons.moon()` | Alternador para Modo Escuro. | +| `arrow-right.svg` | `Icons.arrowRight()` | Navegação para próximo passo ou expansão. | +| `close.svg` | `Icons.close()` | Fechar diálogo, dispensar notificação ou cancelar. | +| `check.svg` | `Icons.check()` | Operação concluída com sucesso ou item selecionado. | +| `error.svg` | `Icons.error()` | Alerta de falha, cancelamento ou erro de hardware. | +| `star.svg` | `Icons.star()` | Certificado padrão ou favorito selecionado. | +| `zoom-in.svg` | `Icons.zoomIn()` | Aumentar zoom na visualização de documento ou selo. | +| `zoom-out.svg` | `Icons.zoomOut()` | Reduzir zoom na visualização de documento ou selo. | +| `zoom-fit.svg` | `Icons.zoomFit()` | Ajustar visualização à tela ou página inteira. | + +--- + +## 5. Implementação Técnica + +### Fachada `Icons` +A classe `br.com.cybercore.signer.ui.components.Icons` centraliza a instanciação: +```java +// Tamanho padrão (24px) com cor do tema ativo: +Node icon = Icons.settings(); + +// Tamanho específico: +Node refresh = Icons.refresh(Icons.SIZE_16); + +// Tinta customizada: +Node custom = Icons.of("pdf", Icons.SIZE_40, Color.web("#0288D1")); +``` + +### Repintura Dinâmica +Ao registrar alteração de tema em `ThemeManager`, os nós de ícone baseados em `currentColor` recebem automaticamente o listener e atualizam suas cores em tempo real sem necessidade de recriar a janela. diff --git a/modules/cybercore-ui/src/main/java/br/com/cybercore/signer/ui/assets/AssetManager.java b/modules/cybercore-ui/src/main/java/br/com/cybercore/signer/ui/assets/AssetManager.java index bf05838..04d7e10 100644 --- a/modules/cybercore-ui/src/main/java/br/com/cybercore/signer/ui/assets/AssetManager.java +++ b/modules/cybercore-ui/src/main/java/br/com/cybercore/signer/ui/assets/AssetManager.java @@ -39,6 +39,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import br.com.cybercore.signer.ui.theme.ThemeManager; import java.util.Optional; import java.util.function.Supplier; @@ -130,18 +131,25 @@ public final class AssetManager { * Retorna um Node de ícone customizado (prioritariamente SVG, com fallback para PNG ou supplier vetorial). */ public static Node getIconOrDefault(String iconName, double size, Supplier fallbackSupplier) { + return getIconOrDefault(iconName, size, null, fallbackSupplier); + } + + /** + * Retorna um Node de ícone customizado com suporte a repintura ou tinta explícita. + */ + public static Node getIconOrDefault(String iconName, double size, Color tint, Supplier fallbackSupplier) { if (iconName != null && !iconName.isBlank()) { String cleanName = cleanBaseName(iconName); // 1. Prioridade para SVG em ./assets/icons/ - Optional localSvg = loadSvgIconFromPath(Path.of("assets", "icons", cleanName + ".svg"), size); + Optional localSvg = loadSvgIconFromPath(Path.of("assets", "icons", cleanName + ".svg"), size, tint); if (localSvg.isPresent()) { return localSvg.get(); } // 2. Procura SVG em ~/.cybercore/assets/icons/ String userHome = System.getProperty("user.home", "."); - Optional userSvg = loadSvgIconFromPath(Path.of(userHome, ".cybercore", "assets", "icons", cleanName + ".svg"), size); + Optional userSvg = loadSvgIconFromPath(Path.of(userHome, ".cybercore", "assets", "icons", cleanName + ".svg"), size, tint); if (userSvg.isPresent()) { return userSvg.get(); } @@ -151,7 +159,7 @@ public final class AssetManager { InputStream resStream = AssetManager.class.getResourceAsStream(resSvgPath); if (resStream != null) { try (resStream) { - Node node = parseSvgToNode(resStream, size, size); + Node node = parseSvgToNode(resStream, size, size, tint); if (node != null) { return node; } @@ -184,7 +192,7 @@ public final class AssetManager { Path localSvg = Path.of("assets", "images", cleanName + ".svg"); if (Files.isRegularFile(localSvg)) { try (InputStream in = new FileInputStream(localSvg.toFile())) { - Node node = parseSvgToNode(in, width, height); + Node node = parseSvgToNode(in, width, height, null); if (node != null) { logger.debug("Carregada imagem SVG local: {}", localSvg); return node; @@ -199,7 +207,7 @@ public final class AssetManager { Path userSvg = Path.of(userHome, ".cybercore", "assets", "images", cleanName + ".svg"); if (Files.isRegularFile(userSvg)) { try (InputStream in = new FileInputStream(userSvg.toFile())) { - Node node = parseSvgToNode(in, width, height); + Node node = parseSvgToNode(in, width, height, null); if (node != null) { logger.debug("Carregada imagem SVG do usuário: {}", userSvg); return node; @@ -214,7 +222,7 @@ public final class AssetManager { InputStream resStream = AssetManager.class.getResourceAsStream(resPath); if (resStream != null) { try (resStream) { - Node node = parseSvgToNode(resStream, width, height); + Node node = parseSvgToNode(resStream, width, height, null); if (node != null) { return node; } @@ -253,10 +261,10 @@ public final class AssetManager { return clean; } - private static Optional loadSvgIconFromPath(Path path, double size) { + private static Optional loadSvgIconFromPath(Path path, double size, Color tint) { if (Files.isRegularFile(path)) { try (InputStream in = new FileInputStream(path.toFile())) { - Node node = parseSvgToNode(in, size, size); + Node node = parseSvgToNode(in, size, size, tint); if (node != null) { logger.debug("Carregado ícone SVG customizado de: {}", path); return Optional.of(node); @@ -272,13 +280,18 @@ public final class AssetManager { * Parser analítico de SVG para nós gráficos JavaFX com suporte a dimensões quadradas. */ public static Node parseSvgToNode(InputStream in, double targetSize) { - return parseSvgToNode(in, targetSize, targetSize); + return parseSvgToNode(in, targetSize, targetSize, null); + } + + public static Node parseSvgToNode(InputStream in, double targetSize, Color tint) { + return parseSvgToNode(in, targetSize, targetSize, tint); } - /** - * Parser analítico completo de SVG para nós gráficos JavaFX com dimensões proporcionais e suporte a defs/gradientes. - */ public static Node parseSvgToNode(InputStream in, double targetWidth, double targetHeight) { + return parseSvgToNode(in, targetWidth, targetHeight, null); + } + + public static Node parseSvgToNode(InputStream in, double targetWidth, double targetHeight, Color tint) { try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(false); @@ -326,8 +339,14 @@ public final class AssetManager { Map defsMap = new HashMap<>(); parseDefs(svg, defsMap); + Color effectiveCurrentColor = (tint != null) ? tint : + (ThemeManager.isDark() ? Color.web("#F1F5F9") : Color.web("#1E293B")); + List dynamicStrokeShapes = new ArrayList<>(); + List dynamicFillShapes = new ArrayList<>(); + RenderContext ctx = new RenderContext(defsMap, effectiveCurrentColor, dynamicStrokeShapes, dynamicFillShapes); + Group contentGroup = new Group(); - renderChildren(svg, contentGroup, defsMap); + renderChildren(svg, contentGroup, ctx); double scaleX = targetWidth / vbWidth; double scaleY = targetHeight / vbHeight; @@ -348,9 +367,24 @@ public final class AssetManager { ); Pane container = new Pane(contentGroup); + container.getStyleClass().add("cyber-icon"); container.setPrefSize(targetWidth, targetHeight); container.setMaxSize(targetWidth, targetHeight); container.setMinSize(targetWidth, targetHeight); + + // Se for dinâmico (sem tint fixo) e contiver elementos currentColor, atualiza com a mudança de tema + if (tint == null && (!dynamicStrokeShapes.isEmpty() || !dynamicFillShapes.isEmpty())) { + ThemeManager.addListener(theme -> { + Color c = (theme == ThemeManager.AppTheme.DARK) ? Color.web("#F1F5F9") : Color.web("#1E293B"); + for (Shape s : dynamicStrokeShapes) { + s.setStroke(c); + } + for (Shape s : dynamicFillShapes) { + s.setFill(c); + } + }); + } + return container; } catch (Exception e) { @@ -444,7 +478,14 @@ public final class AssetManager { } } - private static void renderChildren(Element parent, Group targetGroup, Map defsMap) { + private record RenderContext( + Map defsMap, + Color currentColor, + List dynamicStrokeShapes, + List dynamicFillShapes + ) {} + + private static void renderChildren(Element parent, Group targetGroup, RenderContext ctx) { NodeList children = parent.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { org.w3c.dom.Node n = children.item(i); @@ -452,7 +493,7 @@ public final class AssetManager { if ("defs".equalsIgnoreCase(el.getTagName())) { continue; } - Node jfxNode = createElementNode(el, defsMap); + Node jfxNode = createElementNode(el, ctx); if (jfxNode != null) { targetGroup.getChildren().add(jfxNode); } @@ -460,7 +501,7 @@ public final class AssetManager { } } - private static Node createElementNode(Element el, Map defsMap) { + private static Node createElementNode(Element el, RenderContext ctx) { String tagName = el.getTagName().toLowerCase(); Shape shape = null; @@ -527,7 +568,7 @@ public final class AssetManager { Map inlineStyle = el.hasAttribute("style") ? parseStyleAttribute(el.getAttribute("style")) : Map.of(); String fillVal = inlineStyle.getOrDefault("fill", el.hasAttribute("fill") ? el.getAttribute("fill") : null); if (fillVal != null) { - t.setFill(parsePaint(fillVal, defsMap, Color.BLACK)); + t.setFill(parsePaint(fillVal, ctx, Color.BLACK)); } String anchor = inlineStyle.getOrDefault("text-anchor", el.getAttribute("text-anchor")); @@ -555,9 +596,9 @@ public final class AssetManager { } case "g" -> { Group g = new Group(); - renderChildren(el, g, defsMap); + renderChildren(el, g, ctx); if (el.hasAttribute("stroke")) { - Paint strokePaint = parsePaint(el.getAttribute("stroke"), defsMap, null); + Paint strokePaint = parsePaint(el.getAttribute("stroke"), ctx, null); double sw = parseDouble(el.getAttribute("stroke-width"), 1.0); for (Node child : g.getChildren()) { if (child instanceof Shape s) { @@ -572,7 +613,8 @@ public final class AssetManager { } if (shape != null) { - applyShapeStyles(el, shape, defsMap); + shape.getStyleClass().add("cyber-icon-glyph"); + applyShapeStyles(el, shape, ctx); applyElementTransform(el, shape); return shape; } @@ -597,19 +639,25 @@ public final class AssetManager { return styleMap; } - private static void applyShapeStyles(Element el, Shape shape, Map defsMap) { + private static void applyShapeStyles(Element el, Shape shape, RenderContext ctx) { Map inlineStyle = el.hasAttribute("style") ? parseStyleAttribute(el.getAttribute("style")) : Map.of(); String fillVal = inlineStyle.getOrDefault("fill", el.hasAttribute("fill") ? el.getAttribute("fill") : null); if (fillVal != null) { - shape.setFill(parsePaint(fillVal, defsMap, Color.TRANSPARENT)); + if ("currentColor".equalsIgnoreCase(fillVal.trim()) && ctx != null) { + ctx.dynamicFillShapes().add(shape); + } + shape.setFill(parsePaint(fillVal, ctx, Color.TRANSPARENT)); } else if (shape instanceof Line) { shape.setFill(Color.TRANSPARENT); } String strokeVal = inlineStyle.getOrDefault("stroke", el.hasAttribute("stroke") ? el.getAttribute("stroke") : null); if (strokeVal != null) { - shape.setStroke(parsePaint(strokeVal, defsMap, Color.TRANSPARENT)); + if ("currentColor".equalsIgnoreCase(strokeVal.trim()) && ctx != null) { + ctx.dynamicStrokeShapes().add(shape); + } + shape.setStroke(parsePaint(strokeVal, ctx, Color.TRANSPARENT)); } String strokeWidthVal = inlineStyle.getOrDefault("stroke-width", el.hasAttribute("stroke-width") ? el.getAttribute("stroke-width") : null); @@ -629,20 +677,20 @@ public final class AssetManager { } } - private static Paint parsePaint(String str, Map defsMap, Paint fallback) { + private static Paint parsePaint(String str, RenderContext ctx, Paint fallback) { if (str == null || str.isBlank() || "none".equalsIgnoreCase(str)) { return Color.TRANSPARENT; } String trimmed = str.trim(); if (trimmed.startsWith("url(#") && trimmed.endsWith(")")) { String id = trimmed.substring(5, trimmed.length() - 1).trim(); - Paint defPaint = defsMap.get(id); + Paint defPaint = ctx != null && ctx.defsMap() != null ? ctx.defsMap().get(id) : null; if (defPaint != null) { return defPaint; } return Color.web("#0288d1"); } - return parseColor(trimmed, fallback instanceof Color ? (Color) fallback : Color.BLACK); + return parseColor(trimmed, fallback instanceof Color ? (Color) fallback : Color.BLACK, ctx); } private static void parsePoints(String ptsStr, java.util.List pointsList) { @@ -658,12 +706,19 @@ public final class AssetManager { } private static Color parseColor(String str, Color fallback) { + return parseColor(str, fallback, null); + } + + private static Color parseColor(String str, Color fallback, RenderContext ctx) { if (str == null || str.isBlank() || "none".equalsIgnoreCase(str)) { return Color.TRANSPARENT; } String trimmed = str.trim(); if ("currentColor".equalsIgnoreCase(trimmed)) { - return Color.web("#0288d1"); + if (ctx != null && ctx.currentColor() != null) { + return ctx.currentColor(); + } + return ThemeManager.isDark() ? Color.web("#F1F5F9") : Color.web("#1E293B"); } try { return Color.web(trimmed); diff --git a/modules/cybercore-ui/src/main/java/br/com/cybercore/signer/ui/components/Icons.java b/modules/cybercore-ui/src/main/java/br/com/cybercore/signer/ui/components/Icons.java new file mode 100644 index 0000000..b7026bc --- /dev/null +++ b/modules/cybercore-ui/src/main/java/br/com/cybercore/signer/ui/components/Icons.java @@ -0,0 +1,165 @@ +package br.com.cybercore.signer.ui.components; + +import br.com.cybercore.signer.ui.assets.AssetManager; +import javafx.scene.Node; +import javafx.scene.paint.Color; + +import java.util.function.Supplier; + +/** + * Fachada centralizada e moderna para obtenção de ícones vetoriais padronizados no CyberCore Signer. + *

+ * Segue a gramática visual estipulada em {@code docs/icon-system.md}: + * grid canônico de 24x24 px, safe area de 2px, stroke 1.75-2.0px, sem textos embutidos + * e repintura dinâmica orientada a temas (currentColor). + */ +public final class Icons { + + /** Tamanho micro (16x16 px) para badges, tags e botões compactos. */ + public static final int SIZE_16 = 16; + + /** Tamanho pequeno (20x20 px) para botões auxiliares e itens compactos. */ + public static final int SIZE_20 = 20; + + /** Tamanho padrão canônico (24x24 px) para botões de diálogo e barra lateral. */ + public static final int SIZE_24 = 24; + + /** Tamanho médio (32x32 px) para cabeçalhos e diálogos de aprovação CCSP. */ + public static final int SIZE_32 = 32; + + /** Tamanho grande (40x40 px) para cards e botões do painel principal (Hub). */ + public static final int SIZE_40 = 40; + + private Icons() { + } + + /** + * Retorna um ícone vetorial pelo nome no tamanho especificado, com repintura dinâmica de tema. + */ + public static Node of(String name, int size) { + return of(name, size, null, null); + } + + /** + * Retorna um ícone vetorial pelo nome no tamanho especificado, aplicando uma tinta (tint) fixa. + */ + public static Node of(String name, int size, Color tint) { + return of(name, size, tint, null); + } + + /** + * Retorna um ícone vetorial com fallback customizado. + */ + public static Node of(String name, int size, Color tint, Supplier fallbackSupplier) { + return AssetManager.getIconOrDefault(name, size, tint, fallbackSupplier); + } + + // ========================================== + // MÉTODOS DE CONVENIÊNCIA POR SEMÂNTICA VISUAL + // ========================================== + + public static Node pdf() { return pdf(SIZE_24); } + public static Node pdf(int size) { return of("pdf", size); } + public static Node pdf(int size, Color tint) { return of("pdf", size, tint); } + + public static Node xml() { return xml(SIZE_24); } + public static Node xml(int size) { return of("xml", size); } + + public static Node file() { return file(SIZE_24); } + public static Node file(int size) { return of("file", size); } + + public static Node attached() { return attached(SIZE_24); } + public static Node attached(int size) { return of("attached", size); } + + public static Node batch() { return batch(SIZE_24); } + public static Node batch(int size) { return of("batch", size); } + + public static Node coSign() { return coSign(SIZE_24); } + public static Node coSign(int size) { return of("co-sign", size); } + + public static Node timestamp() { return timestamp(SIZE_24); } + public static Node timestamp(int size) { return of("timestamp", size); } + + public static Node ltv() { return ltv(SIZE_24); } + public static Node ltv(int size) { return of("ltv", size); } + + public static Node validate() { return validate(SIZE_24); } + public static Node validate(int size) { return of("validate", size); } + + public static Node validateTimestamp() { return validateTimestamp(SIZE_24); } + public static Node validateTimestamp(int size) { return of("validate-timestamp", size); } + + public static Node seal() { return seal(SIZE_24); } + public static Node seal(int size) { return of("seal", size); } + + public static Node sealIcpBrasil() { return sealIcpBrasil(SIZE_24); } + public static Node sealIcpBrasil(int size) { return of("seal-icp-brasil", size); } + + public static Node certificates() { return certificates(SIZE_24); } + public static Node certificates(int size) { return of("cert", size); } + + public static Node shield() { return shield(SIZE_24); } + public static Node shield(int size) { return of("shield", size); } + + public static Node settings() { return settings(SIZE_24); } + public static Node settings(int size) { return of("settings", size); } + + public static Node logs() { return logs(SIZE_24); } + public static Node logs(int size) { return of("logs", size); } + + public static Node tutorial() { return tutorial(SIZE_24); } + public static Node tutorial(int size) { return of("tutorial", size); } + + public static Node about() { return about(SIZE_24); } + public static Node about(int size) { return of("about", size); } + + public static Node exit() { return exit(SIZE_24); } + public static Node exit(int size) { return of("exit", size); } + + public static Node refresh() { return refresh(SIZE_16); } + public static Node refresh(int size) { return of("refresh", size); } + + public static Node sun() { return sun(SIZE_16); } + public static Node sun(int size) { return of("sun", size); } + + public static Node moon() { return moon(SIZE_16); } + public static Node moon(int size) { return of("moon", size); } + + public static Node arrowRight() { return arrowRight(SIZE_16); } + public static Node arrowRight(int size) { return of("arrow-right", size); } + + public static Node close() { return close(SIZE_16); } + public static Node close(int size) { return of("close", size); } + + public static Node check() { return check(SIZE_16); } + public static Node check(int size) { return of("check", size); } + + public static Node error() { return error(SIZE_16); } + public static Node error(int size) { return of("error", size); } + + public static Node star() { return star(SIZE_16); } + public static Node star(int size) { return of("star", size); } + + public static Node zoomIn() { return zoomIn(SIZE_16); } + public static Node zoomIn(int size) { return of("zoom-in", size); } + + public static Node zoomOut() { return zoomOut(SIZE_16); } + public static Node zoomOut(int size) { return of("zoom-out", size); } + + public static Node zoomFit() { return zoomFit(SIZE_16); } + public static Node zoomFit(int size) { return of("zoom-fit", size); } + + /** + * Logotipo institucional principal do CyberCore Signer. + */ + public static Node appLogo(double width, double height) { + return AssetManager.getLogoOrDefault(width, height, () -> SvgIcons.buildAppCrystalLogo(Math.min(width, height))); + } + + /** + * Logotipo de cristal CyberCore. + */ + public static Node appCrystal(double size) { + return SvgIcons.createAppCrystalLogo(size); + } +} diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/about.svg b/modules/cybercore-ui/src/main/resources/assets/icons/about.svg index f6aac90..de19102 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/about.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/about.svg @@ -1,6 +1,5 @@ - - - - - + + + + \ No newline at end of file diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/arrow-right.svg b/modules/cybercore-ui/src/main/resources/assets/icons/arrow-right.svg index 1db6d0c..7cb8f33 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/arrow-right.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/arrow-right.svg @@ -1,3 +1,3 @@ - + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/attached.svg b/modules/cybercore-ui/src/main/resources/assets/icons/attached.svg index 7d894e7..07596ef 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/attached.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/attached.svg @@ -1,12 +1,4 @@ - - - - - - - - - - + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/batch.svg b/modules/cybercore-ui/src/main/resources/assets/icons/batch.svg index 5ced311..03b691f 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/batch.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/batch.svg @@ -1,13 +1,6 @@ - - - - - - - - - - - - + + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/cert.svg b/modules/cybercore-ui/src/main/resources/assets/icons/cert.svg index 14cc2b4..5088055 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/cert.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/cert.svg @@ -1,11 +1,7 @@ - - - - - - - - - - + + + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/check.svg b/modules/cybercore-ui/src/main/resources/assets/icons/check.svg index c379af0..f1debcd 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/check.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/check.svg @@ -1,4 +1,4 @@ - - - + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/close.svg b/modules/cybercore-ui/src/main/resources/assets/icons/close.svg index 3f6cc79..57f3e07 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/close.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/close.svg @@ -1,3 +1,3 @@ - + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/co-sign.svg b/modules/cybercore-ui/src/main/resources/assets/icons/co-sign.svg index 283c24f..3516c7a 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/co-sign.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/co-sign.svg @@ -1,12 +1,6 @@ - - - - - - - - - - - + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/error.svg b/modules/cybercore-ui/src/main/resources/assets/icons/error.svg index 5a36ff3..91ccfe6 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/error.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/error.svg @@ -1,5 +1,5 @@ - - - - + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/exit.svg b/modules/cybercore-ui/src/main/resources/assets/icons/exit.svg index d209a6b..dd4ea0d 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/exit.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/exit.svg @@ -1,8 +1,6 @@ - - - - - - + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/file.svg b/modules/cybercore-ui/src/main/resources/assets/icons/file.svg index 023885f..94ce44c 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/file.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/file.svg @@ -1,13 +1,7 @@ - - - - - - - - - - - - + + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/logs.svg b/modules/cybercore-ui/src/main/resources/assets/icons/logs.svg index 0dd89e3..79f1f6f 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/logs.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/logs.svg @@ -1,13 +1,6 @@ - - - - - - - - - - - - + + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/ltv.svg b/modules/cybercore-ui/src/main/resources/assets/icons/ltv.svg index dbc162a..9392d27 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/ltv.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/ltv.svg @@ -1,11 +1,6 @@ - - - - - - - - - - LTV + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/moon.svg b/modules/cybercore-ui/src/main/resources/assets/icons/moon.svg index 9eb6f1a..6687394 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/moon.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/moon.svg @@ -1,6 +1,3 @@ - - - - - + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/pdf.svg b/modules/cybercore-ui/src/main/resources/assets/icons/pdf.svg index d3bc5e9..e003bac 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/pdf.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/pdf.svg @@ -1,13 +1,7 @@ - - - - - - - - - - - - PDF + + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/refresh.svg b/modules/cybercore-ui/src/main/resources/assets/icons/refresh.svg index 8ee09d9..c7694f3 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/refresh.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/refresh.svg @@ -1,5 +1,5 @@ - - - + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/seal-icp-brasil.svg b/modules/cybercore-ui/src/main/resources/assets/icons/seal-icp-brasil.svg index c6b0cc3..139606c 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/seal-icp-brasil.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/seal-icp-brasil.svg @@ -1,15 +1,7 @@ - - - - - - - - - - - - - - + + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/seal.svg b/modules/cybercore-ui/src/main/resources/assets/icons/seal.svg index 1aa3a5f..2f3a1fb 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/seal.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/seal.svg @@ -1,11 +1,5 @@ - - - - - - - - - - + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/settings.svg b/modules/cybercore-ui/src/main/resources/assets/icons/settings.svg index 0a8dbc2..0d63eed 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/settings.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/settings.svg @@ -1,4 +1,5 @@ - - - + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/shield.svg b/modules/cybercore-ui/src/main/resources/assets/icons/shield.svg index 1bc2539..c6f5415 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/shield.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/shield.svg @@ -1,6 +1,5 @@ - - - - - + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/star.svg b/modules/cybercore-ui/src/main/resources/assets/icons/star.svg index ac2213a..08515ae 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/star.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/star.svg @@ -1,4 +1,4 @@ - - + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/sun.svg b/modules/cybercore-ui/src/main/resources/assets/icons/sun.svg index 0327476..e444c96 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/sun.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/sun.svg @@ -1,15 +1,11 @@ - - - - - - - - - - - - - - + + + + + + + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/timestamp.svg b/modules/cybercore-ui/src/main/resources/assets/icons/timestamp.svg index 16238f4..86f4f0b 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/timestamp.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/timestamp.svg @@ -1,13 +1,5 @@ - - - - - - - - - - - - + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/tutorial.svg b/modules/cybercore-ui/src/main/resources/assets/icons/tutorial.svg index 32d13d2..5eabb2f 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/tutorial.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/tutorial.svg @@ -1,8 +1,5 @@ - - - - - - - + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/validate-timestamp.svg b/modules/cybercore-ui/src/main/resources/assets/icons/validate-timestamp.svg index dc0f7c8..36a9505 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/validate-timestamp.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/validate-timestamp.svg @@ -1,10 +1,6 @@ - - - - - - - - - + + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/validate.svg b/modules/cybercore-ui/src/main/resources/assets/icons/validate.svg index f654ce8..e10612d 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/validate.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/validate.svg @@ -1,11 +1,6 @@ - - - - - - - - - - + + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/xml.svg b/modules/cybercore-ui/src/main/resources/assets/icons/xml.svg index f728b5f..711ec86 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/xml.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/xml.svg @@ -1,13 +1,8 @@ - - - - - - - - - - - - <XML> + + + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/zoom-fit.svg b/modules/cybercore-ui/src/main/resources/assets/icons/zoom-fit.svg index 201271c..aac60cb 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/zoom-fit.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/zoom-fit.svg @@ -1,3 +1,6 @@ - + + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/zoom-in.svg b/modules/cybercore-ui/src/main/resources/assets/icons/zoom-in.svg index 6783075..854e624 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/zoom-in.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/zoom-in.svg @@ -1,5 +1,5 @@ - - - + + + diff --git a/modules/cybercore-ui/src/main/resources/assets/icons/zoom-out.svg b/modules/cybercore-ui/src/main/resources/assets/icons/zoom-out.svg index 3882ea9..2c59873 100644 --- a/modules/cybercore-ui/src/main/resources/assets/icons/zoom-out.svg +++ b/modules/cybercore-ui/src/main/resources/assets/icons/zoom-out.svg @@ -1,5 +1,5 @@ - - - + + + diff --git a/modules/cybercore-ui/src/test/java/br/com/cybercore/signer/ui/assets/AssetManagerTest.java b/modules/cybercore-ui/src/test/java/br/com/cybercore/signer/ui/assets/AssetManagerTest.java index 8948b82..f741338 100644 --- a/modules/cybercore-ui/src/test/java/br/com/cybercore/signer/ui/assets/AssetManagerTest.java +++ b/modules/cybercore-ui/src/test/java/br/com/cybercore/signer/ui/assets/AssetManagerTest.java @@ -34,7 +34,7 @@ class AssetManagerTest { "pdf", "xml", "file", "batch", "attached", "co-sign", "timestamp", "ltv", "validate", "validate-timestamp", "exit", "logs", "settings", "tutorial", "cert", "about", "sun", "moon", - "shield", "seal", "check", "error", "star", "close", "arrow-right", + "shield", "seal", "seal-icp-brasil", "check", "error", "star", "close", "arrow-right", "zoom-in", "zoom-out", "zoom-fit", "refresh" }; @@ -44,6 +44,31 @@ class AssetManagerTest { } } + @Test + @DisplayName("Deve instanciar ícones através da fachada Icons nos 5 tamanhos padronizados") + void shouldCreateIconsViaNewFacadeInAllStandardSizes() { + assertThat(br.com.cybercore.signer.ui.components.Icons.settings(br.com.cybercore.signer.ui.components.Icons.SIZE_16)).isNotNull(); + assertThat(br.com.cybercore.signer.ui.components.Icons.pdf(br.com.cybercore.signer.ui.components.Icons.SIZE_20)).isNotNull(); + assertThat(br.com.cybercore.signer.ui.components.Icons.certificates(br.com.cybercore.signer.ui.components.Icons.SIZE_24)).isNotNull(); + assertThat(br.com.cybercore.signer.ui.components.Icons.shield(br.com.cybercore.signer.ui.components.Icons.SIZE_32)).isNotNull(); + assertThat(br.com.cybercore.signer.ui.components.Icons.xml(br.com.cybercore.signer.ui.components.Icons.SIZE_40)).isNotNull(); + assertThat(br.com.cybercore.signer.ui.components.Icons.sealIcpBrasil()).isNotNull(); + } + + @Test + @DisplayName("Deve repintar dinamicamente elementos currentColor ao mudar o tema") + void shouldRepaintCurrentColorDynamicallyOnThemeChange() { + Node iconNode = br.com.cybercore.signer.ui.components.Icons.settings(24); + assertThat(iconNode).isInstanceOf(javafx.scene.layout.Pane.class); + + // Alterna o tema e garante que não lança erro + br.com.cybercore.signer.ui.theme.ThemeManager.setCurrentTheme(br.com.cybercore.signer.ui.theme.ThemeManager.AppTheme.DARK); + assertThat(br.com.cybercore.signer.ui.theme.ThemeManager.isDark()).isTrue(); + + br.com.cybercore.signer.ui.theme.ThemeManager.setCurrentTheme(br.com.cybercore.signer.ui.theme.ThemeManager.AppTheme.LIGHT); + assertThat(br.com.cybercore.signer.ui.theme.ThemeManager.isDark()).isFalse(); + } + @Test @DisplayName("Deve instanciar nós de ícones via fábrica SvgIcons com fallback") void shouldCreateNodesViaSvgIcons() {