A Donate row on the account screen
Opens flamenetmessenger.com/donate in the browser. Nothing is taken in the app, nothing is unlocked by giving and nothing is withheld without it. The address is the project's site rather than the signed-in relay, which is the opposite of the rule the page links follow. Those open the server you are on, because a self-hosted relay's operator writes the terms that bind its users. A donation is not that: their users paying their operator's hosting bill is not what the row offers, and a self-hosted relay serves that page with no form on it unless its operator configured a processor. openDownload gained a plainly named sibling, openLink, since a donation link is not a download. The old name stays and delegates, so the update path is untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
59988a3790
commit
55d7feb302
@@ -69,8 +69,8 @@ object AppUpdate {
|
||||
versionCode: Int,
|
||||
): Boolean = prefs(context).getInt(DISMISSED_CODE, 0) >= versionCode
|
||||
|
||||
/** Hand the download to the browser, which is where an APK install starts. */
|
||||
fun openDownload(
|
||||
/** Hand a link to the browser. */
|
||||
fun openLink(
|
||||
context: Context,
|
||||
url: String,
|
||||
) {
|
||||
@@ -82,11 +82,26 @@ object AppUpdate {
|
||||
}
|
||||
}
|
||||
|
||||
/** The same thing, named for where an APK install starts. */
|
||||
fun openDownload(
|
||||
context: Context,
|
||||
url: String,
|
||||
) = openLink(context, url)
|
||||
|
||||
/**
|
||||
* Where releases are published when the relay does not publish them.
|
||||
*/
|
||||
const val OFFICIAL_SITE = "https://flamenetmessenger.com"
|
||||
|
||||
/**
|
||||
* Where to send somebody who wants to pay for the project rather than for
|
||||
* the relay they are signed in to. The project's own site, not the site
|
||||
* the app is pointed at: on a self-hosted relay that page has no form on
|
||||
* it unless its operator configured a payment processor, and their users
|
||||
* paying their hosting bill is not what this offers.
|
||||
*/
|
||||
const val DONATE_URL = "$OFFICIAL_SITE/donate"
|
||||
|
||||
/** What an explicit check found, including which host answered. */
|
||||
sealed interface CheckResult {
|
||||
data class Available(
|
||||
|
||||
@@ -855,6 +855,9 @@ fun ColumnScope.AccountScreen(
|
||||
SectionBand()
|
||||
SettingsSection { AppVersionSection(model) }
|
||||
|
||||
SectionBand()
|
||||
SettingsSection { DonateSection() }
|
||||
|
||||
// The destructive pair, in their own section.
|
||||
SectionBand()
|
||||
SettingsSection {
|
||||
@@ -914,6 +917,25 @@ fun ColumnScope.AccountScreen(
|
||||
* Your profile picture: show it, change it, remove it.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A way to pay for the project, which opens the browser rather than taking
|
||||
* anything here. Nothing is unlocked by giving and nothing is withheld
|
||||
* without it.
|
||||
*/
|
||||
@Composable
|
||||
private fun ColumnScope.DonateSection() {
|
||||
val context = LocalContext.current
|
||||
Text("Support Flamenet", style = MaterialTheme.typography.titleMedium)
|
||||
SettingsRow(
|
||||
label = "Donate",
|
||||
description =
|
||||
"Servers, an external audit, and Apple's developer fee. The page says " +
|
||||
"where the money goes.",
|
||||
tag = "donate",
|
||||
onClick = { AppUpdate.openLink(context, AppUpdate.DONATE_URL) },
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Which build this is, and a button to go and find out if it is current.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package io.flamenet.messenger.app
|
||||
|
||||
import java.io.File
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/**
|
||||
* The account screen offers a way to pay for the project, and it points at the
|
||||
* project rather than at whichever relay this phone is signed in to.
|
||||
*
|
||||
* A self-hosted relay serves /donate with no form on it unless its operator
|
||||
* configured a payment processor, and their users paying their hosting bill is
|
||||
* not what the row offers. So this one address does not follow the signed-in
|
||||
* site, unlike every page link that describes the server's own terms.
|
||||
*/
|
||||
class DonatingGoesToTheProjectTest {
|
||||
private fun source(name: String): String {
|
||||
val f = File("src/main/kotlin/io/flamenet/messenger/app/$name")
|
||||
assertTrue(f.isFile, "this test reads app/src/main/kotlin/.../$name")
|
||||
return f.readText()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `the account screen has a donate row that opens the link`() {
|
||||
val screens = source("ChatScreens.kt")
|
||||
assertTrue(screens.contains("DonateSection()"), "no donate section on the account screen")
|
||||
assertTrue(
|
||||
screens.contains("AppUpdate.openLink(context, AppUpdate.DONATE_URL)"),
|
||||
"the donate row does not open DONATE_URL",
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `the address is the project's own site`() {
|
||||
val update = source("AppUpdate.kt")
|
||||
val line =
|
||||
update.lines().firstOrNull { it.trimStart().startsWith("const val DONATE_URL") }
|
||||
?: error("DONATE_URL is not declared in AppUpdate.kt")
|
||||
assertEquals(
|
||||
"const val DONATE_URL = \"\$OFFICIAL_SITE/donate\"",
|
||||
line.trim(),
|
||||
"DONATE_URL should be built from OFFICIAL_SITE so one edit moves both",
|
||||
)
|
||||
assertTrue(
|
||||
update.contains("const val OFFICIAL_SITE = \"https://flamenetmessenger.com\""),
|
||||
"OFFICIAL_SITE is not the project site any more, so DONATE_URL is wrong",
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user