diff --git a/.github/workflows/Main.yml b/.github/workflows/Main.yml index 022193ca6..c409d1200 100644 --- a/.github/workflows/Main.yml +++ b/.github/workflows/Main.yml @@ -7,6 +7,7 @@ on: paths-ignore: - '**.md' - 'media/**' + - 'content/**' jobs: multiplatform-build: diff --git a/.github/workflows/PR.yml b/.github/workflows/PR.yml index a3044bccb..fec9330e0 100644 --- a/.github/workflows/PR.yml +++ b/.github/workflows/PR.yml @@ -5,6 +5,7 @@ on: paths-ignore: - '**.md' - 'media/**' + - 'content/**' jobs: multiplatform-build: diff --git a/content/media/buy-me-coffee-cover.png b/content/media/buy-me-coffee-cover.png new file mode 100644 index 000000000..c7ba6f949 Binary files /dev/null and b/content/media/buy-me-coffee-cover.png differ diff --git a/core/localization/src/iosMain/kotlin/br/alexandregpereira/hunter/localization/Localization.kt b/core/localization/src/iosMain/kotlin/br/alexandregpereira/hunter/localization/Localization.ios.kt similarity index 100% rename from core/localization/src/iosMain/kotlin/br/alexandregpereira/hunter/localization/Localization.kt rename to core/localization/src/iosMain/kotlin/br/alexandregpereira/hunter/localization/Localization.ios.kt diff --git a/core/localization/src/jvmMain/kotlin/br/alexandregpereira/hunter/localization/Localization.kt b/core/localization/src/jvmMain/kotlin/br/alexandregpereira/hunter/localization/Localization.jvm.kt similarity index 100% rename from core/localization/src/jvmMain/kotlin/br/alexandregpereira/hunter/localization/Localization.kt rename to core/localization/src/jvmMain/kotlin/br/alexandregpereira/hunter/localization/Localization.jvm.kt diff --git a/core/uuid/src/commonMain/kotlin/br/alexandregpereira/hunter/strings/Strings.kt b/core/uuid/src/commonMain/kotlin/br/alexandregpereira/hunter/strings/Strings.kt new file mode 100644 index 000000000..1301aea1a --- /dev/null +++ b/core/uuid/src/commonMain/kotlin/br/alexandregpereira/hunter/strings/Strings.kt @@ -0,0 +1,12 @@ +package br.alexandregpereira.hunter.strings + +fun String.format(vararg args: Any): String { + return args.foldIndexed(this) { index, string, arg -> + string.replace("{$index}", arg.toString()) + } +} + +fun String.formatWithPlural(arg: Int, plural: String): String { + val string = if (arg != 1 && plural.isNotBlank()) plural else this + return string.format(arg) +} diff --git a/feature/monster-content-manager/compose/build.gradle.kts b/feature/monster-content-manager/compose/build.gradle.kts index 8d23cf7ba..7f835d18d 100644 --- a/feature/monster-content-manager/compose/build.gradle.kts +++ b/feature/monster-content-manager/compose/build.gradle.kts @@ -8,6 +8,7 @@ multiplatform { androidMain() commonMain { implementation(project(":core:ui:state-recovery")) + implementation(project(":core:uuid")) implementation(project(":feature:monster-content-manager:state-holder")) implementation(project(":ui:core")) implementation(project(":ui:monster-compendium")) diff --git a/feature/monster-content-manager/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/content/ui/MonsterContentCard.kt b/feature/monster-content-manager/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/content/ui/MonsterContentCard.kt index 35b9b3932..a5dc9c8ff 100644 --- a/feature/monster-content-manager/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/content/ui/MonsterContentCard.kt +++ b/feature/monster-content-manager/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/content/ui/MonsterContentCard.kt @@ -19,6 +19,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import br.alexandregpereira.hunter.monster.content.MonsterContentManagerEmptyStrings import br.alexandregpereira.hunter.monster.content.MonsterContentManagerStrings +import br.alexandregpereira.hunter.strings.format import br.alexandregpereira.hunter.ui.compose.AppButton import br.alexandregpereira.hunter.ui.compose.AppButtonSize import br.alexandregpereira.hunter.ui.compose.AppCard @@ -55,7 +56,7 @@ internal fun MonsterContentCard( Cover( coverImageUrl = coverImageUrl, name = name, - totalMonsters = strings.totalMonsters(totalMonsters), + totalMonsters = strings.totalMonsters.format(totalMonsters), modifier = Modifier.fillMaxWidth() ) diff --git a/feature/monster-content-manager/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/content/MonsterContentManagerStrings.kt b/feature/monster-content-manager/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/content/MonsterContentManagerStrings.kt index b8b767619..0a4c56046 100644 --- a/feature/monster-content-manager/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/content/MonsterContentManagerStrings.kt +++ b/feature/monster-content-manager/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/content/MonsterContentManagerStrings.kt @@ -7,7 +7,7 @@ interface MonsterContentManagerStrings { val title: String val add: String val remove: String - val totalMonsters: (Int) -> String + val totalMonsters: String val preview: String } @@ -15,7 +15,7 @@ internal data class MonsterContentManagerEnStrings( override val title: String = "Manage Content", override val add: String = "Add", override val remove: String = "Remove", - override val totalMonsters: (Int) -> String = { total -> "$total monsters" }, + override val totalMonsters: String = "{0} monsters", override val preview: String = "Preview", ) : MonsterContentManagerStrings @@ -23,7 +23,7 @@ internal data class MonsterContentManagerPtStrings( override val title: String = "Gerenciar Conteúdo", override val add: String = "Adicionar", override val remove: String = "Remover", - override val totalMonsters: (Int) -> String = { total -> "$total monstros" }, + override val totalMonsters: String = "{0} monstros", override val preview: String = "Prévia", ) : MonsterContentManagerStrings @@ -31,7 +31,7 @@ data class MonsterContentManagerEmptyStrings( override val title: String = "", override val add: String = "", override val remove: String = "", - override val totalMonsters: (Int) -> String = { _ -> "" }, + override val totalMonsters: String = "", override val preview: String = "", ) : MonsterContentManagerStrings diff --git a/feature/monster-registration/compose/build.gradle.kts b/feature/monster-registration/compose/build.gradle.kts index d2b9d4b9d..a8e9010a9 100644 --- a/feature/monster-registration/compose/build.gradle.kts +++ b/feature/monster-registration/compose/build.gradle.kts @@ -8,6 +8,7 @@ multiplatform { androidMain() commonMain { implementation(project(":core:state-holder")) + implementation(project(":core:uuid")) implementation(project(":domain:monster:core")) implementation(project(":domain:monster-lore:core")) implementation(project(":domain:spell:core")) diff --git a/feature/monster-registration/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/registration/ui/form/MonsterImageForm.kt b/feature/monster-registration/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/registration/ui/form/MonsterImageForm.kt index d49814cca..b9276552c 100644 --- a/feature/monster-registration/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/registration/ui/form/MonsterImageForm.kt +++ b/feature/monster-registration/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/registration/ui/form/MonsterImageForm.kt @@ -23,6 +23,7 @@ import androidx.compose.ui.unit.sp import br.alexandregpereira.hunter.domain.model.MonsterImageContentScale import br.alexandregpereira.hunter.monster.registration.MonsterInfoState import br.alexandregpereira.hunter.monster.registration.ui.strings +import br.alexandregpereira.hunter.strings.format import br.alexandregpereira.hunter.ui.compose.AppImageContentScale import br.alexandregpereira.hunter.ui.compose.AppSwitch import br.alexandregpereira.hunter.ui.compose.AppTextField @@ -80,7 +81,7 @@ internal fun LazyListScope.MonsterImageForm( Spacer(modifier = Modifier.padding(4.dp)) val aspectRatio = getMonsterImageAspectRatio(infoState.isImageHorizontal) Text( - text = strings.imageProportion(aspectRatio.toString()), + text = strings.imageProportion.format(aspectRatio), fontWeight = FontWeight.Light, fontSize = 14.sp, ) diff --git a/feature/monster-registration/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/registration/MonsterRegistrationStrings.kt b/feature/monster-registration/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/registration/MonsterRegistrationStrings.kt index 09a38103c..13d7e0585 100644 --- a/feature/monster-registration/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/registration/MonsterRegistrationStrings.kt +++ b/feature/monster-registration/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/registration/MonsterRegistrationStrings.kt @@ -113,7 +113,7 @@ interface MonsterRegistrationStrings { val imageFormTitle: String val imageHorizontalSwitchLabel: String val darkThemeSwitchLabel: String - val imageProportion: (String) -> String + val imageProportion: String val challengeRating: String } @@ -227,7 +227,7 @@ internal data class MonsterRegistrationEnStrings( override val imageFormTitle: String = "Image", override val imageHorizontalSwitchLabel: String = "Landscape Image", override val darkThemeSwitchLabel: String = "Preview Dark Theme", - override val imageProportion: (String) -> String = { "Proportion - $it" }, + override val imageProportion: String = "Proportion - {0}", override val challengeRating: String = "Challenge Rating", ) : MonsterRegistrationStrings @@ -341,7 +341,7 @@ internal data class MonsterRegistrationPtStrings( override val imageFormTitle: String = "Imagem", override val imageHorizontalSwitchLabel: String = "Imagem Landscape", override val darkThemeSwitchLabel: String = "Pré visualizar em Tema Escuro", - override val imageProportion: (String) -> String = { "Proporção - $it" }, + override val imageProportion: String = "Proporção - {0}", override val challengeRating: String = "Nível de Desafio", ) : MonsterRegistrationStrings diff --git a/feature/search/compose/build.gradle.kts b/feature/search/compose/build.gradle.kts index a5b2f5189..f7f982e0f 100644 --- a/feature/search/compose/build.gradle.kts +++ b/feature/search/compose/build.gradle.kts @@ -11,6 +11,7 @@ multiplatform { implementation(project(":core:localization")) implementation(project(":core:state-holder")) implementation(project(":core:search")) + implementation(project(":core:uuid")) implementation(project(":domain:monster:core")) implementation(project(":domain:monster-lore:core")) implementation(project(":domain:spell:core")) diff --git a/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/SearchStateHolder.kt b/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/SearchStateHolder.kt index 7907f6cb1..8a036f5ea 100644 --- a/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/SearchStateHolder.kt +++ b/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/SearchStateHolder.kt @@ -30,6 +30,7 @@ import br.alexandregpereira.hunter.search.domain.SearchKeySymbolAnd import br.alexandregpereira.hunter.search.domain.SearchMonstersByUseCase import br.alexandregpereira.hunter.search.ui.SearchViewState import br.alexandregpereira.hunter.state.UiModel +import br.alexandregpereira.hunter.strings.formatWithPlural import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.Job @@ -87,7 +88,12 @@ internal class SearchStateHolder( copy( monsterRows = monsterRows, totalResults = totalResults, - searchResults = appLocalization.getStrings().searchResults(totalResults) + searchResults = appLocalization.getStrings().run { + searchResultsSingular.formatWithPlural( + totalResults, + searchResultsPlural + ) + } ) } } @@ -111,7 +117,10 @@ internal class SearchStateHolder( setState { copy( searchLabel = strings.search, - searchResults = strings.searchResults(state.value.totalResults) + searchResults = strings.searchResultsSingular.formatWithPlural( + state.value.totalResults, + strings.searchResultsPlural + ) ) } }.launchIn(scope) diff --git a/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/SearchStrings.kt b/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/SearchStrings.kt index 65a2b884b..b3de469c9 100644 --- a/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/SearchStrings.kt +++ b/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/SearchStrings.kt @@ -5,29 +5,20 @@ import br.alexandregpereira.hunter.localization.Language internal interface SearchStrings { val search: String - val searchResults: (Int) -> String + val searchResultsPlural: String + val searchResultsSingular: String } internal data class SearchEnStrings( override val search: String = "Search", - override val searchResults: (Int) -> String = { results -> - if (results == 1) { - "1 result" - } else { - "$results results" - } - } + override val searchResultsPlural: String = "{0} results", + override val searchResultsSingular: String = "{0} result" ) : SearchStrings internal data class SearchPtStrings( override val search: String = "Buscar", - override val searchResults: (Int) -> String = { results -> - if (results == 1) { - "1 resultado" - } else { - "$results resultados" - } - } + override val searchResultsPlural: String = "{0} resultados", + override val searchResultsSingular: String = "{0} resultado" ) : SearchStrings internal fun AppLocalization.getStrings(): SearchStrings { 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 4d7000ee8..2ef7971a8 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 @@ -89,4 +89,16 @@ internal class SettingsAnalytics( eventName = "Settings - appearance settings click", ) } + + fun trackDonateClick() { + analytics.track( + eventName = "Settings - donate click", + ) + } + + fun trackPixCodeCopyClick() { + analytics.track( + eventName = "Donate - pix code 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 276454a26..1477b3939 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 @@ -5,6 +5,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import br.alexandregpereira.hunter.settings.ui.AdvancedSettings import br.alexandregpereira.hunter.settings.ui.AppearanceSettingsBottomSheet +import br.alexandregpereira.hunter.settings.ui.DonateScreen import br.alexandregpereira.hunter.settings.ui.SettingsBottomSheet import br.alexandregpereira.hunter.ui.compose.BottomSheet import org.koin.compose.koinInject @@ -44,5 +45,12 @@ fun SettingsBottomSheets() { onStateChange = stateHolder::onAppearanceChange, onSaveButtonClick = stateHolder::onAppearanceSettingsSaveClick, onClose = stateHolder::onAppearanceSettingsCloseClick - ) + ) + + DonateScreen( + isOpen = state.donateIsOpen, + state = state.donateState, + onClose = stateHolder::onDonateCloseClick, + onPixCodeCopy = stateHolder::onPixCodeCopyClick + ) } 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 f328ffd41..770f7395e 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 @@ -192,6 +192,19 @@ internal class SettingsStateHolder( ).also { sendAction(it) } } + override fun onDonateClick() { + analytics.trackDonateClick() + setState { copy(donateIsOpen = true) } + } + + fun onDonateCloseClick() { + setState { copy(donateIsOpen = false) } + } + + fun onPixCodeCopyClick() { + analytics.trackPixCodeCopyClick() + } + 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 da359bf4b..577a148b2 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 @@ -21,6 +21,17 @@ interface SettingsStrings { val imageContentScaleFit: String val imageContentScaleCrop: String val openGitHubProject: String + val donateStrings: DonateStrings +} + +interface DonateStrings { + val buyMeACoffee: String + val donateDescription: String + val fromBrazil: String + val pixCopyAndPaste: String + val copyPixCode: String + val fromOtherCountries: String + val fromOtherCountriesDescription: String } internal data class SettingsEnStrings( @@ -42,6 +53,15 @@ internal data class SettingsEnStrings( override val imageContentScaleFit: String = "Show entire image", override val imageContentScaleCrop: String = "Expand the image", override val openGitHubProject: String = "Open GitHub Project", + 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" + } ) : SettingsStrings internal data class SettingsPtStrings( @@ -63,27 +83,15 @@ internal data class SettingsPtStrings( override val imageContentScaleFit: String = "Mostrar imagem inteira", override val imageContentScaleCrop: String = "Expandir a imagem", override val openGitHubProject: String = "Abrir Projeto no GitHub", -) : SettingsStrings - -internal data class SettingsEmptyStrings( - override val additionalContent: String = "", - override val monsterImagesJson: String = "", - override val alternativeSourcesJson: String = "", - override val manageMonsterContent: String = "", - override val sync: String = "", - override val manageAdvancedSettings: String = "", - override val settingsTitle: String = "", - override val languageLabel: String = "", - override val save: String = "", - override val appearanceSettingsTitle: String = "", - override val forceLightImageBackground: String = "", - override val defaultLightBackground: String = "", - override val defaultDarkBackground: String = "", - override val importContent: String = "", - override val monsterImageContentScale: String = "", - override val imageContentScaleFit: String = "", - override val imageContentScaleCrop: String = "", - override val openGitHubProject: String = "", + 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 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" + } ) : SettingsStrings internal fun getSettingsStrings(lang: Language): SettingsStrings { diff --git a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsViewIntent.kt b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsViewIntent.kt index 5805265fe..5cf1e5713 100644 --- a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsViewIntent.kt +++ b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/SettingsViewIntent.kt @@ -32,4 +32,6 @@ internal interface SettingsViewIntent { fun onImport() fun onOpenGitHubProjectClick() + + fun onDonateClick() } 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 f914609c2..15ecda733 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 @@ -27,7 +27,15 @@ internal data class SettingsViewState( val appearanceSettingsOpened: Boolean = false, val settingsState: SettingsState = SettingsState(), val appearanceState: AppearanceSettingsState = AppearanceSettingsState(), - val strings: SettingsStrings = SettingsEmptyStrings(), + val strings: SettingsStrings = SettingsEnStrings(), + val donateIsOpen: Boolean = false, + val donateState: DonateState = DonateState(strings = strings.donateStrings), +) + +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, ) 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 new file mode 100644 index 000000000..66d01d8b4 --- /dev/null +++ b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/ui/DonateScreen.kt @@ -0,0 +1,96 @@ +package br.alexandregpereira.hunter.settings.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +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.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 + +@Composable +internal fun DonateScreen( + isOpen: Boolean, + state: DonateState, + onClose: () -> Unit, + onPixCodeCopy: () -> 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), + contentDescription = "", + contentScale = AppImageContentScale.Fit + ) + + Column(Modifier.padding(horizontal = 16.dp).padding(top = 8.dp, bottom = 16.dp)) { + SectionTitle(strings.buyMeACoffee, isHeader = true) + + Text( + text = strings.donateDescription, + fontWeight = FontWeight.Normal, + fontSize = 18.sp, + modifier = Modifier.padding(top = 8.dp) + ) + + SectionTitle( + title = strings.fromBrazil, + isHeader = false, + modifier = Modifier.padding(top = 24.dp) + ) + + AppTextField( + text = state.pixCode, + trailingIcon = null, + label = strings.pixCopyAndPaste, + enabled = false, + modifier = Modifier.fillMaxWidth().padding(top = 16.dp) + ) + + val clipBoardManager = LocalClipboardManager.current + AppButton( + text = strings.copyPixCode, + onClick = { + onPixCodeCopy() + clipBoardManager.setText(AnnotatedString(state.pixCode)) + }, + modifier = Modifier.padding(top = 16.dp) + ) + + SectionTitle( + title = strings.fromOtherCountries, + isHeader = false, + modifier = Modifier.padding(top = 24.dp) + ) + + Text( + text = strings.fromOtherCountriesDescription, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + modifier = Modifier.padding(top = 8.dp) + ) + } + } +} diff --git a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/ui/MenuScreen.kt b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/ui/MenuScreen.kt index a2e198ad2..5ec9f8cd6 100644 --- a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/ui/MenuScreen.kt +++ b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/ui/MenuScreen.kt @@ -43,49 +43,57 @@ internal fun MenuScreen( contentPadding: PaddingValues = PaddingValues(), viewIntent: SettingsViewIntent, ) { + val strings = state.strings Box( modifier = Modifier.fillMaxSize() ) { Column(Modifier.padding(contentPadding).verticalScroll(rememberScrollState())) { MenuItem( - text = state.strings.settingsTitle, + text = strings.settingsTitle, onClick = viewIntent::onSettingsClick ) Divider() MenuItem( - text = state.strings.manageAdvancedSettings, + text = strings.manageAdvancedSettings, onClick = viewIntent::onAdvancedSettingsClick ) Divider() MenuItem( - text = state.strings.appearanceSettingsTitle, + text = strings.appearanceSettingsTitle, onClick = viewIntent::onAppearanceSettingsClick ) Divider() MenuItem( - text = state.strings.importContent, + text = strings.importContent, onClick = viewIntent::onImport ) Divider() MenuItem( - text = state.strings.manageMonsterContent, + text = strings.manageMonsterContent, onClick = viewIntent::onManageMonsterContentClick ) Divider() MenuItem( - text = state.strings.openGitHubProject, + text = strings.openGitHubProject, onClick = viewIntent::onOpenGitHubProjectClick ) + + Divider() + + MenuItem( + text = strings.donateStrings.buyMeACoffee, + onClick = viewIntent::onDonateClick + ) } if (versionName.isNotBlank()) { diff --git a/feature/spell-detail/compose/build.gradle.kts b/feature/spell-detail/compose/build.gradle.kts index 06cc2078b..7a47ef24b 100644 --- a/feature/spell-detail/compose/build.gradle.kts +++ b/feature/spell-detail/compose/build.gradle.kts @@ -8,6 +8,7 @@ multiplatform { implementation(project(":core:analytics")) implementation(project(":core:localization")) implementation(project(":core:state-holder")) + implementation(project(":core:uuid")) implementation(project(":domain:spell:core")) implementation(project(":feature:spell-detail:event")) implementation(project(":ui:core")) diff --git a/feature/spell-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/spell/detail/SpellDetailStrings.kt b/feature/spell-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/spell/detail/SpellDetailStrings.kt index 9db0080b1..6c337f960 100644 --- a/feature/spell-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/spell/detail/SpellDetailStrings.kt +++ b/feature/spell-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/spell/detail/SpellDetailStrings.kt @@ -2,9 +2,11 @@ package br.alexandregpereira.hunter.spell.detail import br.alexandregpereira.hunter.localization.AppLocalization import br.alexandregpereira.hunter.localization.Language +import br.alexandregpereira.hunter.strings.format internal interface SpellDetailStrings { - val subtitle: (Int, String) -> String + val subtitleCantrip: String + val subtitleLevel: String val castingTime: String val range: String val components: String @@ -30,9 +32,8 @@ internal interface SpellDetailStrings { } internal data class SpellDetailEnStrings( - override val subtitle: (Int, String) -> String = { level, school -> - if (level == 0) "Cantrip, $school" else "Level $level, $school" - }, + override val subtitleCantrip: String = "Cantrip, {0}", + override val subtitleLevel: String = "Level {0}, {1}", override val castingTime: String = "Casting Time:", override val range: String = "Range:", override val components: String = "Components:", @@ -58,9 +59,8 @@ internal data class SpellDetailEnStrings( ) : SpellDetailStrings internal data class SpellDetailPtStrings( - override val subtitle: (Int, String) -> String = { level, school -> - if (level == 0) "Truque, $school" else "$level° círculo, $school" - }, + override val subtitleCantrip: String = "Truque, {0}", + override val subtitleLevel: String = "Nível {0}, {1}", override val castingTime: String = "Tempo de Conjuração:", override val range: String = "Alcance:", override val components: String = "Componentes:", @@ -85,6 +85,10 @@ internal data class SpellDetailPtStrings( override val cantrip: String = "Truque", ) : SpellDetailStrings +internal fun SpellDetailStrings.formatSubTitle(level: Int, school: String): String { + return if (level == 0) subtitleCantrip.format(school) else subtitleLevel.format(level, school) +} + internal fun SpellDetailStrings(): SpellDetailStrings = SpellDetailEnStrings() internal fun AppLocalization.getStrings(): SpellDetailStrings { diff --git a/feature/spell-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/spell/detail/SpellDetailViewStateMapper.kt b/feature/spell-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/spell/detail/SpellDetailViewStateMapper.kt index 3c05ad38b..1529ecb3a 100644 --- a/feature/spell-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/spell/detail/SpellDetailViewStateMapper.kt +++ b/feature/spell-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/spell/detail/SpellDetailViewStateMapper.kt @@ -29,7 +29,7 @@ internal fun Spell.asState(strings: SpellDetailStrings): SpellState { return SpellState( index = index, name = name, - subtitle = strings.subtitle(level, school.name(strings)), + subtitle = strings.formatSubTitle(level, school.name(strings)), castingTime = castingTime, components = components, duration = durationText,