mirror of
https://github.com/pawelorzech/Swoosh.git
synced 2026-03-31 11:55:47 +00:00
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
This commit is contained in:
parent
ed11577be1
commit
bbe991b027
1 changed files with 90 additions and 0 deletions
|
|
@ -32,8 +32,11 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import com.swoosh.microblog.data.AccountManager
|
import com.swoosh.microblog.data.AccountManager
|
||||||
|
import com.swoosh.microblog.data.NewsletterPreferences
|
||||||
import com.swoosh.microblog.data.SiteMetadataCache
|
import com.swoosh.microblog.data.SiteMetadataCache
|
||||||
import com.swoosh.microblog.data.api.ApiClient
|
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.data.model.GhostAccount
|
||||||
import com.swoosh.microblog.ui.animation.SwooshMotion
|
import com.swoosh.microblog.ui.animation.SwooshMotion
|
||||||
import com.swoosh.microblog.ui.components.ConfirmationDialog
|
import com.swoosh.microblog.ui.components.ConfirmationDialog
|
||||||
|
|
@ -293,6 +296,13 @@ fun SettingsScreen(
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
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 ---
|
// --- Current Account section ---
|
||||||
Text("Current Account", style = MaterialTheme.typography.titleMedium)
|
Text("Current Account", style = MaterialTheme.typography.titleMedium)
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
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<String?>(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
|
@Composable
|
||||||
fun ThemeModeSelector(
|
fun ThemeModeSelector(
|
||||||
currentMode: ThemeMode,
|
currentMode: ThemeMode,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue