support: Monero, in a popup with the full address, Open in wallet and Copy address

This commit is contained in:
Seb3thehacker committed 2026-10-14 19:29:57 -07:00
1 parent 879b428d1f
commit 2bf4753125
1 file changed
+65 -8
@@ -12,10 +12,25 @@ import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.automirrored.filled.Send import androidx.compose.material.icons.automirrored.filled.Send
import androidx.compose.material.icons.filled.Build import androidx.compose.material.icons.filled.Build
import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.Favorite
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.compose.ui.platform.LocalContext 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. */
@@ -24,7 +39,7 @@ internal object GearslipLinks {
/** 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 = ""
/** Gearslip's Monero address. Its row stays hidden while this is empty. */ /** Gearslip's Monero address. Its row stays hidden while this is empty. */
const val MONERO = "" const val MONERO = "44gTVxQJY3cirBJ41J5i1bPUVnSkTMhn9esSp1kg9MHwJ3TUz8tkkigUTKwiok5zA5RZvNxyM4pqkAfPs79pPLfaNG21pCn"
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"
@@ -35,12 +50,16 @@ internal object GearslipLinks {
} }
} }
/** Opens a Monero wallet on the address, or copies it when no wallet app is installed. */ /** Opens a Monero wallet app on the address; says so when none is installed. */
fun openMonero(context: Context) { fun openMoneroWallet(context: Context) {
val opened = runCatching { runCatching {
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("monero:$MONERO")).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)) context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("monero:$MONERO")).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
}.isSuccess }.onFailure {
if (opened) return Toast.makeText(context, "No Monero wallet app found. Copy the address instead.", Toast.LENGTH_LONG).show()
}
}
fun copyMonero(context: Context) {
context.getSystemService(ClipboardManager::class.java) context.getSystemService(ClipboardManager::class.java)
?.setPrimaryClip(ClipData.newPlainText("Monero address", MONERO)) ?.setPrimaryClip(ClipData.newPlainText("Monero address", MONERO))
Toast.makeText(context, "Monero address copied", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Monero address copied", Toast.LENGTH_SHORT).show()
@@ -76,17 +95,55 @@ internal fun DonateRows() {
) )
} }
if (GearslipLinks.MONERO.isNotEmpty()) { if (GearslipLinks.MONERO.isNotEmpty()) {
var moneroOpen by remember { mutableStateOf(false) }
SettingsDivider() SettingsDivider()
SettingsRow( SettingsRow(
"Monero", "Monero",
Modifier.clickable { GearslipLinks.openMonero(context) }, Modifier.clickable { moneroOpen = true },
subtitle = "Opens your wallet, or copies the address", subtitle = "Open your wallet or copy the address",
icon = Icons.Filled.Favorite, icon = Icons.Filled.Favorite,
trailing = arrow, trailing = arrow,
) )
if (moneroOpen) MoneroDialog { moneroOpen = false }
} }
} }
/** The Monero address in full, with ways to pay it from this phone or another device. */
@Composable
private fun MoneroDialog(onDismiss: () -> Unit) {
val context = LocalContext.current
AlertDialog(
onDismissRequest = onDismiss,
icon = { Icon(Icons.Filled.Favorite, contentDescription = null) },
title = { Text("Support with Monero") },
text = {
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
Text("Send any amount to this address from your Monero wallet.")
SelectionContainer {
Text(
GearslipLinks.MONERO,
style = MaterialTheme.typography.bodySmall.copy(fontFamily = FontFamily.Monospace),
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
},
confirmButton = {
Column(Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(8.dp)) {
Button(onClick = { GearslipLinks.openMoneroWallet(context) }, Modifier.fillMaxWidth()) {
Text("Open in wallet")
}
OutlinedButton(onClick = { GearslipLinks.copyMonero(context) }, Modifier.fillMaxWidth()) {
Text("Copy address")
}
TextButton(onClick = onDismiss, Modifier.fillMaxWidth()) {
Text("Close")
}
}
},
)
}
/** 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. */
@Composable @Composable
internal fun AboutLinkRows() { internal fun AboutLinkRows() {