chore(ui): capture initial baseline screenshots for all views

This commit is contained in:
Claudecio Martins
2026-10-20 19:42:46 -03:00
parent 2c1d4f359e
commit 975885753a
21 changed files with 413 additions and 22 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

@@ -1,62 +1,453 @@
package br.com.cybercore.signer.ui; package br.com.cybercore.signer.ui;
import br.com.cybercore.signer.core.diagnostics.DiagnosticReport;
import br.com.cybercore.signer.core.diagnostics.DiagnosticService;
import br.com.cybercore.signer.core.domain.CertificateStatus;
import br.com.cybercore.signer.core.domain.CertificateType;
import br.com.cybercore.signer.core.domain.ManagedCertificate;
import br.com.cybercore.signer.core.domain.SigningContext;
import br.com.cybercore.signer.ui.components.CertificateCardNode;
import br.com.cybercore.signer.ui.components.SvgIcons;
import br.com.cybercore.signer.ui.theme.ThemeManager; import br.com.cybercore.signer.ui.theme.ThemeManager;
import br.com.cybercore.signer.ui.view.AboutView;
import br.com.cybercore.signer.ui.view.DiagnosticsView;
import br.com.cybercore.signer.ui.view.MainAppView; import br.com.cybercore.signer.ui.view.MainAppView;
import br.com.cybercore.signer.ui.view.SealManagementDialog;
import br.com.cybercore.signer.ui.view.SettingsView;
import br.com.cybercore.signer.ui.view.SignaturePromptDialog;
import br.com.cybercore.signer.ui.view.SignatureValidationDialog;
import javafx.application.Application; import javafx.application.Application;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.PixelReader; import javafx.scene.image.PixelReader;
import javafx.scene.image.WritableImage; import javafx.scene.image.WritableImage;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage; import javafx.stage.Stage;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Objects;
public class UiPreviewGenerator extends Application { public class UiPreviewGenerator extends Application {
private static final File OUTPUT_DIR = new File("docs/screenshots");
public static void main(String[] args) { public static void main(String[] args) {
Application.launch(UiPreviewGenerator.class, args); Application.launch(UiPreviewGenerator.class, args);
} }
@Override @Override
public void start(Stage primaryStage) { public void start(Stage primaryStage) {
// 1. Inicia com Tema Claro OUTPUT_DIR.mkdirs();
ThemeManager.setCurrentTheme(ThemeManager.AppTheme.LIGHT);
MainAppView appView = new MainAppView(primaryStage);
appView.show();
Platform.runLater(() -> { Platform.runLater(() -> {
try { try {
File outputDir = new File("docs/screenshots"); // 1. Hub Principal
outputDir.mkdirs(); captureHubScreenshots(primaryStage);
// Snapshot Modo Claro // 2. Diagnóstico
saveNodeSnapshot(primaryStage.getScene(), new File(outputDir, "01_layout_claro.png")); captureDiagnosticsScreenshots(primaryStage);
// 2. Alterna para Tema Escuro // 3. Configurações
ThemeManager.setCurrentTheme(ThemeManager.AppTheme.DARK); captureSettingsScreenshots(primaryStage);
ThemeManager.applyTheme(primaryStage.getScene());
Platform.runLater(() -> { // 4. Gerenciamento de Certificados
try { captureCertificatesScreenshots(primaryStage);
// Snapshot Modo Escuro
saveNodeSnapshot(primaryStage.getScene(), new File(outputDir, "02_layout_escuro.png")); // 5. Validação de Assinatura
} catch (Exception e) { captureValidationScreenshots(primaryStage);
e.printStackTrace();
} finally { // 6. Solicitação de Assinatura (Prompt CCSP)
Platform.exit(); capturePromptScreenshots(primaryStage);
}
}); // 7. Selos Visuais
captureSealsScreenshots(primaryStage);
// 8. Sobre
captureAboutScreenshots(primaryStage);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally {
Platform.exit(); Platform.exit();
} }
}); });
} }
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();
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"));
}
}
}
private void captureDiagnosticsScreenshots(Stage stage) throws Exception {
for (ThemeManager.AppTheme theme : ThemeManager.AppTheme.values()) {
ThemeManager.setCurrentTheme(theme);
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);
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"));
}
}
}
private void captureSettingsScreenshots(Stage stage) throws Exception {
for (ThemeManager.AppTheme theme : ThemeManager.AppTheme.values()) {
ThemeManager.setCurrentTheme(theme);
SettingsView settingsView = new SettingsView();
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);
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"));
}
}
}
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));
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"
);
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);
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();
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 {
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();
String suffix = theme == ThemeManager.AppTheme.LIGHT ? "claro" : "escuro";
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "05_validacao_" + suffix + ".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
);
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
);
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"));
}
}
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();
String suffix = theme == ThemeManager.AppTheme.LIGHT ? "claro" : "escuro";
saveNodeSnapshot(scene, new File(OUTPUT_DIR, "07_selos_" + suffix + ".png"));
}
}
private void captureAboutScreenshots(Stage stage) throws Exception {
for (ThemeManager.AppTheme theme : ThemeManager.AppTheme.values()) {
ThemeManager.setCurrentTheme(theme);
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);
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"));
}
}
private Scene createScene(VBox root, double w, double h) {
Scene scene = new Scene(root, w, h);
scene.getStylesheets().add(Objects.requireNonNull(
getClass().getResource(CyberCoreUiConstants.MAIN_CSS_PATH)
).toExternalForm());
ThemeManager.applyTheme(scene);
return scene;
}
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));
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);
header.getChildren().addAll(icon, titleBox);
VBox contentBox = new VBox(content);
VBox.setVgrow(contentBox, Priority.ALWAYS);
container.getChildren().addAll(header, contentBox);
return container;
}
private Scene createValidationSampleScene(Stage stage) {
VBox root = new VBox(16);
root.setPadding(new Insets(20));
root.getStyleClass().addAll("dialog-container", "cyber-root");
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)")
);
root.getChildren().addAll(header, box);
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");
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() + "]")
);
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);
root.getChildren().addAll(header, box, actions);
return createScene(root, 620, 440);
}
private Scene createSealsSampleScene() {
VBox root = new VBox(16);
root.setPadding(new Insets(20));
root.getStyleClass().addAll("dialog-container", "cyber-root");
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");
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")
);
root.getChildren().addAll(header, box);
return createScene(root, 680, 460);
}
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 w = (int) image.getWidth();