From bbe991b027f9e0016a817ab3f5e8ab47bef5bc74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Orzech?= Date: Fri, 20 Mar 2026 00:44:58 +0100 Subject: [PATCH] feat: add newsletter toggle in Settings screen - Add "Newsletter" section after Content/Tags section - Switch to enable/disable newsletter features per account - Info text explaining the toggle's effect on composer - Best-effort API validation when toggling ON (fetches newsletters count) - Animated validation status display --- .../microblog/ui/settings/SettingsScreen.kt | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/app/src/main/java/com/swoosh/microblog/ui/settings/SettingsScreen.kt b/app/src/main/java/com/swoosh/microblog/ui/settings/SettingsScreen.kt index 765aed2..b5c1f1a 100644 --- a/app/src/main/java/com/swoosh/microblog/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/com/swoosh/microblog/ui/settings/SettingsScreen.kt @@ -32,8 +32,11 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil.compose.AsyncImage import com.swoosh.microblog.data.AccountManager +import com.swoosh.microblog.data.NewsletterPreferences import com.swoosh.microblog.data.SiteMetadataCache import com.swoosh.microblog.data.api.ApiClient +import com.swoosh.microblog.data.repository.PostRepository +import kotlinx.coroutines.launch import com.swoosh.microblog.data.model.GhostAccount import com.swoosh.microblog.ui.animation.SwooshMotion import com.swoosh.microblog.ui.components.ConfirmationDialog @@ -293,6 +296,13 @@ fun SettingsScreen( HorizontalDivider() Spacer(modifier = Modifier.height(24.dp)) + // --- Newsletter section --- + NewsletterSettingsSection() + + Spacer(modifier = Modifier.height(24.dp)) + HorizontalDivider() + Spacer(modifier = Modifier.height(24.dp)) + // --- Current Account section --- Text("Current Account", style = MaterialTheme.typography.titleMedium) Spacer(modifier = Modifier.height(12.dp)) @@ -444,6 +454,86 @@ fun SettingsScreen( } } +@Composable +fun NewsletterSettingsSection() { + val context = LocalContext.current + val newsletterPreferences = remember { NewsletterPreferences(context) } + var newsletterEnabled by remember { mutableStateOf(newsletterPreferences.isNewsletterEnabled()) } + val coroutineScope = rememberCoroutineScope() + var validationStatus by remember { mutableStateOf(null) } + + Text("Newsletter", style = MaterialTheme.typography.titleMedium) + Spacer(modifier = Modifier.height(12.dp)) + + Card(modifier = Modifier.fillMaxWidth()) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Column(modifier = Modifier.weight(1f)) { + Text( + text = "Enable newsletter features", + style = MaterialTheme.typography.bodyLarge + ) + } + Switch( + checked = newsletterEnabled, + onCheckedChange = { enabled -> + newsletterEnabled = enabled + newsletterPreferences.setNewsletterEnabled(enabled) + if (enabled) { + // Best effort: validate by fetching newsletters + validationStatus = "Checking..." + coroutineScope.launch { + try { + val repository = PostRepository(context) + val result = repository.fetchNewsletters() + validationStatus = if (result.isSuccess) { + val count = result.getOrNull()?.size ?: 0 + "$count newsletter(s) found" + } else { + null + } + } catch (_: Exception) { + validationStatus = null + } + } + } else { + validationStatus = null + } + } + ) + } + + Text( + text = "Show newsletter sending options when publishing posts", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + + // Validation status + AnimatedVisibility( + visible = validationStatus != null, + enter = fadeIn(SwooshMotion.quick()) + expandVertically(animationSpec = SwooshMotion.snappy()), + exit = fadeOut(SwooshMotion.quick()) + shrinkVertically(animationSpec = SwooshMotion.snappy()) + ) { + Text( + text = validationStatus ?: "", + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.padding(top = 4.dp) + ) + } + } + } +} + @Composable fun ThemeModeSelector( currentMode: ThemeMode,