From a35078f96da4d5541e1507ea31f546afdf5c6731 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Sat, 8 Aug 2026 21:15:31 +0200 Subject: [PATCH] Trim the onboarding steps to one screenful (#163) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The permission step said the same privacy point four times — in the body, in two of the three benefit rows, and again in the footnote under the button — which with the new step counter no longer fit without scrolling. Body keeps the ask, the privacy row absorbs the tracking one, the footnote goes, and the app-name eyebrow drops (the mark is right above it). The reminder and backup steps share the shell and would have scrolled the same way, so they lose their eyebrow and third row too. Three permission strings and two reminder ones are left unused rather than deleted: translations still carry them, and a base key a translation has is a fatal ExtraTranslation. Weblate drops them. --- .../calendula/ui/onboarding/BackupStep.kt | 18 +------ .../ui/onboarding/PermissionScreen.kt | 51 ++----------------- .../calendula/ui/onboarding/ReminderStep.kt | 18 +------ app/src/main/res/values/strings.xml | 13 +++-- 4 files changed, 17 insertions(+), 83 deletions(-) diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/onboarding/BackupStep.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/onboarding/BackupStep.kt index 77ba78d..2611731 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/onboarding/BackupStep.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/onboarding/BackupStep.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.CloudOff import androidx.compose.material.icons.filled.FolderOpen -import androidx.compose.material.icons.filled.Restore import androidx.compose.material.icons.filled.Schedule import androidx.compose.material3.Button import androidx.compose.material3.MaterialTheme @@ -20,7 +19,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import de.jeanlucmakiola.calendula.R import de.jeanlucmakiola.floret.components.BenefitRow import de.jeanlucmakiola.floret.components.OnboardingScaffold @@ -52,6 +50,7 @@ internal fun BackupStep( OnboardingScaffold( modifier = modifier, progress = progress, + topSpacing = OnboardingSpace.lg, hero = { IconHero(Icons.Filled.CloudOff) }, actions = { Button( @@ -71,13 +70,6 @@ internal fun BackupStep( } }, ) { - Text( - text = stringResource(R.string.app_name).uppercase(), - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.primary, - letterSpacing = 2.sp, - ) - Spacer(Modifier.height(OnboardingSpace.xs)) Text( text = stringResource(R.string.onboarding_backup_title), style = MaterialTheme.typography.headlineMedium, @@ -91,7 +83,7 @@ internal fun BackupStep( textAlign = TextAlign.Center, ) - Spacer(Modifier.height(OnboardingSpace.xl)) + Spacer(Modifier.height(OnboardingSpace.lg)) BenefitRow( icon = Icons.Filled.FolderOpen, @@ -104,11 +96,5 @@ internal fun BackupStep( title = stringResource(R.string.onboarding_backup_benefit_daily_title), body = stringResource(R.string.onboarding_backup_benefit_daily_body), ) - Spacer(Modifier.height(OnboardingSpace.sm)) - BenefitRow( - icon = Icons.Filled.Restore, - title = stringResource(R.string.onboarding_backup_benefit_restore_title), - body = stringResource(R.string.onboarding_backup_benefit_restore_body), - ) } } diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/onboarding/PermissionScreen.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/onboarding/PermissionScreen.kt index b103c5a..1be8f7f 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/onboarding/PermissionScreen.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/onboarding/PermissionScreen.kt @@ -10,19 +10,15 @@ import android.net.Uri import android.provider.Settings import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowForward import androidx.compose.material.icons.filled.CalendarMonth import androidx.compose.material.icons.filled.Lock -import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Icon @@ -32,13 +28,11 @@ import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import de.jeanlucmakiola.calendula.R @@ -103,6 +97,7 @@ private fun RationaleContent( OnboardingScaffold( modifier = modifier, progress = progress, + topSpacing = OnboardingSpace.lg, hero = { BrandHero(denied = false) }, actions = { Button( @@ -121,16 +116,8 @@ private fun RationaleContent( modifier = Modifier.size(20.dp), ) } - PrivacyFootnote() }, ) { - Text( - text = stringResource(R.string.app_name).uppercase(), - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.primary, - letterSpacing = 2.sp, - ) - Spacer(Modifier.height(OnboardingSpace.xs)) Text( text = stringResource(R.string.permission_rationale_title), style = MaterialTheme.typography.headlineMedium, @@ -144,14 +131,8 @@ private fun RationaleContent( textAlign = TextAlign.Center, ) - Spacer(Modifier.height(OnboardingSpace.xl)) + Spacer(Modifier.height(OnboardingSpace.lg)) - BenefitRow( - icon = Icons.Filled.Lock, - title = stringResource(R.string.permission_benefit_private_title), - body = stringResource(R.string.permission_benefit_private_body), - ) - Spacer(Modifier.height(OnboardingSpace.sm)) BenefitRow( icon = Icons.Filled.CalendarMonth, title = stringResource(R.string.permission_benefit_sync_title), @@ -159,9 +140,9 @@ private fun RationaleContent( ) Spacer(Modifier.height(OnboardingSpace.sm)) BenefitRow( - icon = Icons.Filled.VisibilityOff, - title = stringResource(R.string.permission_benefit_privacy_title), - body = stringResource(R.string.permission_benefit_privacy_body), + icon = Icons.Filled.Lock, + title = stringResource(R.string.permission_benefit_private_title), + body = stringResource(R.string.permission_benefit_private_body), ) } } @@ -215,25 +196,3 @@ private fun DeniedContent( ) } } - -@Composable -private fun PrivacyFootnote() { - Row( - modifier = Modifier.fillMaxWidth().padding(top = 4.dp), - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically, - ) { - Icon( - imageVector = Icons.Filled.Lock, - contentDescription = null, - tint = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier.size(14.dp), - ) - Spacer(Modifier.width(6.dp)) - Text( - text = stringResource(R.string.permission_privacy_footnote), - style = MaterialTheme.typography.labelMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - } -} diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/onboarding/ReminderStep.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/onboarding/ReminderStep.kt index 55f2548..8af40d2 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/onboarding/ReminderStep.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/onboarding/ReminderStep.kt @@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.NotificationsActive import androidx.compose.material.icons.filled.ContentCopy -import androidx.compose.material.icons.filled.Tune import androidx.compose.material3.Button import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -24,7 +23,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import de.jeanlucmakiola.calendula.R /** @@ -50,6 +48,7 @@ fun ReminderStep( OnboardingScaffold( modifier = modifier, progress = progress, + topSpacing = OnboardingSpace.lg, hero = { IconHero(Icons.Filled.NotificationsActive) }, actions = { Button( @@ -75,13 +74,6 @@ fun ReminderStep( } }, ) { - Text( - text = stringResource(R.string.app_name).uppercase(), - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.primary, - letterSpacing = 2.sp, - ) - Spacer(Modifier.height(OnboardingSpace.xs)) Text( text = stringResource(R.string.reminder_onboarding_title), style = MaterialTheme.typography.headlineMedium, @@ -95,7 +87,7 @@ fun ReminderStep( textAlign = TextAlign.Center, ) - Spacer(Modifier.height(OnboardingSpace.xl)) + Spacer(Modifier.height(OnboardingSpace.lg)) BenefitRow( icon = Icons.Filled.NotificationsActive, @@ -108,11 +100,5 @@ fun ReminderStep( title = stringResource(R.string.reminder_benefit_duplicates_title), body = stringResource(R.string.reminder_benefit_duplicates_body), ) - Spacer(Modifier.height(OnboardingSpace.sm)) - BenefitRow( - icon = Icons.Filled.Tune, - title = stringResource(R.string.reminder_benefit_reversible_title), - body = stringResource(R.string.reminder_benefit_reversible_body), - ) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8e6c138..5ead759 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -18,16 +18,20 @@ See all your events, beautifully - Calendula needs access to your calendar to show and manage your events. That\'s all it asks for up front — and nothing ever leaves your device. + Calendula needs access to your calendar to show and manage your events. Grant calendar access Calendar access denied Calendula cannot show events without calendar access. You can grant it again in the system settings. Open system settings Try again - Stays on your device - Your calendars are read locally and never leave the phone. + Private by design + No internet permission, no telemetry — nothing ever leaves your phone. All your calendars, together Google, CalDAV, local — anything synced to the device just appears. + No tracking, ever Zero telemetry, zero analytics, no ads. Stays on your device · no internet permission @@ -276,8 +280,6 @@ Backups are plain .ics files — put them somewhere that syncs, or on an SD card. Once a day, by itself Calendula exports your local calendars in the background. Change how often in Settings. - Restore anytime - Open a backup file to bring the events back — on this phone or a new one. Choose folder and back up Not now What should Calendula open on? @@ -292,6 +294,7 @@ Every reminder on your events arrives as a notification, right on time. Using a second calendar app? If another app also posts reminders, you\'ll see them twice — turn them off there or here. + Change it anytime The switch lives in Settings, under Notifications. Turn on reminders