diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index b0f8513..1e68c6c 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -26,6 +26,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + submodules: recursive with: # Full history so the base..HEAD diff below has a merge-base. fetch-depth: 0 diff --git a/.gitea/workflows/release.yaml b/.gitea/workflows/release.yaml index 635c6a8..82826ea 100644 --- a/.gitea/workflows/release.yaml +++ b/.gitea/workflows/release.yaml @@ -33,6 +33,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + submodules: recursive - name: Resolve version and whether it is a new release id: v @@ -82,6 +84,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + submodules: recursive - name: Setup Java uses: actions/setup-java@v4 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..103c066 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "floret-kit"] + path = floret-kit + url = https://gitea.jeanlucmakiola.de/makiolaj/floret-kit.git diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 46440cf..29669c5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -159,6 +159,7 @@ dependencies { implementation(libs.androidx.glance.material3) implementation(libs.kotlinx.datetime) + implementation("de.jeanlucmakiola.floret:core-time") implementation(libs.kotlinx.coroutines.core) debugImplementation(libs.androidx.ui.tooling) diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarDataSource.kt b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarDataSource.kt index 8e02288..bc650d3 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarDataSource.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarDataSource.kt @@ -1,5 +1,7 @@ package de.jeanlucmakiola.calendula.data.calendar +import de.jeanlucmakiola.floret.time.toEpochMillis +import de.jeanlucmakiola.floret.time.toKotlinInstantFromEpochMillis import android.Manifest import android.content.ContentResolver import android.content.ContentUris diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarRepositoryImpl.kt b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarRepositoryImpl.kt index bde325a..b7bedde 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarRepositoryImpl.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarRepositoryImpl.kt @@ -1,5 +1,6 @@ package de.jeanlucmakiola.calendula.data.calendar +import de.jeanlucmakiola.floret.time.toEpochMillis import de.jeanlucmakiola.calendula.data.di.IoDispatcher import de.jeanlucmakiola.calendula.data.prefs.CalendarPrefs import de.jeanlucmakiola.calendula.data.prefs.SettingsPrefs diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/EventDetailMapper.kt b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/EventDetailMapper.kt index 4a59358..31cf534 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/EventDetailMapper.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/EventDetailMapper.kt @@ -1,5 +1,6 @@ package de.jeanlucmakiola.calendula.data.calendar +import de.jeanlucmakiola.floret.time.toKotlinInstantFromEpochMillis import android.provider.CalendarContract import android.util.Log import de.jeanlucmakiola.calendula.domain.AccessLevel diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/IcsExportMapper.kt b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/IcsExportMapper.kt index 817cff3..ce8befa 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/IcsExportMapper.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/IcsExportMapper.kt @@ -1,5 +1,6 @@ package de.jeanlucmakiola.calendula.data.calendar +import de.jeanlucmakiola.floret.time.toKotlinInstantFromEpochMillis import de.jeanlucmakiola.calendula.domain.EventStatus import de.jeanlucmakiola.calendula.domain.ics.IcsEvent import de.jeanlucmakiola.calendula.domain.ics.deriveIcsUid diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/InstanceMapper.kt b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/InstanceMapper.kt index 263300b..6c72def 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/InstanceMapper.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/InstanceMapper.kt @@ -1,5 +1,6 @@ package de.jeanlucmakiola.calendula.data.calendar +import de.jeanlucmakiola.floret.time.toKotlinInstantFromEpochMillis import android.util.Log import de.jeanlucmakiola.calendula.domain.EventInstance diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/SearchMapper.kt b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/SearchMapper.kt index 4c09781..56ba635 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/SearchMapper.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/SearchMapper.kt @@ -1,5 +1,6 @@ package de.jeanlucmakiola.calendula.data.calendar +import de.jeanlucmakiola.floret.time.toKotlinInstantFromEpochMillis import de.jeanlucmakiola.calendula.domain.EventInstance import de.jeanlucmakiola.calendula.domain.ics.parseRfc2445DurationMillis diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/TimeBridge.kt b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/TimeBridge.kt deleted file mode 100644 index 757c7a8..0000000 --- a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/TimeBridge.kt +++ /dev/null @@ -1,7 +0,0 @@ -package de.jeanlucmakiola.calendula.data.calendar - -import kotlin.time.Instant - -fun Long.toKotlinInstantFromEpochMillis(): Instant = Instant.fromEpochMilliseconds(this) - -fun Instant.toEpochMillis(): Long = toEpochMilliseconds() diff --git a/app/src/test/java/de/jeanlucmakiola/calendula/data/calendar/TimeBridgeTest.kt b/app/src/test/java/de/jeanlucmakiola/calendula/data/calendar/TimeBridgeTest.kt deleted file mode 100644 index 08de313..0000000 --- a/app/src/test/java/de/jeanlucmakiola/calendula/data/calendar/TimeBridgeTest.kt +++ /dev/null @@ -1,26 +0,0 @@ -package de.jeanlucmakiola.calendula.data.calendar - -import com.google.common.truth.Truth.assertThat -import kotlin.time.Instant -import org.junit.jupiter.api.Test - -class TimeBridgeTest { - - @Test - fun `epoch millis round-trips through Instant`() { - val original = 1_717_840_800_000L // 2024-06-08T10:00:00Z - val instant = original.toKotlinInstantFromEpochMillis() - assertThat(instant.toEpochMillis()).isEqualTo(original) - } - - @Test - fun `zero millis maps to Instant epoch`() { - assertThat(0L.toKotlinInstantFromEpochMillis()).isEqualTo(Instant.fromEpochMilliseconds(0L)) - } - - @Test - fun `negative epoch millis is supported`() { - val original = -1_000_000L - assertThat(original.toKotlinInstantFromEpochMillis().toEpochMillis()).isEqualTo(original) - } -} diff --git a/docs/fdroid-official/de.jeanlucmakiola.calendula.yml b/docs/fdroid-official/de.jeanlucmakiola.calendula.yml index 45a7a3e..86b95a7 100644 --- a/docs/fdroid-official/de.jeanlucmakiola.calendula.yml +++ b/docs/fdroid-official/de.jeanlucmakiola.calendula.yml @@ -43,11 +43,21 @@ Builds: versionCode: 20705 commit: v2.7.5 subdir: app + submodules: true gradle: - yes # No NDK / no flavors. The release buildType applies a signingConfig only # when key.properties exists; on the buildserver it does not, so this # produces the unsigned APK F-Droid compares against our binary. + # + # submodules: true — REQUIRED from v2.11.0 onward, where the build pulls + # shared code from the `floret-kit` git submodule via a Gradle composite + # build (`includeBuild("floret-kit")`). Without it F-Droid checks out an + # empty floret-kit/ and the from-source build fails, stalling publishing. + # Inert for v2.7.5 (no submodule yet); kept here so AutoUpdateMode copies it + # onto every auto-generated future build entry. The kit is plain-Kotlin and + # carries no foojay toolchain resolver, so it clears the same reproducibility + # bar (enforced by scripts/check_reproducible_release.sh). # SHA-256 of our app signing certificate (public; embedded in every published # APK). Locks F-Droid to publish only binaries signed with our key. diff --git a/floret-kit b/floret-kit new file mode 160000 index 0000000..554d536 --- /dev/null +++ b/floret-kit @@ -0,0 +1 @@ +Subproject commit 554d536b2fb678f670069648e156cc2c3b015bea diff --git a/scripts/check_reproducible_release.sh b/scripts/check_reproducible_release.sh index 33fc4cb..7011401 100755 --- a/scripts/check_reproducible_release.sh +++ b/scripts/check_reproducible_release.sh @@ -34,8 +34,15 @@ else fi # 2. The foojay toolchain resolver must not be present in any Gradle script. +# This includes the floret-kit submodule: it's an included build (composite +# build via `includeBuild`), so F-Droid evaluates its Gradle scripts too when +# building from source — the same offline-scanner bar applies to it. gradle_files=("$SETTINGS" "$APP") [ -f build.gradle.kts ] && gradle_files+=(build.gradle.kts) +if [ -d floret-kit ]; then + while IFS= read -r f; do gradle_files+=("$f"); done \ + < <(find floret-kit -name '*.gradle.kts' -not -path '*/build/*') +fi if grep -qi 'foojay' "${gradle_files[@]}"; then echo "ERROR: foojay toolchain resolver found in: $(grep -li foojay "${gradle_files[@]}" | tr '\n' ' ')" >&2 echo " F-Droid's source scanner rejects org.gradle.toolchains.foojay-resolver" >&2 diff --git a/settings.gradle.kts b/settings.gradle.kts index 450da9a..39d8e55 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -22,3 +22,4 @@ dependencyResolutionManagement { rootProject.name = "Calendula" include(":app") +includeBuild("floret-kit")