Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code cleanup #278

Merged
merged 11 commits into from
May 4, 2024
2 changes: 1 addition & 1 deletion jfxui/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ tasks.jpackage {

appName = "WhiteRabbit"
vendor = '"It\'s all code"'
copyright = '"Copyright (C) 2021 Christoph Pirkl <christoph at users.sourceforge.net>"'
copyright = '"Copyright (C) 2024 Christoph Pirkl <christoph at users.sourceforge.net>"'
licenseFile = "${rootProject.rootDir}/LICENSE"
appDescription = '"A time recording tool"'
icon = "${projectDir}/src/main/resources/icon.png"
Expand Down
68 changes: 38 additions & 30 deletions jfxui/src/main/java/org/itsallcode/whiterabbit/jfxui/JavaFxApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

import java.lang.ProcessHandle.Info;
import java.nio.file.Paths;
import java.time.*;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalTime;
import java.time.YearMonth;
import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
Expand All @@ -17,8 +21,13 @@
import org.itsallcode.whiterabbit.jfxui.ui.AppUi;
import org.itsallcode.whiterabbit.jfxui.ui.InterruptionDialog;
import org.itsallcode.whiterabbit.jfxui.uistate.UiStateService;
import org.itsallcode.whiterabbit.logic.*;
import org.itsallcode.whiterabbit.logic.model.*;
import org.itsallcode.whiterabbit.logic.Config;
import org.itsallcode.whiterabbit.logic.ConfigLoader;
import org.itsallcode.whiterabbit.logic.DefaultWorkingDirProvider;
import org.itsallcode.whiterabbit.logic.WorkingDirProvider;
import org.itsallcode.whiterabbit.logic.model.Activity;
import org.itsallcode.whiterabbit.logic.model.DayRecord;
import org.itsallcode.whiterabbit.logic.model.MonthIndex;
import org.itsallcode.whiterabbit.logic.service.AppService;
import org.itsallcode.whiterabbit.logic.service.AppServiceCallback;
import org.itsallcode.whiterabbit.logic.service.singleinstance.OtherInstance;
Expand Down Expand Up @@ -56,7 +65,8 @@ public JavaFxApp()
this(new DefaultWorkingDirProvider(), Clock.systemDefaultZone(), new ScheduledThreadPoolExecutor(1));
}

JavaFxApp(WorkingDirProvider workingDirProvider, Clock clock, ScheduledExecutorService executorService)
JavaFxApp(final WorkingDirProvider workingDirProvider, final Clock clock,
final ScheduledExecutorService executorService)
{
this.workingDirProvider = workingDirProvider;
this.clock = clock;
Expand All @@ -70,14 +80,14 @@ public void init()
{
doInitialize();
}
catch (final Exception e)
catch (final RuntimeException e)
{
stop();
throw e;
}
}

private void notifyPreloaderProgress(Type notificationType)
private void notifyPreloaderProgress(final Type notificationType)
{
notifyPreloader(new ProgressPreloaderNotification(this, notificationType));
}
Expand Down Expand Up @@ -113,16 +123,16 @@ private Config loadConfig()
}

@Override
public void start(Stage primaryStage)
public void start(final Stage primaryStage)
{
this.primaryStage = primaryStage;
state.setPrimaryStage(primaryStage);
LOG.info("Starting UI");
LOG.trace("Starting UI");
doStart(primaryStage);
notifyPreloaderProgress(Type.STARTUP_FINISHED);
}

private void doStart(Stage primaryStage)
private void doStart(final Stage primaryStage)
{
this.ui = new AppUi.Builder(this, actions, appService, primaryStage, state).build();

Expand Down Expand Up @@ -193,7 +203,8 @@ private void startAppService()
appService.start();
}

private void messageFromOtherInstanceReceived(String message, RunningInstanceCallback.ClientConnection client)
private void messageFromOtherInstanceReceived(final String message,
final RunningInstanceCallback.ClientConnection client)
{
if (MESSAGE_BRING_TO_FRONT.equals(message))
{
Expand Down Expand Up @@ -268,26 +279,26 @@ public void startManualInterruption()
private final class AppServiceCallbackImplementation implements AppServiceCallback
{
@Override
public InterruptionDetectedDecision automaticInterruptionDetected(LocalTime startOfInterruption,
Duration interruption)
public InterruptionDetectedDecision automaticInterruptionDetected(final LocalTime startOfInterruption,
final Duration interruption)
{
return JavaFxUtil
.runOnFxApplicationThread(() -> showAutomaticInterruptionDialog(startOfInterruption, interruption));
}

private InterruptionDetectedDecision showAutomaticInterruptionDialog(LocalTime startOfInterruption,
Duration interruption)
private InterruptionDetectedDecision showAutomaticInterruptionDialog(final LocalTime startOfInterruption,
final Duration interruption)
{
final Alert alert = createAlertDialog(startOfInterruption, interruption);
LOG.info("Showing automatic interruption alert starting at {} for {}...", startOfInterruption,
interruption);
final Optional<ButtonType> selectedButton = alert.showAndWait();
final InterruptionDetectedDecision decision = evaluateButton(selectedButton);
final InterruptionDetectedDecision decision = evaluateButton(selectedButton.orElse(null));
LOG.info("User clicked button {} -> {}", selectedButton, decision);
return decision;
}

private Alert createAlertDialog(LocalTime startOfInterruption, Duration interruption)
private Alert createAlertDialog(final LocalTime startOfInterruption, final Duration interruption)
{
final Alert alert = new Alert(AlertType.CONFIRMATION);
alert.setTitle("Interruption detected");
Expand All @@ -302,28 +313,25 @@ private Alert createAlertDialog(LocalTime startOfInterruption, Duration interrup
return alert;
}

private InterruptionDetectedDecision evaluateButton(final Optional<ButtonType> selectedButton)
private InterruptionDetectedDecision evaluateButton(final ButtonType selectedButton)
{
if (isButton(selectedButton, ButtonData.FINISH) && !state.stoppedWorkingForToday.get())
if (selectedButton == null)
{
return InterruptionDetectedDecision.SKIP_INTERRUPTION;
}
if (selectedButton.getButtonData() == ButtonData.FINISH && !state.stoppedWorkingForToday.get())
{
return InterruptionDetectedDecision.STOP_WORKING_FOR_TODAY;
}
if (isButton(selectedButton, ButtonData.YES))
if (selectedButton.getButtonData() == ButtonData.YES)
{
return InterruptionDetectedDecision.ADD_INTERRUPTION;
}
return InterruptionDetectedDecision.SKIP_INTERRUPTION;
}

private boolean isButton(Optional<ButtonType> button, ButtonData data)
{
return button.map(ButtonType::getButtonData)
.filter(d -> d == data)
.isPresent();
}

@Override
public void recordUpdated(DayRecord day)
public void recordUpdated(final DayRecord day)
{
final YearMonth month = YearMonth.from(day.getDate());
JavaFxUtil.runOnFxApplicationThread(() -> {
Expand All @@ -339,22 +347,22 @@ public void recordUpdated(DayRecord day)
});
}

private boolean daySelected(DayRecord dayRecord)
private boolean daySelected(final DayRecord dayRecord)
{
final Optional<DayRecord> selectedDay = state.getSelectedDay();
return selectedDay.isPresent() && selectedDay.get().getDate().equals(dayRecord.getDate());
}

@Override
public void exceptionOccurred(Exception e)
public void exceptionOccurred(final Exception e)
{
final String message = "An error occured: " + e.getClass() + ": " + e.getMessage();
LOG.error(message, e);
actions.showErrorDialog(message);
}

@Override
public void workStoppedForToday(boolean stopWorking)
public void workStoppedForToday(final boolean stopWorking)
{
JavaFxUtil.runOnFxApplicationThread(() -> state.stoppedWorkingForToday.setValue(stopWorking));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
package org.itsallcode.whiterabbit.jfxui.feature;

import static java.util.stream.Collectors.toList;

import java.text.NumberFormat;
import java.text.ParsePosition;
import java.time.Duration;
import java.util.List;
import java.util.Locale;
import java.util.function.UnaryOperator;

import org.itsallcode.whiterabbit.logic.service.AppService;

import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.control.ButtonBar.ButtonData;
import javafx.scene.layout.*;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.DialogPane;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Spinner;
import javafx.scene.control.SplitMenuButton;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.util.converter.IntegerStringConverter;

public class InterruptionPresetFeature
Expand Down Expand Up @@ -50,15 +58,15 @@ private List<MenuItem> createPresetMenuItems()
.mapToLong(Integer::longValue)
.mapToObj(Duration::ofMinutes)
.map(this::createMenuitem)
.collect(toList());
.toList();
}

private MenuItem createMenuitem(final Duration interruption)
{
final String verb = interruption.isNegative() ? "Subtract" : "Add";
final MenuItem menuItem = new MenuItem(
verb + " interruption of " + appService.formatter().format(interruption.abs()));
menuItem.setId(verb.toLowerCase() + "-interruption-preset-" + interruption.toString());
menuItem.setId(verb.toLowerCase(Locale.ENGLISH) + "-interruption-preset-" + interruption.toString());
menuItem.setOnAction(event -> addInterruptionForToday(interruption));
return menuItem;
}
Expand All @@ -76,7 +84,6 @@ private static class DurationInputDialog extends Dialog<Duration>

private DurationInputDialog()
{
final DialogPane dialogPane = getDialogPane();
final int maxValue = (int) Duration.ofHours(8).toMinutes();

spinner = new Spinner<>(0, maxValue, 0, 5);
Expand Down Expand Up @@ -110,6 +117,7 @@ private DurationInputDialog()
GridPane.setHgrow(spinner, Priority.ALWAYS);
GridPane.setFillWidth(spinner, true);

final DialogPane dialogPane = getDialogPane();
label = createContentLabel(dialogPane.getContentText());
label.setPrefWidth(Region.USE_COMPUTED_SIZE);
label.textProperty().bind(dialogPane.contentTextProperty());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package org.itsallcode.whiterabbit.jfxui.table.activities;

import static java.util.stream.Collectors.toList;

import java.time.Duration;
import java.util.List;

Expand Down Expand Up @@ -59,6 +57,6 @@ static List<ActivityPropertyAdapter> wrap(final EditListener<DayRecord> editList
{
return activities.stream()
.map(a -> wrap(editListener, a))
.collect(toList());
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package org.itsallcode.whiterabbit.jfxui.table.days;

import static java.util.stream.Collectors.toList;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalTime;
Expand Down Expand Up @@ -52,9 +50,9 @@ public class DayRecordTable

private final ClockService clockService;

public DayRecordTable(SimpleObjectProperty<DayRecord> selectedDay,
ObjectProperty<MonthIndex> currentMonth, EditListener<DayRecord> editListener,
AppService appService)
public DayRecordTable(final SimpleObjectProperty<DayRecord> selectedDay,
final ObjectProperty<MonthIndex> currentMonth, final EditListener<DayRecord> editListener,
final AppService appService)
{
this.editListener = editListener;
this.formatterService = appService.formatter();
Expand All @@ -73,9 +71,9 @@ private void fillTableWith31EmptyRows()
}
}

private void currentMonthChanged(MonthIndex previousMonth, MonthIndex month)
private void currentMonthChanged(final MonthIndex previousMonth, final MonthIndex month)
{
final List<DayRecord> sortedDays = month.getSortedDays().collect(toList());
final List<DayRecord> sortedDays = month.getSortedDays().toList();
JavaFxUtil.runOnFxApplicationThread(() -> {
LOG.trace("Current month changed from {} to {}. Updating {} days.",
previousMonth != null ? previousMonth.getYearMonth() : null, month.getYearMonth(),
Expand Down Expand Up @@ -103,16 +101,13 @@ private void updateRows(final List<DayRecord> sortedDays)
}
}

private void updateSelectedRow(MonthIndex previousMonth, MonthIndex month)
private void updateSelectedRow(final MonthIndex previousMonth, final MonthIndex month)
{
final boolean isCurrentMonth = month.getYearMonth().equals(clockService.getCurrentYearMonth());
final boolean otherMonthSelected = previousMonth != null
&& !month.getYearMonth().equals(previousMonth.getYearMonth());
if (!otherMonthSelected)
if (!otherMonthSelected(previousMonth, month))
{
return;
}
if (isCurrentMonth)
if (isCurrentMonth(month))
{
selectRow(clockService.getCurrentDate());
}
Expand All @@ -122,6 +117,17 @@ private void updateSelectedRow(MonthIndex previousMonth, MonthIndex month)
}
}

private boolean otherMonthSelected(final MonthIndex previousMonth, final MonthIndex month)
{
return previousMonth != null
&& !month.getYearMonth().equals(previousMonth.getYearMonth());
}

private boolean isCurrentMonth(final MonthIndex month)
{
return month.getYearMonth().equals(clockService.getCurrentYearMonth());
}

@SuppressWarnings("java:S110") // Deep inheritance tree required by JavaFx
public TableView<DayRecordPropertyAdapter> initTable()
{
Expand All @@ -147,7 +153,7 @@ public TableView<DayRecordPropertyAdapter> initTable()
table.setRowFactory(param -> new TableRow<DayRecordPropertyAdapter>()
{
@Override
public void updateIndex(int newIndex)
public void updateIndex(final int newIndex)
{
if (newIndex != getIndex() && newIndex >= 0 && newIndex < dayRecords.size())
{
Expand All @@ -160,7 +166,7 @@ public void updateIndex(int newIndex)
}

@Override
protected void updateItem(DayRecordPropertyAdapter item, boolean empty)
protected void updateItem(final DayRecordPropertyAdapter item, final boolean empty)
{
super.updateItem(item, empty);
if (item != null)
Expand All @@ -172,7 +178,7 @@ protected void updateItem(DayRecordPropertyAdapter item, boolean empty)
return table;
}

public void selectRow(LocalDate date)
public void selectRow(final LocalDate date)
{
Objects.requireNonNull(table, "Table not yet initialized");
final int row = date.getDayOfMonth() - 1;
Expand Down
Loading