diff --git a/android/app/src/main/java/app/organicmaps/widget/placepage/OpenStateTextFormatter.java b/android/app/src/main/java/app/organicmaps/widget/placepage/OpenStateTextFormatter.java new file mode 100644 index 000000000..0078902d7 --- /dev/null +++ b/android/app/src/main/java/app/organicmaps/widget/placepage/OpenStateTextFormatter.java @@ -0,0 +1,49 @@ +package app.organicmaps.widget.placepage; + +import java.time.ZonedDateTime; +import java.time.format.TextStyle; +import java.util.Locale; + +public class OpenStateTextFormatter +{ + private OpenStateTextFormatter() {} + + static String formatHoursMinutes(int hour, int minute, boolean use24h) + { + if (use24h) + return String.format(Locale.ROOT, "%02d:%02d", hour, minute); + + int h = hour % 12; + if (h == 0) h = 12; + String ampm = (hour < 12) ? "AM" : "PM"; + return String.format(Locale.ROOT, "%d:%02d %s", h, minute, ampm); + } + + static boolean isSameLocalDate(ZonedDateTime a, ZonedDateTime b) + { + return a.toLocalDate().isEqual(b.toLocalDate()); + } + + static String dayShort(ZonedDateTime t, Locale locale) + { + return t.getDayOfWeek().getDisplayName(TextStyle.SHORT, locale); + } + + static String buildAtLabel( + boolean opens, + boolean isToday, + String dayShort, + String time, + String opensAtLocalized, + String closesAtLocalized, + String opensDayAtLocalized, + String closesDayAtLocalized + ) + { + if (isToday) + return opens ? String.format(Locale.ROOT, opensAtLocalized, time) // Opens at %s + : String.format(Locale.ROOT, closesAtLocalized, time); // Closes at %s + return opens ? String.format(Locale.ROOT, opensDayAtLocalized, dayShort, time) // Opens %s at %s + : String.format(Locale.ROOT, closesDayAtLocalized, dayShort, time); // Closes %s at %s + } +} diff --git a/android/app/src/test/java/app/organicmaps/widget/placepage/OpenStateTextFormatterTest.java b/android/app/src/test/java/app/organicmaps/widget/placepage/OpenStateTextFormatterTest.java new file mode 100644 index 000000000..621f1bee1 --- /dev/null +++ b/android/app/src/test/java/app/organicmaps/widget/placepage/OpenStateTextFormatterTest.java @@ -0,0 +1,72 @@ +package app.organicmaps.widget.placepage; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Locale; + +public class OpenStateTextFormatterTest +{ + private static final String OPENS_AT = "Opens at %s"; + private static final String CLOSES_AT = "Closes at %s"; + private static final String OPENS_DAY_AT = "Opens %1$s at %2$s"; + private static final String CLOSES_DAY_AT = "Closes %1$s at %2$s"; + + @Test + public void formatHoursMinutes_24h() + { + assertEquals("09:00", OpenStateTextFormatter.formatHoursMinutes(9, 0, true)); + assertEquals("18:05", OpenStateTextFormatter.formatHoursMinutes(18, 5, true)); + } + + @Test + public void formatHoursMinutes_12h() + { + assertEquals("9:00 AM", OpenStateTextFormatter.formatHoursMinutes(9, 0, false)); + assertEquals("6:05 PM", OpenStateTextFormatter.formatHoursMinutes(18, 5, false)); + assertEquals("12:00 PM", OpenStateTextFormatter.formatHoursMinutes(12, 0, false)); + assertEquals("12:00 AM", OpenStateTextFormatter.formatHoursMinutes(0, 0, false)); + } + + @Test + public void buildAtLabel_today_open_close() + { + String open = OpenStateTextFormatter.buildAtLabel(true, true, "Sat", "09:00", + OPENS_AT, CLOSES_AT, OPENS_DAY_AT, CLOSES_DAY_AT); + String close = OpenStateTextFormatter.buildAtLabel(false, true, "Sat", "18:00", + OPENS_AT, CLOSES_AT, OPENS_DAY_AT, CLOSES_DAY_AT); + assertEquals("Opens at 09:00", open); + assertEquals("Closes at 18:00", close); + } + + @Test + public void buildAtLabel_other_day() + { + String open = OpenStateTextFormatter.buildAtLabel(true, false, "Sat", "09:00", + OPENS_AT, CLOSES_AT, OPENS_DAY_AT, CLOSES_DAY_AT); + String close = OpenStateTextFormatter.buildAtLabel(false, false, "Tue", "18:00", + OPENS_AT, CLOSES_AT, OPENS_DAY_AT, CLOSES_DAY_AT); + assertEquals("Opens Sat at 09:00", open); + assertEquals("Closes Tue at 18:00", close); + } + + @Test + public void isSameLocalDate_and_dayShort_helpers() + { + ZonedDateTime a = ZonedDateTime.of(2025, 3, 1, 10, 0, 0, 0, ZoneId.of("Europe/Paris")); + ZonedDateTime b = ZonedDateTime.of(2025, 3, 1, 22, 0, 0, 0, ZoneId.of("Europe/Paris")); + ZonedDateTime c = a.plusDays(1); + + assertTrue(OpenStateTextFormatter.isSameLocalDate(a, b)); + assertFalse(OpenStateTextFormatter.isSameLocalDate(a, c)); + + String day = OpenStateTextFormatter.dayShort(c, Locale.US); + // March 2, 2025 is a Sunday; "Sun" in US locale + assertEquals("Sun", day); + } +}