mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-07-30 19:46:17 +00:00
refactor: move ToS / legal links into flavor source sets
The Play-Store-only Terms-of-Use checkbox and the "About & Legal"
Settings section both contain hardcoded GitHub URLs to the published
PRIVACY.md. Previously they were in src/main and gated at call sites
by `BuildConfig.FLAVOR == "play"` — which works at runtime but still
compiles the GitHub URLs into the F-Droid APK.
This commit moves the URL-bearing UI into src/play and adds empty
src/fdroid stubs with the same signatures, so the F-Droid build is
physically free of the URLs.
New composables (same package + signature in both flavor source sets,
so callers in src/main link to whichever flavor is being built):
- com.vitorpamplona.amethyst.ui.screen.loggedOff.legal.TermsGate
* src/play: renders an AcceptTerms checkbox with the PRIVACY.md link
and the "acceptance required" error text.
* src/fdroid: empty body.
- com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.LegalSettingsSection
* src/play: renders the SettingsSection with Privacy Policy and
Child Safety Standards rows that open the GitHub-hosted PRIVACY.md.
* src/fdroid: empty body.
Call-site changes:
- LoginScreen: drop `BuildConfig.FLAVOR == "play"` guard and call
`TermsGate(...)` inside the existing `isFirstLogin` block. The
flavor source set picks the right body.
- SignUpScreen: drop `BuildConfig.FLAVOR == "play"` guard, call
`TermsGate(...)` unconditionally.
- AllSettingsScreen: drop `BuildConfig.FLAVOR == "play"` guard and
the inline About & Legal SettingsSection, call
`LegalSettingsSection()` instead. LocalUriHandler and BuildConfig
imports removed.
The old `src/main/.../loggedOff/AcceptTerms.kt` is deleted; its body
moves into the play-flavor TermsGate as a file-private helper.
The LoginViewModel / SignUpViewModel still use `BuildConfig.FLAVOR` to
decide the initial `acceptedTerms` value (so the login/signup button
isn't disabled on F-Droid). That check is logic only, contains no
URLs, and is safe for F-Droid distribution.
Verified: `grep -r "github.com/vitorpamplona/amethyst/blob"` against
src/main + src/fdroid returns zero matches. Both
:amethyst:compileFdroidDebugKotlin and :amethyst:compilePlayDebugKotlin
compile cleanly.
This commit is contained in:
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
// F-Droid distributes Amethyst as MIT-licensed free software; the build must
|
||||
// not surface links to external (e.g. GitHub-hosted) policy documents.
|
||||
@Composable
|
||||
fun LegalSettingsSection() {
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedOff.legal
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
// F-Droid distributes Amethyst as MIT-licensed free software; there is no
|
||||
// terms-of-use acceptance layered on top of the source license, and the build
|
||||
// must not link to any external (e.g. GitHub) policy document.
|
||||
@Composable
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun TermsGate(
|
||||
checked: Boolean,
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
showError: Boolean,
|
||||
) {
|
||||
}
|
||||
+1
-30
@@ -42,11 +42,9 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.BuildConfig
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
@@ -79,7 +77,6 @@ fun AllSettingsScreen(
|
||||
nav: INav,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val uriHandler = LocalUriHandler.current
|
||||
val scope = rememberCoroutineScope()
|
||||
var showResetMarmotDialog by remember { mutableStateOf(false) }
|
||||
var isResettingMarmot by remember { mutableStateOf(false) }
|
||||
@@ -264,33 +261,7 @@ fun AllSettingsScreen(
|
||||
)
|
||||
}
|
||||
|
||||
if (BuildConfig.FLAVOR == "play") {
|
||||
SettingsSection(R.string.about_legal) {
|
||||
SettingsItem(
|
||||
title = R.string.privacy_policy,
|
||||
icon = MaterialSymbols.Lock,
|
||||
onClick = {
|
||||
runCatching {
|
||||
uriHandler.openUri(
|
||||
"https://github.com/vitorpamplona/amethyst/blob/main/PRIVACY.md",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
SettingsDivider()
|
||||
SettingsItem(
|
||||
title = R.string.child_safety_standards,
|
||||
icon = MaterialSymbols.Shield,
|
||||
onClick = {
|
||||
runCatching {
|
||||
uriHandler.openUri(
|
||||
"https://github.com/vitorpamplona/amethyst/blob/main/PRIVACY.md#child-safety-standards",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
LegalSettingsSection()
|
||||
|
||||
SettingsSection(R.string.danger_zone, isDanger = true) {
|
||||
if (hasPrivateKey) {
|
||||
|
||||
+4
-12
@@ -66,15 +66,14 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.BuildConfig
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.hashtags.Amethyst
|
||||
import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.ui.screen.AccountSessionManager
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedOff.AcceptTerms
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedOff.TorSettingsSetup
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedOff.legal.TermsGate
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size20dp
|
||||
@@ -197,19 +196,12 @@ fun LoginPage(
|
||||
)
|
||||
}
|
||||
|
||||
if (loginViewModel.isFirstLogin && BuildConfig.FLAVOR == "play") {
|
||||
AcceptTerms(
|
||||
if (loginViewModel.isFirstLogin) {
|
||||
TermsGate(
|
||||
checked = loginViewModel.acceptedTerms,
|
||||
onCheckedChange = loginViewModel::updateAcceptedTerms,
|
||||
showError = loginViewModel.termsAcceptanceIsRequiredError,
|
||||
)
|
||||
|
||||
if (loginViewModel.termsAcceptanceIsRequiredError) {
|
||||
Text(
|
||||
text = stringRes(R.string.acceptance_of_terms_is_required),
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(Size10dp))
|
||||
|
||||
+6
-16
@@ -50,13 +50,12 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.BuildConfig
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.hashtags.Amethyst
|
||||
import com.vitorpamplona.amethyst.commons.hashtags.CustomHashTagIcons
|
||||
import com.vitorpamplona.amethyst.ui.screen.AccountSessionManager
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedOff.AcceptTerms
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedOff.TorSettingsSetup
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedOff.legal.TermsGate
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedOff.login.LoginErrorManager
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
||||
@@ -188,20 +187,11 @@ fun SignUpPage(
|
||||
},
|
||||
)
|
||||
|
||||
if (BuildConfig.FLAVOR == "play") {
|
||||
AcceptTerms(
|
||||
checked = signUpViewModel.acceptedTerms,
|
||||
onCheckedChange = signUpViewModel::updateAcceptedTerms,
|
||||
)
|
||||
|
||||
if (signUpViewModel.termsAcceptanceIsRequiredError) {
|
||||
Text(
|
||||
text = stringRes(R.string.acceptance_of_terms_is_required),
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
TermsGate(
|
||||
checked = signUpViewModel.acceptedTerms,
|
||||
onCheckedChange = signUpViewModel::updateAcceptedTerms,
|
||||
showError = signUpViewModel.termsAcceptanceIsRequiredError,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(Size10dp))
|
||||
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
|
||||
@Composable
|
||||
fun LegalSettingsSection() {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
SettingsSection(R.string.about_legal) {
|
||||
SettingsItem(
|
||||
title = R.string.privacy_policy,
|
||||
icon = MaterialSymbols.Lock,
|
||||
onClick = {
|
||||
runCatching {
|
||||
uriHandler.openUri(
|
||||
"https://github.com/vitorpamplona/amethyst/blob/main/PRIVACY.md",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
SettingsDivider()
|
||||
SettingsItem(
|
||||
title = R.string.child_safety_standards,
|
||||
icon = MaterialSymbols.Shield,
|
||||
onClick = {
|
||||
runCatching {
|
||||
uriHandler.openUri(
|
||||
"https://github.com/vitorpamplona/amethyst/blob/main/PRIVACY.md#child-safety-standards",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
+20
-3
@@ -18,7 +18,7 @@
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedOff
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedOff.legal
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.material3.Checkbox
|
||||
@@ -33,9 +33,26 @@ import com.vitorpamplona.amethyst.ui.components.appendLink
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
|
||||
@Composable
|
||||
fun AcceptTerms(
|
||||
fun TermsGate(
|
||||
checked: Boolean,
|
||||
onCheckedChange: ((Boolean) -> Unit)?,
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
showError: Boolean,
|
||||
) {
|
||||
AcceptTerms(checked = checked, onCheckedChange = onCheckedChange)
|
||||
|
||||
if (showError) {
|
||||
Text(
|
||||
text = stringRes(R.string.acceptance_of_terms_is_required),
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AcceptTerms(
|
||||
checked: Boolean,
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Checkbox(
|
||||
Reference in New Issue
Block a user