|
7 | 7 | import de.doubleslash.keeptime.controller.HeimatController; |
8 | 8 | import de.doubleslash.keeptime.model.Project; |
9 | 9 | import de.doubleslash.keeptime.model.Work; |
| 10 | +import de.doubleslash.keeptime.rest.integration.heimat.model.HeimatTask; |
10 | 11 | import javafx.animation.Animation; |
11 | 12 | import javafx.animation.PauseTransition; |
12 | 13 | import javafx.animation.RotateTransition; |
|
17 | 18 | import javafx.beans.property.*; |
18 | 19 | import javafx.beans.value.ChangeListener; |
19 | 20 | import javafx.collections.FXCollections; |
| 21 | +import javafx.collections.ListChangeListener; |
20 | 22 | import javafx.collections.ObservableList; |
| 23 | +import javafx.collections.transformation.FilteredList; |
21 | 24 | import javafx.concurrent.Task; |
22 | 25 | import javafx.fxml.FXML; |
23 | 26 | import javafx.scene.Node; |
|
43 | 46 | import java.util.Collections; |
44 | 47 | import java.util.List; |
45 | 48 | import java.util.function.Consumer; |
| 49 | +import java.util.function.Predicate; |
46 | 50 |
|
47 | 51 | import static de.doubleslash.keeptime.view.ReportController.copyToClipboard; |
48 | 52 |
|
@@ -82,6 +86,11 @@ public class ExternalProjectsSyncController { |
82 | 86 | @FXML |
83 | 87 | private Label loadingMessage; |
84 | 88 |
|
| 89 | + @FXML |
| 90 | + private ComboBox<HeimatTask> heimatTaskComboBox; |
| 91 | + @FXML |
| 92 | + private Button addHeimatTaskButton; |
| 93 | + |
85 | 94 | private final SVGPath loadingSpinner = SvgNodeProvider.getSvgNodeWithScale(Resources.RESOURCE.SVG_SPINNER_SOLID, 0.1, |
86 | 95 | 0.1); |
87 | 96 | private final SVGPath loadingSuccess = SvgNodeProvider.getSvgNodeWithScale(Resources.RESOURCE.SVG_THUMBS_UP_SOLID, |
@@ -148,12 +157,54 @@ public void initForDate(LocalDate currentReportDate, List<Work> currentWorkItems |
148 | 157 | }), items2); |
149 | 158 |
|
150 | 159 | saveButton.disableProperty().bind(projectsValidProperty); |
151 | | - |
152 | 160 | externalSystemLink.setOnAction(ae -> BrowserHelper.openURL(heimatController.getUrlForDay(currentReportDate))); |
| 161 | + |
| 162 | + final List<HeimatTask> tasksForDay = heimatController.getTasks(currentReportDate); |
| 163 | + final FilteredList<HeimatTask> tasksNotInList = new FilteredList<>(FXCollections.observableArrayList(tasksForDay), |
| 164 | + (task) -> items.stream().noneMatch(tr -> task.id() == tr.mapping.heimatTaskId())); |
| 165 | + items.addListener( |
| 166 | + (ListChangeListener<? super TableRow>) c -> { |
| 167 | + final Predicate<? super HeimatTask> predicate = tasksNotInList.getPredicate(); |
| 168 | + tasksNotInList.setPredicate(null); |
| 169 | + tasksNotInList.setPredicate(predicate); |
| 170 | + }); |
| 171 | + heimatTaskComboBox.setItems(tasksNotInList); |
| 172 | + addHeimatTaskButton.disableProperty() |
| 173 | + .bind(heimatTaskComboBox.getSelectionModel().selectedItemProperty().isNull()); |
| 174 | + addHeimatTaskButton.setOnAction(ae -> { |
| 175 | + final HeimatTask task = heimatTaskComboBox.getValue(); |
| 176 | + items.add(new TableRow(new HeimatController.Mapping(task.id(), true, |
| 177 | + "Manually added\n\n" + task.name() + "\n(" + task.taskHolderName() + ")", List.of(), List.of(), "", "", |
| 178 | + 0, 0), "", 0)); |
| 179 | + heimatTaskComboBox.getSelectionModel().clearSelection(); |
| 180 | + }); |
| 181 | + |
153 | 182 | } |
154 | 183 |
|
155 | 184 | @FXML |
156 | 185 | private void initialize() { |
| 186 | + heimatTaskComboBox.setCellFactory(param -> new ListCell<>() { |
| 187 | + @Override |
| 188 | + protected void updateItem(HeimatTask item, boolean empty) { |
| 189 | + super.updateItem(item, empty); |
| 190 | + if (empty || item == null) { |
| 191 | + setText(null); |
| 192 | + } else { |
| 193 | + setText(item.taskHolderName() + " - " + item.name()); |
| 194 | + } |
| 195 | + } |
| 196 | + }); |
| 197 | + heimatTaskComboBox.setButtonCell(new ListCell<>() { |
| 198 | + @Override |
| 199 | + protected void updateItem(HeimatTask item, boolean empty) { |
| 200 | + super.updateItem(item, empty); |
| 201 | + if (empty || item == null) { |
| 202 | + setText(null); |
| 203 | + } else { |
| 204 | + setText(item.name() + " - " + item.taskHolderName()); |
| 205 | + } |
| 206 | + } |
| 207 | + }); |
157 | 208 | initializeLoadingScreen(); |
158 | 209 |
|
159 | 210 | TableColumn<TableRow, TableRow> shouldSyncColumn = new TableColumn<>("Sync"); |
@@ -397,8 +448,6 @@ protected List<HeimatController.HeimatErrors> call() { |
397 | 448 | }); |
398 | 449 |
|
399 | 450 | cancelButton.setOnAction(ae -> thisStage.close()); |
400 | | - |
401 | | - // TODO offer some way to book time to an additional project? |
402 | 451 | } |
403 | 452 |
|
404 | 453 | private static void markNodeValidOrNot(final Node textArea, final boolean isValid) { |
|
0 commit comments