Improves some TimeFormatter code
All checks were successful
EpicKnarvik97/KnarLib/pipeline/head This commit looks good

Adds more comments to make things easier to understand for returning developers
Extracts some functionality to improve cleanliness
Makes sure UNIT_NOW not being registered throws an exception
Makes sure to initialize units before any checks to improve consistency
Reduces the number of indentations where possible
This commit is contained in:
Kristian Knarvik 2023-03-06 20:07:02 +01:00
parent 2618d42992
commit 88ea42783a

View File

@ -29,21 +29,32 @@ public final class TimeFormatter {
* @return <p>The string used for displaying this sign's duration</p> * @return <p>The string used for displaying this sign's duration</p>
*/ */
public static String getDurationString(Translator translator, long duration) { public static String getDurationString(Translator translator, long duration) {
//Initialize time units once, and only if this method is actually used
if (sortedUnits == null) {
initializeUnits(translator);
}
//This case is handled separately to avoid a divide by 0 exception
if (duration == 0) { if (duration == 0) {
return translator.getTranslatedMessage(TranslatableTimeUnit.UNIT_NOW); return translator.getTranslatedMessage(TranslatableTimeUnit.UNIT_NOW);
} else {
if (sortedUnits == null) {
initializeUnits(translator);
}
for (double unit : sortedUnits) {
if (duration / unit >= 1) {
double units = round(duration / unit);
return formatDurationString(units, translator, timeUnits.get(unit)[units == 1 ? 0 : 1],
(units * 10) % 10 == 0);
}
}
return formatDurationString(duration, translator, TranslatableTimeUnit.UNIT_SECONDS, false);
} }
//Loop through all units to find the largest unit less than the remaining duration
for (double unit : sortedUnits) {
if (duration / unit < 1) {
continue;
}
//Round the remaining units of time to two digits
double units = round(duration / unit);
//Cast to int if the number has no decimals
boolean castToInt = (units * 10) % 10 == 0;
//Select the singular form if the unit is 1, and the plural otherwise
TranslatableMessage translatableUnit = timeUnits.get(unit)[units == 1 ? 0 : 1];
return formatDurationString(units, translator, translatableUnit, castToInt);
}
//It can be assumed this case only happens between 0 and 1 seconds, thus plural is used
return formatDurationString(duration, translator, TranslatableTimeUnit.UNIT_SECONDS, false);
} }
/** /**
@ -66,7 +77,7 @@ public final class TimeFormatter {
* @return <p>The formatted duration string</p> * @return <p>The formatted duration string</p>
*/ */
private static String formatDurationString(double duration, Translator translator, private static String formatDurationString(double duration, Translator translator,
TranslatableTimeUnit translatableMessage, boolean castToInt) { TranslatableMessage translatableMessage, boolean castToInt) {
String durationFormat = translator.getTranslatedMessage(TranslatableTimeUnit.DURATION_FORMAT); String durationFormat = translator.getTranslatedMessage(TranslatableTimeUnit.DURATION_FORMAT);
durationFormat = replacePlaceholder(durationFormat, "{unit}", durationFormat = replacePlaceholder(durationFormat, "{unit}",
translator.getTranslatedMessage(translatableMessage)); translator.getTranslatedMessage(translatableMessage));
@ -78,45 +89,43 @@ public final class TimeFormatter {
* Initializes the mapping of available time units for formatting permission sign duration * Initializes the mapping of available time units for formatting permission sign duration
*/ */
private static void initializeUnits(Translator translator) { private static void initializeUnits(Translator translator) {
double minute = 60; //Register each time unit with a registered singular and plural translation
double hour = 60 * minute;
double day = 24 * hour;
double week = 7 * day;
double month = 4 * week;
double year = 365 * day;
double decade = 10 * year;
timeUnits = new HashMap<>(); timeUnits = new HashMap<>();
registerTimeUnit(translator, decade, TranslatableTimeUnit.UNIT_DECADE, TranslatableTimeUnit.UNIT_DECADES); registerTimeUnit(translator, 315360000, TranslatableTimeUnit.UNIT_DECADE, TranslatableTimeUnit.UNIT_DECADES);
registerTimeUnit(translator, year, TranslatableTimeUnit.UNIT_YEAR, TranslatableTimeUnit.UNIT_YEARS); registerTimeUnit(translator, 31536000, TranslatableTimeUnit.UNIT_YEAR, TranslatableTimeUnit.UNIT_YEARS);
registerTimeUnit(translator, month, TranslatableTimeUnit.UNIT_MONTH, TranslatableTimeUnit.UNIT_MONTHS); registerTimeUnit(translator, 2419200, TranslatableTimeUnit.UNIT_MONTH, TranslatableTimeUnit.UNIT_MONTHS);
registerTimeUnit(translator, week, TranslatableTimeUnit.UNIT_WEEK, TranslatableTimeUnit.UNIT_WEEKS); registerTimeUnit(translator, 604800, TranslatableTimeUnit.UNIT_WEEK, TranslatableTimeUnit.UNIT_WEEKS);
registerTimeUnit(translator, day, TranslatableTimeUnit.UNIT_DAY, TranslatableTimeUnit.UNIT_DAYS); registerTimeUnit(translator, 86400, TranslatableTimeUnit.UNIT_DAY, TranslatableTimeUnit.UNIT_DAYS);
registerTimeUnit(translator, hour, TranslatableTimeUnit.UNIT_HOUR, TranslatableTimeUnit.UNIT_HOURS); registerTimeUnit(translator, 3600, TranslatableTimeUnit.UNIT_HOUR, TranslatableTimeUnit.UNIT_HOURS);
registerTimeUnit(translator, minute, TranslatableTimeUnit.UNIT_MINUTE, TranslatableTimeUnit.UNIT_MINUTES); registerTimeUnit(translator, 60, TranslatableTimeUnit.UNIT_MINUTE, TranslatableTimeUnit.UNIT_MINUTES);
if (!registerTimeUnit(translator, 1D, TranslatableTimeUnit.UNIT_SECOND, TranslatableTimeUnit.UNIT_SECONDS)) { boolean registeredSeconds = registerTimeUnit(translator, 1, TranslatableTimeUnit.UNIT_SECOND,
throw new IllegalStateException("No translation has been registered for UNIT_SECOND and UNIT_SECONDS"); TranslatableTimeUnit.UNIT_SECONDS);
//As now and seconds are the base units, those must be registered to use getDurationString
if (!registeredSeconds || !hasTranslation(translator, TranslatableTimeUnit.UNIT_NOW)) {
throw new IllegalStateException("A translation is missing for UNIT_SECOND, UNIT_SECONDS or UNIT_NOW");
} }
//Make a sorted list from each unit's number of seconds
sortedUnits = new ArrayList<>(timeUnits.keySet()); sortedUnits = new ArrayList<>(timeUnits.keySet());
Collections.sort(sortedUnits); Collections.sort(sortedUnits);
Collections.reverse(sortedUnits); Collections.reverse(sortedUnits);
} }
/** /**
* Registers one time unit * Registers one time unit if its translations have been registered
* *
* @param translator <p>The translator to use for checking whether necessary translations have been set</p> * @param translator <p>The translator to use for checking whether necessary translations have been set</p>
* @param seconds <p>The amount of seconds the time unit corresponds to</p> * @param seconds <p>The amount of seconds the time unit corresponds to</p>
* @param singular <p>The translatable time unit to use for the singular form</p> * @param singular <p>The translatable time unit to use for the singular form</p>
* @param plural <p>The translatable time unit to use for the plural form</p> * @param plural <p>The translatable time unit to use for the plural form</p>
* @return <p>True if the time unit was registered. False if a translation is missing</p>
*/ */
private static boolean registerTimeUnit(Translator translator, double seconds, TranslatableTimeUnit singular, private static boolean registerTimeUnit(Translator translator, double seconds, TranslatableTimeUnit singular,
TranslatableTimeUnit plural) { TranslatableTimeUnit plural) {
String singularTranslation = translator.getTranslatedMessage(singular); String singularTranslation = translator.getTranslatedMessage(singular);
String pluralTranslation = translator.getTranslatedMessage(plural); String pluralTranslation = translator.getTranslatedMessage(plural);
if (singularTranslation != null && !singularTranslation.isBlank() && pluralTranslation != null && if (hasTranslation(translator, singular) && hasTranslation(translator, plural)) {
!pluralTranslation.isBlank()) {
timeUnits.put(seconds, new TranslatableTimeUnit[]{singular, plural}); timeUnits.put(seconds, new TranslatableTimeUnit[]{singular, plural});
return true; return true;
} else { } else {
@ -124,4 +133,16 @@ public final class TimeFormatter {
} }
} }
/**
* Checks whether the given translatable message has a registered translation
*
* @param translator <p>The translator to check</p>
* @param translatableMessage <p>The translatable message to check</p>
* @return <p>True if a non-empty translation has been registered</p>
*/
private static boolean hasTranslation(Translator translator, TranslatableMessage translatableMessage) {
String translation = translator.getTranslatedMessage(translatableMessage);
return translation != null && !translation.isBlank();
}
} }