Skip to content

Commit 3f10662

Browse files
authored
Merge pull request #273 from Just1Developer/feature/ui-f/preset-temporary-visibility
Feature/preset temporary visibility
2 parents c13b73c + c799d40 commit 3f10662

6 files changed

Lines changed: 204 additions & 7 deletions

File tree

src/main/java/ui/Date.java

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/* Licensed under MIT 2026. */
2+
package ui;
3+
4+
import lombok.NonNull;
5+
6+
import java.time.LocalDateTime;
7+
import java.util.regex.Matcher;
8+
import java.util.regex.Pattern;
9+
10+
/**
11+
* A date represents any day by its year, month of the year (1-12) and day (1-31
12+
* usually). Dates are immutable and compared by values, Dates have multiple
13+
* methods for earlier/later comparison.
14+
*
15+
* @param year The year.
16+
* @param month The month (1-12).
17+
* @param day The day of the month (1-31).
18+
*/
19+
public record Date(int year, int month, int day) {
20+
21+
private static final Pattern DATE_PATTERN = Pattern.compile("^(\\d{1,7})-(\\d{1,2})-(\\d{1,2})$");
22+
23+
public static final Date ZERO_DATE = new Date(0, 0, 0);
24+
25+
@Override
26+
@NonNull
27+
public String toString() {
28+
return "%04d-%02d-%02d".formatted(year, month, day);
29+
}
30+
31+
/**
32+
* If the Date is zero, so all fields are zero, and thus equal to the constant
33+
* {@link Date#ZERO_DATE}.
34+
*
35+
* @return True if the Date is the same as ZERO_DATE, false if not.
36+
*/
37+
public boolean isZero() {
38+
return this.equals(ZERO_DATE);
39+
}
40+
41+
/**
42+
* Returns if this Date is earlier than another given Date. If the two Dates are
43+
* equal, returns false.
44+
* <p>
45+
* If the given Date is null, returns false.
46+
* </p>
47+
*
48+
* @return True if the other Date is earlier, false if not.
49+
*/
50+
public boolean isEarlierThan(Date other) {
51+
if (other == null)
52+
return false;
53+
if (other.year() > this.year())
54+
return true;
55+
if (other.year() < this.year())
56+
return false;
57+
if (other.month() > this.month())
58+
return true;
59+
if (other.month() < this.month())
60+
return false;
61+
return other.day() > this.day();
62+
}
63+
64+
/**
65+
* Returns if this Date is earlier than or equal to another given Date. If the
66+
* two Dates are equal, returns true.
67+
* <p>
68+
* If the given Date is null, returns false.
69+
* </p>
70+
*
71+
* @return True if the other Date is earlier or equal, false if not.
72+
*/
73+
public boolean isEarlierThanOrEqual(Date other) {
74+
if (other == null)
75+
return false;
76+
if (this.equals(other))
77+
return true;
78+
return isEarlierThan(other);
79+
}
80+
81+
/**
82+
* Returns if this Date is later than another given Date. If the two Dates are
83+
* equal, returns false.
84+
* <p>
85+
* If the given Date is null, returns false.
86+
* </p>
87+
*
88+
* @return True if the other Date is later, false if not.
89+
*/
90+
public boolean isLaterThan(Date other) {
91+
if (other == null || this.equals(other))
92+
return false;
93+
return !isEarlierThan(other);
94+
}
95+
96+
/**
97+
* Returns if this Date is later than or equal to another given Date. If the two
98+
* Dates are equal, returns true.
99+
* <p>
100+
* If the given Date is null, returns false.
101+
* </p>
102+
*
103+
* @return True if the other Date is later or equal, false if not.
104+
*/
105+
public boolean isLaterThanOrEqual(Date other) {
106+
if (other == null)
107+
return false;
108+
if (this.equals(other))
109+
return true;
110+
return !isEarlierThan(other);
111+
}
112+
113+
/**
114+
* Parses a Date from the format YYYY-MM-DD. This format is required but allows
115+
* some variance in the length of numbers. <br/>
116+
* Restrictions for year, month and day:
117+
* <ul>
118+
* <li>Year: A number consisting of 1-7 digits.</li>
119+
* <li>Month: A number consisting of 1-2 digits.</li>
120+
* <li>Day: A number consisting of 1-2 digits.</li>
121+
* </ul>
122+
*
123+
* <p>
124+
* If not Date can be parsed, returns the ZERO_DATE, so the default Date where
125+
* all fields are 0.
126+
* </p>
127+
*
128+
* @param date The date, format YYYY-MM-DD.
129+
* @return The parsed date.
130+
*/
131+
public static Date parseDate(String date) {
132+
Matcher matcher = DATE_PATTERN.matcher(date);
133+
if (!matcher.matches())
134+
return ZERO_DATE;
135+
int year = Integer.parseInt(matcher.group(1));
136+
int month = Integer.parseInt(matcher.group(2));
137+
int day = Integer.parseInt(matcher.group(3));
138+
return new Date(year, month, day);
139+
}
140+
141+
/**
142+
* Gets the current local Date set on this computer.
143+
*
144+
* @return The current local date.
145+
*/
146+
public static Date currentLocalDate() {
147+
LocalDateTime localDateTime = LocalDateTime.now();
148+
return new Date(localDateTime.getYear(), localDateTime.getMonthValue(), localDateTime.getDayOfMonth());
149+
}
150+
}

src/main/java/ui/GlobalSettingsDialog.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Licensed under MIT 2024-2025. */
1+
/* Licensed under MIT 2024-2026. */
22
package ui;
33

44
import mail.MailInformation;
@@ -303,7 +303,7 @@ private static JComboBox<Preset> makePresetSelector() {
303303
JComboBox<Preset> presetSelector = new JComboBox<>();
304304
presetSelector.addItem(Preset.NO_PRESET);
305305
JSONHandler.getPresets().getPresets().forEach(preset -> {
306-
if (preset.isVisible())
306+
if (preset.shouldBeVisible())
307307
presetSelector.addItem(preset);
308308
});
309309
// Now, figure out which preset it selected by field values

src/main/java/ui/MonthlySettingsBar.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Licensed under MIT 2024-2025. */
1+
/* Licensed under MIT 2024-2026. */
22
package ui;
33

44
import ui.json.JSONHandler;
@@ -188,7 +188,8 @@ public void reset() {
188188

189189
public void importMonthSettings(Month month) {
190190
String yearString = String.valueOf(month.getYear());
191-
semesterTextField.setText(yearString.substring(yearString.length() - 2));
191+
int yearShort = Integer.parseInt(yearString.substring(yearString.length() - 2));
192+
semesterTextField.setText("" + (month.getMonth() <= 3 ? yearShort - 1 : yearShort));
192193
monthSelector.setSelectedIndex(month.getMonth() - 1);
193194
if (month.getMonth() >= 4 && month.getMonth() <= 9) {
194195
semesterSelector.setSelectedIndex(0);

src/main/java/ui/json/JSONHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Licensed under MIT 2024-2025. */
1+
/* Licensed under MIT 2024-2026. */
22
package ui.json;
33

44
import com.fasterxml.jackson.databind.DeserializationFeature;
@@ -388,6 +388,7 @@ private static PresetCollection loadPresetCollection() {
388388
PresetCollection mergedCollection;
389389
if (fromFile.isPresent() || fromAPI.isPresent()) {
390390
mergedCollection = PresetCollection.merge(fromFile, fromAPI);
391+
mergedCollection.parseAllDates();
391392
} else {
392393
return new PresetCollection();
393394
}

src/main/java/ui/json/api/Preset.java

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
/* Licensed under MIT 2025. */
1+
/* Licensed under MIT 2025-2026. */
22
package ui.json.api;
33

4+
import com.fasterxml.jackson.annotation.JsonIgnore;
45
import com.fasterxml.jackson.annotation.JsonProperty;
56
import lombok.Getter;
7+
import ui.Date;
68

79
import java.util.List;
810

@@ -16,6 +18,10 @@ public class Preset {
1618
private String displayName;
1719
@JsonProperty("visible")
1820
private boolean isVisible = true;
21+
@JsonProperty("visibleFrom")
22+
private String visibleFrom = "";
23+
@JsonProperty("visibleUntil")
24+
private String visibleUntil = "";
1925
@JsonProperty("description")
2026
private String description = "";
2127
@JsonProperty("fileFormat")
@@ -29,6 +35,11 @@ public class Preset {
2935
@JsonProperty("mailRecipientCC")
3036
private List<String> mailRecipientsCC = List.of();
3137

38+
@JsonIgnore
39+
private Date visibleFromDate;
40+
@JsonIgnore
41+
private Date visibleUntilDate;
42+
3243
@Override
3344
public String toString() {
3445
return displayName;
@@ -49,4 +60,31 @@ private Preset(String presetId, String displayName, boolean isVisible, String fi
4960
this.mailRecipient = mailRecipient;
5061
this.mailRecipientsCC = List.of();
5162
}
63+
64+
/**
65+
* Returns if the Preset should be visible. This is a combination of if the
66+
* isVisible field is true, and if the current Date is within visibleFrom and
67+
* visibleUntil, or if the non-matching Date values are Zero (non-existent).
68+
*
69+
* @return True if the Preset should be visible, taking isVisible and from/until
70+
* into consideration.
71+
*/
72+
public boolean shouldBeVisible() {
73+
if (!isVisible())
74+
return false;
75+
Date currentDate = Date.currentLocalDate();
76+
if (!visibleFromDate.isZero() && currentDate.isEarlierThan(visibleFromDate)) {
77+
return false;
78+
}
79+
return visibleUntilDate.isZero() || !currentDate.isLaterThan(visibleUntilDate);
80+
}
81+
82+
/**
83+
* Parses the stored Dates in the presets. Executed manually after fields have
84+
* been filled.
85+
*/
86+
public void parseDates() {
87+
visibleFromDate = Date.parseDate(visibleFrom);
88+
visibleUntilDate = Date.parseDate(visibleUntil);
89+
}
5290
}

src/main/java/ui/json/api/PresetCollection.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Licensed under MIT 2025. */
1+
/* Licensed under MIT 2025-2026. */
22
package ui.json.api;
33

44
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -51,6 +51,13 @@ public List<Preset> getPresets() {
5151
return new ArrayList<>(presets);
5252
}
5353

54+
/**
55+
* Parses all loaded Dates in all presets of this collection.
56+
*/
57+
public void parseAllDates() {
58+
presets.forEach(Preset::parseDates);
59+
}
60+
5461
/**
5562
* Merges two {@link PresetCollection}, intended for merging the local
5663
* collection with the online collection. Presets are uniquely identified by

0 commit comments

Comments
 (0)