test(ui): update preview generator and screenshots for single theme

This commit is contained in:
Claudecio Martins
2026-10-20 21:25:17 -03:00
parent d27c0f9567
commit 68943221c3
37 changed files with 312 additions and 323 deletions
@@ -45,6 +45,10 @@ import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Objects;
/**
* Utilitário de captura automatizada das telas da interface do CyberCore Signer.
* Gera as capturas de tela atualizadas no tema claro padronizado.
*/
public class UiPreviewGenerator extends Application {
private static final File OUTPUT_DIR = new File("docs/screenshots");
@@ -74,277 +78,242 @@ public class UiPreviewGenerator extends Application {
// 5. Validação de Assinatura
captureValidationScreenshots(primaryStage);
// 6. Solicitação de Assinatura (Prompt CCSP)
// 6. Solicitação de Assinatura Local (Prompt de Autorização)
capturePromptScreenshots(primaryStage);
// 7. Selos Visuais
// 7. Gerenciador de Selos
captureSealsScreenshots(primaryStage);
// 8. Sobre
captureAboutScreenshots(primaryStage);
// 9. Diálogo de Encerramento / Bandeja
// 9. Confirmação de Saída
captureExitDialogScreenshots(primaryStage);
// 10. Diálogo de Posicionamento e Assinatura PDF (PAdES)
// 10. Assinador Visual de PDF
capturePdfSignDialogScreenshots(primaryStage);
// 11. Diálogo de Seleção de Certificado e PIN do PDF
// 11. Seleção de Certificado e PIN do PDF
capturePdfCertificateSignDialogScreenshots(primaryStage);
System.out.println(">>> Capturas de tela concluídas com sucesso em: " + OUTPUT_DIR.getAbsolutePath());
} catch (Exception e) {
e.printStackTrace();
} finally {
Platform.exit();
System.exit(0);
}
});
}
private void captureHubScreenshots(Stage stage) throws Exception {
for (ThemeManager.AppTheme theme : ThemeManager.AppTheme.values()) {
ThemeManager.setCurrentTheme(theme);
MainAppView appView = new MainAppView(stage);
stage.show();
stage.getScene().getRoot().applyCss();
stage.getScene().getRoot().layout();
MainAppView appView = new MainAppView(stage);
stage.show();
stage.getScene().getRoot().applyCss();
stage.getScene().getRoot().layout();
String suffix = theme == ThemeManager.AppTheme.LIGHT ? "claro" : "escuro";
saveNodeSnapshot(stage.getScene(), new File(OUTPUT_DIR, "01_hub_" + suffix + ".png"));
if (theme == ThemeManager.AppTheme.LIGHT) {
saveNodeSnapshot(stage.getScene(), new File(OUTPUT_DIR, "01_layout_claro.png"));
} else {
saveNodeSnapshot(stage.getScene(), new File(OUTPUT_DIR, "02_layout_escuro.png"));
}
}
saveNodeSnapshot(stage.getScene(), new File(OUTPUT_DIR, "01_hub.png"));
saveNodeSnapshot(stage.getScene(), new File(OUTPUT_DIR, "01_hub_claro.png"));
saveNodeSnapshot(stage.getScene(), new File(OUTPUT_DIR, "01_layout_claro.png"));
}
private void captureDiagnosticsScreenshots(Stage stage) throws Exception {
for (ThemeManager.AppTheme theme : ThemeManager.AppTheme.values()) {
ThemeManager.setCurrentTheme(theme);
DiagnosticsView diagView = new DiagnosticsView(new DiagnosticService());
DiagnosticsView diagView = new DiagnosticsView(new DiagnosticService());
VBox container = wrapInDialogContainer("DIAGNÓSTICO DO SISTEMA",
"Verificação de prontidão do runtime, engines criptográficas e dispositivos.",
SvgIcons.cyberShieldLogo(24), diagView, 800, 520);
VBox container = wrapInDialogContainer("DIAGNÓSTICO DO SISTEMA",
"Verificação de prontidão do runtime, engines criptográficas e dispositivos.",
SvgIcons.cyberShieldLogo(24), diagView, 800, 520);
Scene scene = createScene(container, 800, 520);
stage.setScene(scene);
stage.show();
scene.getRoot().applyCss();
scene.getRoot().layout();
Scene scene = createScene(container, 800, 520);
stage.setScene(scene);
stage.show();
scene.getRoot().applyCss();
scene.getRoot().layout();
String suffix = theme == ThemeManager.AppTheme.LIGHT ? "claro" : "escuro";
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "02_diagnostico_" + suffix + ".png"));
if (theme == ThemeManager.AppTheme.LIGHT) {
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "02_diagnostico.png"));
}
}
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "02_diagnostico.png"));
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "02_diagnostico_claro.png"));
}
private void captureSettingsScreenshots(Stage stage) throws Exception {
for (ThemeManager.AppTheme theme : ThemeManager.AppTheme.values()) {
ThemeManager.setCurrentTheme(theme);
SettingsView settingsView = new SettingsView();
SettingsView settingsView = new SettingsView();
ScrollPane sp = new ScrollPane(settingsView);
sp.setFitToWidth(true);
sp.getStyleClass().add("cyber-scroll-pane");
VBox.setVgrow(sp, Priority.ALWAYS);
ScrollPane sp = new ScrollPane(settingsView);
sp.setFitToWidth(true);
sp.getStyleClass().add("cyber-scroll-pane");
VBox.setVgrow(sp, Priority.ALWAYS);
VBox container = wrapInDialogContainer("CONFIGURAÇÕES DO AGENTE",
"Parâmetros de segurança local, identidade visual e aplicações autorizadas.",
SvgIcons.settingsIcon(), sp, 800, 520);
VBox container = wrapInDialogContainer("CONFIGURAÇÕES DO AGENTE",
"Parâmetros de segurança local, identidade visual e aplicações autorizadas.",
SvgIcons.settingsIcon(), sp, 800, 520);
Scene scene = createScene(container, 800, 520);
stage.setScene(scene);
stage.show();
scene.getRoot().applyCss();
scene.getRoot().layout();
Scene scene = createScene(container, 800, 520);
stage.setScene(scene);
stage.show();
scene.getRoot().applyCss();
scene.getRoot().layout();
String suffix = theme == ThemeManager.AppTheme.LIGHT ? "claro" : "escuro";
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "03_configuracoes_" + suffix + ".png"));
if (theme == ThemeManager.AppTheme.LIGHT) {
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "03_configuracoes.png"));
}
}
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "03_configuracoes.png"));
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "03_configuracoes_claro.png"));
}
private void captureCertificatesScreenshots(Stage stage) throws Exception {
for (ThemeManager.AppTheme theme : ThemeManager.AppTheme.values()) {
ThemeManager.setCurrentTheme(theme);
VBox cardsBox = new VBox(12);
cardsBox.setPadding(new Insets(12));
VBox cardsBox = new VBox(12);
cardsBox.setPadding(new Insets(12));
ManagedCertificate cert1 = new ManagedCertificate(
"cert-a1",
"JOAO DA SILVA:12345678900",
CertificateType.A1,
CertificateStatus.AVAILABLE,
"CN=JOAO DA SILVA:12345678900, OU=Autenticado por AR, O=ICP-Brasil, C=BR",
"CN=AC SERPRO RFB v5, O=ICP-Brasil, C=BR",
"1A2B3C4D5E",
"11223344556677889900",
"AABBCCDDEEFF00112233445566778899",
Instant.now().minus(60, ChronoUnit.DAYS),
Instant.now().plus(300, ChronoUnit.DAYS),
"RSA",
2048,
"JOAO DA SILVA:12345678900",
"12345678900",
null,
"SunJSSE",
null
);
ManagedCertificate cert1 = new ManagedCertificate(
"cert-a1",
"JOAO DA SILVA:12345678900",
CertificateType.A1,
CertificateStatus.AVAILABLE,
"CN=JOAO DA SILVA:12345678900, OU=Autenticado por AR, O=ICP-Brasil, C=BR",
"CN=AC SERPRO RFB v5, O=ICP-Brasil, C=BR",
"1A2B3C4D5E",
"11223344556677889900",
"AABBCCDDEEFF00112233445566778899",
Instant.now().minus(60, ChronoUnit.DAYS),
Instant.now().plus(300, ChronoUnit.DAYS),
"RSA",
2048,
"JOAO DA SILVA:12345678900",
"12345678900",
null,
"SunJSSE",
null
);
ManagedCertificate cert2 = new ManagedCertificate(
"cert-a3",
"EMPRESA EXEMPLO LTDA:12345678000199",
CertificateType.A3,
CertificateStatus.AVAILABLE,
"CN=EMPRESA EXEMPLO LTDA:12345678000199, O=ICP-Brasil, C=BR",
"CN=AC VALID Brasil v5, O=ICP-Brasil, C=BR",
"5E4D3C2B1A",
"99887766554433221100",
"FFEEDDCCBBAA99887766554433221100",
Instant.now().minus(120, ChronoUnit.DAYS),
Instant.now().plus(600, ChronoUnit.DAYS),
"RSA",
2048,
"EMPRESA EXEMPLO LTDA:12345678000199",
null,
"12345678000199",
"SunPKCS11",
"Token USB SafeNet eToken 5110"
);
ManagedCertificate cert2 = new ManagedCertificate(
"cert-a3",
"EMPRESA EXEMPLO LTDA:12345678000199",
CertificateType.A3,
CertificateStatus.AVAILABLE,
"CN=EMPRESA EXEMPLO LTDA:12345678000199, O=ICP-Brasil, C=BR",
"CN=AC VALID Brasil v5, O=ICP-Brasil, C=BR",
"5E4D3C2B1A",
"99887766554433221100",
"FFEEDDCCBBAA99887766554433221100",
Instant.now().minus(120, ChronoUnit.DAYS),
Instant.now().plus(600, ChronoUnit.DAYS),
"RSA",
2048,
"EMPRESA EXEMPLO LTDA:12345678000199",
null,
"12345678000199",
"SunPKCS11",
"Token USB SafeNet eToken 5110"
);
cardsBox.getChildren().addAll(new CertificateCardNode(cert1), new CertificateCardNode(cert2));
cardsBox.getChildren().addAll(new CertificateCardNode(cert1), new CertificateCardNode(cert2));
ScrollPane sp = new ScrollPane(cardsBox);
sp.setFitToWidth(true);
sp.getStyleClass().add("cyber-scroll-pane");
VBox.setVgrow(sp, Priority.ALWAYS);
ScrollPane sp = new ScrollPane(cardsBox);
sp.setFitToWidth(true);
sp.getStyleClass().add("cyber-scroll-pane");
VBox.setVgrow(sp, Priority.ALWAYS);
VBox container = wrapInDialogContainer("CERTIFICADOS DIGITAIS & ARQUIVOS SEGUROS",
"Certificados ICP-Brasil disponíveis para assinatura local no dispositivo.",
SvgIcons.certificatesIcon(), sp, 760, 520);
VBox container = wrapInDialogContainer("CERTIFICADOS DIGITAIS & ARQUIVOS SEGUROS",
"Certificados ICP-Brasil disponíveis para assinatura local no dispositivo.",
SvgIcons.certificatesIcon(), sp, 760, 520);
Scene scene = createScene(container, 760, 520);
stage.setScene(scene);
stage.show();
scene.getRoot().applyCss();
scene.getRoot().layout();
Scene scene = createScene(container, 760, 520);
stage.setScene(scene);
stage.show();
scene.getRoot().applyCss();
scene.getRoot().layout();
String suffix = theme == ThemeManager.AppTheme.LIGHT ? "claro" : "escuro";
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "04_certificados_" + suffix + ".png"));
}
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "04_certificados.png"));
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "04_certificados_claro.png"));
}
private void captureValidationScreenshots(Stage stage) throws Exception {
for (ThemeManager.AppTheme theme : ThemeManager.AppTheme.values()) {
ThemeManager.setCurrentTheme(theme);
SignatureValidationDialog dlg = new SignatureValidationDialog(null);
// Captura layout do diálogo
Scene scene = createValidationSampleScene(stage);
stage.setScene(scene);
stage.show();
scene.getRoot().applyCss();
scene.getRoot().layout();
SignatureValidationDialog dlg = new SignatureValidationDialog(null);
Scene scene = createValidationSampleScene(stage);
stage.setScene(scene);
stage.show();
scene.getRoot().applyCss();
scene.getRoot().layout();
String suffix = theme == ThemeManager.AppTheme.LIGHT ? "claro" : "escuro";
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "05_validacao_" + suffix + ".png"));
}
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "05_validacao.png"));
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "05_validacao_claro.png"));
}
private void capturePromptScreenshots(Stage stage) throws Exception {
for (ThemeManager.AppTheme theme : ThemeManager.AppTheme.values()) {
ThemeManager.setCurrentTheme(theme);
ManagedCertificate cert = new ManagedCertificate(
"cert-a1",
"MARIA OLIVEIRA:98765432100",
CertificateType.A1,
CertificateStatus.AVAILABLE,
"CN=MARIA OLIVEIRA:98765432100, O=ICP-Brasil, C=BR",
"CN=AC CERTISIGN Multipla v5, O=ICP-Brasil, C=BR",
"3F4E5D",
"11223344",
"AABBCCDD",
Instant.now().minus(30, ChronoUnit.DAYS),
Instant.now().plus(330, ChronoUnit.DAYS),
"RSA",
2048,
"MARIA OLIVEIRA:98765432100",
"98765432100",
null,
"SunJSSE",
null
);
ManagedCertificate cert = new ManagedCertificate(
"cert-a1",
"MARIA OLIVEIRA:98765432100",
CertificateType.A1,
CertificateStatus.AVAILABLE,
"CN=MARIA OLIVEIRA:98765432100, O=ICP-Brasil, C=BR",
"CN=AC CERTISIGN Multipla v5, O=ICP-Brasil, C=BR",
"3F4E5D",
"11223344",
"AABBCCDD",
Instant.now().minus(30, ChronoUnit.DAYS),
Instant.now().plus(330, ChronoUnit.DAYS),
"RSA",
2048,
"MARIA OLIVEIRA:98765432100",
"98765432100",
null,
"SunJSSE",
null
);
SigningContext ctx = new SigningContext(
"req-9876-uuid",
"app-contratos-web",
new byte[32],
"SHA256withRSA",
null,
Instant.now().plusSeconds(120)
);
SigningContext ctx = new SigningContext(
"req-9876-uuid",
"app-contratos-web",
new byte[32],
"SHA256withRSA",
null,
Instant.now().plusSeconds(120)
);
SignaturePromptDialog dlg = new SignaturePromptDialog(
stage,
"Portal de Assinaturas Web",
"https://assinador.empresa.com.br",
cert,
ctx,
"Contrato_Prestacao_Servicos_2026.pdf",
"PDF",
false
);
SignaturePromptDialog dlg = new SignaturePromptDialog(
stage,
"Portal de Assinaturas Web",
"https://assinador.empresa.com.br",
cert,
ctx,
"Contrato_Prestacao_Servicos_2026.pdf",
"PDF",
false
);
Scene scene = createPromptSampleScene(cert, ctx);
stage.setScene(scene);
stage.show();
scene.getRoot().applyCss();
scene.getRoot().layout();
Scene scene = createPromptSampleScene(cert, ctx);
stage.setScene(scene);
stage.show();
scene.getRoot().applyCss();
scene.getRoot().layout();
String suffix = theme == ThemeManager.AppTheme.LIGHT ? "claro" : "escuro";
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "06_solicitacao_" + suffix + ".png"));
}
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "06_solicitacao.png"));
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "06_solicitacao_claro.png"));
}
private void captureSealsScreenshots(Stage stage) throws Exception {
for (ThemeManager.AppTheme theme : ThemeManager.AppTheme.values()) {
ThemeManager.setCurrentTheme(theme);
SealManagementDialog dlg = new SealManagementDialog(stage);
Scene scene = createSealsSampleScene();
stage.setScene(scene);
stage.show();
scene.getRoot().applyCss();
scene.getRoot().layout();
SealManagementDialog dlg = new SealManagementDialog(stage);
Scene scene = createSealsSampleScene();
stage.setScene(scene);
stage.show();
scene.getRoot().applyCss();
scene.getRoot().layout();
String suffix = theme == ThemeManager.AppTheme.LIGHT ? "claro" : "escuro";
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "07_selos_" + suffix + ".png"));
}
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "07_selos.png"));
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "07_selos_claro.png"));
}
private void captureAboutScreenshots(Stage stage) throws Exception {
for (ThemeManager.AppTheme theme : ThemeManager.AppTheme.values()) {
ThemeManager.setCurrentTheme(theme);
AboutView aboutView = new AboutView();
AboutView aboutView = new AboutView();
VBox container = wrapInDialogContainer("SOBRE O ASSINADOR",
"Agente de assinatura digital ICP-Brasil com segurança criptográfica em nível de hardware.",
SvgIcons.aboutIcon(), aboutView, 620, 480);
VBox container = wrapInDialogContainer("SOBRE O ASSINADOR",
"Agente de assinatura digital ICP-Brasil com segurança criptográfica em nível de hardware.",
SvgIcons.aboutIcon(), aboutView, 620, 480);
Scene scene = createScene(container, 620, 480);
stage.setScene(scene);
stage.show();
scene.getRoot().applyCss();
scene.getRoot().layout();
Scene scene = createScene(container, 620, 480);
stage.setScene(scene);
stage.show();
scene.getRoot().applyCss();
scene.getRoot().layout();
String suffix = theme == ThemeManager.AppTheme.LIGHT ? "claro" : "escuro";
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "08_sobre_" + suffix + ".png"));
}
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "08_sobre.png"));
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "08_sobre_claro.png"));
}
private Scene createScene(VBox root, double w, double h) {
@@ -358,105 +327,140 @@ public class UiPreviewGenerator extends Application {
private VBox wrapInDialogContainer(String title, String subtitle, Node icon, Node content, double w, double h) {
VBox container = new VBox(16);
container.getStyleClass().addAll("dialog-container", "cyber-root");
container.setPadding(new Insets(20));
container.getStyleClass().add("dialog-container");
container.setPadding(new Insets(24));
HBox header = new HBox(12);
header.setAlignment(Pos.CENTER_LEFT);
VBox titleBox = new VBox(2);
Label titleLbl = new Label(title);
titleLbl.getStyleClass().add("dialog-header-title");
Label subLbl = new Label(subtitle);
subLbl.getStyleClass().add("dialog-header-subtitle");
titleBox.getChildren().addAll(titleLbl, subLbl);
Label lblTitle = new Label(title);
lblTitle.getStyleClass().addAll("dialog-header-title", "text-bold");
Label lblSub = new Label(subtitle);
lblSub.getStyleClass().add("dialog-subtitle");
titleBox.getChildren().addAll(lblTitle, lblSub);
header.getChildren().addAll(icon, titleBox);
VBox contentBox = new VBox(content);
VBox.setVgrow(contentBox, Priority.ALWAYS);
container.getChildren().addAll(header, contentBox);
container.getChildren().addAll(header, content);
return container;
}
private Scene createValidationSampleScene(Stage stage) {
VBox root = new VBox(16);
root.setPadding(new Insets(20));
root.getStyleClass().addAll("dialog-container", "cyber-root");
root.getStyleClass().add("dialog-container");
root.setPadding(new Insets(24));
HBox header = new HBox(12);
header.setAlignment(Pos.CENTER_LEFT);
header.getChildren().addAll(
SvgIcons.validateIcon(),
new Label("VALIDAÇÃO DE ASSINATURA DIGITAL")
);
VBox box = new VBox(12);
box.getStyleClass().add("dialog-box");
box.getChildren().addAll(
new Label("Arquivo: Contrato_Prestacao_Servicos_Assinado.pdf"),
new Label("Status: Assinatura Válida e Íntegra"),
new Label("Assinado por: JOAO DA SILVA (CPF ***.123.456-**)"),
new Label("Autoridade Certificadora: AC SERPRO RFB v5 (ICP-Brasil)")
);
VBox titleBox = new VBox(2);
Label title = new Label("VALIDAÇÃO DE DOCUMENTO ASSINADO");
title.getStyleClass().addAll("dialog-header-title", "text-bold");
Label sub = new Label("Verificação criptográfica de conformidade de assinaturas PAdES, CAdES e XMLDSig.");
sub.getStyleClass().add("dialog-subtitle");
titleBox.getChildren().addAll(title, sub);
header.getChildren().addAll(SvgIcons.validateIcon(), titleBox);
root.getChildren().addAll(header, box);
VBox resultBox = new VBox(12);
resultBox.getStyleClass().add("content-card");
resultBox.setPadding(new Insets(16));
Label docTitle = new Label("Documento: Relatorio_Financeiro_2026.pdf (Conforme ICP-Brasil)");
docTitle.getStyleClass().add("text-bold");
Label statusLbl = new Label("✓ 1 Assinatura Digital VÁLIDA detectada");
statusLbl.getStyleClass().addAll("status-badge", "status-badge-success", "text-bold");
VBox signerCard = new VBox(6);
signerCard.getStyleClass().add("certificate-card");
signerCard.setPadding(new Insets(12));
Label signerName = new Label("Assinante: CARLOS EDUARDO SANTOS:55443322100");
signerName.getStyleClass().add("text-bold");
Label signerAc = new Label("Autoridade Certificadora: AC SERPRO RFB v5");
signerAc.getStyleClass().add("text-muted");
Label signerDate = new Label("Data/Hora: 20/10/2026 15:42:10 (Carimbo do Tempo Validado)");
signerDate.getStyleClass().add("text-muted");
signerCard.getChildren().addAll(signerName, signerAc, signerDate);
resultBox.getChildren().addAll(docTitle, statusLbl, signerCard);
root.getChildren().addAll(header, resultBox);
return createScene(root, 720, 480);
}
private Scene createPromptSampleScene(ManagedCertificate cert, SigningContext ctx) {
VBox root = new VBox(16);
root.setPadding(new Insets(22));
root.getStyleClass().addAll("dialog-container", "cyber-root");
root.getStyleClass().add("dialog-container");
root.setPadding(new Insets(24));
HBox header = new HBox(12);
header.setAlignment(Pos.CENTER_LEFT);
header.getChildren().addAll(
SvgIcons.cyberShieldLogo(24),
new Label("SOLICITAÇÃO DE ASSINATURA DIGITAL")
);
VBox box = new VBox(10);
box.getStyleClass().add("dialog-box");
box.getChildren().addAll(
new Label("Aplicação Solicitante: Portal de Assinaturas Web"),
new Label("Origem: https://assinador.empresa.com.br"),
new Label("Documento: Contrato_Prestacao_Servicos_2026.pdf"),
new Label("Algoritmo: " + ctx.algorithm()),
new Label("Certificado: " + cert.commonName() + " [" + cert.type().getCode() + "]")
);
VBox titleBox = new VBox(2);
Label title = new Label("SOLICITAÇÃO DE ASSINATURA DIGITAL");
title.getStyleClass().addAll("dialog-header-title", "text-bold");
Label sub = new Label("Uma aplicação web autorizada requer sua confirmação para assinar um documento.");
sub.getStyleClass().add("dialog-subtitle");
titleBox.getChildren().addAll(title, sub);
header.getChildren().addAll(SvgIcons.cyberShieldLogo(24), titleBox);
HBox actions = new HBox(12);
actions.setAlignment(Pos.CENTER_RIGHT);
Button btnReject = new Button("Recusar");
btnReject.getStyleClass().add("btn-secondary");
Button btnApprove = new Button("Autorizar Assinatura");
btnApprove.getStyleClass().add("btn-primary");
actions.getChildren().addAll(btnReject, btnApprove);
VBox box = new VBox(14);
box.getStyleClass().add("content-card");
box.setPadding(new Insets(16));
root.getChildren().addAll(header, box, actions);
return createScene(root, 620, 440);
Label appLbl = new Label("Aplicação Solicitante: Portal de Assinaturas Web (https://assinador.empresa.com.br)");
appLbl.getStyleClass().add("text-bold");
Label docLbl = new Label("Documento: Contrato_Prestacao_Servicos_2026.pdf (Hash SHA-256)");
docLbl.getStyleClass().add("text-muted");
VBox certNode = new VBox(6);
certNode.getStyleClass().add("certificate-card");
certNode.setPadding(new Insets(12));
Label certTitle = new Label("Certificado Digital Selecionado:");
certTitle.getStyleClass().addAll("text-bold", "text-muted");
Label certSubject = new Label(cert.commonName());
certSubject.getStyleClass().add("text-bold");
Label certEmissor = new Label("Emissor: " + cert.issuerDn());
certEmissor.getStyleClass().add("text-muted");
certNode.getChildren().addAll(certTitle, certSubject, certEmissor);
HBox btnBar = new HBox(12);
btnBar.setAlignment(Pos.CENTER_RIGHT);
Button btnRecusar = new Button("Recusar");
btnRecusar.getStyleClass().addAll("btn-ghost");
Button btnConfirmar = new Button("Autorizar e Assinar");
btnConfirmar.getStyleClass().addAll("btn-primary");
btnBar.getChildren().addAll(btnRecusar, btnConfirmar);
box.getChildren().addAll(appLbl, docLbl, certNode, btnBar);
root.getChildren().addAll(header, box);
return createScene(root, 700, 480);
}
private Scene createSealsSampleScene() {
VBox root = new VBox(16);
root.setPadding(new Insets(20));
root.getStyleClass().addAll("dialog-container", "cyber-root");
root.getStyleClass().add("dialog-container");
root.setPadding(new Insets(24));
HBox header = new HBox(12);
header.setAlignment(Pos.CENTER_LEFT);
header.getChildren().addAll(
SvgIcons.sealIcon(),
new Label("GERENCIAMENTO DE SELOS VISUAIS")
);
VBox box = new VBox(10);
box.getStyleClass().add("dialog-box");
VBox titleBox = new VBox(2);
Label title = new Label("TEMAS E SELOS VISUAIS PAdES");
title.getStyleClass().addAll("dialog-header-title", "text-bold");
Label sub = new Label("Personalize a aparência dos carimbos visuais de assinatura digital em PDFs.");
sub.getStyleClass().add("dialog-subtitle");
titleBox.getChildren().addAll(title, sub);
header.getChildren().addAll(SvgIcons.sealIcon(), titleBox);
HBox box = new HBox(16);
box.getChildren().addAll(
new Label("Selo Ativo: Padrão ICP-Brasil Institucional"),
new Label("Dimensões: 200 x 60 mm • Posição: Canto inferior direito"),
new Label("Elementos: Carimbo de Tempo + Brasão + Dados do Titular")
new Label("Visualização de Selos Padronizados ICP-Brasil"),
br.com.cybercore.signer.ui.components.Icons.sealIcpBrasil()
);
root.getChildren().addAll(header, box);
@@ -464,32 +468,26 @@ public class UiPreviewGenerator extends Application {
}
private void captureExitDialogScreenshots(Stage stage) throws Exception {
for (ThemeManager.AppTheme theme : ThemeManager.AppTheme.values()) {
ThemeManager.setCurrentTheme(theme);
ExitConfirmationDialog dialog = new ExitConfirmationDialog(null);
Scene scene = dialog.getStage().getScene();
scene.getRoot().applyCss();
scene.getRoot().layout();
ExitConfirmationDialog dialog = new ExitConfirmationDialog(null);
Scene scene = dialog.getStage().getScene();
scene.getRoot().applyCss();
scene.getRoot().layout();
String suffix = theme == ThemeManager.AppTheme.LIGHT ? "claro" : "escuro";
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "09_exit_dialog_" + suffix + ".png"));
}
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "09_exit_dialog.png"));
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "09_exit_dialog_claro.png"));
}
private void capturePdfSignDialogScreenshots(Stage stage) throws Exception {
File samplePdf = getOrCreateSamplePdf();
CertificateManager certManager = CertificateManager.createDefault();
for (ThemeManager.AppTheme theme : ThemeManager.AppTheme.values()) {
ThemeManager.setCurrentTheme(theme);
PdfSignDialog dialog = new PdfSignDialog(null, certManager, samplePdf);
Scene scene = dialog.getStage().getScene();
scene.getRoot().applyCss();
scene.getRoot().layout();
PdfSignDialog dialog = new PdfSignDialog(null, certManager, samplePdf);
Scene scene = dialog.getStage().getScene();
scene.getRoot().applyCss();
scene.getRoot().layout();
String suffix = theme == ThemeManager.AppTheme.LIGHT ? "claro" : "escuro";
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "10_pdf_sign_" + suffix + ".png"));
}
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "10_pdf_sign.png"));
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "10_pdf_sign_claro.png"));
}
private void capturePdfCertificateSignDialogScreenshots(Stage stage) throws Exception {
@@ -514,23 +512,20 @@ public class UiPreviewGenerator extends Application {
);
br.com.cybercore.signer.core.pdf.PdfSigningService pdfSigningService = new br.com.cybercore.signer.core.pdf.PdfSigningService(certManager);
for (ThemeManager.AppTheme theme : ThemeManager.AppTheme.values()) {
ThemeManager.setCurrentTheme(theme);
PdfCertificateSignDialog dialog = new PdfCertificateSignDialog(
null,
certManager,
pdfSigningService,
samplePdf,
config,
"Selo Padrão ICP-Brasil (Canto Inferior Direito)"
);
Scene scene = dialog.getStage().getScene();
scene.getRoot().applyCss();
scene.getRoot().layout();
PdfCertificateSignDialog dialog = new PdfCertificateSignDialog(
null,
certManager,
pdfSigningService,
samplePdf,
config,
"Selo Padrão ICP-Brasil (Canto Inferior Direito)"
);
Scene scene = dialog.getStage().getScene();
scene.getRoot().applyCss();
scene.getRoot().layout();
String suffix = theme == ThemeManager.AppTheme.LIGHT ? "claro" : "escuro";
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "11_pdf_cert_sign_" + suffix + ".png"));
}
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "11_pdf_cert_sign.png"));
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "11_pdf_cert_sign_claro.png"));
}
private static File getOrCreateSamplePdf() throws Exception {
@@ -539,17 +534,17 @@ public class UiPreviewGenerator extends Application {
if (pdf.getParentFile() != null) {
pdf.getParentFile().mkdirs();
}
try (org.apache.pdfbox.pdmodel.PDDocument doc = new org.apache.pdfbox.pdmodel.PDDocument()) {
try (org.apache.pdfbox.pdmodel.PDDocument document = new org.apache.pdfbox.pdmodel.PDDocument()) {
org.apache.pdfbox.pdmodel.PDPage page = new org.apache.pdfbox.pdmodel.PDPage();
doc.addPage(page);
try (org.apache.pdfbox.pdmodel.PDPageContentStream stream = new org.apache.pdfbox.pdmodel.PDPageContentStream(doc, page)) {
stream.beginText();
stream.setFont(new org.apache.pdfbox.pdmodel.font.PDType1Font(org.apache.pdfbox.pdmodel.font.Standard14Fonts.FontName.HELVETICA_BOLD), 16);
stream.newLineAtOffset(50, 700);
stream.showText("CyberCore Signer — Documento PDF de Demonstração");
stream.endText();
document.addPage(page);
try (org.apache.pdfbox.pdmodel.PDPageContentStream cs = new org.apache.pdfbox.pdmodel.PDPageContentStream(document, page)) {
cs.beginText();
cs.setFont(new org.apache.pdfbox.pdmodel.font.PDType1Font(org.apache.pdfbox.pdmodel.font.Standard14Fonts.FontName.HELVETICA_BOLD), 16);
cs.newLineAtOffset(50, 700);
cs.showText("CyberCore Signer - Documento de Teste de Assinatura");
cs.endText();
}
doc.save(pdf);
document.save(pdf);
}
}
return pdf;
@@ -557,15 +552,16 @@ public class UiPreviewGenerator extends Application {
private static void saveNodeSnapshot(Scene scene, File targetFile) throws Exception {
WritableImage image = scene.snapshot(null);
int w = (int) image.getWidth();
int h = (int) image.getHeight();
BufferedImage bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
int width = (int) image.getWidth();
int height = (int) image.getHeight();
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
PixelReader reader = image.getPixelReader();
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
bufferedImage.setRGB(x, y, reader.getArgb(x, y));
}
}
ImageIO.write(bufferedImage, "png", targetFile);
System.out.println("Screenshot gerada: " + targetFile.getName());
}
}
@@ -33,7 +33,7 @@ class AssetManagerTest {
String[] iconNames = {
"pdf", "xml", "file", "batch", "attached", "co-sign",
"timestamp", "ltv", "validate", "validate-timestamp", "exit",
"logs", "settings", "tutorial", "cert", "about", "sun", "moon",
"logs", "settings", "tutorial", "cert", "about",
"shield", "seal", "seal-icp-brasil", "check", "error", "star", "close", "arrow-right",
"zoom-in", "zoom-out", "zoom-fit", "refresh"
};
@@ -56,17 +56,10 @@ class AssetManagerTest {
}
@Test
@DisplayName("Deve repintar dinamicamente elementos currentColor ao mudar o tema")
void shouldRepaintCurrentColorDynamicallyOnThemeChange() {
@DisplayName("Deve carregar ícones SVG com cor dinâmica sem lançar exceções")
void shouldRenderDynamicSvgIcons() {
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