Skip to content

Commit e60f819

Browse files
authored
Merge pull request #24 from doubleSlashde/feature/advanced_controlls
Feature/advanced controlls
2 parents ae7e070 + b52d523 commit e60f819

File tree

6 files changed

+231
-109
lines changed

6 files changed

+231
-109
lines changed
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
package de.doubleslash.keeptime.view;
2+
3+
import java.util.Optional;
4+
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
8+
import de.doubleslash.keeptime.common.DateFormatter;
9+
import de.doubleslash.keeptime.model.Model;
10+
import de.doubleslash.keeptime.model.Project;
11+
import javafx.application.Platform;
12+
import javafx.beans.binding.Bindings;
13+
import javafx.beans.property.LongProperty;
14+
import javafx.geometry.Insets;
15+
import javafx.scene.control.Button;
16+
import javafx.scene.control.ButtonType;
17+
import javafx.scene.control.Dialog;
18+
import javafx.scene.control.Label;
19+
import javafx.scene.control.Slider;
20+
import javafx.scene.input.KeyCode;
21+
import javafx.scene.layout.GridPane;
22+
import javafx.scene.layout.VBox;
23+
24+
public class ChangeWithTimeDialog {
25+
26+
private static final Logger LOG = LoggerFactory.getLogger(ChangeWithTimeDialog.class);
27+
private static final String TIME_ZERO = "00:00:00";
28+
private static final int FAST_MINUTE_STEPS = 5;
29+
30+
private final Model model;
31+
private final LongProperty activeWorkSecondsProperty;
32+
private final Project projectToChangeTo;
33+
34+
private Dialog<Integer> dialog;
35+
private boolean ctrlIsPressed = false;
36+
37+
public ChangeWithTimeDialog(final Model model, final LongProperty activeWorkSecondsProperty,
38+
final Project projectToChangeTo) {
39+
this.model = model;
40+
this.activeWorkSecondsProperty = activeWorkSecondsProperty;
41+
this.projectToChangeTo = projectToChangeTo;
42+
43+
setUpDialog();
44+
}
45+
46+
private void setUpDialog() {
47+
dialog = new Dialog<>();
48+
dialog.setTitle("Change project with time transfer");
49+
dialog.setHeaderText("Choose the time to transfer");
50+
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
51+
final Button okButton = (Button) dialog.getDialogPane().lookupButton(ButtonType.OK);
52+
okButton.setDefaultButton(true);
53+
final Button cancelButton = (Button) dialog.getDialogPane().lookupButton(ButtonType.CANCEL);
54+
cancelButton.setDefaultButton(false);
55+
56+
final VBox vBox = new VBox();
57+
final Label description = new Label(
58+
"Choose the amount of minutes to transfer from the active project to the new project");
59+
description.setWrapText(true);
60+
vBox.getChildren().add(description);
61+
62+
final GridPane grid = new GridPane();
63+
grid.setHgap(10);
64+
grid.setVgap(10);
65+
grid.setPadding(new Insets(20, 150, 10, 10));
66+
int gridRow = 0;
67+
grid.add(new Label("Minutes to transfer"), 0, gridRow);
68+
final Slider slider = setupSlider();
69+
70+
grid.add(slider, 1, gridRow);
71+
final Label minutesToTransferLabel = new Label("999 minute(s)");
72+
grid.add(minutesToTransferLabel, 2, gridRow);
73+
gridRow++;
74+
75+
grid.add(new Label("New time distribution"), 0, gridRow);
76+
gridRow++;
77+
grid.add(new Label("Active project duration: " + model.activeWorkItem.get().getProject().getName()), 0, gridRow);
78+
final Label currentProjectTimeLabel = new Label(TIME_ZERO);
79+
grid.add(currentProjectTimeLabel, 1, gridRow);
80+
gridRow++;
81+
82+
grid.add(new Label("New end and start time:"), 0, gridRow);
83+
final Label newEndTimeLabel = new Label(TIME_ZERO);
84+
grid.add(newEndTimeLabel, 1, gridRow);
85+
gridRow++;
86+
87+
grid.add(new Label("New project duration: " + projectToChangeTo.getName()), 0, gridRow);
88+
final Label newProjectTimeLabel = new Label(TIME_ZERO);
89+
grid.add(newProjectTimeLabel, 1, gridRow);
90+
91+
final Runnable updateLabelsRunnable = () -> {
92+
final long minutesOffset = slider.valueProperty().longValue();
93+
final long secondsOffset = minutesOffset * 60;
94+
95+
final long secondsActiveWork = activeWorkSecondsProperty.get() - secondsOffset;
96+
final long secondsNewWork = 0 + secondsOffset;
97+
minutesToTransferLabel.setText(minutesOffset + " minute(s)");
98+
currentProjectTimeLabel.setText(DateFormatter.secondsToHHMMSS(secondsActiveWork));
99+
newProjectTimeLabel.setText(DateFormatter.secondsToHHMMSS(secondsNewWork));
100+
newEndTimeLabel.setText(
101+
DateFormatter.toTimeString(model.activeWorkItem.get().getEndTime().minusSeconds(secondsOffset)));
102+
};
103+
activeWorkSecondsProperty.addListener((obs, oldValue, newValue) -> updateLabelsRunnable.run());
104+
slider.valueProperty().addListener((obs, oldValue, newValue) -> updateLabelsRunnable.run());
105+
vBox.getChildren().add(grid);
106+
107+
dialog.setOnShown(de -> {
108+
// workaround to set focus to slider when showing the dialog
109+
// onShown is actually called before the dialog is shown
110+
Platform.runLater(slider::requestFocus);
111+
});
112+
113+
dialog.getDialogPane().setContent(vBox);
114+
115+
dialog.setResultConverter(dialogButton -> {
116+
if (dialogButton == ButtonType.OK) {
117+
return slider.valueProperty().intValue() * 60;
118+
}
119+
return null;
120+
});
121+
122+
}
123+
124+
/**
125+
* Shows the dialog to the user.
126+
*
127+
* @return optional with the amount of seconds to transfer to the new project or null if the user does not confirm
128+
*/
129+
public Optional<Integer> showAndWait() {
130+
LOG.info("Showing dialog");
131+
return dialog.showAndWait();
132+
}
133+
134+
private Slider setupSlider() {
135+
final Slider slider = new Slider();
136+
137+
slider.setMin(0);
138+
slider.maxProperty().bind(Bindings.createLongBinding(() -> {
139+
final long maxValue = activeWorkSecondsProperty.longValue() / 60;
140+
if (maxValue > 0) {
141+
slider.setDisable(false);
142+
return maxValue;
143+
}
144+
slider.setDisable(true);
145+
return 1l;
146+
}, activeWorkSecondsProperty));
147+
148+
slider.setValue(0);
149+
slider.setShowTickLabels(true);
150+
slider.setShowTickMarks(true);
151+
slider.setMajorTickUnit(60);
152+
slider.setMinorTickCount(58);
153+
slider.setBlockIncrement(1);
154+
slider.setSnapToTicks(true);
155+
slider.setFocusTraversable(true);
156+
157+
// allows you to make bigger steps with arrow keys on slider if ctrl is pressed
158+
slider.setOnKeyPressed(ke -> {
159+
if (ke.getCode() == KeyCode.CONTROL) {
160+
ctrlIsPressed = true;
161+
}
162+
163+
if (ke.getCode() == KeyCode.LEFT && ctrlIsPressed) {
164+
slider.adjustValue(slider.getValue() - FAST_MINUTE_STEPS);
165+
}
166+
167+
if (ke.getCode() == KeyCode.RIGHT && ctrlIsPressed) {
168+
slider.adjustValue(slider.getValue() + FAST_MINUTE_STEPS);
169+
}
170+
});
171+
172+
slider.setOnKeyReleased(ke -> {
173+
if (ke.getCode() == KeyCode.CONTROL) {
174+
ctrlIsPressed = false;
175+
}
176+
});
177+
178+
return slider;
179+
}
180+
181+
}

src/main/java/de/doubleslash/keeptime/view/ReportController.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import javafx.scene.control.ScrollPane;
4949
import javafx.scene.input.Clipboard;
5050
import javafx.scene.input.ClipboardContent;
51+
import javafx.scene.layout.AnchorPane;
5152
import javafx.scene.layout.BorderPane;
5253
import javafx.scene.layout.GridPane;
5354
import javafx.scene.layout.HBox;
@@ -74,9 +75,13 @@ public class ReportController {
7475

7576
@FXML
7677
private GridPane gridPane;
78+
7779
@FXML
7880
private ScrollPane scrollPane;
7981

82+
@FXML
83+
private AnchorPane reportRoot;
84+
8085
@FXML
8186
private Canvas colorTimeLineCanvas;
8287

@@ -103,9 +108,11 @@ private void initialize() {
103108
colorTimeLine = new ColorTimeLine(colorTimeLineCanvas);
104109
}
105110

106-
private void updateReport(final LocalDate newvalue) {
107-
this.currentDayLabel.setText(DateFormatter.toDayDateString(newvalue));
108-
final List<Work> currentWorkItems = model.getWorkRepository().findByCreationDate(newvalue);
111+
private void updateReport(final LocalDate dateToShow) {
112+
reportRoot.requestFocus();
113+
114+
this.currentDayLabel.setText(DateFormatter.toDayDateString(dateToShow));
115+
final List<Work> currentWorkItems = model.getWorkRepository().findByCreationDate(dateToShow);
109116

110117
colorTimeLine.update(currentWorkItems, controller.calcSeconds(currentWorkItems));
111118

src/main/java/de/doubleslash/keeptime/view/SettingsController.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import javafx.scene.control.CheckBox;
4040
import javafx.scene.control.ColorPicker;
4141
import javafx.scene.control.Label;
42+
import javafx.scene.layout.AnchorPane;
4243
import javafx.scene.layout.Region;
4344
import javafx.scene.paint.Color;
4445
import javafx.stage.Modality;
@@ -94,6 +95,9 @@ public class SettingsController {
9495
@FXML
9596
private Label globalKeyloggerLabel;
9697

98+
@FXML
99+
private AnchorPane settingsRoot;
100+
97101
private static final Logger LOG = LoggerFactory.getLogger(SettingsController.class);
98102

99103
private Controller controller;
@@ -211,6 +215,9 @@ public void setControllerAndModel(final Controller controller, final Model model
211215
}
212216

213217
void update() {
218+
// needed to close stage on esc
219+
settingsRoot.requestFocus();
220+
214221
hoverBackgroundColor.setValue(model.hoverBackgroundColor.get());
215222
hoverFontColor.setValue(model.hoverFontColor.get());
216223

0 commit comments

Comments
 (0)