feat(legal): ExternalLinks utility, Privacy/Terms links in Settings + Paywall screens (batch 12)
This commit is contained in:
parent
f3bad90ec6
commit
4ede77f067
|
|
@ -1,8 +1,23 @@
|
||||||
package app.closer.core.navigation
|
package app.closer.core.navigation
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.widget.Toast
|
||||||
|
|
||||||
object ExternalLinks {
|
object ExternalLinks {
|
||||||
const val PRIVACY_POLICY = "https://couplesconnect.app/privacy"
|
const val PRIVACY_POLICY = "https://closer.app/privacy"
|
||||||
const val TERMS_OF_SERVICE = "https://couplesconnect.app/terms"
|
const val TERMS_OF_SERVICE = "https://closer.app/terms"
|
||||||
const val SUBSCRIPTION_TERMS = "https://couplesconnect.app/subscription-terms"
|
const val SUBSCRIPTION_TERMS = "https://closer.app/subscription-terms"
|
||||||
const val SUPPORT = "https://couplesconnect.app/support"
|
const val SUPPORT = "https://couplesconnect.app/support"
|
||||||
|
|
||||||
|
fun openUrl(context: Context, url: String) {
|
||||||
|
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||||
|
val resolved = intent.resolveActivity(context.packageManager)
|
||||||
|
if (resolved != null) {
|
||||||
|
context.startActivity(intent)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(context, "No browser app found", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
|
||||||
import androidx.compose.ui.semantics.Role
|
import androidx.compose.ui.semantics.Role
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
|
@ -83,7 +82,6 @@ fun PaywallScreen(
|
||||||
) {
|
) {
|
||||||
val uiState by viewModel.uiState.collectAsState()
|
val uiState by viewModel.uiState.collectAsState()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val uriHandler = LocalUriHandler.current
|
|
||||||
var showThankYou by remember { mutableStateOf(false) }
|
var showThankYou by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
LaunchedEffect(uiState.purchaseState) {
|
LaunchedEffect(uiState.purchaseState) {
|
||||||
|
|
@ -148,7 +146,7 @@ fun PaywallScreen(
|
||||||
onRestore = { viewModel.restore() }
|
onRestore = { viewModel.restore() }
|
||||||
)
|
)
|
||||||
|
|
||||||
LegalLinks(uriHandler = uriHandler)
|
LegalLinks()
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
}
|
}
|
||||||
|
|
@ -370,21 +368,31 @@ private fun ActionButtons(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun LegalLinks(
|
private fun LegalLinks(
|
||||||
uriHandler: androidx.compose.ui.platform.UriHandler,
|
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
Row(
|
val context = LocalContext.current
|
||||||
|
Column(
|
||||||
modifier = modifier.fillMaxWidth(),
|
modifier = modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterHorizontally)
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
) {
|
) {
|
||||||
TextButton(onClick = { uriHandler.openUri(ExternalLinks.PRIVACY_POLICY) }) {
|
Row(
|
||||||
Text("Privacy", style = MaterialTheme.typography.labelSmall, color = Color(0xFF9B8AA6))
|
horizontalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterHorizontally)
|
||||||
|
) {
|
||||||
|
TextButton(onClick = { ExternalLinks.openUrl(context, ExternalLinks.PRIVACY_POLICY) }) {
|
||||||
|
Text("Privacy Policy", style = MaterialTheme.typography.labelSmall, color = Color(0xFF9B8AA6))
|
||||||
|
}
|
||||||
|
TextButton(onClick = { ExternalLinks.openUrl(context, ExternalLinks.TERMS_OF_SERVICE) }) {
|
||||||
|
Text("Terms of Service", style = MaterialTheme.typography.labelSmall, color = Color(0xFF9B8AA6))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TextButton(onClick = { uriHandler.openUri(ExternalLinks.TERMS_OF_SERVICE) }) {
|
|
||||||
Text("Terms", style = MaterialTheme.typography.labelSmall, color = Color(0xFF9B8AA6))
|
TextButton(onClick = { ExternalLinks.openUrl(context, ExternalLinks.SUBSCRIPTION_TERMS) }) {
|
||||||
}
|
Text(
|
||||||
TextButton(onClick = { uriHandler.openUri(ExternalLinks.SUBSCRIPTION_TERMS) }) {
|
"Subscription terms apply",
|
||||||
Text("Subscription terms", style = MaterialTheme.typography.labelSmall, color = Color(0xFF9B8AA6))
|
style = MaterialTheme.typography.labelSmall,
|
||||||
|
color = Color(0xFF9B8AA6)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,10 @@ import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import app.closer.core.navigation.AppRoute
|
import app.closer.core.navigation.AppRoute
|
||||||
|
import app.closer.core.navigation.ExternalLinks
|
||||||
import app.closer.ui.settings.SettingsDanger
|
import app.closer.ui.settings.SettingsDanger
|
||||||
import app.closer.ui.settings.SettingsInk
|
import app.closer.ui.settings.SettingsInk
|
||||||
import app.closer.ui.settings.SettingsMuted
|
import app.closer.ui.settings.SettingsMuted
|
||||||
|
|
@ -349,6 +352,35 @@ fun SettingsScreen(
|
||||||
|
|
||||||
Spacer(Modifier.height(8.dp))
|
Spacer(Modifier.height(8.dp))
|
||||||
|
|
||||||
|
// Legal
|
||||||
|
Text(
|
||||||
|
text = "Legal",
|
||||||
|
style = MaterialTheme.typography.labelLarge,
|
||||||
|
color = SettingsMuted,
|
||||||
|
modifier = Modifier.padding(horizontal = 4.dp, vertical = 4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Card(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
shape = RoundedCornerShape(16.dp),
|
||||||
|
colors = CardDefaults.cardColors(containerColor = SettingsCard)
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
Column {
|
||||||
|
SettingsLegalRow(
|
||||||
|
label = "Privacy Policy",
|
||||||
|
onClick = { ExternalLinks.openUrl(context, ExternalLinks.PRIVACY_POLICY) }
|
||||||
|
)
|
||||||
|
Divider(modifier = Modifier.padding(horizontal = 16.dp), thickness = 0.5.dp)
|
||||||
|
SettingsLegalRow(
|
||||||
|
label = "Terms of Service",
|
||||||
|
onClick = { ExternalLinks.openUrl(context, ExternalLinks.TERMS_OF_SERVICE) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(Modifier.height(8.dp))
|
||||||
|
|
||||||
// Account lifecycle — separated from legal links
|
// Account lifecycle — separated from legal links
|
||||||
Card(
|
Card(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
|
@ -422,3 +454,32 @@ private fun SettingsRow(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SettingsLegalRow(
|
||||||
|
label: String,
|
||||||
|
onClick: () -> Unit
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable(onClick = onClick)
|
||||||
|
.padding(horizontal = 16.dp, vertical = 14.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = label,
|
||||||
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
|
color = SettingsInk,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
Icon(
|
||||||
|
Icons.AutoMirrored.Filled.ArrowForwardIos,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(14.dp),
|
||||||
|
tint = SettingsMuted
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue