Draw core-time from floret-kit via submodule + composite build
Some checks failed
CI / ci (push) Failing after 2m12s
Some checks failed
CI / ci (push) Failing after 2m12s
Phase 0 of the shared-kit plan: floret-kit is embedded as a git submodule and
wired in with Gradle includeBuild("floret-kit"), so the app depends on
de.jeanlucmakiola.floret:core-time and Gradle substitutes the local source
module (built from source — F-Droid-safe). Proves the submodule + composite-build
pipeline before any design layers move.
- Remove app copies of DayWindow + Instant date/time formatting (now in
core-time); repoint imports to de.jeanlucmakiola.floret.time.
- DateTimeField gains an explicit import (was same-package).
- CI checkouts fetch submodules recursively.
- Clean composite build + unit tests + debug assemble green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "floret-kit"]
|
||||||
|
path = floret-kit
|
||||||
|
url = https://gitea.jeanlucmakiola.de/makiolaj/floret-kit.git
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package de.jeanlucmakiola.agendula.domain
|
|
||||||
|
|
||||||
import java.time.ZoneId
|
|
||||||
import kotlin.time.Instant
|
|
||||||
|
|
||||||
/** Local-day boundaries used by the smart-list predicates. Pure + testable. */
|
|
||||||
object DayWindow {
|
|
||||||
|
|
||||||
/** Returns `[startOfToday, startOfTomorrow)` in [zone] for the instant [now]. */
|
|
||||||
fun today(now: Instant, zone: ZoneId): Pair<Instant, Instant> {
|
|
||||||
val date = java.time.Instant.ofEpochMilli(now.toEpochMilliseconds())
|
|
||||||
.atZone(zone)
|
|
||||||
.toLocalDate()
|
|
||||||
val start = date.atStartOfDay(zone).toInstant().toEpochMilli()
|
|
||||||
val end = date.plusDays(1).atStartOfDay(zone).toInstant().toEpochMilli()
|
|
||||||
return Instant.fromEpochMilliseconds(start) to Instant.fromEpochMilliseconds(end)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package de.jeanlucmakiola.agendula.ui.common
|
|
||||||
|
|
||||||
import java.time.ZoneId
|
|
||||||
import java.time.format.DateTimeFormatter
|
|
||||||
import java.time.format.FormatStyle
|
|
||||||
import kotlin.time.Instant
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Locale-aware display formatting for the [kotlin.time.Instant]s the domain
|
|
||||||
* uses. Kept tiny and dependency-free; the data layer stores instants, the UI
|
|
||||||
* renders them in the device's zone and locale.
|
|
||||||
*/
|
|
||||||
private val dateFormatter: DateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
|
|
||||||
private val timeFormatter: DateTimeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
|
|
||||||
|
|
||||||
private fun Instant.atSystemZone() =
|
|
||||||
java.time.Instant.ofEpochMilli(toEpochMilliseconds())
|
|
||||||
.atZone(ZoneId.systemDefault())
|
|
||||||
|
|
||||||
/** Medium localized date, e.g. "18 Jun 2026". */
|
|
||||||
fun Instant.formatDate(): String = atSystemZone().format(dateFormatter)
|
|
||||||
|
|
||||||
/** Short localized time, e.g. "14:30". */
|
|
||||||
fun Instant.formatTime(): String = atSystemZone().format(timeFormatter)
|
|
||||||
|
|
||||||
/** Date alone for all-day items, otherwise date + time. */
|
|
||||||
fun Instant.formatDateTime(allDay: Boolean): String =
|
|
||||||
if (allDay) formatDate() else "${formatDate()} · ${formatTime()}"
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package de.jeanlucmakiola.agendula.domain
|
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import java.time.ZoneId
|
|
||||||
import kotlin.time.Instant
|
|
||||||
|
|
||||||
class DayWindowTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `today spans exactly 24h in UTC and contains now`() {
|
|
||||||
val zone = ZoneId.of("UTC")
|
|
||||||
val now = Instant.fromEpochMilliseconds(1_750_000_000_000L)
|
|
||||||
val (start, end) = DayWindow.today(now, zone)
|
|
||||||
|
|
||||||
assertThat(end.toEpochMilliseconds() - start.toEpochMilliseconds()).isEqualTo(86_400_000L)
|
|
||||||
assertThat(now >= start).isTrue()
|
|
||||||
assertThat(now < end).isTrue()
|
|
||||||
// In UTC, midnight aligns to a multiple of one day since the epoch.
|
|
||||||
assertThat(start.toEpochMilliseconds() % 86_400_000L).isEqualTo(0L)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `start is local midnight in a non-UTC zone`() {
|
|
||||||
val zone = ZoneId.of("Europe/Berlin")
|
|
||||||
val now = Instant.fromEpochMilliseconds(1_750_000_000_000L)
|
|
||||||
val (start, end) = DayWindow.today(now, zone)
|
|
||||||
|
|
||||||
val startLocal = java.time.Instant.ofEpochMilli(start.toEpochMilliseconds()).atZone(zone)
|
|
||||||
assertThat(startLocal.hour).isEqualTo(0)
|
|
||||||
assertThat(startLocal.minute).isEqualTo(0)
|
|
||||||
assertThat(now >= start).isTrue()
|
|
||||||
assertThat(now < end).isTrue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1
floret-kit
Submodule
1
floret-kit
Submodule
Submodule floret-kit added at d3ae83f1a4
Reference in New Issue
Block a user