1818import javafx .scene .layout .HBox ;
1919import javafx .scene .layout .VBox ;
2020import javafx .scene .shape .Circle ;
21+ import javafx .stage .Stage ;
2122import javafx .util .converter .LocalTimeStringConverter ;
2223import org .slf4j .Logger ;
2324import org .slf4j .LoggerFactory ;
3435@ Component
3536public class ExternalProjectsSyncController {
3637
37- private static final Logger LOG = LoggerFactory .getLogger (MapExternalProjectsController .class );
38+ private static final Logger LOG = LoggerFactory .getLogger (ExternalProjectsSyncController .class );
3839
3940 @ FXML
4041 private TableView <TableRow > mappingTableView ;
@@ -60,21 +61,26 @@ public class ExternalProjectsSyncController {
6061 private final ExternalProjectsMappingsRepository externalProjectsMappingsRepository ;
6162
6263 private final LocalTimeStringConverter localTimeStringConverter = new LocalTimeStringConverter (FormatStyle .MEDIUM );
64+ private ObservableList <TableRow > items ;
65+ private final HeimatAPI heimatAPI ;
66+ private LocalDate currentReportDate ;
67+ private Stage thisStage ;
6368
6469 public ExternalProjectsSyncController (final Controller controller , final Model model , HeimatSettings heimatSettings ,
6570 ExternalProjectsMappingsRepository externalProjectsMappingsRepository ) {
6671 this .controller = controller ;
6772 this .model = model ;
6873 this .heimatSettings = heimatSettings ;
6974 this .externalProjectsMappingsRepository = externalProjectsMappingsRepository ;
75+ heimatAPI = new HeimatAPI (heimatSettings .getHeimatUrl (), heimatSettings .getHeimatPat ());
7076 }
7177
7278 public void initForDate (LocalDate currentReportDate , List <Work > currentWorkItems ) {
7379 dayOfSyncLabel .setText (currentReportDate .format (DateTimeFormatter .BASIC_ISO_DATE ));
74-
75- final HeimatAPI heimatAPI = new HeimatAPI (heimatSettings .getHeimatUrl (), heimatSettings .getHeimatPat ());
80+ this .currentReportDate = currentReportDate ;
7681 // TODO check if external projects are available for the currentDay
7782 // final List<HeimatTask> heimatTasks = heimatAPI.getMyTasks(currentReportDate);
83+ // TODO add a spinner while loading?
7884 final List <HeimatTime > heimatTimes = heimatAPI .getMyTimes (currentReportDate );
7985 final List <ExternalProjectMapping > mappedProjects = externalProjectsMappingsRepository .findByExternalSystemId (
8086 ExternalSystem .Heimat );
@@ -95,13 +101,13 @@ public void initForDate(LocalDate currentReportDate, List<Work> currentWorkItems
95101 .getId ()
96102 == project .getId ())
97103 .findAny ();
104+ Optional <HeimatTime > optionalAlreadyBookedTime = Optional .empty ();
98105 if (optionalHeimatMapping .isPresent ()) {
99106 isMappedInHeimat = true ;
100- final Optional <HeimatTime > optionalAlreadyBookedTime = heimatTimes .stream ()
101- .filter (heimatTime -> heimatTime .taskId ()
102- == optionalHeimatMapping .get ()
103- .getExternalTaskId ())
104- .findAny ();
107+ optionalAlreadyBookedTime = heimatTimes .stream ()
108+ .filter (heimatTime -> heimatTime .taskId ()
109+ == optionalHeimatMapping .get ().getExternalTaskId ())
110+ .findAny ();
105111 if (optionalAlreadyBookedTime .isPresent ()) {
106112 heimatNotes = optionalAlreadyBookedTime .get ().note ();
107113 heimatTimeSeconds = optionalAlreadyBookedTime .get ().durationInMinutes () * 60L ;
@@ -123,10 +129,11 @@ public void initForDate(LocalDate currentReportDate, List<Work> currentWorkItems
123129 if (!isMappedInHeimat ) {
124130 canBeSynced = "Not mapped in Heimat" ;
125131 }
126- list .add (new TableRow (project , isMappedInHeimat , canBeSynced , heimatNotes , keeptimeNotes , keeptimeNotes ,
127- heimatTimeSeconds , projectWorkSeconds , projectWorkSeconds ));
132+ list .add (new TableRow (project , isMappedInHeimat ? optionalHeimatMapping .get ().getExternalTaskId () : -1 ,
133+ optionalAlreadyBookedTime .orElse (null ), isMappedInHeimat , canBeSynced , heimatNotes , keeptimeNotes ,
134+ keeptimeNotes , heimatTimeSeconds , projectWorkSeconds , projectWorkSeconds ));
128135 }
129- final ObservableList < TableRow > items = FXCollections .observableArrayList (list );
136+ items = FXCollections .observableArrayList (list );
130137 mappingTableView .setItems (items );
131138
132139 ObservableList <TableRow > items2 = FXCollections .observableArrayList (
@@ -138,6 +145,8 @@ public void initForDate(LocalDate currentReportDate, List<Work> currentWorkItems
138145 .mapToLong (item -> item .userTimeSeconds .getValue ())
139146 .sum ())), items2 );
140147 sumTimeLabel .textProperty ().bind (Bindings .concat ("Total Sum: " , totalSum ));
148+ // TODO add a label with current Heimat Time
149+ // TODO add a label with current Keeptime time
141150 }
142151
143152 @ FXML
@@ -161,6 +170,7 @@ protected void updateItem(Project item, boolean empty) {
161170 setGraphic (null );
162171 setText (null );
163172 } else {
173+ // TODO add a reference to the Heimat project which will be used
164174 //label.setText(item.getName());
165175 setText (item .getName ());
166176 final Circle circle = new Circle (6 , item .getColor ());
@@ -222,6 +232,8 @@ protected void updateItem(TableRow item, boolean empty) {
222232 textArea .setPrefHeight (50 );
223233 textArea .setPrefWidth (100 );
224234 textArea .setWrapText (true );
235+ // TODO mark textArea red when not content
236+ // TODO make it possible to copy content of heimatNotesLabel
225237 hbox .getChildren ().addAll (new Label ("Heimat:" ), heimatNotesLabel );
226238 container .getChildren ().addAll (textArea , hbox );
227239 }
@@ -235,7 +247,7 @@ protected void updateItem(TableRow item, boolean empty) {
235247 setGraphic (null );
236248 } else {
237249 textArea .setText (item .keeptimeNotes .get ());
238- stringChangeListener = (obs , oldText , newText ) -> item .keeptimeNotes .set (newText );
250+ stringChangeListener = (obs , oldText , newText ) -> item .userNotes .set (newText );
239251 textArea .textProperty ().addListener (stringChangeListener );
240252 heimatNotesLabel .setText (item .heimatNotes .get ());
241253 setGraphic (container );
@@ -251,12 +263,43 @@ protected void updateItem(TableRow item, boolean empty) {
251263
252264 saveButton .setOnAction ((ae ) -> {
253265 LOG .debug ("New mappings to be synced '{}'." , "TODO" );
254- // TODO close
266+
267+ // TODO show progress
268+ items .stream ().filter (tr -> tr .shouldSyncCheckBox .get ()).forEach (tr -> {
269+ if (tr .userNotes .get ().isEmpty ()) {
270+ LOG .warn ("No notes were given. Skipping '{}'" , tr .project .getName ());
271+ return ;
272+ }
273+ final int durationInMinutes = Math .toIntExact (tr .userTimeSeconds .get () / 60 );
274+ if (durationInMinutes <= 0 || durationInMinutes % 15 != 0 ) {
275+ LOG .warn ("Duration '{}' is not valid for project '{}'." , durationInMinutes , tr .project .getName ());
276+ return ;
277+ }
278+
279+ final HeimatTime heimatTime = new HeimatTime (tr .heimatTaskId , currentReportDate , null , null ,
280+ durationInMinutes , tr .userNotes .get (), 0L );
281+
282+ try {
283+ if (tr .optionalExistingTime != null ) {
284+ LOG .info ("Removing existing booked time '{}'" , tr .optionalExistingTime );
285+ heimatAPI .deleteMyTime (tr .optionalExistingTime .id ());
286+ }
287+ LOG .info ("Adding new time time '{}'" , heimatTime );
288+ heimatAPI .addMyTime (heimatTime );
289+ } catch (Exception e ) {
290+ // TODO show errors to the user
291+ LOG .error ("Error while persisting time '{}'" , heimatTime , e );
292+ }
293+ });
294+
295+ thisStage .close ();
255296 });
256297
257298 cancelButton .setOnAction (ae -> {
258- // TODO Close
299+ thisStage . close ();
259300 });
301+
302+ // TODO offer some way to book time to an additional project?
260303 }
261304
262305 private void setUpTimeSpinner (final Spinner <LocalTime > spinner ) {
@@ -319,7 +362,13 @@ public static LocalTime incrementToNextFullQuarter(LocalTime time) {
319362 return time .plusMinutes (increment ).withSecond (0 ).withNano (0 );
320363 }
321364
365+ public void setStage (final Stage thisStage ) {
366+ this .thisStage = thisStage ;
367+ }
368+
322369 static class TableRow {
370+ private final long heimatTaskId ;
371+ private final HeimatTime optionalExistingTime ;
323372 public BooleanProperty shouldSyncCheckBox ;
324373 public Project project ;
325374
@@ -333,10 +382,12 @@ static class TableRow {
333382
334383 public StringProperty syncStatus ;
335384
336- public TableRow (final Project project , final boolean shouldSync , final String syncStatus ,
337- final String heimatNotes , final String keeptimeNotes , String userNotes , final long heimatTimeSeconds ,
338- final long keeptimeSeconds , final long userSeconds ) {
385+ public TableRow (final Project project , long heimatTaskId , HeimatTime optionalExistingTime ,
386+ final boolean shouldSync , final String syncStatus , final String heimatNotes , final String keeptimeNotes ,
387+ String userNotes , final long heimatTimeSeconds , final long keeptimeSeconds , final long userSeconds ) {
339388 this .project = project ;
389+ this .heimatTaskId = heimatTaskId ;
390+ this .optionalExistingTime = optionalExistingTime ;
340391 this .shouldSyncCheckBox = new SimpleBooleanProperty (shouldSync );
341392 this .syncStatus = new SimpleStringProperty (syncStatus );
342393 this .heimatNotes = new SimpleStringProperty (heimatNotes );
0 commit comments