Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,6 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.kordamp.bootstrapfx</groupId>
<artifactId>bootstrapfx-core</artifactId>
<version>0.4.0</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
Expand Down
10 changes: 2 additions & 8 deletions src/main/java/com/DesktopApplicationClientJava/Program.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,19 @@
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.kordamp.bootstrapfx.BootstrapFX;

public class Program extends Application {
private static final String INITIAL_PAGE_PATH =
System.getenv().getOrDefault("INITIAL_PAGE_PATH", "/fxml/LoginForm.fxml");
private static final boolean MOCK_DATA =
Boolean.parseBoolean(System.getenv().getOrDefault("MOCK_DATA", "false"));
private static final boolean MOCK_DATA = true;
// Boolean.parseBoolean(System.getenv().getOrDefault("MOCK_DATA", "false"));
private static final double WINDOW_WIDTH = 800.0;
private static final double WINDOW_HEIGHT = 600.0;

private final Session session = new Session();
private final ApiClient apiClient = new ApiClient(session);
private final ServiceRegistry services = createServices();

public static void main(String[] args) {
launch(args);
}

@Override
public void start(Stage stage) throws IOException {
Navigator navigator = new Navigator(stage, session, services);
Expand All @@ -47,7 +42,6 @@ public void start(Stage stage) throws IOException {

Parent root = loader.load();
Scene scene = new Scene(root);
scene.getStylesheets().add(BootstrapFX.bootstrapFXStylesheet());
loadStyleSheet(scene, "/styles.css");

stage.setScene(scene);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ private void onSubmit(ActionEvent event) {
}

try {
// ← ВЫЗОВ СЕРВИСА (middleware): session уже обновлён сервисом при успехе
User user = services.getAuthService().login(email, password);
if (user == null) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
import javafx.beans.property.SimpleStringProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
Expand All @@ -23,7 +25,6 @@
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.DirectoryChooser;
import javafx.stage.Window;
import lombok.Setter;

public class ResourceDetailsController extends Controller {

Expand All @@ -38,20 +39,55 @@ public class ResourceDetailsController extends Controller {
@FXML private Label statusLabel;
@FXML private TableView<FileInfo> filesTable;
@FXML private TableColumn<FileInfo, String> nameColumn;
@FXML private TableColumn<FileInfo, Long> sizeColumn;
@FXML private TableColumn<FileInfo, String> sizeColumn;
@FXML private TableColumn<FileInfo, String> contentTypeColumn;
@FXML private TableColumn<FileInfo, Void> downloadColumn;
@FXML private Button backButton;
@FXML private Button editButton;

@Setter private UUID resourceId;
private UUID resourceId;

/**
* Navigator sets the id <i>after</i> FXML load (see {@code Navigator.goTo}), so the setter itself
* must load the resource when the view is already initialized.
*/
public void setResourceId(UUID resourceId) {
this.resourceId = resourceId;
if (titleLabel != null && resourceId != null && services != null) {
load();
}
}

@FXML
private void initialize() {
hideError();

nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
sizeColumn.setCellValueFactory(new PropertyValueFactory<>("size"));
contentTypeColumn.setCellValueFactory(new PropertyValueFactory<>("contentType"));
sizeColumn.setCellValueFactory(
c -> new SimpleStringProperty(formatSize(c.getValue().getSize())));
sizeColumn.setCellFactory(
col -> {
TableCell<FileInfo, String> cell =
new TableCell<>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setText(empty ? null : item);
setAlignment(Pos.CENTER_RIGHT);
}
};
return cell;
});

downloadColumn.setCellFactory(col -> new DownloadCell(this::onDownload));
filesTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_FLEX_LAST_COLUMN);
filesTable.setPlaceholder(new Label("У этого документа нет файлов"));
// NB: services/getAuthService may be a partial mock in tests — stay null-safe.
var authService = services == null ? null : services.getAuthService();
boolean canEdit = authService != null && (authService.isAdmin() || authService.isModerator());
editButton.setVisible(canEdit);
editButton.setManaged(canEdit);
autoSelectFirstInMockMode();
}

Expand Down Expand Up @@ -92,18 +128,17 @@ protected File chooseDirectory(Window owner) {
* resource list. Never triggers against the real backend.
*/
private void autoSelectFirstInMockMode() {
if (resourceId != null || !(services.getResourceService() instanceof MockService mock)) {
if (resourceId != null
|| services == null
|| services.getResourceService() == null
|| !(services.getResourceService() instanceof MockService mock)) {
return;
}
mock.doIfInitialPage();
services.getResourceService().search(ResourceFilter.empty(), 0, 1).stream()
.map(Resource::getUuid)
.findFirst()
.ifPresent(
id -> {
setResourceId(id);
load();
});
.ifPresent(this::setResourceId); // the setter loads the resource
}

private void showResource(Resource resource) {
Expand All @@ -120,6 +155,14 @@ private static String formatDateTime(LocalDateTime value) {
return value == null ? "" : DATE_TIME_FORMAT.format(value);
}

private static String formatSize(Long bytes) {
if (bytes == null) return "";
if (bytes < 1024) return bytes + " B";
if (bytes < 1024 * 1024) return String.format("%.1f KB", bytes / 1024.0);
if (bytes < 1024L * 1024 * 1024) return String.format("%.1f MB", bytes / (1024.0 * 1024));
return String.format("%.1f GB", bytes / (1024.0 * 1024 * 1024));
}

private void showError(String message) {
errorLabel.setText(message);
errorLabel.setVisible(true);
Expand All @@ -136,7 +179,7 @@ private static final class DownloadCell extends TableCell<FileInfo, Void> {
private final Button button = new Button("Скачать");

DownloadCell(Consumer<FileInfo> onDownload) {
button.getStyleClass().setAll("btn", "btn-default");
button.getStyleClass().setAll("btn-ghost");
button.setOnAction(event -> onDownload.accept(getTableView().getItems().get(getIndex())));
}

Expand All @@ -146,4 +189,11 @@ protected void updateItem(Void item, boolean empty) {
setGraphic(empty ? null : button);
}
}

@FXML
private void onEdit(ActionEvent event) {
if (resourceId == null) return;
navigator.goTo(
"/fxml/ResourceForm.fxml", c -> ((ResourceFormController) c).setResourceId(resourceId));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.DesktopApplicationClientJava.controllers;

import com.DesktopApplicationClientJava.controllers.utils.Controller;
import com.DesktopApplicationClientJava.entities.Resource;
import com.DesktopApplicationClientJava.services.ServiceException;
import java.util.UUID;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;

public class ResourceFormController extends Controller {

private static final int TITLE_MIN = 3;
private static final int TITLE_MAX = 255;

@FXML private Label formTitleLabel;
@FXML private TextField titleField;
@FXML private TextArea descriptionArea;
@FXML private Label errorLabel;
@FXML private Button cancelButton;
@FXML private Button saveButton;

private UUID resourceId;

/**
* Navigator sets the id <i>after</i> FXML load (see {@code Navigator.goTo}), so the setter itself
* must switch the form into edit mode when the view is already initialized. Setting the id before
* load is also honored by {@link #initialize()}.
*/
public void setResourceId(UUID resourceId) {
this.resourceId = resourceId;
if (formTitleLabel != null && resourceId != null && services != null) {
formTitleLabel.setText("Редактирование документа");
loadExisting();
}
}

@FXML
private void initialize() {
hideError();
if (resourceId == null) {
formTitleLabel.setText("Новый документ");
} else {
formTitleLabel.setText("Редактирование документа");
loadExisting();
}
}

private void loadExisting() {
try {
Resource r = services.getResourceService().getById(resourceId);
titleField.setText(r.getTitle() == null ? "" : r.getTitle());
descriptionArea.setText(r.getDescription() == null ? "" : r.getDescription());
} catch (ServiceException e) {
showError(e.getMessage());
}
}

@FXML
private void onSave(ActionEvent event) {
hideError();
String title = titleField.getText() == null ? "" : titleField.getText().trim();
String description = descriptionArea.getText() == null ? "" : descriptionArea.getText().trim();
String descriptionOrNull = description.isBlank() ? null : description;

if (title.isBlank()) {
showError("Название обязательно для заполнения");
titleField.requestFocus();
return;
}
if (title.length() < TITLE_MIN) {
showError("Название не может быть короче " + TITLE_MIN + " символов");
titleField.requestFocus();
return;
}
if (title.length() > TITLE_MAX) {
showError("Название не может быть длиннее " + TITLE_MAX + " символов");
titleField.requestFocus();
return;
}

try {
if (resourceId == null) {
services.getResourceService().create(title, descriptionOrNull);
} else {
services.getResourceService().update(resourceId, title, descriptionOrNull);
}
navigator.goTo("/fxml/ResourceList.fxml");
} catch (ServiceException e) {
showError(e.getMessage());
}
}

@FXML
private void onCancel(ActionEvent event) {
navigator.goTo("/fxml/ResourceList.fxml");
}

private void showError(String message) {
errorLabel.setText(message);
errorLabel.setVisible(true);
errorLabel.setManaged(true);
}

private void hideError() {
errorLabel.setText("");
errorLabel.setVisible(false);
errorLabel.setManaged(false);
}
}
Loading
Loading