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
Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

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