Skip to content

Commit add660f

Browse files
authored
Merge pull request #28 from Death111/feature/#10_showDueTasksInBar
Feature/#10 show due tasks in bar
2 parents 76994d6 + baa3f8e commit add660f

File tree

2 files changed

+125
-3
lines changed

2 files changed

+125
-3
lines changed

src/main/java/de/doubleslash/keeptask/App.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import de.doubleslash.keeptask.common.Resources.RESOURCE;
2525
import de.doubleslash.keeptask.controller.Controller;
2626
import de.doubleslash.keeptask.model.Model;
27+
import de.doubleslash.keeptask.view.IconController;
2728
import de.doubleslash.keeptask.view.MainWindowController;
2829
import java.io.IOException;
2930
import java.io.PrintWriter;
@@ -60,6 +61,7 @@ public class App extends Application {
6061
private Controller controller;
6162

6263
private MainWindowController viewController;
64+
private IconController iconController;
6365

6466
@Override
6567
public void init() throws Exception {
@@ -90,7 +92,7 @@ public void start(final Stage primaryStage) {
9092
LOG.info("UI successfully initialised.");
9193
} catch (final Exception e) {
9294
LOG.error("There was an error while initialising the UI", e);
93-
showExceptionAndExit(e);
95+
showExceptionAndExit(e, primaryStage);
9496
}
9597
}
9698

@@ -101,13 +103,17 @@ private void initialiseApplication(final Stage primaryStage) throws Exception {
101103
controller.init();
102104

103105
initialiseAndShowUI(primaryStage);
106+
iconController = new IconController(model, controller, primaryStage);
107+
iconController.initialize();
104108
}
105109

106110
private void initialiseAndShowUI(final Stage primaryStage) throws IOException {
107111
LOG.debug("Initialising main UI.");
108112
primaryStage.setTitle("KeepTask");
109113
primaryStage.initStyle(StageStyle.TRANSPARENT);
110-
primaryStage.getIcons().add(new Image(Resources.getResource(RESOURCE.ICON_MAIN).toString()));
114+
Image applicationIcon = new Image(Resources.getResource(RESOURCE.ICON_MAIN).toString());
115+
primaryStage.getIcons().setAll(applicationIcon);
116+
111117
primaryStage.setAlwaysOnTop(true);
112118
primaryStage.setResizable(false);
113119
primaryStage.setOnCloseRequest(windowEvent -> LOG.info("On close request"));
@@ -124,7 +130,7 @@ private void initialiseAndShowUI(final Stage primaryStage) throws IOException {
124130
primaryStage.show();
125131
}
126132

127-
private static void showExceptionAndExit(Exception e) {
133+
private static void showExceptionAndExit(Exception e, Stage primaryStage) {
128134
final Alert alert = new Alert(AlertType.ERROR);
129135
alert.setTitle("Error");
130136
alert.setHeaderText("Could not start application");
@@ -150,6 +156,7 @@ private static void showExceptionAndExit(Exception e) {
150156

151157
alert.getDialogPane().setExpandableContent(expContent);
152158

159+
alert.initOwner(primaryStage);
153160
alert.showAndWait();
154161
System.exit(1);
155162
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright 2023 - Death111
3+
*
4+
* This file is part of KeepTask.
5+
* KeepTask is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
package de.doubleslash.keeptask.view;
20+
21+
import de.doubleslash.keeptask.common.Resources;
22+
import de.doubleslash.keeptask.common.Resources.RESOURCE;
23+
import de.doubleslash.keeptask.controller.Controller;
24+
import de.doubleslash.keeptask.model.Model;
25+
import de.doubleslash.keeptask.model.WorkItem;
26+
import java.awt.image.BufferedImage;
27+
import java.time.LocalDateTime;
28+
import javafx.collections.ListChangeListener;
29+
import javafx.embed.swing.SwingFXUtils;
30+
import javafx.scene.SnapshotParameters;
31+
import javafx.scene.canvas.Canvas;
32+
import javafx.scene.canvas.GraphicsContext;
33+
import javafx.scene.image.Image;
34+
import javafx.scene.image.WritableImage;
35+
import javafx.scene.paint.Color;
36+
import javafx.scene.text.Font;
37+
import javafx.scene.text.TextAlignment;
38+
import javafx.stage.Stage;
39+
40+
public class IconController {
41+
42+
private final Model model;
43+
private final Controller controller;
44+
private final Stage primaryStage;
45+
46+
private final Image applicationIcon = new Image(
47+
Resources.getResource(RESOURCE.ICON_MAIN).toString());
48+
49+
private final Canvas taskbarCanvas = new Canvas(64, 64);
50+
51+
public IconController(Model model, Controller controller, Stage primaryStage) {
52+
this.model = model;
53+
this.controller = controller;
54+
this.primaryStage = primaryStage;
55+
}
56+
57+
public void initialize() {
58+
model.getWorkItems().addListener((ListChangeListener<? super WorkItem>) change -> {
59+
updateProjectFilterButtons();
60+
});
61+
updateProjectFilterButtons();
62+
}
63+
64+
private void updateProjectFilterButtons() {
65+
LocalDateTime now = LocalDateTime.now();
66+
int expiredTasks = (int) model.getWorkItems().stream().filter(item -> {
67+
LocalDateTime dueDateTime = item.getDueDateTime();
68+
if (dueDateTime == null) {
69+
return false;
70+
}
71+
return !item.isFinished() && now.isAfter(dueDateTime);
72+
}).count();
73+
74+
updateTaskbarIcon(expiredTasks, primaryStage);
75+
}
76+
77+
private void updateTaskbarIcon(int expiredTasks, Stage primaryStage) {
78+
final GraphicsContext gcIcon = taskbarCanvas.getGraphicsContext2D();
79+
80+
gcIcon.clearRect(0, 0, taskbarCanvas.getWidth(), taskbarCanvas.getHeight());
81+
gcIcon.drawImage(applicationIcon, 0, 0, 64, 64);
82+
83+
if (expiredTasks > 0) {
84+
drawExpiredTasksToGC(expiredTasks, gcIcon);
85+
}
86+
87+
final Image icon = canvasToImage();
88+
89+
primaryStage.getIcons().setAll(icon);
90+
}
91+
92+
private static void drawExpiredTasksToGC(int expiredTasks, GraphicsContext gcIcon) {
93+
gcIcon.setFill(Color.RED);
94+
gcIcon.fillOval(32, 32, 32, 32);
95+
96+
gcIcon.setStroke(Color.WHITE);
97+
gcIcon.setTextAlign(TextAlignment.CENTER);
98+
Font aDefault = Font.getDefault();
99+
gcIcon.setFont(new Font(aDefault.getName(), 30));
100+
gcIcon.setStroke(Color.WHITE);
101+
gcIcon.setLineWidth(2);
102+
103+
gcIcon.strokeText(Integer.toString(expiredTasks), 47, 57);
104+
}
105+
106+
private Image canvasToImage() {
107+
final SnapshotParameters snapshotParameters = new SnapshotParameters();
108+
snapshotParameters.setFill(Color.TRANSPARENT);
109+
final WritableImage image = taskbarCanvas.snapshot(snapshotParameters, null);
110+
111+
final BufferedImage bi = SwingFXUtils.fromFXImage(image, null);
112+
final Image icon = SwingFXUtils.toFXImage(bi, null);
113+
return icon;
114+
}
115+
}

0 commit comments

Comments
 (0)