support: Buy Me a Coffee first in Settings, the popup, the thank-you page and the repo's Sponsor button; Monero last

This commit is contained in:
Seb3thehacker committed 2026-10-14 23:36:30 -07:00
1 parent 77b84212db
commit c6d8d8e787
4 files changed
+27 -5

No files matched your search

+1 -1
View File
@@ -10,6 +10,6 @@ liberapay: Seb3thehacker
issuehunt: # Replace with a single IssueHunt username issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username buy_me_a_coffee: seb3thehacker
thanks_dev: # Replace with a single thanks.dev username thanks_dev: # Replace with a single thanks.dev username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
@@ -35,6 +35,7 @@ import androidx.compose.ui.platform.LocalContext
/** Where Gearslip lives outside the app: support, the chat room, and the code. */ /** Where Gearslip lives outside the app: support, the chat room, and the code. */
internal object GearslipLinks { internal object GearslipLinks {
const val BUY_ME_A_COFFEE = "https://buymeacoffee.com/seb3thehacker"
const val LIBERAPAY = "https://liberapay.com/Seb3thehacker" const val LIBERAPAY = "https://liberapay.com/Seb3thehacker"
/** A card payment page for giving once, any amount. Its row stays hidden while this is empty. */ /** A card payment page for giving once, any amount. Its row stays hidden while this is empty. */
const val PAYMENT_LINK = "" const val PAYMENT_LINK = ""
@@ -66,7 +67,7 @@ internal object GearslipLinks {
} }
} }
/** The ways to support Gearslip. Liberapay always; card and Monero once they're set up. */ /** The ways to support Gearslip: Buy Me a Coffee first, Monero last, card once it's set up. */
@Composable @Composable
internal fun DonateRows() { internal fun DonateRows() {
val context = LocalContext.current val context = LocalContext.current
@@ -77,6 +78,14 @@ internal fun DonateRows() {
tint = MaterialTheme.colorScheme.onSurfaceVariant, tint = MaterialTheme.colorScheme.onSurfaceVariant,
) )
} }
SettingsRow(
"Buy Me a Coffee",
Modifier.clickable { GearslipLinks.open(context, GearslipLinks.BUY_ME_A_COFFEE) },
subtitle = "Give once or monthly, by card",
icon = Icons.Filled.Favorite,
trailing = arrow,
)
SettingsDivider()
SettingsRow( SettingsRow(
"Liberapay", "Liberapay",
Modifier.clickable { GearslipLinks.open(context, GearslipLinks.LIBERAPAY) }, Modifier.clickable { GearslipLinks.open(context, GearslipLinks.LIBERAPAY) },
@@ -110,7 +119,7 @@ internal fun DonateRows() {
/** The Monero address in full, with ways to pay it from this phone or another device. */ /** The Monero address in full, with ways to pay it from this phone or another device. */
@Composable @Composable
private fun MoneroDialog(onDismiss: () -> Unit) { internal fun MoneroDialog(onDismiss: () -> Unit) {
val context = LocalContext.current val context = LocalContext.current
AlertDialog( AlertDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
@@ -14,7 +14,9 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -85,7 +87,12 @@ object DonatePrompt {
internal fun DonateDialog(live: Boolean) { internal fun DonateDialog(live: Boolean) {
val context = LocalContext.current val context = LocalContext.current
val waiting by remember { DonatePrompt.pending(context) }.collectAsStateWithLifecycle() val waiting by remember { DonatePrompt.pending(context) }.collectAsStateWithLifecycle()
var monero by remember { mutableStateOf(false) }
if (!waiting || live) return if (!waiting || live) return
if (monero) {
MoneroDialog { DonatePrompt.answer(context, donated = true) }
return
}
fun give(url: String) { fun give(url: String) {
DonatePrompt.answer(context, donated = true) DonatePrompt.answer(context, donated = true)
GearslipLinks.open(context, url) GearslipLinks.open(context, url)
@@ -102,7 +109,10 @@ internal fun DonateDialog(live: Boolean) {
}, },
confirmButton = { confirmButton = {
Column(Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(8.dp)) { Column(Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(8.dp)) {
Button(onClick = { give(GearslipLinks.LIBERAPAY) }, Modifier.fillMaxWidth()) { Button(onClick = { give(GearslipLinks.BUY_ME_A_COFFEE) }, Modifier.fillMaxWidth()) {
Text("Buy me a coffee")
}
OutlinedButton(onClick = { give(GearslipLinks.LIBERAPAY) }, Modifier.fillMaxWidth()) {
Text("Support on Liberapay") Text("Support on Liberapay")
} }
if (GearslipLinks.PAYMENT_LINK.isNotEmpty()) { if (GearslipLinks.PAYMENT_LINK.isNotEmpty()) {
@@ -110,6 +120,9 @@ internal fun DonateDialog(live: Boolean) {
Text("Give once by card") Text("Give once by card")
} }
} }
OutlinedButton(onClick = { monero = true }, Modifier.fillMaxWidth()) {
Text("Monero")
}
TextButton(onClick = { DonatePrompt.answer(context, donated = false) }, Modifier.fillMaxWidth()) { TextButton(onClick = { DonatePrompt.answer(context, donated = false) }, Modifier.fillMaxWidth()) {
Text("Not now") Text("Not now")
} }
@@ -228,7 +228,7 @@ fun IntroScreen(onDone: () -> Unit) {
"Each note shows which cars work and which still fail, so I know what to fix next.", step, "Each note shows which cars work and which still fail, so I know what to fix next.", step,
action = "See which cars work" to { GearslipLinks.open(context, GearslipLinks.CARS) }, action = "See which cars work" to { GearslipLinks.open(context, GearslipLinks.CARS) },
outlined = true, outlined = true,
secondAction = "Support on Liberapay" to { GearslipLinks.open(context, GearslipLinks.LIBERAPAY) }, secondAction = "Buy me a coffee" to { GearslipLinks.open(context, GearslipLinks.BUY_ME_A_COFFEE) },
) { HeartIcon(c.onTertiaryC) } ) { HeartIcon(c.onTertiaryC) }
IntroStep.CHAT -> BadgeStep(c, ::cq, ::cqSp, c.primaryC, "Come say hi.", IntroStep.CHAT -> BadgeStep(c, ::cq, ::cqSp, c.primaryC, "Come say hi.",
"Gearslip has a chat room on Matrix. Talk with other drivers about cars, apps, and " + "Gearslip has a chat room on Matrix. Talk with other drivers about cars, apps, and " +