diff --git a/commons/src/main/AndroidManifest.xml b/commons/src/main/AndroidManifest.xml index 5b7a39e79..1c15af909 100644 --- a/commons/src/main/AndroidManifest.xml +++ b/commons/src/main/AndroidManifest.xml @@ -57,6 +57,11 @@ android:exported="false" android:label="@string/manage_blocked_numbers" /> + + { val showWebsite = remember { resources.getBoolean(R.bool.show_donate_in_about) && !showExternalLinks } var version = intent.getStringExtra(APP_VERSION_NAME) ?: "" @@ -170,7 +170,7 @@ class AboutActivity : ComponentActivity() { } private fun onEmailClick( - showConfirmationAdvancedDialog: () -> Unit + showConfirmationAdvancedDialog: () -> Unit, ) { if (intent.getBooleanExtra(SHOW_FAQ_BEFORE_MAIL, false) && !baseConfig.wasBeforeAskingShown) { baseConfig.wasBeforeAskingShown = true @@ -228,7 +228,7 @@ class AboutActivity : ComponentActivity() { private fun onRateUsClick( showConfirmationAdvancedDialog: () -> Unit, - showRateStarsDialog: () -> Unit + showRateStarsDialog: () -> Unit, ) { if (baseConfig.wasBeforeRateShown) { launchRateUsPrompt(showRateStarsDialog) @@ -239,7 +239,7 @@ class AboutActivity : ComponentActivity() { } private fun launchRateUsPrompt( - showRateStarsDialog: () -> Unit + showRateStarsDialog: () -> Unit, ) { if (baseConfig.wasAppRated) { redirectToRateUs() @@ -266,7 +266,7 @@ class AboutActivity : ComponentActivity() { private fun onDonateClick() { - launchViewIntent(getString(R.string.donate_url)) + startActivity(Intent(applicationContext, DonationActivity::class.java)) } private fun onGithubClick() { diff --git a/commons/src/main/kotlin/org/fossify/commons/activities/DonationActivity.kt b/commons/src/main/kotlin/org/fossify/commons/activities/DonationActivity.kt new file mode 100644 index 000000000..0a8ee107b --- /dev/null +++ b/commons/src/main/kotlin/org/fossify/commons/activities/DonationActivity.kt @@ -0,0 +1,38 @@ +package org.fossify.commons.activities + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.text.AnnotatedString +import org.fossify.commons.R +import org.fossify.commons.compose.extensions.enableEdgeToEdgeSimple +import org.fossify.commons.compose.screens.donation.DonationScreen +import org.fossify.commons.compose.screens.donation.FossifyCryptoAddresses +import org.fossify.commons.compose.screens.donation.FossifyDonationPlatforms +import org.fossify.commons.compose.theme.AppThemeSurface +import org.fossify.commons.extensions.openWebsiteIntent +import org.fossify.commons.extensions.toast + +class DonationActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdgeSimple() + setContent { + val clipboardManager = LocalClipboardManager.current + AppThemeSurface { + DonationScreen( + donationOptions = FossifyDonationPlatforms, + cryptoAddresses = FossifyCryptoAddresses, + goBack = ::finish, + openWebsite = ::openWebsiteIntent, + copyToClipboard = { + clipboardManager.setText(AnnotatedString(it)) + toast(R.string.value_copied_to_clipboard) + }, + ) + } + } + } +} diff --git a/commons/src/main/kotlin/org/fossify/commons/compose/screens/AboutScreen.kt b/commons/src/main/kotlin/org/fossify/commons/compose/screens/AboutScreen.kt index 8ac98be3c..c3d97c865 100644 --- a/commons/src/main/kotlin/org/fossify/commons/compose/screens/AboutScreen.kt +++ b/commons/src/main/kotlin/org/fossify/commons/compose/screens/AboutScreen.kt @@ -63,8 +63,8 @@ internal fun HelpUsSection( if (showDonate) { TwoLinerTextItem( click = onDonateClick, - text = stringResource(id = R.string.donate), - icon = R.drawable.ic_dollar_vector + text = stringResource(id = R.string.donate_to_fossify), + icon = R.drawable.ic_donate_vector ) } SettingsHorizontalDivider() @@ -126,7 +126,7 @@ internal fun OtherSection( internal fun AboutSection( setupFAQ: Boolean, onFAQClick: () -> Unit, - onEmailClick: () -> Unit + onEmailClick: () -> Unit, ) { SettingsGroup(title = { SettingsTitleTextComponent(text = stringResource(id = R.string.support), modifier = startingTitlePadding) @@ -151,7 +151,7 @@ internal fun AboutSection( internal fun SocialSection( onGithubClick: () -> Unit, onRedditClick: () -> Unit, - onTelegramClick: () -> Unit + onTelegramClick: () -> Unit, ) { SettingsGroup(title = { SettingsTitleTextComponent(text = stringResource(id = R.string.social), modifier = startingTitlePadding) @@ -181,7 +181,7 @@ internal fun SocialText( text: String, icon: Int, tint: Color? = null, - click: () -> Unit + click: () -> Unit, ) { SettingsListItem( click = click, diff --git a/commons/src/main/kotlin/org/fossify/commons/compose/screens/donation/DonationData.kt b/commons/src/main/kotlin/org/fossify/commons/compose/screens/donation/DonationData.kt new file mode 100644 index 000000000..269f575f2 --- /dev/null +++ b/commons/src/main/kotlin/org/fossify/commons/compose/screens/donation/DonationData.kt @@ -0,0 +1,75 @@ +package org.fossify.commons.compose.screens.donation + +import org.fossify.commons.R + +sealed class Donation { + data class Platform( + val fee: Int, + val icon: Int, + val link: String, + val name: String, + ) : Donation() + + data class Crypto( + val address: String, + val icon: Int, + val name: String, + ) : Donation() +} + +val FossifyDonationPlatforms = listOf( + Donation.Platform( + fee = 0, + icon = R.drawable.ic_github_tinted_vector, + link = "https://github.com/sponsors/FossifyOrg", + name = "GitHub Sponsors" + ), + Donation.Platform( + fee = 0, + icon = R.drawable.ic_liberapay_vector, + link = "https://liberapay.com/naveensingh", + name = "Liberapay" + ), + Donation.Platform( + fee = 10, + icon = R.drawable.ic_open_collective_vector, + link = "https://opencollective.com/fossify/donate?interval=month&amount=20", + name = "OpenCollective" + ), + Donation.Platform( + fee = 10, + icon = R.drawable.ic_patreon_vector, + link = "https://www.patreon.com/naveen3singh", + name = "Patreon" + ), + Donation.Platform( + fee = 5, + icon = R.drawable.ic_paypal_vector, + link = "https://paypal.me/naveen3singh", + name = "PayPal" + ), +) + +@Suppress("SpellCheckingInspection") +val FossifyCryptoAddresses = listOf( + Donation.Crypto( + address = "bc1qn5h97qdqsazpzvxm7gryke6vmrcx85t7neqp95", + icon = R.drawable.ic_bitcoin_vector, + name = "Bitcoin (BTC)" + ), + Donation.Crypto( + address = "0x9354fC372BC3BdA58766a8a9Fabadf77A76CdE01", + icon = R.drawable.ic_ethereum_vector, + name = "Ethereum (ETH)" + ), + Donation.Crypto( + address = "48FkVUcJ7AGeBMR4SC4J7QU5nAt6YNwKZWz6sGDT1s5haEY7reZtJr5CniXLaQzTzGAuZNoc83BQAcETHw1d3Lkn8AAf1XF", + icon = R.drawable.ic_monero_vector, + name = "Monero (XMR)" + ), + Donation.Crypto( + address = "TGi4VpD1D9A9ZvyP9d3aVowwzMSvev2hub", + icon = R.drawable.ic_tron_vector, + name = "Tron (TRX)" + ) +) diff --git a/commons/src/main/kotlin/org/fossify/commons/compose/screens/donation/DonationScreen.kt b/commons/src/main/kotlin/org/fossify/commons/compose/screens/donation/DonationScreen.kt new file mode 100644 index 000000000..71b464a36 --- /dev/null +++ b/commons/src/main/kotlin/org/fossify/commons/compose/screens/donation/DonationScreen.kt @@ -0,0 +1,163 @@ +package org.fossify.commons.compose.screens.donation + +import androidx.annotation.DrawableRes +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.ContentCopy +import androidx.compose.material3.Icon +import androidx.compose.material3.ListItem +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.fossify.commons.R +import org.fossify.commons.compose.lists.SimpleColumnScaffold +import org.fossify.commons.compose.settings.SettingsGroup +import org.fossify.commons.compose.settings.SettingsHorizontalDivider +import org.fossify.commons.compose.settings.SettingsTitleTextComponent +import org.fossify.commons.compose.theme.Shapes +import org.fossify.commons.compose.theme.SimpleTheme +import org.fossify.commons.compose.theme.textSubTitleColor + +@Composable +fun DonationScreen( + donationOptions: List, + cryptoAddresses: List, + goBack: () -> Unit, + openWebsite: (String) -> Unit, + copyToClipboard: (String) -> Unit, +) { + SimpleColumnScaffold(title = stringResource(id = R.string.donate_to_fossify), goBack = goBack) { + DonationPlatforms( + options = donationOptions, + copyToClipboard = copyToClipboard, + openWebsite = openWebsite + ) + + SettingsHorizontalDivider() + + DonationCryptos( + options = cryptoAddresses, + copyToClipboard = copyToClipboard, + ) + } +} + +@Composable +fun DonationPlatforms( + options: List, + openWebsite: (String) -> Unit, + copyToClipboard: (String) -> Unit, +) { + SettingsGroup(title = { + SettingsTitleTextComponent( + text = stringResource(id = R.string.platforms), + modifier = Modifier + .padding(start = 56.dp) + ) + }) { + options.forEach { + DonationListItem( + name = it.name, + description = if (it.fee == 0) { + stringResource(id = R.string.little_to_no_fee) + } else { + stringResource(R.string.fee_up_to_pct, it.fee) + }, + icon = it.icon, + onClick = { openWebsite(it.link) }, + onCopyClick = { copyToClipboard(it.link) }, + ) + } + } +} + +@Composable +fun DonationCryptos( + options: List, + copyToClipboard: (String) -> Unit, +) { + SettingsGroup(title = { + SettingsTitleTextComponent( + text = stringResource(id = R.string.cryptocurrency), + modifier = Modifier + .padding(start = 56.dp) + ) + }) { + options.forEach { + DonationListItem( + name = it.name, + description = it.address, + icon = it.icon, + onClick = { copyToClipboard(it.address) }, + onCopyClick = { copyToClipboard(it.address) }, + ) + } + } +} + +@Composable +fun DonationListItem( + name: String, + description: String, + @DrawableRes icon: Int, + onClick: () -> Unit, + onCopyClick: () -> Unit, +) { + ListItem( + modifier = Modifier + .clickable(onClick = onClick), + headlineContent = { + Text( + text = name, + modifier = Modifier + .fillMaxWidth(), + ) + }, + leadingContent = { + Image( + modifier = Modifier + .size(SimpleTheme.dimens.icon.medium), + painter = painterResource(id = icon), + contentDescription = name, + ) + }, + supportingContent = { + Text( + text = description, + style = SimpleTheme.typography.bodyMedium.copy(color = textSubTitleColor) + ) + }, + trailingContent = { + Icon( + imageVector = Icons.Rounded.ContentCopy, + contentDescription = stringResource(id = R.string.copy_to_clipboard), + tint = SimpleTheme.colorScheme.primary, + modifier = Modifier + .clip(Shapes.extraLarge) + .clickable(onClick = onCopyClick) + .padding(12.dp), + ) + } + ) +} + +@Composable +@Preview +fun PreviewDonationScreen() { + DonationScreen( + donationOptions = FossifyDonationPlatforms, + cryptoAddresses = FossifyCryptoAddresses, + goBack = {}, + openWebsite = {}, + copyToClipboard = {}, + ) +} diff --git a/commons/src/main/res/drawable/ic_bitcoin_vector.xml b/commons/src/main/res/drawable/ic_bitcoin_vector.xml new file mode 100644 index 000000000..1d5d7223a --- /dev/null +++ b/commons/src/main/res/drawable/ic_bitcoin_vector.xml @@ -0,0 +1,4 @@ + + + + diff --git a/commons/src/main/res/drawable/ic_donate_vector.xml b/commons/src/main/res/drawable/ic_donate_vector.xml new file mode 100644 index 000000000..64929b77a --- /dev/null +++ b/commons/src/main/res/drawable/ic_donate_vector.xml @@ -0,0 +1,3 @@ + + + diff --git a/commons/src/main/res/drawable/ic_ethereum_vector.xml b/commons/src/main/res/drawable/ic_ethereum_vector.xml new file mode 100644 index 000000000..48828b65a --- /dev/null +++ b/commons/src/main/res/drawable/ic_ethereum_vector.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/commons/src/main/res/drawable/ic_github_tinted_vector.xml b/commons/src/main/res/drawable/ic_github_tinted_vector.xml new file mode 100644 index 000000000..6ce798247 --- /dev/null +++ b/commons/src/main/res/drawable/ic_github_tinted_vector.xml @@ -0,0 +1,4 @@ + + + + diff --git a/commons/src/main/res/drawable/ic_liberapay_vector.xml b/commons/src/main/res/drawable/ic_liberapay_vector.xml new file mode 100644 index 000000000..bbacd41f2 --- /dev/null +++ b/commons/src/main/res/drawable/ic_liberapay_vector.xml @@ -0,0 +1,4 @@ + + + + diff --git a/commons/src/main/res/drawable/ic_monero_vector.xml b/commons/src/main/res/drawable/ic_monero_vector.xml new file mode 100644 index 000000000..571360413 --- /dev/null +++ b/commons/src/main/res/drawable/ic_monero_vector.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/commons/src/main/res/drawable/ic_open_collective_vector.xml b/commons/src/main/res/drawable/ic_open_collective_vector.xml new file mode 100644 index 000000000..18242a286 --- /dev/null +++ b/commons/src/main/res/drawable/ic_open_collective_vector.xml @@ -0,0 +1,4 @@ + + + + diff --git a/commons/src/main/res/drawable/ic_patreon_vector.xml b/commons/src/main/res/drawable/ic_patreon_vector.xml new file mode 100644 index 000000000..23af9bb8c --- /dev/null +++ b/commons/src/main/res/drawable/ic_patreon_vector.xml @@ -0,0 +1,4 @@ + + + + diff --git a/commons/src/main/res/drawable/ic_paypal_vector.xml b/commons/src/main/res/drawable/ic_paypal_vector.xml new file mode 100644 index 000000000..400b4218b --- /dev/null +++ b/commons/src/main/res/drawable/ic_paypal_vector.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/commons/src/main/res/drawable/ic_tron_vector.xml b/commons/src/main/res/drawable/ic_tron_vector.xml new file mode 100644 index 000000000..be9f7944e --- /dev/null +++ b/commons/src/main/res/drawable/ic_tron_vector.xml @@ -0,0 +1,4 @@ + + + + diff --git a/commons/src/main/res/values/strings.xml b/commons/src/main/res/values/strings.xml index 4eebdc3ce..d2eb2d122 100644 --- a/commons/src/main/res/values/strings.xml +++ b/commons/src/main/res/values/strings.xml @@ -975,6 +975,13 @@ ]]> + + Donate to Fossify + Platforms + Little to no fee + Up to %1$d%% fee + Cryptocurrency + Frequently asked questions Before you ask a question, please first read the