Centralise the app's motion vocabulary in CalendarTransitions.kt and route every surface through it so animation is consistent app-wide: - Shared expand/collapse, list-item and fade-through helpers; the event-edit expand pattern is now the shared one (no duplicate). - Settings reminder-override rows and the reminder Custom field now expand/ collapse instead of bare-fading. - Search and agenda rows animate (fade/relocate) via animateItem. - Month/week/day slide and the onboarding gates honour the new helpers. - View switching (month/week/day/agenda) now fades through instead of snapping — lateral navigation per M3, while in-view paging keeps its slide. Add full predictive-back support: - enableOnBackInvokedCallback in the manifest. - New Modifier.predictiveBack(onBack) drives the standard preview transform (scale/shift/round) following the back gesture; applied to detail, edit, search, settings (+ sub-screens & calendar manager via CollapsingScaffold), the calendar editor and import — each keeping its existing back semantics. Reduced-motion guardrail throughout: rememberReduceMotion() (reads the OS "remove animations" setting, which Compose ignores by default) collapses spatial motion to a quick fade and skips the back preview. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
198 lines
9.0 KiB
XML
198 lines
9.0 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||
xmlns:tools="http://schemas.android.com/tools">
|
||
|
||
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
||
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
|
||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||
<!--
|
||
Lets the "Reliable delivery" setting open the direct system dialog to
|
||
exempt Calendula from battery optimisation (so reminder broadcasts aren't
|
||
delayed by Doze). Used only to launch that dialog; falls back to the
|
||
battery-optimisation list if the OS declines the direct intent.
|
||
-->
|
||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||
|
||
<!--
|
||
Re-fire a snoozed reminder at an exact time (the calendar provider won't —
|
||
its alert is already fired). USE_EXACT_ALARM is auto-granted to calendar
|
||
apps on API 33+; SCHEDULE_EXACT_ALARM covers API 31–32 (user-revocable,
|
||
with an inexact fallback if withheld). F-Droid-clean: no Play allowlisting.
|
||
-->
|
||
<uses-permission
|
||
android:name="android.permission.SCHEDULE_EXACT_ALARM"
|
||
android:maxSdkVersion="32" />
|
||
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
|
||
|
||
<!-- Package visibility (Android 11+): without this, getLaunchIntentForPackage
|
||
returns null and the calendar manager's per-account "manage" button can't
|
||
open the source sync app (DAVx5, ICSx5, Google Calendar, …). The LAUNCHER
|
||
intent makes launchable apps visible so we can launch whichever app owns a
|
||
calendar account's authenticator. -->
|
||
<queries>
|
||
<intent>
|
||
<action android:name="android.intent.action.MAIN" />
|
||
<category android:name="android.intent.category.LAUNCHER" />
|
||
</intent>
|
||
</queries>
|
||
|
||
<application
|
||
android:name=".CalendulaApp"
|
||
android:allowBackup="true"
|
||
android:enableOnBackInvokedCallback="true"
|
||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||
android:fullBackupContent="@xml/backup_rules"
|
||
android:icon="@mipmap/ic_launcher"
|
||
android:label="@string/app_name"
|
||
android:localeConfig="@xml/locales_config"
|
||
android:roundIcon="@mipmap/ic_launcher_round"
|
||
android:supportsRtl="true"
|
||
android:theme="@style/Theme.Calendula"
|
||
tools:targetApi="35">
|
||
<activity
|
||
android:name=".MainActivity"
|
||
android:exported="true"
|
||
android:launchMode="singleTop"
|
||
android:windowSoftInputMode="adjustResize">
|
||
<intent-filter>
|
||
<action android:name="android.intent.action.MAIN" />
|
||
<category android:name="android.intent.category.LAUNCHER" />
|
||
</intent-filter>
|
||
|
||
<!-- Open a .ics file (file manager / email attachment / browser). -->
|
||
<intent-filter>
|
||
<action android:name="android.intent.action.VIEW" />
|
||
<category android:name="android.intent.category.DEFAULT" />
|
||
<category android:name="android.intent.category.BROWSABLE" />
|
||
<data android:scheme="content" android:mimeType="text/calendar" />
|
||
<data android:scheme="file" android:mimeType="text/calendar" />
|
||
</intent-filter>
|
||
<!-- Receive a .ics shared from another app. -->
|
||
<intent-filter>
|
||
<action android:name="android.intent.action.SEND" />
|
||
<category android:name="android.intent.category.DEFAULT" />
|
||
<data android:mimeType="text/calendar" />
|
||
</intent-filter>
|
||
|
||
<!-- Launcher long-press shortcuts (e.g. "New event"). -->
|
||
<meta-data
|
||
android:name="android.app.shortcuts"
|
||
android:resource="@xml/shortcuts" />
|
||
</activity>
|
||
|
||
<!-- Standalone surface for a captured crash report. MainActivity routes
|
||
here on a startup crash-loop, so it stays clear of the app's Hilt
|
||
graph and Compose content. Not exported: launched only by us. -->
|
||
<activity
|
||
android:name=".ui.crash.CrashReportActivity"
|
||
android:exported="false"
|
||
android:excludeFromRecents="true"
|
||
android:launchMode="singleTask" />
|
||
|
||
<!-- Quick Settings tile: a one-tap "New event" shortcut in the QS panel.
|
||
Exported with BIND_QUICK_SETTINGS_TILE so only the system QS host can
|
||
bind it; the action mirrors the launcher "New event" shortcut. -->
|
||
<service
|
||
android:name=".qs.NewEventTileService"
|
||
android:exported="true"
|
||
android:icon="@drawable/ic_qs_new_event"
|
||
android:label="@string/qs_tile_new_event_label"
|
||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
|
||
<intent-filter>
|
||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||
</intent-filter>
|
||
</service>
|
||
|
||
<!-- The provider broadcasts EVENT_REMINDER at reminder time but posts
|
||
no notification itself — a calendar app must (v1.4, Etar model).
|
||
Exported: the broadcast arrives from the provider's process. -->
|
||
<receiver
|
||
android:name=".data.reminders.EventReminderReceiver"
|
||
android:exported="true">
|
||
<intent-filter>
|
||
<action android:name="android.intent.action.EVENT_REMINDER" />
|
||
<data
|
||
android:host="com.android.calendar"
|
||
android:scheme="content" />
|
||
</intent-filter>
|
||
</receiver>
|
||
|
||
<!-- Snooze / dismiss actions on a reminder notification, plus the snooze
|
||
re-show alarm. Not exported: only our own notification buttons and
|
||
AlarmManager PendingIntents target it. -->
|
||
<receiver
|
||
android:name=".data.reminders.ReminderActionReceiver"
|
||
android:exported="false" />
|
||
|
||
<!-- Home-screen widgets (Glance). Exported: the launcher/host binds them. -->
|
||
<receiver
|
||
android:name=".widget.agenda.AgendaWidgetReceiver"
|
||
android:label="@string/widget_agenda_label"
|
||
android:exported="true">
|
||
<intent-filter>
|
||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||
</intent-filter>
|
||
<meta-data
|
||
android:name="android.appwidget.provider"
|
||
android:resource="@xml/appwidget_info_agenda" />
|
||
</receiver>
|
||
|
||
<receiver
|
||
android:name=".widget.month.MonthWidgetReceiver"
|
||
android:label="@string/widget_month_label"
|
||
android:exported="true">
|
||
<intent-filter>
|
||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||
</intent-filter>
|
||
<meta-data
|
||
android:name="android.appwidget.provider"
|
||
android:resource="@xml/appwidget_info_month" />
|
||
</receiver>
|
||
|
||
<!-- Keeps both widgets fresh: the calendar provider broadcasts
|
||
PROVIDER_CHANGED on any data change (our writes and external sync),
|
||
and the system broadcasts the date/time ones at midnight / clock
|
||
changes so "today" highlighting rolls over. -->
|
||
<receiver
|
||
android:name=".widget.WidgetUpdateReceiver"
|
||
android:exported="true">
|
||
<intent-filter>
|
||
<action android:name="android.intent.action.PROVIDER_CHANGED" />
|
||
<data
|
||
android:host="com.android.calendar"
|
||
android:scheme="content" />
|
||
</intent-filter>
|
||
<intent-filter>
|
||
<action android:name="android.intent.action.DATE_CHANGED" />
|
||
<action android:name="android.intent.action.TIME_SET" />
|
||
<action android:name="android.intent.action.TIMEZONE_CHANGED" />
|
||
</intent-filter>
|
||
</receiver>
|
||
|
||
<!-- Hands .ics files we stage in the cache to other apps via a content
|
||
Uri (single-event share). Authority tracks applicationId so the
|
||
debug suffix doesn't break getUriForFile. -->
|
||
<provider
|
||
android:name="androidx.core.content.FileProvider"
|
||
android:authorities="${applicationId}.fileprovider"
|
||
android:exported="false"
|
||
android:grantUriPermissions="true">
|
||
<meta-data
|
||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||
android:resource="@xml/file_paths" />
|
||
</provider>
|
||
|
||
<!-- Persists the per-app language (M4) on API < 33, where the platform
|
||
per-app-languages API is unavailable. On 33+ this is a no-op. -->
|
||
<service
|
||
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
|
||
android:enabled="false"
|
||
android:exported="false">
|
||
<meta-data
|
||
android:name="autoStoreLocales"
|
||
android:value="true" />
|
||
</service>
|
||
</application>
|
||
|
||
</manifest>
|