Compare commits

..

1 Commits

Author SHA1 Message Date
a46a7e1280 chore(deps): update kotlin to v2.4.0
Some checks failed
renovate/stability-days Updates have met minimum release age requirement
Translations / check (pull_request) Successful in 6s
CI / ci (pull_request) Failing after 9m14s
2026-07-25 20:33:21 +00:00
16 changed files with 46 additions and 224 deletions

View File

@@ -72,14 +72,9 @@ jobs:
distribution: 'zulu'
java-version: '17'
# Fully qualified on purpose. Codeberg resolves bare `uses:` refs against
# data.forgejo.org, Forgejo's own action mirror — actions/checkout,
# setup-java and cache all exist there, but android-actions/setup-android
# does not, and the job dies with "repository not found". Gitea's instance
# defaults to GitHub, which is why this never surfaced before the split.
- name: Setup Android SDK
if: steps.scope.outputs.code == 'true'
uses: https://github.com/android-actions/setup-android@v3
uses: android-actions/setup-android@v3
with:
# Default ("tools platform-tools") drags in the Android Emulator
# (~300 MB) which the build never uses.

View File

@@ -27,14 +27,6 @@ jobs:
# whether this push actually cuts a new release (no tag for it yet). Keeps the
# heavy job from running on every merge to main.
detect:
# Gitea only. The workflow directory split already keeps this file invisible
# to Codeberg — Forgejo's lookup is first-match-wins, and .forgejo/workflows
# exists — but that only holds while .forgejo/ is non-empty. Move the last
# file out of it and Codeberg would fall back to .gitea/workflows and start
# running the release pipeline on the contributor-facing runner, with no
# secrets. repository_owner differs between the two forges regardless of
# URL, proxy or instance rename, so this closes it permanently.
if: github.repository_owner == 'makiolaj'
runs-on: docker
outputs:
is_release: ${{ steps.v.outputs.is_release }}
@@ -49,16 +41,8 @@ jobs:
- name: Resolve version and whether it is a new release
id: v
env:
# Tags are read from Codeberg, which is canonical — deliberately NOT
# from the Gitea API this workflow runs on. The Codeberg -> Gitea sync
# is a push mirror, i.e. `git push --mirror`, which deletes refs the
# source does not have. A tag minted here on Gitea is therefore wiped
# by the next sync (Codeberg does not have it yet) and only reappears
# once the tag push at the end of this workflow propagates back.
# Asking Gitea inside that window would report "no tag" for a release
# that already shipped, and cut it a second time.
# Public repo, so this read needs no token.
TAG_API: https://codeberg.org/api/v1/repos/jlmakiola/calendula
TOKEN: ${{ secrets.GITHUB_TOKEN }}
API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
run: |
set -e
VERSION=$(grep -oP 'versionName\s*=\s*"\K[^"]+' app/build.gradle.kts)
@@ -76,28 +60,15 @@ jobs:
fi
# A tag for this version already existing means the release shipped on
# an earlier push; do nothing. Absent => this merge cuts the release.
#
# Anything other than a clean 200/404 is treated as fatal rather than
# as "no tag". A Codeberg outage or a network blip would otherwise
# read as absent and re-cut a release that has already shipped —
# republishing to F-Droid and Play. Failing here is recoverable; a
# duplicate release is not.
STATUS=$(curl -s -o /dev/null -w '%{http_code}' "$TAG_API/git/refs/tags/v$VERSION" || echo 000)
case "$STATUS" in
200)
echo "Tag v$VERSION already exists on Codeberg — nothing to release."
echo "is_release=false" >> "$GITHUB_OUTPUT"
;;
404)
echo "No tag for v$VERSION on Codeberg yet — cutting the release."
echo "is_release=true" >> "$GITHUB_OUTPUT"
;;
*)
echo "Codeberg tag lookup for v$VERSION returned HTTP $STATUS." >&2
echo "Refusing to guess: treating this as 'no tag' could re-cut a shipped release." >&2
exit 1
;;
esac
STATUS=$(curl -s -o /dev/null -w '%{http_code}' \
-H "Authorization: token $TOKEN" "$API/git/refs/tags/v$VERSION")
if [ "$STATUS" = "200" ]; then
echo "Tag v$VERSION already exists — nothing to release."
echo "is_release=false" >> "$GITHUB_OUTPUT"
else
echo "No tag for v$VERSION yet — cutting the release."
echo "is_release=true" >> "$GITHUB_OUTPUT"
fi
# Releases: build + sign + publish, then mint the tag and Gitea release.
# Also runs on manual dispatch, where it skips the build and just re-signs and

View File

@@ -29,29 +29,18 @@ jobs:
- name: Run Renovate
run: renovate
env:
# Renovate targets Codeberg (canonical) while still RUNNING on the
# Gitea runner. Moving the job to Codeberg would put a repo-write
# token on the contributor-facing runner, which is exactly what the
# .forgejo/ vs .gitea/ split exists to prevent — so the token stays
# where the other secrets live and only the API calls cross over.
#
# Platform is `forgejo`, not `gitea`: Codeberg runs Forgejo, and the
# pinned image ships a distinct forgejo platform module.
RENOVATE_PLATFORM: forgejo
RENOVATE_ENDPOINT: https://codeberg.org/api/v1
# Codeberg bot-account token (Gitea secret). Needs repo read/write +
# PR scope on jlmakiola/calendula.
# Self-hosted Gitea, not github.com.
RENOVATE_PLATFORM: gitea
RENOVATE_ENDPOINT: https://gitea.jeanlucmakiola.de/api/v1
# Bot-account token (Gitea secret). Needs repo read/write + PR scope.
RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
# Scope to this repo only — no org-wide autodiscovery.
RENOVATE_AUTODISCOVER: 'false'
RENOVATE_REPOSITORIES: '["jlmakiola/calendula"]'
# Commits/PRs authored as the bot, not a real maintainer. This address
# must be a verified email on the Codeberg bot account, otherwise the
# commits show up unattributed there.
RENOVATE_REPOSITORIES: '["makiolaj/calendula"]'
# Commits/PRs authored as the bot, not a real maintainer.
RENOVATE_GIT_AUTHOR: 'Renovate Bot <renovate@jeanlucmakiola.de>'
# Read-only github.com PAT (no scopes needed). Unaffected by the forge
# move — nearly every dependency is *released* on GitHub, and without
# this,
# Read-only github.com PAT (no scopes needed). We run on Gitea, but
# nearly every dependency is *released* on GitHub without this,
# changelog/release-note lookups hit the 60/h anonymous rate limit
# and PRs arrive with an empty "Release Notes" section.
RENOVATE_GITHUB_COM_TOKEN: ${{ secrets.GITHUB_COM_TOKEN }}

2
.gitmodules vendored
View File

@@ -1,3 +1,3 @@
[submodule "floret-kit"]
path = floret-kit
url = https://codeberg.org/jlmakiola/floret-kit.git
url = https://gitea.jeanlucmakiola.de/makiolaj/floret-kit.git

View File

@@ -7,13 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Changed
- Calendula's source code now lives on **Codeberg**, where its issues already
were. The **Source code** and **License** links in Settings → About point
there, so reporting a bug and reading the code no longer land on two different
sites. Nothing about the app itself changes, and the F-Droid repository is
unaffected.
## [2.16.0] — 2026-07-24
### Added

View File

@@ -8,7 +8,7 @@
Reads, writes, and reminds — on top of the system calendar, with zero network access.</p>
<p>
<a href="https://codeberg.org/jlmakiola/calendula/actions"><img src="https://codeberg.org/jlmakiola/calendula/actions/workflows/ci.yaml/badge.svg?branch=main" alt="CI"></a>
<a href="https://gitea.jeanlucmakiola.de/makiolaj/calendula/actions"><img src="https://gitea.jeanlucmakiola.de/makiolaj/calendula/actions/workflows/ci.yaml/badge.svg?branch=main" alt="CI"></a>
<img src="https://img.shields.io/badge/Android-10%2B-3DDC84?logo=android&logoColor=white" alt="Android 10+">
<img src="https://img.shields.io/badge/Kotlin-Compose-7F52FF?logo=kotlin&logoColor=white" alt="Kotlin + Compose">
<img src="https://img.shields.io/badge/Material%203-Expressive-4285F4" alt="Material 3 Expressive">

View File

@@ -56,7 +56,6 @@ import androidx.compose.material.icons.filled.Keyboard
import androidx.compose.material.icons.filled.Language
import androidx.compose.material.icons.filled.Notifications
import androidx.compose.material.icons.filled.Palette
import androidx.compose.material.icons.filled.PrivacyTip
import androidx.compose.material.icons.filled.Translate
import androidx.compose.material.icons.filled.Tune
import androidx.compose.material.icons.filled.UploadFile
@@ -409,9 +408,7 @@ private fun LanguageRow(position: Position) {
@Composable
private fun AboutCard() {
// The card layout lives in floret-kit (components.AboutCard); Calendula
// supplies its own logo, author and the source / licence / privacy / support
// links. The privacy policy has to be reachable from inside the app, not just
// from the store listing, because Calendula touches calendar and contact data.
// supplies its own logo, author and the source / licence / support links.
AboutCard(
logo = { AppLogo() },
appName = stringResource(R.string.app_name),
@@ -427,11 +424,6 @@ private fun AboutCard() {
label = stringResource(R.string.settings_license),
url = stringResource(R.string.about_license_url),
),
AboutLink(
icon = Icons.Default.PrivacyTip,
label = stringResource(R.string.settings_about_privacy),
url = stringResource(R.string.about_privacy_url),
),
),
highlightLink = AboutLink(
icon = Icons.Default.Favorite,

View File

@@ -53,11 +53,11 @@
<string name="event_share_failed">تعذّر مشاركة هذا الحدث.</string>
<string name="event_delete_title">حذف الحدث؟</string>
<string name="event_delete_body">الحدث أُزيل من تقويمك ومن كل جهاز تتم مزامنته معه.</string>
<string name="event_delete_recurring_title">حذف الحدث المتكرّر</string>
<string name="event_delete_recurring_title">حذف الحدث المتكرر</string>
<string name="event_delete_option_occurrence">فقط هذا الحدث</string>
<string name="event_delete_option_following">هذا وجميع الأحداث اللاحقة</string>
<string name="event_delete_option_series">جميع الأحداث في السلسلة</string>
<string name="event_edit_recurring_title">تعديل الحدث المتكرّر</string>
<string name="event_edit_recurring_title">تعديل الحدث المتكرر</string>
<string name="event_delete_failed">تعذّر حذف الحدث</string>
<string name="event_delete_write_denied">Calendula يحتاج إلى صلاحية للكتابة لحذف الأحداث</string>
<string name="dialog_cancel">إلغاء</string>
@@ -108,7 +108,7 @@
<string name="event_edit_conflict_discard_hint">الحدث يبقى كما هو الآن</string>
<string name="import_reminder_prompt_title">هل تريد تطبيق تذكيرك الافتراضي؟</string>
<string name="event_edit_gone_body">هذا الحدث حُذف في هذه الأثناء، على سبيل المثال على جهاز آخر. لم يعد من الممكن حفظ تغييراتك.</string>
<string name="event_edit_more_fields">المزيد من الخانات</string>
<string name="event_edit_more_fields">المزيد من الخيارات</string>
<string name="event_access_public">علني</string>
<string name="event_access_default">الافتراضي</string>
<string name="event_availability_busy">مشغول</string>
@@ -153,7 +153,7 @@
<string name="recurrence_with_until">%1$s حتى %2$s</string>
<string name="recurrence_with_count">%1$s، %2$d مرّات</string>
<string name="import_reminder_prompt_apply">طَبِّق الافتراضي</string>
<string name="event_detail_recurring">حدث متكرّر</string>
<string name="event_detail_recurring">حدث مُتكرر</string>
<string name="recurrence_on_days">%1$s في %2$s</string>
<string name="event_attendee_unknown"></string>
<string name="event_attendee_accepted">تم القُبول</string>
@@ -166,7 +166,7 @@
<string name="event_status_cancelled">ملغي</string>
<string name="event_availability_free">متاح</string>
<string name="event_access_private">خاص</string>
<string name="event_access_confidential">سرّي</string>
<string name="event_access_confidential">سري</string>
<string name="event_attendee_organizer">المُنظِّم</string>
<string name="event_attendee_optional">اختياري</string>
<string name="reminder_default">التذكير الافتراضي</string>
@@ -180,7 +180,7 @@
<string name="reminder_onboarding_body">Android لا يعرض تذكيرات الأحداث من نفسه — بل يجب أن يقوم تطبيق تقويم بذلك. دع Calendula يتولى هذه المهمة.</string>
<string name="reminder_benefit_delivery_body">كل تذكير لأحداثك يصِل كإشعار، في الوقت المحدد تمامًا.</string>
<string name="reminder_benefit_duplicates_title">هل تستخدم تطبيق تقويم ثانٍ؟</string>
<string name="reminder_benefit_duplicates_body">إذا تطبيق آخر أيضًا ينشر تذكيرات، فستراهم مرتين — قم بإيقاف تشغيلهم هناك أو هنا.</string>
<string name="reminder_benefit_duplicates_body">إذا كان تطبيق آخر أيضًا ينشر تذكيرات، فستراهم مرتين — قم بإيقاف تشغيلهم هناك أو هنا.</string>
<string name="reminder_benefit_reversible_title">يمكنك تغييره في أي وقت</string>
<string name="reminder_onboarding_enable_button">شَغِّل التذكيرات</string>
<string name="reminder_onboarding_skip_button">ليس الآن</string>
@@ -200,7 +200,7 @@
<string name="search_hint">البحث عن الأحداث</string>
<string name="search_clear">مسح</string>
<string name="agenda_no_more_today">لا مزيد من الأحداث اليوم</string>
<string name="search_empty">لا أحداث مطابقة ”%1$s“.</string>
<string name="search_empty">لا توجد أحداث مطابقة ”%1$s“.</string>
<string name="search_idle_hint">ابحث عن أحداثك بالعنوان، الموقع أو الملاحظات.</string>
<string name="search_back">الرجوع</string>
<string name="search_action">البحث</string>
@@ -217,7 +217,7 @@
<string name="back">رجوع</string>
<string name="settings_section_appearance">المظهر</string>
<string name="settings_dynamic_color">اللون الديناميكي</string>
<string name="settings_dynamic_color_unavailable">يتطلب أندرويد ١٢ أو أحدث</string>
<string name="settings_dynamic_color_unavailable">يتطلب Android 12 أو أحدث</string>
<string name="settings_default_view">طريقة العرض الافتراضية</string>
<string name="settings_soften_colors">ألوان تقويم ناعمة</string>
<string name="settings_soften_colors_summary">خفف ألوان التقويم والأحداث لتتناسب مع الثيم. قم بإيقافه لإظهار الألوان الخام من مصدر التقويم.</string>
@@ -227,7 +227,7 @@
<string name="settings_font_choose_file">اختر ملفًا…</string>
<string name="settings_font_custom_selected">خط مخصص</string>
<string name="settings_font_import_failed">تعذّر قراءة هذا الملف كخط</string>
<string name="settings_week_start">الأسبوع يبدأ في</string>
<string name="settings_week_start">يبدأ الأسبوع في</string>
<string name="settings_week_start_auto">تلقائي</string>
<string name="settings_time_format_auto">تلقائي</string>
<string name="settings_time_format">تنسيق الوقت</string>
@@ -243,58 +243,4 @@
<string name="settings_past_events_show">إظهار</string>
<string name="settings_past_events_hide">إخفاء</string>
<string name="settings_agenda_header">جدول</string>
<string name="event_edit_timezone_device">المنطقة الزمنية للجهاز</string>
<string name="event_edit_timezone_search">البحث عن المناطق الزمنية</string>
<string name="event_edit_timezone_all">جميع المناطق الزمنية</string>
<string name="event_edit_timezone_none">لا منطقة زمنية تطابق \"%1$s\"</string>
<string name="event_edit_timezone_local_time">%1$s توقيتك</string>
<string name="event_edit_timezone_recent">الأحدث</string>
<string name="event_edit_recurrence_incomplete">أدخل رقمًا من ١ إلى ٩٩٩</string>
<plurals name="duration_minutes">
<item quantity="zero">(%d) لا دقائق</item>
<item quantity="one">(%d) دقيقة واحده</item>
<item quantity="two">%d دقيقتان</item>
<item quantity="few">%d دقائق</item>
<item quantity="many">%d دقيقة</item>
<item quantity="other">%d دقيقة</item>
</plurals>
<plurals name="duration_hours">
<item quantity="zero">(%d) لا ساعات</item>
<item quantity="one">(%d) ساعة واحده</item>
<item quantity="two">%d ساعتان</item>
<item quantity="few">%d ساعات</item>
<item quantity="many">%d ساعة</item>
<item quantity="other">%d ساعة</item>
</plurals>
<plurals name="duration_days">
<item quantity="zero">(%d) لا أيام</item>
<item quantity="one">(%d) يوم واحد</item>
<item quantity="two">%d يومان</item>
<item quantity="few">%d أيام</item>
<item quantity="many">%d يوم</item>
<item quantity="other">%d يوم</item>
</plurals>
<plurals name="duration_weeks">
<item quantity="zero">(%d) لا أسابيع</item>
<item quantity="one">(%d) أسبوع واحد</item>
<item quantity="two">%d أسبوعان</item>
<item quantity="few">%d أسابيع</item>
<item quantity="many">%d أسبوع</item>
<item quantity="other">%d أسبوع</item>
</plurals>
<string name="agenda_span_starts">يبدأ %1$s</string>
<string name="agenda_span_ends">ينتهي %1$s</string>
<string name="today_jump_action">الانتقال إلى اليوم</string>
<string name="widget_refresh">تحديث</string>
<string name="settings_app_name">اسم التطبيق</string>
<string name="settings_dim_completed">تعتيم الأحداث المكتملة</string>
<string name="settings_dim_completed_summary">تعتيم الأحداث التي انتهت بالفعل في عرض الشهر والأسبوع</string>
<string name="settings_today_toolbar">زر اليوم في شريط الأدوات</string>
<string name="settings_today_toolbar_summary">إظهار زر الانتقال إلى اليوم في شريط الأدوات بدلاً من زر عائم</string>
<string name="settings_app_name_summary">اعرض Calendula كـ \"Calendar\" في مشغّل التطبيقات الخاص بك. فقط الاسم في المشغّل يتغير؛ وقد ينتقل الرمز إلى مكان جديد بعد التبديل.</string>
<string name="settings_past_events_dim">تعتيم</string>
<string name="settings_past_events">الأحداث السابقة</string>
<string name="settings_agenda_range">مدى الجدول</string>
<string name="agenda_range_custom">مخصص…</string>
<string name="agenda_range_custom_hint">أيام</string>
</resources>

View File

@@ -354,7 +354,7 @@
<string name="settings_translate">Pomóż w tłumaczeniu</string>
<string name="settings_translate_hint">Dodaj lub ulepsz tłumaczenie w Weblate</string>
<string name="settings_appearance_subtitle">Motyw, domyślny widok, pierwszy dzień tygodnia</string>
<string name="settings_views_subtitle">Układ widoku miesiąca, przycisk szybkiego przełączania, kolejność menu</string>
<string name="settings_views_subtitle">Kolejność przycisku szybkiego przełączania oraz menu</string>
<string name="settings_event_form_subtitle">Domyślne pola dla nowych wydarzeń</string>
<string name="settings_notifications_subtitle">Przypomnienia o wydarzeniach</string>
<string name="settings_special_dates_subtitle">Urodziny i rocznice kontaktów</string>
@@ -517,32 +517,4 @@
<string name="settings_agenda_show_today_hint">Zachowaj dzisiejszy dzień na górze agendy i widżetu, nawet gdy nie ma już na dziś żadnych zadań.</string>
<string name="special_dates_calendar_birthday">Urodziny</string>
<string name="special_dates_calendar_anniversary">Rocznice</string>
<string name="event_edit_timezone_device">Strefa czasowa urządzenia</string>
<string name="event_edit_timezone_device_summary">Podąża za Twoją lokalizacją</string>
<string name="event_edit_timezone_search">Znajdź strefę czasową</string>
<string name="event_edit_timezone_recent">Ostatnie</string>
<string name="event_edit_timezone_all">Wszystkie strefy czasowe</string>
<string name="event_edit_timezone_none">Żadna strefa czasowa nie pasuje do „%1$s”</string>
<string name="event_edit_timezone_local_time">%1$s Twojego czasu</string>
<string name="event_edit_recurrence_incomplete">Wpisz liczbę od 1 do 999</string>
<string name="agenda_span_starts">Początek o %1$s</string>
<string name="agenda_span_ends">Koniec o %1$s</string>
<string name="today_jump_action">Dzisiaj</string>
<string name="settings_today_toolbar">Przycisk „Dzisiaj” na pasku narzędzi</string>
<string name="settings_today_toolbar_summary">Pokaż przycisk skoku do dzisiaj na pasku narzędzi zamiast przycisku pływającego</string>
<string name="settings_app_name">Nazwa aplikacji</string>
<string name="settings_app_name_summary">Wyświetlaj Calendula jako „Kalendarz” w menu aplikacji. Zmieni się tylko nazwa w menu; po przełączeniu ikona może pojawić się w innym miejscu.</string>
<string name="settings_month_header">Widok miesiąca</string>
<string name="settings_month_view_style">Styl widoku miesiąca</string>
<string name="month_style_paged">Strony</string>
<string name="month_style_paged_summary">Jeden miesiąc wypełnia ekran. Przesuń w lewo lub w prawo, aby zmienić miesiąc.</string>
<string name="month_style_continuous">Przewijanie miesięcy</string>
<string name="month_style_continuous_summary">Każdy miesiąc znajduje się pod własnym nagłówkiem, oddzielony od następnego niewielkim odstępem.</string>
<string name="month_style_dense">Tygodnie bez przerw</string>
<string name="month_style_dense_summary">Tygodnie są ułożone jeden po drugim, każdy miesiąc płynnie łączy się z następnym, bez odstępu pomiędzy.</string>
<string name="month_style_split">Podzielony</string>
<string name="month_style_split_summary">Zwięzła siatka wyróżnia dni z wydarzeniami a lista dla dnia wybranego dotknięciem wyświetla się poniżej.</string>
<string name="month_split_no_events">Brak planów</string>
<string name="month_split_expand">Pokaż cały miesiąc</string>
<string name="month_split_collapse">Pokaż wydarzenia dnia</string>
</resources>

View File

@@ -462,7 +462,6 @@
<string name="settings_license_value">MIT</string>
<string name="settings_about_author">by Jean-Luc Makiola</string>
<string name="settings_about_source">Source</string>
<string name="settings_about_privacy">Privacy policy</string>
<string name="settings_about_support">Support development</string>
<string name="settings_about_version">Version %1$s</string>
<string name="settings_about_logo_desc">Calendula app icon</string>
@@ -571,9 +570,8 @@
<string name="settings_qs_tile">Add Quick Settings tile</string>
<string name="settings_qs_tile_hint">Add a “New event” tile to the Quick Settings panel.</string>
<string name="about_source_url" translatable="false">https://codeberg.org/jlmakiola/calendula</string>
<string name="about_license_url" translatable="false">https://codeberg.org/jlmakiola/calendula/src/branch/main/LICENSE</string>
<string name="about_privacy_url" translatable="false">https://jeanlucmakiola.de/calendula/privacy</string>
<string name="about_source_url" translatable="false">https://gitea.jeanlucmakiola.de/makiolaj/calendula</string>
<string name="about_license_url" translatable="false">https://gitea.jeanlucmakiola.de/makiolaj/calendula/src/branch/main/LICENSE</string>
<string name="about_support_url" translatable="false">https://ko-fi.com/jeanlucmakiola</string>
<string name="about_translate_url" translatable="false">https://weblate.dev.jeanlucmakiola.de/engage/calendula/</string>

View File

@@ -73,8 +73,7 @@ Published version codes so far: `v0.1.0`→100 … `v1.0.0`→10000 … `v2.0.0`
CI and release are split so a change is built once on its PR and only does
release work when a merge actually cuts a release:
- **`ci.yaml`** (`.forgejo/workflows/`, on `pull_request`, **Codeberg**) — lint +
unit tests + a debug assemble (and
- **`ci.yaml`** (on `pull_request`) — lint + unit tests + a debug assemble (and
a Trivy scan), once per PR. Docs/metadata-only PRs skip the Android build but
still report a green `CI` check.
- **`release.yaml`** (on push to `main`, plus `workflow_dispatch`) — a cheap
@@ -92,9 +91,9 @@ release work when a merge actually cuts a release:
Alongside F-Droid, each release is mirrored to the Codeberg repo
(`jlmakiola/calendula`) as a plain download for users who don't want F-Droid.
Codeberg **push-mirrors** branches and tags to Gitea, but releases aren't git
objects and don't sync in either direction, so the pipeline creates the release
over the Codeberg API and attaches `calendula_v<version>.apk` + its `.sha256`. It's the
Gitea already **push-mirrors** branches and tags to Codeberg, but releases
aren't git objects and don't sync, so the pipeline creates the release over the
Codeberg API and attaches `calendula_v<version>.apk` + its `.sha256`. It's the
same APK the F-Droid repo serves (same **app key**), so it adds no trust
surface. The step is best-effort: a Codeberg outage never fails an
already-published F-Droid release, and it skips cleanly if `CODEBERG_RELEASE_TOKEN` is
@@ -110,39 +109,6 @@ build, the version bump, and tag/release creation, and just re-signs the
existing F-Droid index with the configured repo key and re-uploads. Use this
for key rotation or repo recovery without publishing a new app version.
## Two forges, one repo
**Codeberg (`jlmakiola/calendula`) is canonical** — git, issues, PRs, tags and
releases. The self-hosted Gitea instance is build infrastructure: it holds the
signing key, publishes the F-Droid repo, and runs the release pipeline. Codeberg
push-mirrors `main` and tags to Gitea, and a bumped `versionName` arriving there
triggers `release.yaml` exactly as before.
Workflows are separated by **directory**, not by conditionals. Forgejo looks in
`.forgejo/workflows` → `.gitea/workflows` → `.github/workflows` and stops at the
first that exists; Gitea doesn't know `.forgejo/` at all:
| Directory | Runs on | Contains | Secrets |
| --- | --- | --- | --- |
| `.forgejo/workflows/` | Codeberg | `ci.yaml`, `translations.yaml` | **none** |
| `.gitea/workflows/` | Gitea | `release.yaml`, `renovate.yml` | signing key, F-Droid, Play, bot tokens |
The line is drawn at **secrets, not at CI-vs-release**. That's what makes fork
PRs safe: everything a contributor can trigger lives in `.forgejo/` and can
reference no secret. Renovate stays on the Gitea runner *even though it opens
PRs on Codeberg* — it talks to Codeberg's API rather than moving its token onto
the contributor-facing runner.
Two consequences worth remembering:
- **`detect` reads tags from Codeberg**, not from the Gitea instance it runs on.
Push mirroring is `git push --mirror`, so a tag minted on Gitea is deleted by
the next sync until the Codeberg tag push propagates back. Asking Gitea inside
that window would re-cut a shipped release.
- **Any ref that exists only on Gitea gets deleted** by the mirror. That's
correct under Codeberg-canonical, but don't debug a "vanished" branch without
remembering it.
## Secrets (Gitea → repo Settings → Actions → Secrets)
| Secret | Purpose |

View File

@@ -18,9 +18,9 @@ Categories:
- Calendar & Agenda
License: MIT
AuthorName: Jean-Luc Makiola
SourceCode: https://codeberg.org/jlmakiola/calendula
IssueTracker: https://codeberg.org/jlmakiola/calendula/issues
Changelog: https://codeberg.org/jlmakiola/calendula/src/branch/main/CHANGELOG.md
SourceCode: https://gitea.jeanlucmakiola.de/makiolaj/calendula
IssueTracker: https://gitea.jeanlucmakiola.de/makiolaj/calendula/issues
Changelog: https://gitea.jeanlucmakiola.de/makiolaj/calendula/src/branch/main/CHANGELOG.md
Donate: https://ko-fi.com/jeanlucmakiola
AutoName: Calendula

View File

@@ -6,6 +6,6 @@ Summary: A modern Material 3 Expressive calendar for Android.
Categories:
- Time
SourceCode: https://codeberg.org/jlmakiola/calendula
IssueTracker: https://codeberg.org/jlmakiola/calendula/issues
SourceCode: https://gitea.jeanlucmakiola.de/makiolaj/calendula
IssueTracker: https://gitea.jeanlucmakiola.de/makiolaj/calendula/issues
Donate: https://ko-fi.com/jeanlucmakiola

View File

@@ -1,6 +1,6 @@
[versions]
agp = "9.2.1"
kotlin = "2.3.21"
kotlin = "2.4.0"
ksp = "2.3.9"
hilt = "2.59.2"
coreKtx = "1.19.0"

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip
distributionSha256Sum=bafc141b619ad6350fd975fc903156dd5c151998cc8b058e8c1044ab5f7b031f
networkTimeout=10000
validateDistributionUrl=true