mirror of
https://github.com/twinksoftware/Gearslip.git
synced 2026-11-11 08:12:26 +01:00
support: a Liberapay button on the intro's thank-you page, no "through a nonprofit", and room for Monero and a give-once card link, hidden until they're set
This commit is contained in:
1 parent
35bd239c2f
commit
879b428d1f
3 files changed
+51
-6
No files matched your search
@@ -1,8 +1,11 @@
|
|||||||
package app.seb3thehacker.gearslip.ui
|
package app.seb3thehacker.gearslip.ui
|
||||||
|
|
||||||
|
import android.content.ClipData
|
||||||
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||||
@@ -18,6 +21,10 @@ 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 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. */
|
||||||
|
const val PAYMENT_LINK = ""
|
||||||
|
/** Gearslip's Monero address. Its row stays hidden while this is empty. */
|
||||||
|
const val MONERO = ""
|
||||||
const val MATRIX = "https://matrix.to/#/!mf0_mgBd5KqKpc9FfX_wHp1jFCcwAtPrndIn_oGIyMk?via=matrix.org"
|
const val MATRIX = "https://matrix.to/#/!mf0_mgBd5KqKpc9FfX_wHp1jFCcwAtPrndIn_oGIyMk?via=matrix.org"
|
||||||
const val SOURCE = "https://github.com/Seb3thehacker/gearslip"
|
const val SOURCE = "https://github.com/Seb3thehacker/gearslip"
|
||||||
const val CARS = "$SOURCE/blob/main/CARS.md"
|
const val CARS = "$SOURCE/blob/main/CARS.md"
|
||||||
@@ -27,9 +34,20 @@ internal object GearslipLinks {
|
|||||||
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
|
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Opens a Monero wallet on the address, or copies it when no wallet app is installed. */
|
||||||
|
fun openMonero(context: Context) {
|
||||||
|
val opened = runCatching {
|
||||||
|
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("monero:$MONERO")).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
|
||||||
|
}.isSuccess
|
||||||
|
if (opened) return
|
||||||
|
context.getSystemService(ClipboardManager::class.java)
|
||||||
|
?.setPrimaryClip(ClipData.newPlainText("Monero address", MONERO))
|
||||||
|
Toast.makeText(context, "Monero address copied", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The way to support Gearslip, opening in the browser. */
|
/** The ways to support Gearslip. Liberapay always; card and Monero once they're set up. */
|
||||||
@Composable
|
@Composable
|
||||||
internal fun DonateRows() {
|
internal fun DonateRows() {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
@@ -43,10 +61,30 @@ internal fun DonateRows() {
|
|||||||
SettingsRow(
|
SettingsRow(
|
||||||
"Liberapay",
|
"Liberapay",
|
||||||
Modifier.clickable { GearslipLinks.open(context, GearslipLinks.LIBERAPAY) },
|
Modifier.clickable { GearslipLinks.open(context, GearslipLinks.LIBERAPAY) },
|
||||||
subtitle = "Give weekly or monthly, through a nonprofit",
|
subtitle = "Give weekly or monthly",
|
||||||
icon = Icons.Filled.Favorite,
|
icon = Icons.Filled.Favorite,
|
||||||
trailing = arrow,
|
trailing = arrow,
|
||||||
)
|
)
|
||||||
|
if (GearslipLinks.PAYMENT_LINK.isNotEmpty()) {
|
||||||
|
SettingsDivider()
|
||||||
|
SettingsRow(
|
||||||
|
"Give once",
|
||||||
|
Modifier.clickable { GearslipLinks.open(context, GearslipLinks.PAYMENT_LINK) },
|
||||||
|
subtitle = "Any amount, by card",
|
||||||
|
icon = Icons.Filled.Favorite,
|
||||||
|
trailing = arrow,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (GearslipLinks.MONERO.isNotEmpty()) {
|
||||||
|
SettingsDivider()
|
||||||
|
SettingsRow(
|
||||||
|
"Monero",
|
||||||
|
Modifier.clickable { GearslipLinks.openMonero(context) },
|
||||||
|
subtitle = "Opens your wallet, or copies the address",
|
||||||
|
icon = Icons.Filled.Favorite,
|
||||||
|
trailing = arrow,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The About section's links: the chat room, the source code, and credits. */
|
/** The About section's links: the chat room, the source code, and credits. */
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import androidx.compose.material.icons.filled.Favorite
|
|||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.OutlinedButton
|
||||||
import androidx.compose.material3.Text
|
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
|
||||||
@@ -104,6 +105,11 @@ internal fun DonateDialog(live: Boolean) {
|
|||||||
Button(onClick = { give(GearslipLinks.LIBERAPAY) }, Modifier.fillMaxWidth()) {
|
Button(onClick = { give(GearslipLinks.LIBERAPAY) }, Modifier.fillMaxWidth()) {
|
||||||
Text("Support on Liberapay")
|
Text("Support on Liberapay")
|
||||||
}
|
}
|
||||||
|
if (GearslipLinks.PAYMENT_LINK.isNotEmpty()) {
|
||||||
|
OutlinedButton(onClick = { give(GearslipLinks.PAYMENT_LINK) }, Modifier.fillMaxWidth()) {
|
||||||
|
Text("Give once by card")
|
||||||
|
}
|
||||||
|
}
|
||||||
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,6 +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) },
|
||||||
) { 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 " +
|
||||||
@@ -396,6 +397,7 @@ private fun BadgeStep(
|
|||||||
c: IntroColors, cq: (Float) -> Dp, cqSp: (Float) -> TextUnit, badge: Color,
|
c: IntroColors, cq: (Float) -> Dp, cqSp: (Float) -> TextUnit, badge: Color,
|
||||||
title: String, body: String, key: Any,
|
title: String, body: String, key: Any,
|
||||||
action: Pair<String, () -> Unit>? = null, outlined: Boolean = false,
|
action: Pair<String, () -> Unit>? = null, outlined: Boolean = false,
|
||||||
|
secondAction: Pair<String, () -> Unit>? = null,
|
||||||
extra: (@Composable () -> Unit)? = null,
|
extra: (@Composable () -> Unit)? = null,
|
||||||
icon: @Composable () -> Unit,
|
icon: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
@@ -423,15 +425,14 @@ private fun BadgeStep(
|
|||||||
modifier = Modifier.up(entrance(key, 350, 700), cq(7f)),
|
modifier = Modifier.up(entrance(key, 350, 700), cq(7f)),
|
||||||
)
|
)
|
||||||
extra?.invoke()
|
extra?.invoke()
|
||||||
if (action != null) {
|
listOfNotNull(action, secondAction).forEachIndexed { i, (label, onClick) ->
|
||||||
val (label, onClick) = action
|
Spacer(Modifier.height(if (i > 0) cq(3f) else if (outlined) cq(7f) else cq(9f)))
|
||||||
Spacer(Modifier.height(if (outlined) cq(7f) else cq(9f)))
|
|
||||||
Text(
|
Text(
|
||||||
label,
|
label,
|
||||||
color = if (outlined) c.primary else c.onPrimary,
|
color = if (outlined) c.primary else c.onPrimary,
|
||||||
style = TextStyle(fontSize = cqSp(if (outlined) 4.4f else 4.6f), fontWeight = FontWeight.Bold),
|
style = TextStyle(fontSize = cqSp(if (outlined) 4.4f else 4.6f), fontWeight = FontWeight.Bold),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.up(entrance(key, 500, 700), cq(7f))
|
.up(entrance(key, 500 + i * 150, 700), cq(7f))
|
||||||
.clip(RoundedCornerShape(50))
|
.clip(RoundedCornerShape(50))
|
||||||
.then(
|
.then(
|
||||||
if (outlined) Modifier.border(BorderStroke(2.dp, c.outline), RoundedCornerShape(50))
|
if (outlined) Modifier.border(BorderStroke(2.dp, c.outline), RoundedCornerShape(50))
|
||||||
|
|||||||
Reference in new issue
Block a user