diff --git a/feature/settings/compose/build.gradle.kts b/feature/settings/compose/build.gradle.kts index 9857bd0c..1e1f41c4 100644 --- a/feature/settings/compose/build.gradle.kts +++ b/feature/settings/compose/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("com.android.library") kotlin("multiplatform") + alias(libs.plugins.compose) alias(libs.plugins.compose.compiler) } @@ -33,3 +34,9 @@ androidLibrary { composeCompiler { enableStrongSkippingMode = true } + +compose.resources { + publicResClass = false + packageOfResClass = "br.alexandregpereira.hunter.settings.ui.resources" + generateResClass = always +} diff --git a/feature/settings/compose/src/commonMain/composeResources/drawable/ic-ko-fi-logo.png b/feature/settings/compose/src/commonMain/composeResources/drawable/ic-ko-fi-logo.png new file mode 100644 index 00000000..c943497d Binary files /dev/null and b/feature/settings/compose/src/commonMain/composeResources/drawable/ic-ko-fi-logo.png differ diff --git a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsAnalytics.kt b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsAnalytics.kt index 2ef7971a..705ac75a 100644 --- a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsAnalytics.kt +++ b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsAnalytics.kt @@ -101,4 +101,16 @@ internal class SettingsAnalytics( eventName = "Donate - pix code copy click", ) } + + fun trackBuyMeCoffeeClick() { + analytics.track( + eventName = "Donate - buy me coffee click", + ) + } + + fun trackPixKeyCopyClick() { + analytics.track( + eventName = "Donate - pix key copy click", + ) + } } \ No newline at end of file diff --git a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsBottomSheets.kt b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsBottomSheets.kt index 1477b393..85537fc1 100644 --- a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsBottomSheets.kt +++ b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsBottomSheets.kt @@ -50,7 +50,10 @@ fun SettingsBottomSheets() { DonateScreen( isOpen = state.donateIsOpen, state = state.donateState, + strings = state.strings.donateStrings, onClose = stateHolder::onDonateCloseClick, - onPixCodeCopy = stateHolder::onPixCodeCopyClick + onPixCodeCopy = stateHolder::onPixCodeCopyClick, + onPixKeyCopy = stateHolder::onPixKeyCopyClick, + onBuyMeCoffeeClick = stateHolder::onBuyMeCoffeeClick, ) } diff --git a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsStateHolder.kt b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsStateHolder.kt index 770f7395..5820d590 100644 --- a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsStateHolder.kt +++ b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsStateHolder.kt @@ -205,6 +205,17 @@ internal class SettingsStateHolder( analytics.trackPixCodeCopyClick() } + fun onPixKeyCopyClick() { + analytics.trackPixKeyCopyClick() + } + + fun onBuyMeCoffeeClick() { + analytics.trackBuyMeCoffeeClick() + SettingsViewAction.GoToExternalUrl( + url = "https://ko-fi.com/monstercompendium" + ).also { sendAction(it) } + } + private fun load() { getMonsterImageJsonUrl() .zip(getAlternativeSourceJsonUrl()) { imageBaseUrl, alternativeSourceBaseUrl -> diff --git a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsStrings.kt b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsStrings.kt index 577a148b..99be5dff 100644 --- a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsStrings.kt +++ b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsStrings.kt @@ -28,10 +28,12 @@ interface DonateStrings { val buyMeACoffee: String val donateDescription: String val fromBrazil: String + val fromBrazilDescription: String val pixCopyAndPaste: String - val copyPixCode: String - val fromOtherCountries: String - val fromOtherCountriesDescription: String + val pixKey: String + val supportMe: String + val donateAppName: String + val copy: String } internal data class SettingsEnStrings( @@ -56,11 +58,13 @@ internal data class SettingsEnStrings( override val donateStrings: DonateStrings = object : DonateStrings { override val buyMeACoffee: String = "Buy me a Coffee" override val donateDescription: String = "If you are enjoying this app and want to help me maintain it, please consider buying me a coffee." - override val fromBrazil: String = "From Brazil" - override val pixCopyAndPaste: String = "Pix Copia e Cola" - override val copyPixCode: String = "Copy Pix Code" - override val fromOtherCountries: String = "From Other Countries" - override val fromOtherCountriesDescription: String = "Soon" + override val fromBrazil: String = "Hey Brazil" + override val fromBrazilDescription: String = "If you are from Brazil, you can also support me by using Pix." + override val pixCopyAndPaste: String = "Pix Copy and Paste" + override val pixKey: String = "Pix Key" + override val supportMe: String = "Support me" + override val donateAppName: String = "on Ko-fi" + override val copy: String = "Copy" } ) : SettingsStrings @@ -86,11 +90,13 @@ internal data class SettingsPtStrings( override val donateStrings: DonateStrings = object : DonateStrings { override val buyMeACoffee: String = "Compre-me um Café" override val donateDescription: String = "Se você está gostando deste aplicativo e quer me ajudar a mantê-lo, considere me comprar um café." - override val fromBrazil: String = "Do Brasil" + override val fromBrazil: String = "E aí Brasil" + override val fromBrazilDescription: String = "Se você é do Brasil, também pode me apoiar usando Pix." override val pixCopyAndPaste: String = "Pix Copia e Cola" - override val copyPixCode: String = "Copiar código Pix" - override val fromOtherCountries: String = "De Outros Países" - override val fromOtherCountriesDescription: String = "Em breve" + override val pixKey: String = "Chave Pix" + override val supportMe: String = "Me apoie" + override val donateAppName: String = "no Ko-fi" + override val copy: String = "Copiar" } ) : SettingsStrings diff --git a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsViewState.kt b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsViewState.kt index 15ecda73..b2dddb9c 100644 --- a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsViewState.kt +++ b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsViewState.kt @@ -29,13 +29,13 @@ internal data class SettingsViewState( val appearanceState: AppearanceSettingsState = AppearanceSettingsState(), val strings: SettingsStrings = SettingsEnStrings(), val donateIsOpen: Boolean = false, - val donateState: DonateState = DonateState(strings = strings.donateStrings), + val donateState: DonateState = DonateState(), ) internal data class DonateState( val coverImageUrl: String = "https://raw.githubusercontent.com/alexandregpereira/Monster-Compendium/main/content/media/buy-me-coffee-cover.png", val pixCode: String = "00020126580014BR.GOV.BCB.PIX01365bc29fc7-557c-4935-bdad-1d1f53dd29e65204000053039865802BR5923Alexandre Gomes Pereira6009SAO PAULO62140510FdKlqycExz6304BCEF", - val strings: DonateStrings, + val pixKey: String = "5bc29fc7-557c-4935-bdad-1d1f53dd29e6", ) internal data class SettingsState( diff --git a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/ui/DonateScreen.kt b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/ui/DonateScreen.kt index 66d01d8b..5cdcfad9 100644 --- a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/ui/DonateScreen.kt +++ b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/ui/DonateScreen.kt @@ -1,96 +1,204 @@ package br.alexandregpereira.hunter.settings.ui +import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import br.alexandregpereira.hunter.settings.DonateState -import br.alexandregpereira.hunter.ui.compose.AppButton +import br.alexandregpereira.hunter.settings.DonateStrings +import br.alexandregpereira.hunter.settings.ui.resources.Res +import br.alexandregpereira.hunter.settings.ui.resources.ic_ko_fi_logo import br.alexandregpereira.hunter.ui.compose.AppImageContentScale import br.alexandregpereira.hunter.ui.compose.AppTextField import br.alexandregpereira.hunter.ui.compose.BottomSheet import br.alexandregpereira.hunter.ui.compose.CoilImage import br.alexandregpereira.hunter.ui.compose.SectionTitle +import br.alexandregpereira.hunter.ui.compose.animatePressed +import org.jetbrains.compose.resources.painterResource @Composable internal fun DonateScreen( isOpen: Boolean, state: DonateState, + strings: DonateStrings, onClose: () -> Unit, - onPixCodeCopy: () -> Unit + onPixCodeCopy: () -> Unit, + onPixKeyCopy: () -> Unit, + onBuyMeCoffeeClick: () -> Unit, ) = BottomSheet( opened = isOpen, topSpaceHeight = 0.dp, onClose = onClose, ) { - val strings = state.strings Column { CoilImage( imageUrl = state.coverImageUrl, modifier = Modifier .fillMaxWidth() - .aspectRatio(16f / 9f) - .background(color = MaterialTheme.colors.background), + .aspectRatio(16f / 9f), contentDescription = "", contentScale = AppImageContentScale.Fit ) - Column(Modifier.padding(horizontal = 16.dp).padding(top = 8.dp, bottom = 16.dp)) { - SectionTitle(strings.buyMeACoffee, isHeader = true) + Column(Modifier.padding(horizontal = 12.dp).padding(top = 8.dp, bottom = 16.dp)) { + SectionTitle(strings.buyMeACoffee, isHeader = false) Text( text = strings.donateDescription, fontWeight = FontWeight.Normal, - fontSize = 18.sp, + fontSize = 16.sp, modifier = Modifier.padding(top = 8.dp) ) - SectionTitle( - title = strings.fromBrazil, - isHeader = false, + BuyMeCoffeeButton( + text = strings.donateAppName, + label = strings.supportMe, + onClick = onBuyMeCoffeeClick, + modifier = Modifier.padding(top = 16.dp) + ) + + Text( + text = strings.fromBrazil, + fontWeight = FontWeight.Bold, + fontSize = 18.sp, modifier = Modifier.padding(top = 24.dp) ) - AppTextField( - text = state.pixCode, - trailingIcon = null, - label = strings.pixCopyAndPaste, - enabled = false, - modifier = Modifier.fillMaxWidth().padding(top = 16.dp) + Text( + text = strings.fromBrazilDescription, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + modifier = Modifier.padding(top = 8.dp) ) val clipBoardManager = LocalClipboardManager.current - AppButton( - text = strings.copyPixCode, + CopyTextField( + text = state.pixKey, + label = strings.pixKey, + buttonText = strings.copy, + onClick = { + onPixKeyCopy() + clipBoardManager.setText(AnnotatedString(state.pixKey)) + }, + modifier = Modifier.fillMaxWidth().padding(top = 16.dp) + ) + + CopyTextField( + text = state.pixCode, + label = strings.pixCopyAndPaste, + buttonText = strings.copy, onClick = { onPixCodeCopy() clipBoardManager.setText(AnnotatedString(state.pixCode)) }, - modifier = Modifier.padding(top = 16.dp) + modifier = Modifier.fillMaxWidth().padding(top = 16.dp) ) + } + } +} - SectionTitle( - title = strings.fromOtherCountries, - isHeader = false, - modifier = Modifier.padding(top = 24.dp) - ) +@Composable +private fun CopyTextField( + label: String, + text: String, + buttonText: String, + modifier: Modifier = Modifier, + onClick: () -> Unit = {}, +) = Row( + modifier = modifier, + verticalAlignment = Alignment.Bottom +) { + AppTextField( + text = text, + trailingIcon = null, + label = label, + enabled = false, + modifier = Modifier.weight(1f) + ) + Spacer(modifier = Modifier.width(8.dp)) - Text( - text = strings.fromOtherCountriesDescription, - fontWeight = FontWeight.Normal, - fontSize = 16.sp, - modifier = Modifier.padding(top = 8.dp) - ) - } + val buttonModifier = Modifier + .height(56.dp) + .animatePressed( + onClick = onClick, + ) + .clip(RoundedCornerShape(20)) + .background(MaterialTheme.colors.primary) + Box( + modifier = buttonModifier, + contentAlignment = Alignment.Center, + ) { + Text( + text = buttonText, + fontWeight = FontWeight.Normal, + color = MaterialTheme.colors.onPrimary, + fontSize = 16.sp, + modifier = Modifier.padding(horizontal = 16.dp) + ) + } +} + +@Composable +private fun BuyMeCoffeeButton( + text: String, + label: String, + onClick: () -> Unit, + modifier: Modifier = Modifier +) = Row( + modifier = modifier + .height(54.dp) + .animatePressed( + onClick = onClick, + ) + .clip(RoundedCornerShape(12.dp)) + .background(MaterialTheme.colors.primary), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center +) { + val contentHorizontalPadding = 16.dp + val contentVerticalPadding = 8.dp + Spacer(modifier = Modifier.width(contentHorizontalPadding)) + Image( + painter = painterResource(Res.drawable.ic_ko_fi_logo), + contentDescription = null, + modifier = Modifier.padding(vertical = contentVerticalPadding) + ) + Spacer(modifier = Modifier.width(8.dp)) + Column( + modifier = Modifier.padding(vertical = contentVerticalPadding) + ) { + Text( + text = label, + fontWeight = FontWeight.Light, + fontSize = 12.sp, + color = MaterialTheme.colors.onPrimary, + ) + Text( + text = text, + fontWeight = FontWeight.Bold, + fontSize = 22.sp, + color = MaterialTheme.colors.onPrimary, + ) } + Spacer(modifier = Modifier.width(contentHorizontalPadding)) } diff --git a/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/BottomSheet.kt b/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/BottomSheet.kt index 67c6b405..d8abaeb3 100644 --- a/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/BottomSheet.kt +++ b/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/BottomSheet.kt @@ -100,6 +100,7 @@ fun BottomSheet( ).fillMaxWidth( fraction = widthFraction.takeIf { screenSize.isLandscape } ?: 1f ).noIndicationClick(), + level = 0, ) { Column( modifier = modifier.padding(