Publish the whole Play listing from the repo (#285)
This commit is contained in:
@@ -43,6 +43,19 @@ jobs:
|
||||
- name: Changelog length invariant
|
||||
run: bash scripts/check_changelog_lengths.sh
|
||||
|
||||
# The whole listing goes to Play with every release; a field over its cap
|
||||
# or an image Play rejects would fail that upload.
|
||||
- name: Store listing invariant
|
||||
run: |
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
apt-get update && apt-get install -y python3
|
||||
elif command -v apk >/dev/null 2>&1; then
|
||||
apk add --no-cache python3
|
||||
fi
|
||||
fi
|
||||
python3 scripts/check_store_listing.py
|
||||
|
||||
# Decide whether anything that affects the app build changed. Docs, store
|
||||
# metadata, licence texts and forge housekeeping don't, so those PRs skip
|
||||
# the SDK + Gradle work below but still report a green `ci`.
|
||||
|
||||
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Changed
|
||||
- **Split view opens with the month's agenda.** It starts at today in the current month; tapping a day filters the list, and the filter chip restores the full month. Swiping the list moves by day when filtered and by month otherwise ([#142]).
|
||||
- **Today stands out in the month grid.** Its whole cell has a distinct background; tapping Today briefly expands that cell and nudges its neighbours aside ([#241]).
|
||||
- **The store listing speaks every app language.** Google Play and F-Droid now show Calendula's description in all 16 languages the app ships, and the Play listing is published from the repository with each release ([#285]).
|
||||
|
||||
### Fixed
|
||||
- **Multi-day events stay above shorter events.** Month and Week bars, Split day lists, and Agenda now place multi-day events before one-day all-day events, then timed events; declined events remain last ([#291]).
|
||||
@@ -1787,3 +1788,4 @@ automatically, with zero telemetry and no internet permission.
|
||||
[#304]: https://codeberg.org/jlmakiola/calendula/issues/304
|
||||
[#321]: https://codeberg.org/jlmakiola/calendula/issues/321
|
||||
[#329]: https://codeberg.org/jlmakiola/calendula/issues/329
|
||||
[#285]: https://codeberg.org/jlmakiola/calendula/issues/285
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ Where to look for what:
|
||||
| [Issues](https://codeberg.org/jlmakiola/calendula/issues) + [milestones](https://codeberg.org/jlmakiola/calendula/milestones) | **The roadmap.** What's planned, in progress, and shipped — a milestone maps to its `release/vX.Y.Z` branch |
|
||||
| [`../.planning/PROJECT.md`](../.planning/PROJECT.md) | What the project is: core value, stack + version pins, constraints, naming, forge/release infrastructure |
|
||||
| [`design/`](design/) | Per-feature design notes kept for features whose provider behaviour is worth recording |
|
||||
| [`../fastlane/metadata/android/`](../fastlane/metadata/android/) | Store metadata (single source of truth): descriptions, title, icon, screenshots (DE + EN). Harvested directly by the official F-Droid repo; transformed into the self-hosted repo layout at release time by [`../scripts/fastlane_to_fdroid_localized.sh`](../scripts/fastlane_to_fdroid_localized.sh) |
|
||||
| [`../fastlane/metadata/android/`](../fastlane/metadata/android/) | Store metadata (single source of truth) for every app language, mapped in `store-locales.txt`: descriptions, title, graphics. Harvested directly by the official F-Droid repo, pushed to Google Play with every release, validated by [`../scripts/check_store_listing.py`](../scripts/check_store_listing.py); transformed into the self-hosted repo layout at release time by [`../scripts/fastlane_to_fdroid_localized.sh`](../scripts/fastlane_to_fdroid_localized.sh) |
|
||||
| [`../fdroid-metadata/`](../fdroid-metadata/) | App-level F-Droid control file (`*.yml`: Categories, License, links) for the self-hosted repo's `fdroid update` |
|
||||
| [`fdroid-official/`](fdroid-official/) | Recipe + notes for publishing to the **official** F-Droid repo (reproducible build + developer-signed binary) |
|
||||
|
||||
|
||||
+24
-14
@@ -162,24 +162,34 @@ before. fastlane appears only as the Play Developer API client (`supply`),
|
||||
because the store listing already lives in `fastlane/metadata/android/` — the
|
||||
same tree the official F-Droid repo harvests. One metadata source, two stores.
|
||||
|
||||
**What gets uploaded per release:** the AAB, plus the per-version "What's New"
|
||||
from `fastlane/metadata/android/en-US/changelogs/<versionCode>.txt` — the
|
||||
**What gets uploaded per release:** the AAB, the per-version "What's New"
|
||||
from `fastlane/metadata/android/<locale>/changelogs/<versionCode>.txt` (the
|
||||
hand-written summary from step 3, which is why it must stay **under 500
|
||||
characters**: Play rejects a longer one. Listing text is
|
||||
**not** touched — an accidental overwrite of a live listing triggers a Play
|
||||
policy review. Sync it deliberately with `bundle exec fastlane listing`.
|
||||
characters**), and the **whole store listing** — title, short and full
|
||||
description, icon, feature graphic and screenshots for every locale — all in one
|
||||
Play edit. Nothing about the Play listing is edited in the console any more:
|
||||
change the files, and the next release pushes them. Unchanged images are
|
||||
skipped (`sync_image_upload`). Every listing change goes through Play's review,
|
||||
together with the bundle. To push a listing fix between releases, run
|
||||
`bundle exec fastlane listing` (add `version_code:<code>` if the track holds
|
||||
more than one release).
|
||||
|
||||
**Screenshots and graphics are skipped**, because the committed assets satisfy
|
||||
F-Droid but not Play:
|
||||
The listing tree is guarded by `scripts/check_store_listing.py`, which CI runs
|
||||
on every pull request:
|
||||
|
||||
| Asset | Committed | Play requires |
|
||||
| --- | --- | --- |
|
||||
| `phoneScreenshots/*.png` | 1280×2856, 32-bit RGBA | long edge ≤ 2× short edge (so ≤ 2560), 24-bit PNG, no alpha |
|
||||
| `icon.png` | 512×512, 24-bit RGB | 512×512, 32-bit PNG |
|
||||
| `featureGraphic.png` | *missing* | required, exactly 1024×500 |
|
||||
| Rule | Play limit |
|
||||
| --- | --- |
|
||||
| `title.txt` / `short_description.txt` / `full_description.txt` | 30 / 80 / 4000 chars, all three present in every locale |
|
||||
| `full_description.txt` | one line per paragraph — Play renders every newline |
|
||||
| `images/icon.png` | 512×512, 32-bit PNG |
|
||||
| `images/featureGraphic.png` | 1024×500, JPEG or 24-bit PNG |
|
||||
| `images/*Screenshots/*` | JPEG or 24-bit PNG (no alpha), sides 320–3840, long edge ≤ 2× short, 2–8 per type |
|
||||
| locale directories | exactly the ones in `fastlane/store-locales.txt`, which maps every app `values-*` to a Play locale code |
|
||||
|
||||
Until those are fixed, Play's graphics are managed by hand in the console. Then
|
||||
pass `images:true` to the `listing` lane.
|
||||
A locale without its own images falls back to en-US in both stores, so graphics
|
||||
only need to exist there. Adding an app language means adding its line to
|
||||
`fastlane/store-locales.txt` and its listing directory — CI fails until both
|
||||
exist. Store text is not on Weblate; it is edited here.
|
||||
|
||||
**Track.** Uploads go straight to `production` at a full rollout
|
||||
(`PLAY_RELEASE_STATUS=completed`). The merge to `main` is already the human
|
||||
|
||||
+24
-37
@@ -8,9 +8,9 @@
|
||||
# the one build whose byte-for-byte output is verified by a third party.
|
||||
#
|
||||
# What fastlane IS here for is `supply` — the Play Developer API client — because
|
||||
# the store listing already lives in fastlane/metadata/android, which the
|
||||
# official F-Droid repo harvests from the tagged source tree. One metadata tree,
|
||||
# two stores.
|
||||
# the store listing lives in fastlane/metadata/android, which the official
|
||||
# F-Droid repo harvests from the tagged source tree. One metadata tree, two
|
||||
# stores; nothing about the Play listing is edited in the console.
|
||||
|
||||
default_platform(:android)
|
||||
|
||||
@@ -21,8 +21,18 @@ def project_path(path)
|
||||
File.expand_path(path, File.expand_path("..", FastlaneCore::FastlaneFolder.path || "."))
|
||||
end
|
||||
|
||||
# Listing text, graphics and screenshots all come from fastlane/metadata/android;
|
||||
# scripts/check_store_listing.py keeps the tree within Play's rules on every PR.
|
||||
LISTING = {
|
||||
skip_upload_metadata: false,
|
||||
skip_upload_images: false,
|
||||
skip_upload_screenshots: false,
|
||||
# Only re-upload graphics whose content changed.
|
||||
sync_image_upload: true,
|
||||
}.freeze
|
||||
|
||||
platform :android do
|
||||
desc "Upload an already-built, already-signed AAB to Play"
|
||||
desc "Upload an already-built, already-signed AAB to Play, with the store listing"
|
||||
lane :deploy do |options|
|
||||
aab = project_path(options[:aab] || "app/build/outputs/bundle/release/app-release.aab")
|
||||
UI.user_error!("AAB not found at #{aab}") unless File.exist?(aab)
|
||||
@@ -36,52 +46,29 @@ platform :android do
|
||||
# gets the bundle. Never let the uploader reach for the other artifact.
|
||||
skip_upload_apk: true,
|
||||
|
||||
# Listing text is synced deliberately via the `listing` lane, not on every
|
||||
# release. Overwriting a live listing by accident triggers a Play policy
|
||||
# review, which is not a quick revert.
|
||||
skip_upload_metadata: true,
|
||||
|
||||
# "What's New" DOES track every release.
|
||||
# scripts/sync_changelog_to_fastlane.sh writes
|
||||
# fastlane/metadata/android/en-US/changelogs/<versionCode>.txt from
|
||||
# CHANGELOG.md, so Play shows exactly the text F-Droid does.
|
||||
# "What's New" tracks every release: changelogs/<versionCode>.txt, the
|
||||
# same file F-Droid shows.
|
||||
skip_upload_changelogs: false,
|
||||
|
||||
# See the `listing` lane for why the committed images can't go to Play yet.
|
||||
skip_upload_images: true,
|
||||
skip_upload_screenshots: true,
|
||||
|
||||
# Dry run: validate the edit against the API and roll it back instead of
|
||||
# committing it. Used for the first end-to-end rehearsal.
|
||||
validate_only: options[:dry_run].to_s == "true",
|
||||
**LISTING,
|
||||
)
|
||||
end
|
||||
|
||||
desc "Sync the store listing text (and, once the assets qualify, the images)"
|
||||
desc "Push only the store listing, e.g. a listing fix between releases"
|
||||
lane :listing do |options|
|
||||
# Deliberate and manual: `bundle exec fastlane listing`. Not wired into the
|
||||
# release pipeline.
|
||||
#
|
||||
# Images stay off by default because the committed assets do not satisfy
|
||||
# Play today, even though F-Droid accepts all of them:
|
||||
#
|
||||
# * phoneScreenshots are 1280x2856. Play caps the long edge at twice the
|
||||
# short edge (2560 here), so every screenshot is rejected.
|
||||
# * those PNGs are 32-bit RGBA. Play wants 24-bit PNG, no alpha.
|
||||
# * icon.png is 512x512 but 24-bit RGB. Play's icon wants 32-bit PNG.
|
||||
# * there is no featureGraphic.png. Play requires one, exactly 1024x500.
|
||||
#
|
||||
# Until that is fixed, the Play listing's graphics are managed by hand in the
|
||||
# console. Pass images:true once the assets qualify.
|
||||
upload_images = options[:images].to_s == "true"
|
||||
|
||||
# supply still anchors the edit on a release: pass version_code: when the
|
||||
# track holds more than one.
|
||||
supply(
|
||||
track: options[:track] || "production",
|
||||
version_code: options[:version_code],
|
||||
skip_upload_aab: true,
|
||||
skip_upload_apk: true,
|
||||
skip_upload_metadata: false,
|
||||
skip_upload_changelogs: true,
|
||||
skip_upload_images: !upload_images,
|
||||
skip_upload_screenshots: !upload_images,
|
||||
validate_only: options[:dry_run].to_s == "true",
|
||||
**LISTING,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
Calendula تطبيق تقويم عصري ومفتوح المصدر لنظام أندرويد. يعمل مباشرةً على مزوّد التقويم في النظام، لذا يظهر تلقائيًا أي مصدر متزامن مع جهازك — Nextcloud عبر DAVx5 أو Google أو التقويمات المحلية أو اشتراكات WebCal — وتُزامَن التغييرات التي تجريها بالطريقة نفسها.
|
||||
|
||||
أنشئ الأحداث وعدّلها واحذفها، بما في ذلك الأحداث المتكررة مع تحديد نطاق التغيير (هذا الحدث فقط / هذا الحدث وكل ما يليه / السلسلة بأكملها) ومنتقي تكرار بسيط. كما يعرض Calendula تذكيرات أحداثك كإشعارات — المس الإشعار لتنتقل إلى الحدث مباشرةً.
|
||||
|
||||
يمكنك اختياريًا عرض أعياد ميلاد جهات الاتصال والذكريات السنوية وغيرها من التواريخ المميزة في تقويمك. أنت من يفعّل ذلك؛ تُقرأ جهات الاتصال على جهازك فقط، ولا تُرفع أبدًا ولا تُعدَّل أبدًا — يكتفي Calendula بنسخ التواريخ إلى تقويمات محلية تتحكم فيها بالكامل.
|
||||
|
||||
ما يميّزه هو التصميم: Material 3 Expressive حقيقي في كل مكان، مع ألوان ديناميكية وحركة معبّرة وأشكال معبّرة.
|
||||
|
||||
الخصوصية: لا قياس عن بُعد، ولا تحليلات، ولا وصول إلى الشبكة — بياناتك لا تغادر جهازك أبدًا.
|
||||
@@ -0,0 +1 @@
|
||||
تقويم عصري بتصميم Material 3 Expressive لنظام أندرويد.
|
||||
@@ -0,0 +1 @@
|
||||
Calendula
|
||||
@@ -0,0 +1,9 @@
|
||||
Calendula — сучасная праграма-каляндар з адкрытым зыходным кодам для Android. Яна працуе непасрэдна з сістэмным пастаўшчыком календароў, таму любая крыніца, сінхранізаваная з вашай прыладай, — Nextcloud праз DAVx5, Google, лакальныя календары, падпіскі WebCal — з'яўляецца аўтаматычна, а вашы змены сінхранізуюцца назад тым жа шляхам.
|
||||
|
||||
Стварайце, змяняйце і выдаляйце падзеі, у тым ліку паўтаральныя — з выбарам абсягу змен (толькі гэтая падзея / гэтая і ўсе наступныя / уся серыя) і простым выбарам паўтору. Calendula таксама паказвае напаміны пра падзеі ў выглядзе апавяшчэнняў — націсніце на апавяшчэнне, і адкрыецца падзея.
|
||||
|
||||
Пры жаданні ў календары можна паказваць дні нараджэння, гадавіны і іншыя памятныя даты вашых кантактаў. Гэту функцыю вы ўключаеце самі; кантакты чытаюцца толькі на прыладзе, нікуды не адпраўляюцца і ніколі не змяняюцца — Calendula толькі пераносіць даты ў лакальныя календары, якія цалкам пад вашым кантролем.
|
||||
|
||||
Галоўная адметнасць — дызайн: сапраўдны Material 3 Expressive ва ўсім, з дынамічнымі колерамі, выразнай анімацыяй і выразнымі формамі.
|
||||
|
||||
Прыватнасць: ніякай тэлеметрыі, ніякай аналітыкі, ніякага доступу да сеткі — вашы даныя ніколі не пакідаюць прыладу.
|
||||
@@ -0,0 +1 @@
|
||||
Сучасны каляндар у стылі Material 3 Expressive для Android.
|
||||
@@ -0,0 +1 @@
|
||||
Calendula
|
||||
@@ -0,0 +1,9 @@
|
||||
Calendula je moderní open-source kalendář pro Android. Pracuje přímo se systémovým poskytovatelem kalendáře, takže se automaticky zobrazí jakýkoli zdroj synchronizovaný do vašeho zařízení — Nextcloud přes DAVx5, Google, místní kalendáře, odběry WebCal — a vaše změny se stejnou cestou synchronizují zpět.
|
||||
|
||||
Vytvářejte, upravujte a mažte události, včetně opakovaných s volbou rozsahu změny (jen tato událost / tato a všechny následující / celá série) a jednoduchým výběrem opakování. Calendula také doručuje připomínky událostí jako oznámení — klepněte na ně a otevře se událost.
|
||||
|
||||
Volitelně můžete v kalendáři zobrazit narozeniny, výročí a další významná data svých kontaktů. Zapínáte si to sami; kontakty se čtou pouze v zařízení, nikdy se neodesílají a nikdy se nemění — Calendula data jen zrcadlí do místních kalendářů, které máte plně pod kontrolou.
|
||||
|
||||
Rozdíl dělá design: skutečný Material 3 Expressive všude, s dynamickými barvami, výrazným pohybem a výraznými tvary.
|
||||
|
||||
Soukromí: žádná telemetrie, žádná analytika, žádný přístup k síti — vaše data nikdy neopustí zařízení.
|
||||
@@ -0,0 +1 @@
|
||||
Moderní kalendář v Material 3 Expressive pro Android.
|
||||
@@ -0,0 +1 @@
|
||||
Calendula
|
||||
@@ -1,23 +1,9 @@
|
||||
Calendula ist eine moderne, quelloffene Kalender-App für Android. Sie
|
||||
arbeitet direkt auf dem System-Kalender-Provider — jede Quelle, die mit
|
||||
deinem Gerät synchronisiert ist (Nextcloud über DAVx5, Google, lokal,
|
||||
WebCal-Subscriptions), erscheint automatisch, und deine Änderungen
|
||||
synchronisieren auf demselben Weg zurück.
|
||||
Calendula ist eine moderne, quelloffene Kalender-App für Android. Sie arbeitet direkt auf dem System-Kalender-Provider — jede Quelle, die mit deinem Gerät synchronisiert ist (Nextcloud über DAVx5, Google, lokal, WebCal-Subscriptions), erscheint automatisch, und deine Änderungen synchronisieren auf demselben Weg zurück.
|
||||
|
||||
Termine erstellen, bearbeiten und löschen — auch wiederkehrende, mit
|
||||
wählbarer Reichweite (nur dieser Termin / dieser und alle folgenden / ganze
|
||||
Serie) und einem einfachen Wiederholungs-Picker. Erinnerungen stellt
|
||||
Calendula selbst als Benachrichtigung zu — ein Tipp darauf öffnet den
|
||||
Termin.
|
||||
Termine erstellen, bearbeiten und löschen — auch wiederkehrende, mit wählbarer Reichweite (nur dieser Termin / dieser und alle folgenden / ganze Serie) und einem einfachen Wiederholungs-Picker. Erinnerungen stellt Calendula selbst als Benachrichtigung zu — ein Tipp darauf öffnet den Termin.
|
||||
|
||||
Optional lassen sich Geburtstage, Jahrestage und weitere besondere Tage
|
||||
deiner Kontakte im Kalender anzeigen. Du schaltest das selbst ein; Kontakte
|
||||
werden nur auf deinem Gerät gelesen, nie hochgeladen und nie verändert —
|
||||
Calendula spiegelt die Daten lediglich in lokale Kalender, die du voll
|
||||
kontrollierst.
|
||||
Optional lassen sich Geburtstage, Jahrestage und weitere besondere Tage deiner Kontakte im Kalender anzeigen. Du schaltest das selbst ein; Kontakte werden nur auf deinem Gerät gelesen, nie hochgeladen und nie verändert — Calendula spiegelt die Daten lediglich in lokale Kalender, die du voll kontrollierst.
|
||||
|
||||
Der Unterschied liegt im Design: echtes Material 3 Expressive durchgehend,
|
||||
mit Dynamic Color, expressiven Animationen und neuen Shape-Sprachen.
|
||||
Der Unterschied liegt im Design: echtes Material 3 Expressive durchgehend, mit Dynamic Color, expressiven Animationen und neuen Shape-Sprachen.
|
||||
|
||||
Datenschutz: keinerlei Telemetrie, kein Tracking, kein Netzwerkzugriff —
|
||||
deine Daten bleiben auf dem Gerät.
|
||||
Datenschutz: keinerlei Telemetrie, kein Tracking, kein Netzwerkzugriff — deine Daten bleiben auf dem Gerät.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
@@ -1,2 +0,0 @@
|
||||
Fixed
|
||||
• Week and day view: tapping an empty slot now creates the event at the hour you tapped, even after zooming the timeline or changing the hour height.
|
||||
@@ -1,6 +0,0 @@
|
||||
New
|
||||
• Drag an event to reschedule it — press and hold it in month, week or day view and drop it on another time or day. Recurring events ask what the move applies to.
|
||||
• Delete several search results at once: long-press a hit to start selecting, then delete them in one action.
|
||||
|
||||
Changed
|
||||
• First launch is now a short wizard. It can also set up automatic backup and let you pick the view Calendula opens on, both with previews.
|
||||
@@ -1,3 +0,0 @@
|
||||
Added
|
||||
• Drag to reschedule can now be turned off: Settings → Views → “Drag to reschedule”. It stays on by default; switched off, events can no longer be picked up in the month, week or day view.
|
||||
• Calendula now speaks Brazilian Portuguese, thanks to a community translation. Pick it under Settings → Language.
|
||||
@@ -1,8 +0,0 @@
|
||||
Fixed
|
||||
• Tapping an event in month view now opens the event instead of its day.
|
||||
• An edit shows straight away when you re-open the event.
|
||||
• The month widget's arrows no longer die after a few taps — an oversized update was killing the launcher's widget host.
|
||||
• Jump-to-today in seamless weeks lands on the current week, and day/week view no longer run flush against the right edge.
|
||||
|
||||
Changed
|
||||
• A meeting you declined is struck through everywhere and no longer reminds you.
|
||||
@@ -1,2 +0,0 @@
|
||||
Fixed
|
||||
• A custom Agenda range no longer crashes the app in French. Choosing a custom range — or just typing a number into that field — closed the app on any phone set to French, and only a range of exactly one day escaped it. Other languages were never affected.
|
||||
@@ -1,20 +1,9 @@
|
||||
Calendula is a modern, open-source calendar app for Android. It works
|
||||
directly on the system calendar provider, so any source synced to your
|
||||
device — Nextcloud via DAVx5, Google, local, WebCal subscriptions — shows up
|
||||
automatically, and changes you make sync back the same way.
|
||||
Calendula is a modern, open-source calendar app for Android. It works directly on the system calendar provider, so any source synced to your device — Nextcloud via DAVx5, Google, local, WebCal subscriptions — shows up automatically, and changes you make sync back the same way.
|
||||
|
||||
Create, edit and delete events, including recurring events with scoped
|
||||
changes (only this event / this and all following / the whole series) and a
|
||||
simple repeat picker. Calendula also delivers your event reminders as
|
||||
notifications — tap one and you're on the event.
|
||||
Create, edit and delete events, including recurring events with scoped changes (only this event / this and all following / the whole series) and a simple repeat picker. Calendula also delivers your event reminders as notifications — tap one and you're on the event.
|
||||
|
||||
Optionally, show your contacts' birthdays, anniversaries and other special
|
||||
dates in your calendar. You turn this on yourself; contacts are read only on
|
||||
your device, are never uploaded, and are never changed — Calendula only
|
||||
mirrors the dates into local calendars you fully control.
|
||||
Optionally, show your contacts' birthdays, anniversaries and other special dates in your calendar. You turn this on yourself; contacts are read only on your device, are never uploaded, and are never changed — Calendula only mirrors the dates into local calendars you fully control.
|
||||
|
||||
The differentiator is the design: real Material 3 Expressive throughout,
|
||||
with dynamic color, expressive motion, and expressive shapes.
|
||||
The differentiator is the design: real Material 3 Expressive throughout, with dynamic color, expressive motion, and expressive shapes.
|
||||
|
||||
Privacy: zero telemetry, no analytics, no network access — your data never
|
||||
leaves the device.
|
||||
Privacy: zero telemetry, no analytics, no network access — your data never leaves the device.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 18 KiB |
@@ -1,25 +1,9 @@
|
||||
Calendula es una aplicación de calendario moderna y de código abierto
|
||||
para Android. Funciona directamente sobre el proveedor de calendario del
|
||||
sistema: cualquier origen sincronizado en tu dispositivo — Nextcloud
|
||||
mediante DAVx5, Google, calendarios locales, suscripciones WebCal —
|
||||
aparece automáticamente, y los cambios que hagas se sincronizan de vuelta
|
||||
del mismo modo.
|
||||
Calendula es una aplicación de calendario moderna y de código abierto para Android. Funciona directamente sobre el proveedor de calendario del sistema: cualquier origen sincronizado en tu dispositivo — Nextcloud mediante DAVx5, Google, calendarios locales, suscripciones WebCal — aparece automáticamente, y los cambios que hagas se sincronizan de vuelta del mismo modo.
|
||||
|
||||
Crea, edita y elimina eventos, incluidos los recurrentes con cambios
|
||||
acotados (solo este evento / este y todos los siguientes / toda la serie)
|
||||
y un sencillo selector de repetición. Calendula también entrega los
|
||||
recordatorios de tus eventos como notificaciones: toca una y estarás en
|
||||
el evento.
|
||||
Crea, edita y elimina eventos, incluidos los recurrentes con cambios acotados (solo este evento / este y todos los siguientes / toda la serie) y un sencillo selector de repetición. Calendula también entrega los recordatorios de tus eventos como notificaciones: toca una y estarás en el evento.
|
||||
|
||||
Si quieres, muestra en tu calendario los cumpleaños, aniversarios y otras
|
||||
fechas especiales de tus contactos. Tú mismo lo activas; los contactos se
|
||||
leen solo en tu dispositivo, nunca se suben y nunca se modifican —
|
||||
Calendula solo refleja las fechas en calendarios locales que controlas
|
||||
por completo.
|
||||
Si quieres, muestra en tu calendario los cumpleaños, aniversarios y otras fechas especiales de tus contactos. Tú mismo lo activas; los contactos se leen solo en tu dispositivo, nunca se suben y nunca se modifican — Calendula solo refleja las fechas en calendarios locales que controlas por completo.
|
||||
|
||||
El factor diferenciador es el diseño: auténtico Material 3 Expressive en
|
||||
toda la aplicación, con Dynamic Color, movimiento expresivo y formas
|
||||
expresivas.
|
||||
El factor diferenciador es el diseño: auténtico Material 3 Expressive en toda la aplicación, con Dynamic Color, movimiento expresivo y formas expresivas.
|
||||
|
||||
Privacidad: cero telemetría, sin analíticas, sin acceso a la red — tus
|
||||
datos nunca salen del dispositivo.
|
||||
Privacidad: cero telemetría, sin analíticas, sin acceso a la red — tus datos nunca salen del dispositivo.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,9 @@
|
||||
Calendula est une application de calendrier moderne et open source pour Android. Elle fonctionne directement sur le fournisseur de calendrier du système : toute source synchronisée sur votre appareil — Nextcloud via DAVx5, Google, calendriers locaux, abonnements WebCal — apparaît automatiquement, et vos modifications sont synchronisées en retour de la même manière.
|
||||
|
||||
Créez, modifiez et supprimez des événements, y compris des événements récurrents avec des modifications ciblées (uniquement cet événement / cet événement et les suivants / toute la série) et un sélecteur de répétition simple. Calendula affiche aussi vos rappels sous forme de notifications — touchez-en une pour ouvrir l'événement.
|
||||
|
||||
Si vous le souhaitez, affichez dans votre calendrier les anniversaires, anniversaires de mariage et autres dates importantes de vos contacts. C'est vous qui l'activez ; les contacts sont lus uniquement sur votre appareil, ne sont jamais envoyés et jamais modifiés — Calendula se contente de reporter les dates dans des calendriers locaux que vous contrôlez entièrement.
|
||||
|
||||
Ce qui fait la différence, c'est le design : du vrai Material 3 Expressive partout, avec couleurs dynamiques, animations expressives et formes expressives.
|
||||
|
||||
Confidentialité : aucune télémétrie, aucune analyse, aucun accès réseau — vos données ne quittent jamais l'appareil.
|
||||
@@ -0,0 +1 @@
|
||||
Un calendrier Material 3 Expressive moderne pour Android.
|
||||
@@ -0,0 +1 @@
|
||||
Calendula
|
||||
@@ -0,0 +1,9 @@
|
||||
A Calendula egy modern, nyílt forráskódú naptáralkalmazás Androidra. Közvetlenül a rendszer naptárszolgáltatójával dolgozik, így bármely, az eszközödre szinkronizált forrás — Nextcloud a DAVx5-ön keresztül, Google, helyi naptárak, WebCal-előfizetések — automatikusan megjelenik, és a módosításaid ugyanígy szinkronizálódnak vissza.
|
||||
|
||||
Hozz létre, szerkessz és törölj eseményeket, ismétlődőket is, a módosítás hatókörének megválasztásával (csak ez az esemény / ez és az összes következő / a teljes sorozat) és egyszerű ismétlésválasztóval. A Calendula az emlékeztetőidet értesítésként is megjeleníti — egy koppintás, és már az eseménynél is vagy.
|
||||
|
||||
Ha szeretnéd, a naptárban megjelenítheted a névjegyeid születésnapjait, évfordulóit és más különleges dátumait. Ezt te magad kapcsolod be; a névjegyeket csak az eszközön olvassa, soha nem tölti fel és soha nem módosítja — a Calendula csupán átmásolja a dátumokat a teljesen általad kezelt helyi naptárakba.
|
||||
|
||||
A különbséget a dizájn adja: valódi Material 3 Expressive mindenhol, dinamikus színekkel, kifejező mozgással és kifejező formákkal.
|
||||
|
||||
Adatvédelem: nincs telemetria, nincs analitika, nincs hálózati hozzáférés — az adataid soha nem hagyják el az eszközt.
|
||||
@@ -0,0 +1 @@
|
||||
Modern, Material 3 Expressive stílusú naptár Androidra.
|
||||
@@ -0,0 +1 @@
|
||||
Calendula
|
||||
@@ -1,24 +1,9 @@
|
||||
Calendula è un'app di calendario moderna e open source per Android.
|
||||
Funziona direttamente sul provider di calendario di sistema: qualsiasi
|
||||
origine sincronizzata sul tuo dispositivo — Nextcloud tramite DAVx5,
|
||||
Google, calendari locali, iscrizioni WebCal — compare automaticamente, e
|
||||
le modifiche che apporti vengono sincronizzate a ritroso allo stesso
|
||||
modo.
|
||||
Calendula è un'app di calendario moderna e open source per Android. Funziona direttamente sul provider di calendario di sistema: qualsiasi origine sincronizzata sul tuo dispositivo — Nextcloud tramite DAVx5, Google, calendari locali, iscrizioni WebCal — compare automaticamente, e le modifiche che apporti vengono sincronizzate a ritroso allo stesso modo.
|
||||
|
||||
Crea, modifica ed elimina eventi, compresi quelli ricorrenti con
|
||||
modifiche mirate (solo questo evento / questo e tutti i successivi /
|
||||
l'intera serie) e un semplice selettore di ripetizione. Calendula
|
||||
recapita anche i promemoria dei tuoi eventi come notifiche: ne tocchi una
|
||||
e sei subito sull'evento.
|
||||
Crea, modifica ed elimina eventi, compresi quelli ricorrenti con modifiche mirate (solo questo evento / questo e tutti i successivi / l'intera serie) e un semplice selettore di ripetizione. Calendula recapita anche i promemoria dei tuoi eventi come notifiche: ne tocchi una e sei subito sull'evento.
|
||||
|
||||
Se vuoi, mostra nel calendario i compleanni, gli anniversari e le altre
|
||||
date speciali dei tuoi contatti. Sei tu ad attivarlo; i contatti vengono
|
||||
letti solo sul tuo dispositivo, non vengono mai caricati e non vengono
|
||||
mai modificati — Calendula si limita a rispecchiare le date in calendari
|
||||
locali che controlli completamente.
|
||||
Se vuoi, mostra nel calendario i compleanni, gli anniversari e le altre date speciali dei tuoi contatti. Sei tu ad attivarlo; i contatti vengono letti solo sul tuo dispositivo, non vengono mai caricati e non vengono mai modificati — Calendula si limita a rispecchiare le date in calendari locali che controlli completamente.
|
||||
|
||||
La differenza sta nel design: vero Material 3 Expressive ovunque, con
|
||||
Dynamic Color, animazioni espressive e forme espressive.
|
||||
La differenza sta nel design: vero Material 3 Expressive ovunque, con Dynamic Color, animazioni espressive e forme espressive.
|
||||
|
||||
Privacy: zero telemetria, nessuna analisi, nessun accesso alla rete — i
|
||||
tuoi dati non lasciano mai il dispositivo.
|
||||
Privacy: zero telemetria, nessuna analisi, nessun accesso alla rete — i tuoi dati non lasciano mai il dispositivo.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,9 @@
|
||||
Calendula は、Android 向けのモダンなオープンソースのカレンダーアプリです。システムのカレンダープロバイダ上で直接動作するため、端末に同期されているあらゆるソース(DAVx5 経由の Nextcloud、Google、ローカル、WebCal の購読)が自動的に表示され、加えた変更も同じ経路で同期されます。
|
||||
|
||||
予定の作成・編集・削除に対応。繰り返しの予定も、変更範囲(この予定のみ / この予定以降すべて / シリーズ全体)を選んで編集でき、シンプルな繰り返し設定も使えます。予定のリマインダーは通知として届き、タップするとその予定が開きます。
|
||||
|
||||
必要に応じて、連絡先の誕生日や記念日などの特別な日をカレンダーに表示できます。この機能はご自身でオンにするものです。連絡先は端末上でのみ読み取られ、アップロードや変更は一切行われません。Calendula は日付を、あなたが完全に管理できるローカルカレンダーに反映するだけです。
|
||||
|
||||
最大の特長はデザインです。あらゆる場面で本物の Material 3 Expressive を採用し、ダイナミックカラー、表現豊かなモーションとシェイプを備えています。
|
||||
|
||||
プライバシー:テレメトリなし、解析なし、ネットワークアクセスなし。あなたのデータが端末の外に出ることはありません。
|
||||
@@ -0,0 +1 @@
|
||||
Material 3 Expressive デザインのモダンな Android カレンダー。
|
||||
@@ -0,0 +1 @@
|
||||
Calendula
|
||||
@@ -0,0 +1,9 @@
|
||||
Calendula to nowoczesna aplikacja kalendarza open source na Androida. Działa bezpośrednio na systemowym dostawcy kalendarza, więc każde źródło zsynchronizowane z urządzeniem — Nextcloud przez DAVx5, Google, kalendarze lokalne, subskrypcje WebCal — pojawia się automatycznie, a wprowadzone zmiany synchronizują się z powrotem tą samą drogą.
|
||||
|
||||
Twórz, edytuj i usuwaj wydarzenia, także cykliczne, ze zmianami o wybranym zakresie (tylko to wydarzenie / to i wszystkie następne / cała seria) oraz prostym wyborem powtarzania. Calendula dostarcza też przypomnienia jako powiadomienia — dotknij jednego, a otworzy się wydarzenie.
|
||||
|
||||
Opcjonalnie możesz wyświetlać w kalendarzu urodziny, rocznice i inne ważne daty swoich kontaktów. Włączasz to samodzielnie; kontakty są odczytywane tylko na urządzeniu, nigdy nie są wysyłane ani zmieniane — Calendula jedynie przenosi daty do lokalnych kalendarzy, nad którymi masz pełną kontrolę.
|
||||
|
||||
Tym, co ją wyróżnia, jest wygląd: prawdziwy Material 3 Expressive w każdym miejscu, z dynamicznymi kolorami, ekspresyjnym ruchem i ekspresyjnymi kształtami.
|
||||
|
||||
Prywatność: zero telemetrii, zero analityki, brak dostępu do sieci — Twoje dane nigdy nie opuszczają urządzenia.
|
||||
@@ -0,0 +1 @@
|
||||
Nowoczesny kalendarz w stylu Material 3 Expressive na Androida.
|
||||
@@ -0,0 +1 @@
|
||||
Calendula
|
||||
@@ -0,0 +1,9 @@
|
||||
Calendula é um app de calendário moderno e de código aberto para Android. Ele funciona diretamente sobre o provedor de calendário do sistema, então qualquer fonte sincronizada no seu aparelho — Nextcloud via DAVx5, Google, calendários locais, assinaturas WebCal — aparece automaticamente, e as alterações que você faz são sincronizadas de volta do mesmo jeito.
|
||||
|
||||
Crie, edite e exclua eventos, inclusive eventos recorrentes com alterações por escopo (só este evento / este e os seguintes / a série inteira) e um seletor de repetição simples. O Calendula também entrega seus lembretes como notificações — toque em uma e você vai direto para o evento.
|
||||
|
||||
Se quiser, mostre no calendário os aniversários, datas comemorativas e outras datas especiais dos seus contatos. Você mesmo ativa isso; os contatos são lidos apenas no seu aparelho, nunca são enviados e nunca são alterados — o Calendula só espelha as datas em calendários locais que você controla totalmente.
|
||||
|
||||
O diferencial é o design: Material 3 Expressive de verdade em todo o app, com cores dinâmicas, movimento expressivo e formas expressivas.
|
||||
|
||||
Privacidade: zero telemetria, nenhuma análise, nenhum acesso à rede — seus dados nunca saem do aparelho.
|
||||
@@ -0,0 +1 @@
|
||||
Um calendário moderno em Material 3 Expressive para Android.
|
||||
@@ -0,0 +1 @@
|
||||
Calendula
|
||||
@@ -0,0 +1,9 @@
|
||||
O Calendula é uma aplicação de calendário moderna e de código aberto para Android. Funciona diretamente sobre o fornecedor de calendário do sistema, pelo que qualquer origem sincronizada no seu dispositivo — Nextcloud através do DAVx5, Google, calendários locais, subscrições WebCal — aparece automaticamente, e as alterações que fizer são sincronizadas de volta da mesma forma.
|
||||
|
||||
Crie, edite e elimine eventos, incluindo eventos recorrentes com alterações por âmbito (apenas este evento / este e os seguintes / toda a série) e um seletor de repetição simples. O Calendula também entrega os seus lembretes como notificações — toque numa e abre o evento.
|
||||
|
||||
Opcionalmente, mostre no calendário os aniversários, datas comemorativas e outras datas especiais dos seus contactos. É o utilizador que ativa esta opção; os contactos são lidos apenas no dispositivo, nunca são enviados nem alterados — o Calendula limita-se a espelhar as datas em calendários locais que controla totalmente.
|
||||
|
||||
O que o distingue é o design: verdadeiro Material 3 Expressive em toda a aplicação, com cores dinâmicas, movimento expressivo e formas expressivas.
|
||||
|
||||
Privacidade: zero telemetria, nenhuma análise, nenhum acesso à rede — os seus dados nunca saem do dispositivo.
|
||||
@@ -0,0 +1 @@
|
||||
Um calendário moderno em Material 3 Expressive para Android.
|
||||
@@ -0,0 +1 @@
|
||||
Calendula
|
||||
@@ -0,0 +1,9 @@
|
||||
Calendula — современное приложение-календарь с открытым исходным кодом для Android. Оно работает напрямую с системным поставщиком календарей, поэтому любой источник, синхронизированный с вашим устройством, — Nextcloud через DAVx5, Google, локальные календари, подписки WebCal — появляется автоматически, а ваши изменения синхронизируются обратно тем же путём.
|
||||
|
||||
Создавайте, изменяйте и удаляйте события, в том числе повторяющиеся — с выбором области изменений (только это событие / это и все последующие / вся серия) и простым выбором повторения. Calendula также показывает напоминания о событиях в виде уведомлений — нажмите на уведомление, и откроется событие.
|
||||
|
||||
При желании в календаре можно показывать дни рождения, годовщины и другие памятные даты ваших контактов. Эту функцию вы включаете сами; контакты читаются только на устройстве, никуда не отправляются и никогда не изменяются — Calendula лишь переносит даты в локальные календари, которые полностью под вашим контролем.
|
||||
|
||||
Главное отличие — дизайн: настоящий Material 3 Expressive во всём, с динамическими цветами, выразительной анимацией и выразительными формами.
|
||||
|
||||
Конфиденциальность: никакой телеметрии, никакой аналитики, никакого доступа к сети — ваши данные никогда не покидают устройство.
|
||||
@@ -0,0 +1 @@
|
||||
Современный календарь в стиле Material 3 Expressive для Android.
|
||||
@@ -0,0 +1 @@
|
||||
Calendula
|
||||
@@ -0,0 +1,9 @@
|
||||
Calendula je moderná open-source kalendárová aplikácia pre Android. Pracuje priamo so systémovým poskytovateľom kalendára, takže sa automaticky zobrazí akýkoľvek zdroj synchronizovaný do vášho zariadenia — Nextcloud cez DAVx5, Google, miestne kalendáre, odbery WebCal — a vaše zmeny sa rovnakou cestou synchronizujú späť.
|
||||
|
||||
Vytvárajte, upravujte a odstraňujte udalosti vrátane opakujúcich sa, s voľbou rozsahu zmeny (len táto udalosť / táto a všetky nasledujúce / celá séria) a jednoduchým výberom opakovania. Calendula tiež doručuje pripomienky udalostí ako upozornenia — ťuknite na upozornenie a otvorí sa udalosť.
|
||||
|
||||
Voliteľne môžete v kalendári zobraziť narodeniny, výročia a ďalšie významné dátumy svojich kontaktov. Zapínate si to sami; kontakty sa čítajú iba v zariadení, nikdy sa neodosielajú a nikdy sa nemenia — Calendula dátumy len zrkadlí do miestnych kalendárov, ktoré máte plne pod kontrolou.
|
||||
|
||||
Rozdiel robí dizajn: skutočný Material 3 Expressive všade, s dynamickými farbami, výrazným pohybom a výraznými tvarmi.
|
||||
|
||||
Súkromie: žiadna telemetria, žiadna analytika, žiadny prístup k sieti — vaše údaje nikdy neopustia zariadenie.
|
||||
@@ -0,0 +1 @@
|
||||
Moderný kalendár v štýle Material 3 Expressive pre Android.
|
||||
@@ -0,0 +1 @@
|
||||
Calendula
|
||||
@@ -0,0 +1,9 @@
|
||||
Calendula 是一款现代、开源的 Android 日历应用。它直接基于系统日历提供程序工作,因此设备上同步的任何来源——通过 DAVx5 同步的 Nextcloud、Google、本地日历、WebCal 订阅——都会自动显示,你所做的更改也会通过同样的方式同步回去。
|
||||
|
||||
创建、编辑和删除日程,包括可按范围修改的重复日程(仅此日程 / 此日程及之后所有 / 整个系列),以及简单的重复规则选择器。Calendula 还会以通知形式提醒你的日程——点按通知即可直接打开该日程。
|
||||
|
||||
你还可以选择在日历中显示联系人的生日、纪念日和其他特殊日期。此功能需要你自行开启;联系人仅在设备上读取,绝不会上传,也绝不会被修改——Calendula 只会把这些日期同步到完全由你掌控的本地日历中。
|
||||
|
||||
与众不同之处在于设计:全面采用真正的 Material 3 Expressive,带来动态配色、富有表现力的动效和形状。
|
||||
|
||||
隐私:零遥测、无分析、无网络访问——你的数据永远不会离开设备。
|
||||
@@ -0,0 +1 @@
|
||||
一款采用 Material 3 Expressive 设计的现代 Android 日历。
|
||||
@@ -0,0 +1 @@
|
||||
Calendula
|
||||
@@ -0,0 +1,20 @@
|
||||
# Android resource qualifier -> store listing directory under metadata/android/.
|
||||
# Store codes must be ones Google Play accepts; F-Droid takes any of them.
|
||||
# `default` is app/src/main/res/values/ (English).
|
||||
# Checked by scripts/check_store_listing.py.
|
||||
default en-US
|
||||
ar ar
|
||||
be be
|
||||
cs cs-CZ
|
||||
de de-DE
|
||||
es es-ES
|
||||
fr fr-FR
|
||||
hu hu-HU
|
||||
it it-IT
|
||||
ja ja-JP
|
||||
pl pl-PL
|
||||
pt pt-PT
|
||||
pt-rBR pt-BR
|
||||
ru ru-RU
|
||||
sk sk
|
||||
zh-rCN zh-CN
|
||||
@@ -0,0 +1,168 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate fastlane/metadata/android against Google Play's listing rules.
|
||||
|
||||
The tree is pushed to Play on every release (and harvested by F-Droid), so a
|
||||
field over its cap, an image Play rejects, or a locale Play doesn't know would
|
||||
fail the upload after the release has shipped everywhere else.
|
||||
|
||||
- every locale directory is listed in fastlane/store-locales.txt, and every
|
||||
app language (res/values-*) has an entry there and a directory
|
||||
- title / short / full description exist, are non-empty and within Play's caps,
|
||||
and the full description isn't hard-wrapped
|
||||
- icon: 512x512 32-bit PNG; featureGraphic: 1024x500 JPEG or 24-bit PNG
|
||||
- screenshots: JPEG or 24-bit PNG, sides 320..3840, long edge <= 2x short,
|
||||
2..8 per type
|
||||
"""
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
META = ROOT / "fastlane/metadata/android"
|
||||
MAPPING = ROOT / "fastlane/store-locales.txt"
|
||||
RES = ROOT / "app/src/main/res"
|
||||
|
||||
TEXT_LIMITS = {"title.txt": 30, "short_description.txt": 80, "full_description.txt": 4000}
|
||||
LISTING_ENTRIES = set(TEXT_LIMITS) | {"changelogs", "images", "video.txt"}
|
||||
SCREENSHOT_DIRS = {"phoneScreenshots", "sevenInchScreenshots", "tenInchScreenshots",
|
||||
"tvScreenshots", "wearScreenshots"}
|
||||
IMAGE_EXTS = {".png", ".jpg", ".jpeg"}
|
||||
|
||||
errors = []
|
||||
|
||||
|
||||
def error(msg):
|
||||
errors.append(msg)
|
||||
|
||||
|
||||
def rel(path):
|
||||
return path.relative_to(ROOT)
|
||||
|
||||
|
||||
def image_info(path):
|
||||
"""(width, height, has_alpha, bits_per_pixel) for a PNG or baseline JPEG."""
|
||||
data = path.read_bytes()
|
||||
if data[:8] == b"\x89PNG\r\n\x1a\n":
|
||||
width, height, depth, color_type = struct.unpack(">IIBB", data[16:26])
|
||||
channels = {0: 1, 2: 3, 3: 1, 4: 2, 6: 4}.get(color_type, 0)
|
||||
has_alpha = color_type in (4, 6) or b"tRNS" in data[:data.find(b"IDAT")]
|
||||
return width, height, has_alpha, depth * channels
|
||||
if data[:2] == b"\xff\xd8":
|
||||
i = 2
|
||||
while i + 9 < len(data):
|
||||
if data[i] != 0xFF:
|
||||
i += 1
|
||||
continue
|
||||
marker = data[i + 1]
|
||||
length = struct.unpack(">H", data[i + 2:i + 4])[0]
|
||||
if 0xC0 <= marker <= 0xCF and marker not in (0xC4, 0xC8, 0xCC):
|
||||
height, width = struct.unpack(">HH", data[i + 5:i + 9])
|
||||
return width, height, False, 24
|
||||
i += 2 + length
|
||||
return None
|
||||
|
||||
|
||||
def check_mapping():
|
||||
mapping = {}
|
||||
for line in MAPPING.read_text(encoding="utf-8").splitlines():
|
||||
line = line.split("#", 1)[0].strip()
|
||||
if line:
|
||||
qualifier, store = line.split()
|
||||
mapping[qualifier] = store
|
||||
|
||||
app_langs = {"default"} | {
|
||||
d.name[len("values-"):] for d in RES.glob("values-*")
|
||||
if re.fullmatch(r"values-[a-z]{2,3}(-r[A-Z]{2})?", d.name)
|
||||
}
|
||||
for q in sorted(app_langs - mapping.keys()):
|
||||
error(f"app ships values-{q} but {rel(MAPPING)} has no store locale for it")
|
||||
for q in sorted(mapping.keys() - app_langs):
|
||||
error(f"{rel(MAPPING)} maps '{q}' but the app has no values-{q}")
|
||||
|
||||
stores = set(mapping.values())
|
||||
dirs = {d.name for d in META.iterdir() if d.is_dir()}
|
||||
for d in sorted(dirs - stores):
|
||||
error(f"{rel(META / d)} is not a mapped store locale (see {rel(MAPPING)})")
|
||||
for d in sorted(stores - dirs):
|
||||
error(f"no listing for {d} — create {rel(META / d)}")
|
||||
return sorted(dirs & stores)
|
||||
|
||||
|
||||
def check_text(locale_dir):
|
||||
for name, limit in TEXT_LIMITS.items():
|
||||
f = locale_dir / name
|
||||
if not f.is_file():
|
||||
error(f"{rel(f)} is missing")
|
||||
continue
|
||||
text = f.read_text(encoding="utf-8").strip()
|
||||
if not text:
|
||||
error(f"{rel(f)} is empty")
|
||||
elif len(text) > limit:
|
||||
error(f"{rel(f)} is {len(text)} chars (Play limit {limit})")
|
||||
if name == "full_description.txt" and re.search(r"[^\n]\n(?![\n•*-])", text):
|
||||
error(f"{rel(f)} is hard-wrapped; Play shows every newline, so keep a paragraph on one line")
|
||||
for entry in locale_dir.iterdir():
|
||||
if entry.name not in LISTING_ENTRIES:
|
||||
error(f"{rel(entry)} is not a listing file supply knows")
|
||||
|
||||
|
||||
def check_image(f, kind):
|
||||
info = image_info(f)
|
||||
if f.suffix.lower() not in IMAGE_EXTS or info is None:
|
||||
error(f"{rel(f)} is not a PNG or JPEG")
|
||||
return
|
||||
width, height, has_alpha, bpp = info
|
||||
if kind == "icon":
|
||||
if (width, height) != (512, 512) or bpp != 32 or f.suffix.lower() != ".png":
|
||||
error(f"{rel(f)} is {width}x{height} {bpp}-bit; Play wants a 512x512 32-bit PNG")
|
||||
elif kind == "featureGraphic":
|
||||
if (width, height) != (1024, 500):
|
||||
error(f"{rel(f)} is {width}x{height}; Play wants exactly 1024x500")
|
||||
if has_alpha:
|
||||
error(f"{rel(f)} has an alpha channel; Play wants JPEG or 24-bit PNG")
|
||||
else:
|
||||
short, long = sorted((width, height))
|
||||
if short < 320 or long > 3840:
|
||||
error(f"{rel(f)} is {width}x{height}; each side must be 320..3840")
|
||||
if long > 2 * short:
|
||||
error(f"{rel(f)} is {width}x{height}; the long edge may be at most 2x the short edge")
|
||||
if has_alpha:
|
||||
error(f"{rel(f)} has an alpha channel; Play wants JPEG or 24-bit PNG")
|
||||
|
||||
|
||||
def check_images(locale_dir):
|
||||
images = locale_dir / "images"
|
||||
if not images.is_dir():
|
||||
return
|
||||
for entry in sorted(images.iterdir()):
|
||||
if entry.is_dir():
|
||||
if entry.name not in SCREENSHOT_DIRS:
|
||||
error(f"{rel(entry)} is not a screenshot type supply knows")
|
||||
continue
|
||||
shots = sorted(p for p in entry.iterdir() if p.is_file())
|
||||
if not 2 <= len(shots) <= 8:
|
||||
error(f"{rel(entry)} has {len(shots)} images; Play takes 2..8")
|
||||
for shot in shots:
|
||||
check_image(shot, "screenshot")
|
||||
elif entry.stem in ("icon", "featureGraphic"):
|
||||
check_image(entry, entry.stem)
|
||||
else:
|
||||
error(f"{rel(entry)} is not an image supply knows (icon, featureGraphic, *Screenshots/)")
|
||||
|
||||
|
||||
def main():
|
||||
for locale in check_mapping():
|
||||
check_text(META / locale)
|
||||
check_images(META / locale)
|
||||
if errors:
|
||||
for e in errors:
|
||||
print(f"ERROR: {e}", file=sys.stderr)
|
||||
print(f"\n{len(errors)} store listing problem(s).", file=sys.stderr)
|
||||
return 1
|
||||
print("Store listing OK.")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -15,6 +15,7 @@
|
||||
# full_description.txt -> description.txt
|
||||
# title.txt -> name.txt
|
||||
# images/icon.png -> icon.png
|
||||
# images/featureGraphic.png -> featureGraphic.png
|
||||
# images/phoneScreenshots/* -> phoneScreenshots/*
|
||||
# changelogs/<versionCode>.txt -> changelogs/<versionCode>.txt
|
||||
# (changelogs are seeded into the fastlane tree by
|
||||
@@ -33,6 +34,7 @@ for locdir in "$SRC"/*/; do
|
||||
[ -f "$locdir/full_description.txt" ] && cp "$locdir/full_description.txt" "$dst/description.txt"
|
||||
[ -f "$locdir/title.txt" ] && cp "$locdir/title.txt" "$dst/name.txt"
|
||||
[ -f "$locdir/images/icon.png" ] && cp "$locdir/images/icon.png" "$dst/icon.png"
|
||||
[ -f "$locdir/images/featureGraphic.png" ] && cp "$locdir/images/featureGraphic.png" "$dst/featureGraphic.png"
|
||||
if [ -d "$locdir/images/phoneScreenshots" ]; then
|
||||
mkdir -p "$dst/phoneScreenshots"
|
||||
cp "$locdir"images/phoneScreenshots/* "$dst/phoneScreenshots/"
|
||||
|
||||
Reference in New Issue
Block a user