Skip to content

Commit b6ded44

Browse files
authored
Merge pull request #185 from doubleSlashde/feature/PTBAS-738_syncDialogAnpassungen
PTBAS-738: Adjust sync window
2 parents 2d0f68d + 661f71a commit b6ded44

File tree

9 files changed

+584
-104
lines changed

9 files changed

+584
-104
lines changed

src/main/java/de/doubleslash/keeptime/common/FileOpenHelper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public static boolean openFile(final String filePath) {
3232
final File file = new File(filePath);
3333
final Runtime rt = Runtime.getRuntime();
3434

35-
if (!file.exists() || file.isFile()) {
35+
if (!file.exists() || !file.isFile()) {
3636
LOG.warn("Filepath does not seem to exist or does not point to a file: '{}'.", filePath);
3737
return false;
3838
}

src/main/java/de/doubleslash/keeptime/controller/HeimatController.java

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ public List<Mapping> getTableRows(final LocalDate currentReportDate, final List<
110110
String heimatNotes = "";
111111
long heimatTimeSeconds = 0;
112112
boolean isMappedInHeimat = false;
113+
String bookingHint = "";
113114
final Optional<ExternalProjectMapping> optHeimatMapping = mappedProjects.stream()
114115
.filter(mp -> mp.getProject().getId()
115116
== project.getId())
@@ -118,6 +119,11 @@ public List<Mapping> getTableRows(final LocalDate currentReportDate, final List<
118119
Optional<Mapping> optionalExistingMapping = Optional.empty();
119120
if (optHeimatMapping.isPresent()) {
120121
isMappedInHeimat = true;
122+
bookingHint = heimatTasks.stream()
123+
.filter(ht -> ht.id() == optHeimatMapping.get().getExternalTaskId())
124+
.map(HeimatTask::bookingHint)
125+
.findAny()
126+
.orElseGet(String::new);
121127
optionalExistingMapping = list.stream()
122128
.filter(mapping -> mapping.heimatTaskId == optHeimatMapping.get()
123129
.getExternalTaskId())
@@ -145,16 +151,20 @@ public List<Mapping> getTableRows(final LocalDate currentReportDate, final List<
145151
pr.appendToWorkNotes(currentWorkNote);
146152
}
147153
final String keeptimeNotes = pr.getNotes();
148-
String canBeSyncedMessage;
154+
StyledMessage canBeSyncedMessage;
155+
149156
if (!isMappedInHeimat) {
150-
canBeSyncedMessage = "Not mapped to Heimat task.\nMap in settings dialog.";
157+
canBeSyncedMessage = StyledMessage.of(
158+
new StyledMessage.TextSegment("Not mapped to Heimat task.\nMap in settings dialog."));
151159
} else if (heimatTasks.stream().noneMatch(ht -> ht.id() == optHeimatMapping.get().getExternalTaskId())) {
152-
canBeSyncedMessage = "Heimat Task is not available (anymore).\nPlease check mappings in settings dialog.";
160+
canBeSyncedMessage = StyledMessage.of(new StyledMessage.TextSegment(
161+
"Heimat Task is not available (anymore).\nPlease check mappings in settings dialog."));
153162
isMappedInHeimat = false;
154163
} else {
155164
final ExternalProjectMapping externalProjectMapping = optHeimatMapping.get();
156-
canBeSyncedMessage = "Sync to " + externalProjectMapping.getExternalTaskName() + "\n("
157-
+ externalProjectMapping.getExternalProjectName() + ")";
165+
canBeSyncedMessage = StyledMessage.of(new StyledMessage.TextSegment("Sync to "),
166+
new StyledMessage.TextSegment(externalProjectMapping.getExternalTaskName(), true),
167+
new StyledMessage.TextSegment("\n(" + externalProjectMapping.getExternalProjectName() + ")"));
158168
}
159169

160170
if (optionalExistingMapping.isPresent()) {
@@ -166,18 +176,18 @@ public List<Mapping> getTableRows(final LocalDate currentReportDate, final List<
166176
final boolean shouldBeSynced =
167177
isMappedInHeimat && differenceGreaterOrEqual15Minutes(heimatSeconds, keepTimeSeconds);
168178
final Mapping mapping = new Mapping(isMappedInHeimat ? optHeimatMapping.get().getExternalTaskId() : -1,
169-
isMappedInHeimat, shouldBeSynced, canBeSyncedMessage, existingMapping.existingTimes(), projects,
170-
existingMapping.heimatNotes(), existingMapping.keeptimeNotes() + ". " + keeptimeNotes, heimatSeconds,
171-
keepTimeSeconds);
179+
isMappedInHeimat, shouldBeSynced, canBeSyncedMessage, bookingHint, existingMapping.existingTimes(),
180+
projects, existingMapping.heimatNotes(), existingMapping.keeptimeNotes() + ". " + keeptimeNotes,
181+
heimatSeconds, keepTimeSeconds);
172182
list.remove(existingMapping);
173183
list.add(mapping);
174184
} else {
175185
final boolean shouldBeSynced =
176186
isMappedInHeimat && differenceGreaterOrEqual15Minutes(heimatTimeSeconds, projectWorkSeconds);
177187
final List<Project> projects = Collections.singletonList(project);
178188
final Mapping mapping = new Mapping(isMappedInHeimat ? optHeimatMapping.get().getExternalTaskId() : -1,
179-
isMappedInHeimat, shouldBeSynced, canBeSyncedMessage, optionalAlreadyBookedTimes, projects,
180-
heimatNotes, keeptimeNotes, heimatTimeSeconds, projectWorkSeconds);
189+
isMappedInHeimat, shouldBeSynced, canBeSyncedMessage, bookingHint, optionalAlreadyBookedTimes,
190+
projects, heimatNotes, keeptimeNotes, heimatTimeSeconds, projectWorkSeconds);
181191
list.add(mapping);
182192
}
183193
}
@@ -193,15 +203,17 @@ public List<Mapping> getTableRows(final LocalDate currentReportDate, final List<
193203
long heimatTimeSeconds = times.stream()
194204
.reduce(0L, (subtotal, element) -> subtotal + element.durationInMinutes() * 60L,
195205
Long::sum);
196-
final Optional<HeimatTask> optionalHeimatTask = heimatTasks.stream()
197-
.filter(t -> t.id() == id)
198-
.findAny();
206+
207+
final Optional<HeimatTask> optionalHeimatTask = heimatTasks.stream().filter(t -> t.id() == id).findAny();
199208
String taskName = "Cannot resolve Heimat Task Id: " + id + " to name\nPlease check in Heimat";
200209
if (optionalHeimatTask.isPresent()) {
201210
final HeimatTask heimatTask = optionalHeimatTask.get();
202211
taskName = heimatTask.name() + "\n" + heimatTask.taskHolderName();
203212
}
204-
final Mapping mapping = new Mapping(id, true, false, "Not mapped in KeepTime\n\n" + taskName, times,
213+
214+
final Mapping mapping = new Mapping(id, true, false,
215+
StyledMessage.of(new StyledMessage.TextSegment("Not mapped in KeepTime\n\n" + taskName)), "", times,
216+
205217
new ArrayList<>(0), heimatNotes, "", heimatTimeSeconds, 0);
206218
list.add(mapping);
207219
});
@@ -224,14 +236,17 @@ public List<Mapping> getTableRows(final LocalDate currentReportDate, final List<
224236
String heimatNotes = addHeimatNotes(times);
225237
long heimatTimeSeconds = addHeimatTimes(times);
226238

227-
final Mapping mapping2 = new Mapping(id, true, false,
228-
"Present in HEIMAT but not KeepTime\n\nSync to " + externalProjectMapping.getExternalTaskName() + "\n("
229-
+ externalProjectMapping.getExternalProjectName() + ")", times, mappedProjects.stream()
230-
.filter(
231-
mp -> mp.getExternalTaskId()
232-
== id)
233-
.map(ExternalProjectMapping::getProject)
234-
.toList(),
239+
StyledMessage syncMessage = StyledMessage.of(
240+
new StyledMessage.TextSegment("Present in HEIMAT but not KeepTime\n\nSync to "),
241+
new StyledMessage.TextSegment(externalProjectMapping.getExternalTaskName(), true),
242+
new StyledMessage.TextSegment("\n(" + externalProjectMapping.getExternalProjectName() + ")"));
243+
244+
final Mapping mapping2 = new Mapping(id, true, false, syncMessage, "", times, mappedProjects.stream()
245+
.filter(
246+
mp -> mp.getExternalTaskId()
247+
== id)
248+
.map(ExternalProjectMapping::getProject)
249+
.toList(),
235250
heimatNotes, "", heimatTimeSeconds, 0);
236251
list.add(mapping2);
237252
});
@@ -424,8 +439,8 @@ public ExistingAndInvalidMappings getExistingProjectMappings(List<HeimatTask> ex
424439

425440
public record UserMapping(Mapping mapping, boolean shouldSync, String userNotes, int userMinutes) {}
426441

427-
public record Mapping(long heimatTaskId, boolean canBeSynced, boolean shouldBeSynced, String syncMessage,
428-
List<HeimatTime> existingTimes, List<Project> projects, String heimatNotes,
442+
public record Mapping(long heimatTaskId, boolean canBeSynced, boolean shouldBeSynced, StyledMessage syncMessage,
443+
String bookingHint, List<HeimatTime> existingTimes, List<Project> projects, String heimatNotes,
429444
String keeptimeNotes, long heimatSeconds, long keeptimeSeconds) {}
430445

431446
public record HeimatErrors(UserMapping mapping, String errorMessage) {}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright 2025 doubleSlash Net Business GmbH
2+
//
3+
// This file is part of KeepTime.
4+
// KeepTime is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package de.doubleslash.keeptime.model;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
/**
23+
* Represents a styled text message composed of multiple text segments. This class provides a UI-agnostic way to
24+
* represent formatted text, allowing separation of business logic from UI components.
25+
*/
26+
public class StyledMessage {
27+
28+
/**
29+
* Represents a single text segment with optional styling.
30+
*
31+
* @param text
32+
* The text content
33+
* @param bold
34+
* Whether the text should be displayed in bold
35+
*/
36+
public record TextSegment(String text, boolean bold) {
37+
public TextSegment(String text) {
38+
this(text, false);
39+
}
40+
}
41+
42+
private final List<TextSegment> segments;
43+
44+
public StyledMessage(List<TextSegment> segments) {
45+
this.segments = new ArrayList<>(segments);
46+
}
47+
48+
/**
49+
* Creates a StyledMessage from a variable number of text segments.
50+
*
51+
* @param segments
52+
* The text segments to include in the message
53+
* @return A new StyledMessage containing the provided segments
54+
*/
55+
public static StyledMessage of(TextSegment... segments) {
56+
return new StyledMessage(List.of(segments));
57+
}
58+
59+
public List<TextSegment> getSegments() {
60+
return new ArrayList<>(segments);
61+
}
62+
63+
/**
64+
* Returns the message as plain text without styling.
65+
*/
66+
public String toPlainText() {
67+
return segments.stream().map(TextSegment::text).reduce("", String::concat);
68+
}
69+
}
70+

0 commit comments

Comments
 (0)