From 1fd6545422d7af69ce507317d2c9311a82e1cbb3 Mon Sep 17 00:00:00 2001 From: Dark25 Date: Sun, 14 Jan 2024 22:17:00 +0100 Subject: [PATCH 1/3] feat(onboarding): add privacy policy to onboarding. --- .../more/onboarding/OnboardingScreen.kt | 2 + .../more/onboarding/PrivacyPolicyStep.kt | 223 ++++++++++++++++++ .../commonMain/resources/MR/base/strings.xml | 8 +- 3 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/eu/kanade/presentation/more/onboarding/PrivacyPolicyStep.kt diff --git a/app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingScreen.kt b/app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingScreen.kt index c5fd8c2faf..72d4c45f73 100644 --- a/app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingScreen.kt @@ -24,6 +24,7 @@ import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.screens.InfoScreen + @Composable fun OnboardingScreen( onComplete: () -> Unit, @@ -34,6 +35,7 @@ fun OnboardingScreen( var currentStep by rememberSaveable { mutableIntStateOf(0) } val steps = remember { listOf( + PrivacyPolicyStep(), ThemeStep(), StorageStep(), PermissionStep(), diff --git a/app/src/main/java/eu/kanade/presentation/more/onboarding/PrivacyPolicyStep.kt b/app/src/main/java/eu/kanade/presentation/more/onboarding/PrivacyPolicyStep.kt new file mode 100644 index 0000000000..e15eb0b6b6 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/more/onboarding/PrivacyPolicyStep.kt @@ -0,0 +1,223 @@ +package eu.kanade.presentation.more.onboarding + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.text.ClickableText +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Checkbox +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import tachiyomi.i18n.MR +import tachiyomi.presentation.core.i18n.stringResource + +class PrivacyPolicyStep : OnboardingStep { + private var _isComplete by mutableStateOf(false) + + override val isComplete: Boolean + get() = _isComplete + + @Composable + override fun Content() { + var isAgreed by remember { mutableStateOf(false) } + val scrollState = rememberScrollState() + + val isScrolledToEnd = remember(scrollState) { + derivedStateOf { + val maxScroll = scrollState.maxValue + scrollState.value >= maxScroll + } + } + + Column(modifier = Modifier.fillMaxSize()) { + Box( + modifier = Modifier + .height(500.dp) + .padding(16.dp) + .verticalScroll(scrollState), + ) { + Column { + PrivacyPolicyIntro() + PrivacyInformationCollectionUse() + } + } + + // Agreement Checkbox + Row( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Text( + stringResource(MR.strings.onboarding_privacy_agree_to_terms), + style = TextStyle( + fontSize = 18.sp, + ), + ) + Checkbox( + enabled = isScrolledToEnd.value, + checked = isAgreed, + onCheckedChange = { + isAgreed = it + _isComplete = it + }, + ) + } + } + } + + @Composable + fun HeadingText(text: String, modifier: Modifier = Modifier) { + Text( + modifier = modifier, + text = text, + style = TextStyle(fontSize = 20.sp, fontWeight = FontWeight.Bold), + ) + } + + @Composable + fun BodyText(text: String, modifier: Modifier = Modifier) { + Text( + modifier = modifier, + text = text, + style = TextStyle(fontSize = 16.sp), + ) + } + + @Composable + fun HorizontalDivider() { + HorizontalDivider(color = Color.Gray) + } + + @Composable + fun Spacer(size: Int, modifier: Modifier = Modifier) { + Spacer(modifier = modifier.height(size.dp)) + } + + @Composable + fun BulletPoint(text: String, url: String, modifier: Modifier = Modifier) { + val uriHandler = LocalUriHandler.current + + val annotatedString = buildAnnotatedString { + withStyle(style = SpanStyle(color = Color(0xFF0645AD), fontSize = 16.sp)) { + append("• $text") + } + addStringAnnotation( + tag = "URL", + annotation = url, + start = 2, + end = 2 + text.length, + ) + } + + ClickableText( + modifier = modifier, + text = annotatedString, + onClick = { offset -> + annotatedString.getStringAnnotations(tag = "URL", start = offset, end = offset) + .firstOrNull()?.let { annotation -> + uriHandler.openUri(annotation.item) + } + }, + style = TextStyle(fontSize = 16.sp), + ) + } + + @Composable + fun MoreInfoText(url: String, modifier: Modifier = Modifier) { + val uriHandler = LocalUriHandler.current + + val annotatedString = buildAnnotatedString { + withStyle(style = SpanStyle(color = Color(0xFF0645AD), fontSize = 16.sp)) { + append(stringResource(MR.strings.learn_more)) + } + addStringAnnotation( + tag = "URL", + annotation = url, + start = 0, + end = stringResource(MR.strings.learn_more).length, + ) + } + + ClickableText( + text = annotatedString, + modifier = modifier, + onClick = { offset -> + annotatedString.getStringAnnotations(tag = "URL", start = offset, end = offset) + .firstOrNull()?.let { annotation -> + uriHandler.openUri(annotation.item) + } + }, + style = TextStyle(fontSize = 16.sp), + ) + } + + @Composable + fun PrivacyPolicyIntro(modifier: Modifier = Modifier) { + Column(modifier = modifier) { + HeadingText(stringResource(MR.strings.privacy_policy)) + Spacer(20) + + BodyText(stringResource(MR.strings.onboarding_privacy_intro)) + Spacer(10) + + BodyText(stringResource(MR.strings.onboarding_privacy_info_overview)) + Spacer(10) + + BodyText(stringResource(MR.strings.onboarding_privacy_agreement_acknowledgement)) + Spacer(20) + + HorizontalDivider() + Spacer(20) + } + } + + @Composable + fun PrivacyInformationCollectionUse(modifier: Modifier = Modifier) { + Column(modifier = modifier) { + HeadingText(stringResource(MR.strings.onboarding_privacy_information_collection_use)) + Spacer(20) + + BodyText(stringResource(MR.strings.onboarding_privacy_information_collection_use_intro)) + Spacer(10) + + BodyText(stringResource(MR.strings.onboarding_privacy_information_collection_use_data)) + Spacer(10) + + BulletPoint("Sentry", "https://sentry.io/privacy/") + BulletPoint("Firebase Analytics", "https://www.google.com/analytics/terms/") + + Spacer(20) + HorizontalDivider() + Spacer(20) + + MoreInfoText("https://aniyomi.org/privacy/") + } + } +} diff --git a/i18n/src/commonMain/resources/MR/base/strings.xml b/i18n/src/commonMain/resources/MR/base/strings.xml index 31a003c195..931e5da7e2 100644 --- a/i18n/src/commonMain/resources/MR/base/strings.xml +++ b/i18n/src/commonMain/resources/MR/base/strings.xml @@ -174,7 +174,13 @@ Grant New to %s? We recommend checking out the getting started guide. Reinstalling %s? - + I agree to the Privacy Policy + Aniyomi is an Open Source app. This SERVICE is provided at no cost and is intended for use as is. + This page details our policies with the collection, use, and disclosure of Personal Information if anyone decided to use our Service. + If you choose to use our Service, then you agree to the collection and use of information in relation to this policy. The Personal Information that we collect is used for providing and improving the Service. We will not use or share your information with anyone except as described in this Privacy Policy. + Information Collection and Use + For a better experience, while using our Service, we may require you to provide us with certain personally identifiable information. The information that we request will be retained by us and used as described in this privacy policy. + Links to the privacy policy of third-party service providers used by the app: General From 913f3ae7c190c4458f5c4025b7abb81f5b146c5b Mon Sep 17 00:00:00 2001 From: Dark25 Date: Sun, 14 Jan 2024 23:39:34 +0100 Subject: [PATCH 2/3] delete firebase and crashlytics. --- .../kanade/presentation/more/onboarding/PrivacyPolicyStep.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/more/onboarding/PrivacyPolicyStep.kt b/app/src/main/java/eu/kanade/presentation/more/onboarding/PrivacyPolicyStep.kt index e15eb0b6b6..009b83dcde 100644 --- a/app/src/main/java/eu/kanade/presentation/more/onboarding/PrivacyPolicyStep.kt +++ b/app/src/main/java/eu/kanade/presentation/more/onboarding/PrivacyPolicyStep.kt @@ -210,9 +210,6 @@ class PrivacyPolicyStep : OnboardingStep { BodyText(stringResource(MR.strings.onboarding_privacy_information_collection_use_data)) Spacer(10) - BulletPoint("Sentry", "https://sentry.io/privacy/") - BulletPoint("Firebase Analytics", "https://www.google.com/analytics/terms/") - Spacer(20) HorizontalDivider() Spacer(20) From 68803b77ed8ac935bb2ca68a901f38c2981193ab Mon Sep 17 00:00:00 2001 From: Dark25 Date: Mon, 15 Jan 2024 22:38:14 +0100 Subject: [PATCH 3/3] unnecessary space --- .../eu/kanade/presentation/more/onboarding/OnboardingScreen.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingScreen.kt b/app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingScreen.kt index 72d4c45f73..c9051419f9 100644 --- a/app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingScreen.kt @@ -24,7 +24,6 @@ import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.screens.InfoScreen - @Composable fun OnboardingScreen( onComplete: () -> Unit,