diff --git a/domain/monster-folder/core/build.gradle.kts b/domain/monster-folder/core/build.gradle.kts index 9db56f758..a20be9547 100644 --- a/domain/monster-folder/core/build.gradle.kts +++ b/domain/monster-folder/core/build.gradle.kts @@ -4,7 +4,6 @@ plugins { multiplatform { commonMain { - implementation(project(":domain:monster:core")) implementation(libs.koin.core) implementation(libs.kotlin.coroutines.core) } diff --git a/domain/monster-folder/core/src/commonMain/kotlin/br/alexandregpereira/hunter/domain/folder/model/MonsterPreviewFolder.kt b/domain/monster-folder/core/src/commonMain/kotlin/br/alexandregpereira/hunter/domain/folder/model/MonsterPreviewFolder.kt index 63d221771..f51ce69d6 100644 --- a/domain/monster-folder/core/src/commonMain/kotlin/br/alexandregpereira/hunter/domain/folder/model/MonsterPreviewFolder.kt +++ b/domain/monster-folder/core/src/commonMain/kotlin/br/alexandregpereira/hunter/domain/folder/model/MonsterPreviewFolder.kt @@ -24,5 +24,11 @@ data class MonsterPreviewFolder( val imageUrl: String = "", val backgroundColorLight: String, val backgroundColorDark: String, + val imageContentScale: MonsterPreviewFolderImageContentScale, val isHorizontalImage: Boolean = false, ) + +enum class MonsterPreviewFolderImageContentScale { + Fit, + Crop +} diff --git a/domain/monster-folder/data/build.gradle.kts b/domain/monster-folder/data/build.gradle.kts index 61089880f..0d31b26b1 100644 --- a/domain/monster-folder/data/build.gradle.kts +++ b/domain/monster-folder/data/build.gradle.kts @@ -7,6 +7,7 @@ multiplatform { commonMain { implementation(project(":domain:monster:data")) implementation(project(":domain:monster-folder:core")) + implementation(project(":domain:settings:core")) implementation(libs.kotlin.coroutines.core) implementation(libs.kotlin.datetime) implementation(libs.koin.core) diff --git a/domain/monster-folder/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/folder/DefaultFolderRepository.kt b/domain/monster-folder/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/folder/DefaultFolderRepository.kt index 0fca1e844..d493f23e5 100644 --- a/domain/monster-folder/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/folder/DefaultFolderRepository.kt +++ b/domain/monster-folder/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/folder/DefaultFolderRepository.kt @@ -21,11 +21,16 @@ import br.alexandregpereira.hunter.domain.folder.FolderMonsterPreviewRepository import br.alexandregpereira.hunter.domain.folder.MonsterFolderRepository import br.alexandregpereira.hunter.domain.folder.model.MonsterFolder import br.alexandregpereira.hunter.domain.folder.model.MonsterPreviewFolder +import br.alexandregpereira.hunter.domain.folder.model.MonsterPreviewFolderImageContentScale +import br.alexandregpereira.hunter.domain.settings.AppSettingsImageContentScale +import br.alexandregpereira.hunter.domain.settings.GetAppearanceSettings import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.single internal class DefaultFolderRepository( - private val monsterFolderLocalDataSource: MonsterFolderLocalDataSource + private val monsterFolderLocalDataSource: MonsterFolderLocalDataSource, + private val getAppearanceSettings: GetAppearanceSettings, ) : MonsterFolderRepository, FolderMonsterPreviewRepository { override fun addMonsters(folderName: String, indexes: List): Flow { @@ -33,16 +38,20 @@ internal class DefaultFolderRepository( } override fun getMonsterFolders(): Flow> { - return monsterFolderLocalDataSource.getMonsterFolders().map { it.asDomain() } + return monsterFolderLocalDataSource.getMonsterFolders().map { + it.asDomain(getImageContentScale()) + } } override fun getMonstersFromFolder(folderName: String): Flow { - return monsterFolderLocalDataSource.getMonstersFromFolder(folderName).map { it?.asDomain() } + return monsterFolderLocalDataSource.getMonstersFromFolder(folderName).map { + it?.asDomain(getImageContentScale()) + } } override fun getMonstersFromFolders(foldersName: List): Flow> { return monsterFolderLocalDataSource.getMonstersFromFolders(foldersName) - .map { it.asDomainMonsterPreviewFolderEntity() } + .map { it.asDomainMonsterPreviewFolderEntity(getImageContentScale()) } } override fun removeMonsters(folderName: String, indexes: List): Flow { @@ -53,10 +62,19 @@ internal class DefaultFolderRepository( indexes: List ): Flow> { return monsterFolderLocalDataSource.getFolderMonsterPreviewsByIds(indexes) - .map { it.asDomainMonsterPreviewFolderEntity() } + .map { it.asDomainMonsterPreviewFolderEntity(getImageContentScale()) } } override fun removeMonsterFolders(folderNames: List): Flow { return monsterFolderLocalDataSource.removeMonsterFolders(folderNames) } + + private suspend fun getImageContentScale(): MonsterPreviewFolderImageContentScale { + return getAppearanceSettings().single().let { settings -> + when (settings.imageContentScale) { + AppSettingsImageContentScale.Fit -> MonsterPreviewFolderImageContentScale.Fit + AppSettingsImageContentScale.Crop -> MonsterPreviewFolderImageContentScale.Crop + } + } + } } diff --git a/domain/monster-folder/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/folder/MonsterFolderEntityMapper.kt b/domain/monster-folder/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/folder/MonsterFolderEntityMapper.kt index e6e417544..8cafcc863 100644 --- a/domain/monster-folder/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/folder/MonsterFolderEntityMapper.kt +++ b/domain/monster-folder/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/folder/MonsterFolderEntityMapper.kt @@ -20,20 +20,27 @@ import br.alexandregpereira.hunter.data.monster.folder.local.entity.MonsterFolde import br.alexandregpereira.hunter.data.monster.local.entity.MonsterEntity import br.alexandregpereira.hunter.domain.folder.model.MonsterFolder import br.alexandregpereira.hunter.domain.folder.model.MonsterPreviewFolder +import br.alexandregpereira.hunter.domain.folder.model.MonsterPreviewFolderImageContentScale import br.alexandregpereira.hunter.domain.folder.model.MonsterPreviewFolderType -internal fun List.asDomain(): List { - return this.map { it.asDomain() } +internal fun List.asDomain( + monsterImageContentScale: MonsterPreviewFolderImageContentScale +): List { + return this.map { it.asDomain(monsterImageContentScale) } } -internal fun MonsterFolderCompleteEntity.asDomain(): MonsterFolder { +internal fun MonsterFolderCompleteEntity.asDomain( + monsterImageContentScale: MonsterPreviewFolderImageContentScale +): MonsterFolder { return MonsterFolder( name = monsterFolderEntity.folderName, - monsters = monsters.asDomainMonsterPreviewFolderEntity() + monsters = monsters.asDomainMonsterPreviewFolderEntity(monsterImageContentScale) ) } -internal fun List.asDomainMonsterPreviewFolderEntity(): List { +internal fun List.asDomainMonsterPreviewFolderEntity( + monsterImageContentScale: MonsterPreviewFolderImageContentScale +): List { return map { it.run { MonsterPreviewFolder( @@ -45,6 +52,7 @@ internal fun List.asDomainMonsterPreviewFolderEntity(): List { DefaultMonsterFolderLocalDataSource(get(), get()) } factory { - createMonsterFolderRepository() ?: DefaultFolderRepository(get()) + createMonsterFolderRepository() ?: DefaultFolderRepository(get(), get()) } factory { - createFolderMonsterPreviewRepository() ?: DefaultFolderRepository(get()) + createFolderMonsterPreviewRepository() ?: DefaultFolderRepository(get(), get()) } }.apply { includes(getAdditionalModule()) } diff --git a/domain/monster/core/src/commonMain/kotlin/br/alexandregpereira/hunter/domain/model/Monster.kt b/domain/monster/core/src/commonMain/kotlin/br/alexandregpereira/hunter/domain/model/Monster.kt index 8d82732b3..22f82bd41 100644 --- a/domain/monster/core/src/commonMain/kotlin/br/alexandregpereira/hunter/domain/model/Monster.kt +++ b/domain/monster/core/src/commonMain/kotlin/br/alexandregpereira/hunter/domain/model/Monster.kt @@ -85,9 +85,14 @@ fun Float.getChallengeRatingFormatted(): String { data class MonsterImageData( val url: String = "", val backgroundColor: Color = Color(), - val isHorizontal: Boolean = false + val isHorizontal: Boolean = false, + val contentScale: MonsterImageContentScale = MonsterImageContentScale.Fit, ) +enum class MonsterImageContentScale { + Fit, Crop +} + data class Color( val light: String = "", val dark: String = "" diff --git a/domain/monster/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/DefaultMonsterLocalRepository.kt b/domain/monster/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/DefaultMonsterLocalRepository.kt index 145521d68..d09078292 100644 --- a/domain/monster/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/DefaultMonsterLocalRepository.kt +++ b/domain/monster/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/DefaultMonsterLocalRepository.kt @@ -22,13 +22,18 @@ import br.alexandregpereira.hunter.data.monster.local.mapper.toDomainMonsterEnti import br.alexandregpereira.hunter.data.monster.local.mapper.toEntity import br.alexandregpereira.hunter.data.monster.local.mapper.toEntityStatus import br.alexandregpereira.hunter.domain.model.Monster +import br.alexandregpereira.hunter.domain.model.MonsterImageContentScale import br.alexandregpereira.hunter.domain.model.MonsterStatus import br.alexandregpereira.hunter.domain.repository.MonsterLocalRepository +import br.alexandregpereira.hunter.domain.settings.AppSettingsImageContentScale +import br.alexandregpereira.hunter.domain.settings.GetAppearanceSettings import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.single internal class DefaultMonsterLocalRepository( - private val localDataSource: MonsterLocalDataSource + private val localDataSource: MonsterLocalDataSource, + private val getAppearanceSettings: GetAppearanceSettings, ) : MonsterLocalRepository { override fun saveMonsters(monsters: List, isSync: Boolean): Flow { @@ -36,27 +41,33 @@ internal class DefaultMonsterLocalRepository( } override fun getMonsterPreviews(): Flow> { - return localDataSource.getMonsterPreviews().map { it.toDomainMonsterEntity() } + return localDataSource.getMonsterPreviews().map { + it.toDomainMonsterEntity(getImageContentScale()) + } } override fun getMonsterPreviewsEdited(): Flow> { - return localDataSource.getMonsterPreviewsEdited().map { it.toDomainMonsterEntity() } + return localDataSource.getMonsterPreviewsEdited().map { + it.toDomainMonsterEntity(getImageContentScale()) + } } override fun getMonsters(): Flow> { - return localDataSource.getMonsters().map { it.toDomain() } + return localDataSource.getMonsters().map { it.toDomain(getImageContentScale()) } } override fun getMonsters(indexes: List): Flow> { - return localDataSource.getMonsters(indexes).map { it.toDomain() } + return localDataSource.getMonsters(indexes).map { it.toDomain(getImageContentScale()) } } override fun getMonster(index: String): Flow { - return localDataSource.getMonster(index).map { it.toDomain() } + return localDataSource.getMonster(index).map { it.toDomain(getImageContentScale()) } } override fun getMonstersByQuery(query: String): Flow> { - return localDataSource.getMonstersByQuery(query).map { it.toDomainMonsterEntity() } + return localDataSource.getMonstersByQuery(query).map { + it.toDomainMonsterEntity(getImageContentScale()) + } } override fun deleteMonster(index: String): Flow { @@ -65,6 +76,15 @@ internal class DefaultMonsterLocalRepository( override fun getMonstersByStatus(status: Set): Flow> { return localDataSource.getMonstersByStatus(status.map { it.toEntityStatus() }.toSet()) - .map { it.toDomain() } + .map { it.toDomain(getImageContentScale()) } + } + + private suspend fun getImageContentScale(): MonsterImageContentScale { + return getAppearanceSettings().single().imageContentScale.let { imageContentScale -> + when (imageContentScale) { + AppSettingsImageContentScale.Fit -> MonsterImageContentScale.Fit + AppSettingsImageContentScale.Crop -> MonsterImageContentScale.Crop + } + } } } diff --git a/domain/monster/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/di/CommonDataModule.kt b/domain/monster/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/di/CommonDataModule.kt index 733eac8eb..a2e2fbb1d 100644 --- a/domain/monster/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/di/CommonDataModule.kt +++ b/domain/monster/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/di/CommonDataModule.kt @@ -56,7 +56,7 @@ val monsterDataModule = module { single { MonsterCacheDataSource() } factory { MonsterRepositoryImpl(get(), get()) } factory { - createMonsterLocalRepository() ?: DefaultMonsterLocalRepository(get()) + createMonsterLocalRepository() ?: DefaultMonsterLocalRepository(get(), get()) } factory { MonsterRemoteRepositoryImpl(get(), get()) } factory { MonsterCacheRepositoryImpl(get()) } diff --git a/domain/monster/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/local/mapper/MonsterEntityMapper.kt b/domain/monster/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/local/mapper/MonsterEntityMapper.kt index def1cd295..3181d673c 100644 --- a/domain/monster/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/local/mapper/MonsterEntityMapper.kt +++ b/domain/monster/data/src/commonMain/kotlin/br/alexandregpereira/hunter/data/monster/local/mapper/MonsterEntityMapper.kt @@ -24,27 +24,34 @@ import br.alexandregpereira.hunter.data.monster.spell.local.mapper.toEntity import br.alexandregpereira.hunter.domain.model.ChallengeRating import br.alexandregpereira.hunter.domain.model.Color import br.alexandregpereira.hunter.domain.model.Monster +import br.alexandregpereira.hunter.domain.model.MonsterImageContentScale import br.alexandregpereira.hunter.domain.model.MonsterImageData import br.alexandregpereira.hunter.domain.model.MonsterStatus import br.alexandregpereira.hunter.domain.model.MonsterType import br.alexandregpereira.hunter.domain.model.Speed import br.alexandregpereira.hunter.domain.model.Stats -fun List.toDomain(): List { +fun List.toDomain( + monsterImageContentScale: MonsterImageContentScale, +): List { return this.map { - it.toDomain() + it.toDomain(monsterImageContentScale) } } -fun List.toDomainMonsterEntity(): List { +fun List.toDomainMonsterEntity( + monsterImageContentScale: MonsterImageContentScale, +): List { return this.map { - it.toDomain() + it.toDomain(monsterImageContentScale) } } -internal fun MonsterCompleteEntity.toDomain(): Monster { +internal fun MonsterCompleteEntity.toDomain( + monsterImageContentScale: MonsterImageContentScale, +): Monster { val monster = this.monster - return monster.toDomain().copy( + return monster.toDomain(monsterImageContentScale).copy( speed = this.speed?.toDomain() ?: Speed(hover = false, values = emptyList()), abilityScores = this.abilityScores.toDomain(), savingThrows = this.savingThrows.toDomain(), @@ -114,7 +121,9 @@ internal fun List.toEntity(): List { return this.map { it.toEntity() } } -private fun MonsterEntity.toDomain(): Monster { +private fun MonsterEntity.toDomain( + monsterImageContentScale: MonsterImageContentScale, +): Monster { val monster = this return Monster( index = monster.index, @@ -127,7 +136,8 @@ private fun MonsterEntity.toDomain(): Monster { light = monster.backgroundColorLight, dark = monster.backgroundColorDark ), - isHorizontal = monster.isHorizontalImage + isHorizontal = monster.isHorizontalImage, + contentScale = monsterImageContentScale ), subtype = monster.subtype, group = monster.group, diff --git a/domain/settings/core/src/commonMain/kotlin/br/alexandregpereira/hunter/domain/settings/AppearanceSettings.kt b/domain/settings/core/src/commonMain/kotlin/br/alexandregpereira/hunter/domain/settings/AppearanceSettings.kt index 178d246cf..fdfa3a07e 100644 --- a/domain/settings/core/src/commonMain/kotlin/br/alexandregpereira/hunter/domain/settings/AppearanceSettings.kt +++ b/domain/settings/core/src/commonMain/kotlin/br/alexandregpereira/hunter/domain/settings/AppearanceSettings.kt @@ -20,6 +20,10 @@ internal fun SaveAppearanceSettings( "forceLightImageBackground" to appearance.forceLightImageBackground.toString(), "defaultLightBackground" to appearance.defaultLightBackground, "defaultDarkBackground" to appearance.defaultDarkBackground, + "imageContentScale" to when (appearance.imageContentScale) { + AppSettingsImageContentScale.Fit -> "Fit" + AppSettingsImageContentScale.Crop -> "Crop" + } ) ) } @@ -32,10 +36,18 @@ internal fun GetAppearanceSettings( .single()?.toBoolean() ?: false val defaultLightBackground = settings.getString("defaultLightBackground").single() ?: "" val defaultDarkBackground = settings.getString("defaultDarkBackground").single() ?: "" + val imageContentScale = settings.getString("imageContentScale").single()?.let { + when (it) { + "Fit" -> AppSettingsImageContentScale.Fit + "Crop" -> AppSettingsImageContentScale.Crop + else -> null + } + } ?: AppSettingsImageContentScale.Fit AppearanceSettings( forceLightImageBackground = forceLightImageBackground, defaultLightBackground = defaultLightBackground, defaultDarkBackground = defaultDarkBackground, + imageContentScale = imageContentScale, ).let { emit(it) } @@ -43,7 +55,13 @@ internal fun GetAppearanceSettings( } data class AppearanceSettings( - val forceLightImageBackground: Boolean = false, - val defaultLightBackground: String = "", - val defaultDarkBackground: String = "", + val forceLightImageBackground: Boolean, + val defaultLightBackground: String, + val defaultDarkBackground: String, + val imageContentScale: AppSettingsImageContentScale, ) + +enum class AppSettingsImageContentScale { + Fit, + Crop, +} diff --git a/feature/folder-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/folder/detail/FolderDetailFeature.kt b/feature/folder-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/folder/detail/FolderDetailFeature.kt index 83ef9ca15..47c622d04 100644 --- a/feature/folder-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/folder/detail/FolderDetailFeature.kt +++ b/feature/folder-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/folder/detail/FolderDetailFeature.kt @@ -22,12 +22,14 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import br.alexandregpereira.hunter.domain.folder.model.MonsterPreviewFolder +import br.alexandregpereira.hunter.domain.folder.model.MonsterPreviewFolderImageContentScale import br.alexandregpereira.hunter.folder.detail.di.FolderDetailStateRecoveryQualifier import br.alexandregpereira.hunter.folder.detail.ui.FolderDetailScreen import br.alexandregpereira.hunter.ui.compendium.monster.ColorState import br.alexandregpereira.hunter.ui.compendium.monster.MonsterCardState import br.alexandregpereira.hunter.ui.compendium.monster.MonsterImageState import br.alexandregpereira.hunter.ui.compendium.monster.MonsterTypeState +import br.alexandregpereira.hunter.ui.compose.AppImageContentScale import br.alexandregpereira.hunter.ui.compose.StateRecoveryLaunchedEffect import org.koin.compose.koinInject import org.koin.core.qualifier.named @@ -71,7 +73,11 @@ private fun List.asState(): List = map { ), challengeRating = challengeRating, isHorizontal = isHorizontalImage, - contentDescription = name + contentDescription = name, + contentScale = when (imageContentScale) { + MonsterPreviewFolderImageContentScale.Fit -> AppImageContentScale.Fit + MonsterPreviewFolderImageContentScale.Crop -> AppImageContentScale.Crop + } ) ) } diff --git a/feature/folder-list/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/folder/list/ui/FolderCard.kt b/feature/folder-list/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/folder/list/ui/FolderCard.kt index e86e70a70..a86167499 100644 --- a/feature/folder-list/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/folder/list/ui/FolderCard.kt +++ b/feature/folder-list/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/folder/list/ui/FolderCard.kt @@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.RectangleShape -import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.Layout import androidx.compose.ui.layout.MeasureResult import androidx.compose.ui.layout.MeasureScope @@ -33,6 +32,7 @@ import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import br.alexandregpereira.hunter.folder.list.FolderCardImageState +import br.alexandregpereira.hunter.ui.compose.AppImageContentScale import br.alexandregpereira.hunter.ui.compose.ImageCard import br.alexandregpereira.hunter.ui.compose.MonsterCoilImage import br.alexandregpereira.hunter.ui.compose.Window @@ -81,7 +81,7 @@ private fun FolderCardImage( imageUrl = url, contentDescription = contentDescription, backgroundColor = backgroundColor, - contentScale = ContentScale.Crop, + contentScale = AppImageContentScale.Crop, shape = RectangleShape, ) } @@ -95,7 +95,7 @@ private fun FolderCardImage( imageUrl = url, contentDescription = contentDescription, backgroundColor = backgroundColor, - contentScale = ContentScale.Crop, + contentScale = AppImageContentScale.Crop, shape = RectangleShape, ) } @@ -109,7 +109,7 @@ private fun FolderCardImage( imageUrl = url, contentDescription = contentDescription, backgroundColor = backgroundColor, - contentScale = ContentScale.Crop, + contentScale = AppImageContentScale.Crop, shape = RectangleShape, ) } diff --git a/feature/monster-compendium/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/compendium/MonsterCompendiumStateMapper.kt b/feature/monster-compendium/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/compendium/MonsterCompendiumStateMapper.kt index 4f938fbb2..7f94fc502 100644 --- a/feature/monster-compendium/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/compendium/MonsterCompendiumStateMapper.kt +++ b/feature/monster-compendium/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/compendium/MonsterCompendiumStateMapper.kt @@ -16,6 +16,7 @@ package br.alexandregpereira.hunter.monster.compendium +import br.alexandregpereira.hunter.domain.model.MonsterImageContentScale import br.alexandregpereira.hunter.monster.compendium.domain.model.TableContentItem import br.alexandregpereira.hunter.monster.compendium.state.MonsterCompendiumItemState import br.alexandregpereira.hunter.monster.compendium.state.MonsterPreviewState @@ -24,6 +25,7 @@ import br.alexandregpereira.hunter.ui.compendium.monster.ColorState import br.alexandregpereira.hunter.ui.compendium.monster.MonsterCardState import br.alexandregpereira.hunter.ui.compendium.monster.MonsterImageState import br.alexandregpereira.hunter.ui.compendium.monster.MonsterTypeState +import br.alexandregpereira.hunter.ui.compose.AppImageContentScale import br.alexandregpereira.hunter.ui.compose.tablecontent.TableContentItemState import br.alexandregpereira.hunter.ui.compose.tablecontent.TableContentItemTypeState @@ -54,7 +56,11 @@ private fun MonsterPreviewState.asState(): MonsterCardState { light = backgroundColorLight, dark = backgroundColorDark ), - isHorizontal = isImageHorizontal + isHorizontal = isImageHorizontal, + contentScale = when (imageContentScale) { + MonsterImageContentScale.Fit -> AppImageContentScale.Fit + MonsterImageContentScale.Crop -> AppImageContentScale.Crop + }, ) ) } diff --git a/feature/monster-compendium/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/compendium/state/MonsterCompendiumState.kt b/feature/monster-compendium/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/compendium/state/MonsterCompendiumState.kt index b078b05c7..cd7a9ae1e 100644 --- a/feature/monster-compendium/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/compendium/state/MonsterCompendiumState.kt +++ b/feature/monster-compendium/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/compendium/state/MonsterCompendiumState.kt @@ -16,6 +16,7 @@ package br.alexandregpereira.hunter.monster.compendium.state +import br.alexandregpereira.hunter.domain.model.MonsterImageContentScale import br.alexandregpereira.hunter.domain.model.MonsterType import br.alexandregpereira.hunter.monster.compendium.domain.MonsterCompendiumError import br.alexandregpereira.hunter.monster.compendium.domain.model.TableContentItem @@ -56,7 +57,6 @@ sealed class MonsterCompendiumItemState { ) : MonsterCompendiumItemState() } -@ObjCName(name = "MonsterPreviewState", exact = true) data class MonsterPreviewState( val index: String = "", val name: String = "", @@ -66,6 +66,7 @@ data class MonsterPreviewState( val backgroundColorLight: String = "", val backgroundColorDark: String = "", val isImageHorizontal: Boolean = false, + val imageContentScale: MonsterImageContentScale = MonsterImageContentScale.Fit, ) fun MonsterCompendiumState.loading(isLoading: Boolean): MonsterCompendiumState { diff --git a/feature/monster-compendium/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/compendium/state/MonsterCompendiumStateMapper.kt b/feature/monster-compendium/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/compendium/state/MonsterCompendiumStateMapper.kt index f776f8a3c..708a45542 100644 --- a/feature/monster-compendium/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/compendium/state/MonsterCompendiumStateMapper.kt +++ b/feature/monster-compendium/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/compendium/state/MonsterCompendiumStateMapper.kt @@ -43,6 +43,7 @@ private fun Monster.asState(): MonsterPreviewState { imageUrl = imageData.url, backgroundColorLight = imageData.backgroundColor.light, backgroundColorDark = imageData.backgroundColor.dark, - isImageHorizontal = imageData.isHorizontal + isImageHorizontal = imageData.isHorizontal, + imageContentScale = imageData.contentScale, ) } diff --git a/feature/monster-content-manager/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/content/preview/ui/MonsterContentPreviewScreen.kt b/feature/monster-content-manager/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/content/preview/ui/MonsterContentPreviewScreen.kt index 46323cce4..caa21d7c4 100644 --- a/feature/monster-content-manager/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/content/preview/ui/MonsterContentPreviewScreen.kt +++ b/feature/monster-content-manager/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/content/preview/ui/MonsterContentPreviewScreen.kt @@ -31,6 +31,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import br.alexandregpereira.hunter.domain.model.ChallengeRating import br.alexandregpereira.hunter.domain.model.Monster +import br.alexandregpereira.hunter.domain.model.MonsterImageContentScale import br.alexandregpereira.hunter.domain.model.MonsterType import br.alexandregpereira.hunter.monster.compendium.domain.model.MonsterCompendiumItem import br.alexandregpereira.hunter.monster.compendium.domain.model.TableContentItem @@ -45,6 +46,7 @@ import br.alexandregpereira.hunter.ui.compendium.monster.MonsterCardState import br.alexandregpereira.hunter.ui.compendium.monster.MonsterCompendium import br.alexandregpereira.hunter.ui.compendium.monster.MonsterImageState import br.alexandregpereira.hunter.ui.compendium.monster.MonsterTypeState +import br.alexandregpereira.hunter.ui.compose.AppImageContentScale import br.alexandregpereira.hunter.ui.compose.AppScreen import br.alexandregpereira.hunter.ui.compose.LoadingScreen import br.alexandregpereira.hunter.ui.compose.PopupContainer @@ -212,7 +214,11 @@ private fun Monster.asState(): MonsterCardState { light = imageData.backgroundColor.light, dark = imageData.backgroundColor.dark ), - isHorizontal = imageData.isHorizontal + isHorizontal = imageData.isHorizontal, + contentScale = when (imageData.contentScale) { + MonsterImageContentScale.Fit -> AppImageContentScale.Fit + MonsterImageContentScale.Crop -> AppImageContentScale.Crop + } ) ) } 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 11606be67..35b9b3932 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 @@ -13,7 +13,6 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp @@ -23,6 +22,7 @@ import br.alexandregpereira.hunter.monster.content.MonsterContentManagerStrings import br.alexandregpereira.hunter.ui.compose.AppButton import br.alexandregpereira.hunter.ui.compose.AppButtonSize import br.alexandregpereira.hunter.ui.compose.AppCard +import br.alexandregpereira.hunter.ui.compose.AppImageContentScale import br.alexandregpereira.hunter.ui.compose.AppSurface import br.alexandregpereira.hunter.ui.compose.CoilImage import br.alexandregpereira.hunter.ui.compose.SectionTitle @@ -93,7 +93,7 @@ private fun Cover( imageUrl = coverImageUrl, contentDescription = name, shape = Shapes.large, - contentScale = ContentScale.Crop, + contentScale = AppImageContentScale.Crop, modifier = Modifier .background(color = MaterialTheme.colors.surface, shape = Shapes.large) .height(IMAGE_HEIGHT.dp) diff --git a/feature/monster-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/detail/ui/MonsterDetailScreen.kt b/feature/monster-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/detail/ui/MonsterDetailScreen.kt index 1bf0be6b6..b593fb4d7 100644 --- a/feature/monster-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/detail/ui/MonsterDetailScreen.kt +++ b/feature/monster-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/detail/ui/MonsterDetailScreen.kt @@ -62,6 +62,7 @@ import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.util.lerp +import br.alexandregpereira.hunter.domain.model.MonsterImageContentScale import br.alexandregpereira.hunter.domain.model.MonsterType.CELESTIAL import br.alexandregpereira.hunter.monster.detail.ColorState import br.alexandregpereira.hunter.monster.detail.MonsterImageState @@ -69,6 +70,7 @@ import br.alexandregpereira.hunter.monster.detail.MonsterState import br.alexandregpereira.hunter.monster.detail.SpeedState import br.alexandregpereira.hunter.monster.detail.StatsState import br.alexandregpereira.hunter.ui.compose.AppBarIcon +import br.alexandregpereira.hunter.ui.compose.AppImageContentScale import br.alexandregpereira.hunter.ui.compose.AppSurface import br.alexandregpereira.hunter.ui.compose.BoxCloseButton import br.alexandregpereira.hunter.ui.compose.ChallengeRatingCircle @@ -261,7 +263,18 @@ private fun MonsterImageCompose( ) ) { MonsterImages( - images = monsters.map { ImageState(it.imageUrl, it.name) }, + images = remember(monsters) { + monsters.map { + ImageState( + url = it.imageUrl, + contentDescription = it.name, + contentScale = when (it.imageContentScale) { + MonsterImageContentScale.Fit -> AppImageContentScale.Fit + MonsterImageContentScale.Crop -> AppImageContentScale.Crop + }, + ) + } + }, pagerState = pagerState, shape = cardShape, ) diff --git a/feature/monster-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/detail/ui/MonsterImages.kt b/feature/monster-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/detail/ui/MonsterImages.kt index c8d2fe699..764b2d14b 100644 --- a/feature/monster-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/detail/ui/MonsterImages.kt +++ b/feature/monster-detail/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/detail/ui/MonsterImages.kt @@ -24,11 +24,16 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Shape import androidx.compose.ui.unit.dp +import br.alexandregpereira.hunter.ui.compose.AppImageContentScale import br.alexandregpereira.hunter.ui.compose.MonsterCoilImage import br.alexandregpereira.hunter.ui.compose.monsterAspectRatio import br.alexandregpereira.hunter.ui.transition.AlphaTransition -data class ImageState(val url: String, val contentDescription: String) +data class ImageState( + val url: String, + val contentDescription: String, + val contentScale: AppImageContentScale, +) @OptIn(ExperimentalFoundationApi::class) @Composable @@ -47,6 +52,7 @@ internal fun MonsterImages( imageUrl = image.url, contentDescription = image.contentDescription, shape = shape, + contentScale = image.contentScale, modifier = Modifier.monsterAspectRatio().padding(contentPadding) ) } diff --git a/feature/monster-detail/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/detail/MonsterDetailState.kt b/feature/monster-detail/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/detail/MonsterDetailState.kt index 58afc40d0..dabb9cd0a 100644 --- a/feature/monster-detail/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/detail/MonsterDetailState.kt +++ b/feature/monster-detail/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/detail/MonsterDetailState.kt @@ -19,6 +19,7 @@ package br.alexandregpereira.hunter.monster.detail import br.alexandregpereira.hunter.domain.model.ConditionType import br.alexandregpereira.hunter.domain.model.DamageType import br.alexandregpereira.hunter.domain.model.MeasurementUnit +import br.alexandregpereira.hunter.domain.model.MonsterImageContentScale import br.alexandregpereira.hunter.domain.model.MonsterType import br.alexandregpereira.hunter.domain.model.SpeedType import br.alexandregpereira.hunter.domain.monster.spell.model.SchoolOfMagic @@ -80,6 +81,9 @@ data class MonsterState( val imageUrl: String get() = imageState.url + val imageContentScale: MonsterImageContentScale + get() = imageState.contentScale + fun getBackgroundColor(isDarkTheme: Boolean): String { return imageState.backgroundColor.getColor(isDarkTheme) } @@ -155,14 +159,14 @@ data class DamageDiceState( val damage: DamageState ) -@ObjCName(name = "MonsterImageState", exact = true) data class MonsterImageState( val url: String= "", val type: MonsterType = MonsterType.ABERRATION, val backgroundColor: ColorState = ColorState(), val challengeRating: String = "", val xp: String = "", - val contentDescription: String = "" + val contentDescription: String = "", + val contentScale: MonsterImageContentScale = MonsterImageContentScale.Fit, ) @ObjCName(name = "ColorState", exact = true) diff --git a/feature/monster-detail/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/detail/MonsterDetailStateMapper.kt b/feature/monster-detail/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/detail/MonsterDetailStateMapper.kt index a4a646682..28b88adc9 100644 --- a/feature/monster-detail/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/detail/MonsterDetailStateMapper.kt +++ b/feature/monster-detail/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/detail/MonsterDetailStateMapper.kt @@ -95,6 +95,7 @@ private fun MonsterImageData.asState( challengeRating = challengeRating, xp = xp, contentDescription = contentDescription, + contentScale = contentScale, ) } 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 93677e3bf..d49814cca 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 @@ -17,12 +17,13 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment.Companion.CenterHorizontally import androidx.compose.ui.Modifier -import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp 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.ui.compose.AppImageContentScale import br.alexandregpereira.hunter.ui.compose.AppSwitch import br.alexandregpereira.hunter.ui.compose.AppTextField import br.alexandregpereira.hunter.ui.compose.ColorTextField @@ -66,8 +67,11 @@ internal fun LazyListScope.MonsterImageForm( imageUrl = infoState.imageUrl, contentDescription = infoState.name, backgroundColor = color, + contentScale = when (infoState.imageContentScale) { + MonsterImageContentScale.Fit -> AppImageContentScale.Fit + MonsterImageContentScale.Crop -> AppImageContentScale.Crop + }, shape = RoundedCornerShape(16.dp), - contentScale = ContentScale.Crop, modifier = Modifier.widthIn(max = 500.dp).monsterAspectRatio( isHorizontal = infoState.isImageHorizontal, widthFraction = widthFraction, diff --git a/feature/monster-registration/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/registration/MonsterRegistrationState.kt b/feature/monster-registration/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/registration/MonsterRegistrationState.kt index 4d8ee8773..f5126cdac 100644 --- a/feature/monster-registration/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/registration/MonsterRegistrationState.kt +++ b/feature/monster-registration/state-holder/src/commonMain/kotlin/br/alexandregpereira/hunter/monster/registration/MonsterRegistrationState.kt @@ -1,5 +1,6 @@ package br.alexandregpereira.hunter.monster.registration +import br.alexandregpereira.hunter.domain.model.MonsterImageContentScale import br.alexandregpereira.hunter.uuid.generateUUID data class MonsterRegistrationState( @@ -64,6 +65,7 @@ data class MonsterInfoState( val typeIndex: Int = 0, val typeOptions: List = emptyList(), val challengeRating: String = "", + val imageContentScale: MonsterImageContentScale = MonsterImageContentScale.Fit, ) { val type: String = typeOptions.getOrNull(typeIndex).orEmpty() } diff --git a/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/SearchMonsterStateMapper.kt b/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/SearchMonsterStateMapper.kt index dc113e0ec..f3b651513 100644 --- a/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/SearchMonsterStateMapper.kt +++ b/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/SearchMonsterStateMapper.kt @@ -16,6 +16,7 @@ package br.alexandregpereira.hunter.search +import br.alexandregpereira.hunter.domain.model.MonsterImageContentScale import br.alexandregpereira.hunter.search.domain.SearchKey import br.alexandregpereira.hunter.search.domain.SearchMonsterResult import br.alexandregpereira.hunter.search.domain.SearchValueType @@ -24,6 +25,7 @@ import br.alexandregpereira.hunter.ui.compendium.monster.ColorState import br.alexandregpereira.hunter.ui.compendium.monster.MonsterCardState import br.alexandregpereira.hunter.ui.compendium.monster.MonsterImageState import br.alexandregpereira.hunter.ui.compendium.monster.MonsterTypeState +import br.alexandregpereira.hunter.ui.compose.AppImageContentScale internal fun List.asState(): List { return this.asMonsterCardStates() @@ -43,7 +45,11 @@ internal fun List.asMonsterCardStates(): List AppImageContentScale.Fit + MonsterImageContentScale.Crop -> AppImageContentScale.Crop + }, ), ) } diff --git a/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/domain/SearchMonsterResult.kt b/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/domain/SearchMonsterResult.kt index 82be19a5f..cae6541e6 100644 --- a/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/domain/SearchMonsterResult.kt +++ b/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/domain/SearchMonsterResult.kt @@ -16,6 +16,7 @@ package br.alexandregpereira.hunter.search.domain +import br.alexandregpereira.hunter.domain.model.MonsterImageContentScale import br.alexandregpereira.hunter.domain.model.MonsterType internal data class SearchMonsterResult( @@ -26,5 +27,6 @@ internal data class SearchMonsterResult( val imageUrl: String, val backgroundColorLight: String, val backgroundColorDark: String, - val isHorizontalImage: Boolean = false + val imageContentScale: MonsterImageContentScale, + val isHorizontalImage: Boolean = false, ) diff --git a/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/domain/SearchMonstersByUseCase.kt b/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/domain/SearchMonstersByUseCase.kt index 270b1c4d2..c8d8dabd6 100644 --- a/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/domain/SearchMonstersByUseCase.kt +++ b/feature/search/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/search/domain/SearchMonstersByUseCase.kt @@ -89,6 +89,7 @@ internal class SearchMonstersByUseCase internal constructor( backgroundColorLight = monster.imageData.backgroundColor.light, backgroundColorDark = monster.imageData.backgroundColor.dark, isHorizontalImage = monster.imageData.isHorizontal, + imageContentScale = monster.imageData.contentScale, ) } } 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 3085a1d34..446f6d56c 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 @@ -18,6 +18,7 @@ package br.alexandregpereira.hunter.settings import br.alexadregpereira.hunter.shareContent.event.ShareContentEvent import br.alexadregpereira.hunter.shareContent.event.ShareContentEventDispatcher +import br.alexandregpereira.hunter.domain.settings.AppSettingsImageContentScale import br.alexandregpereira.hunter.domain.settings.AppearanceSettings import br.alexandregpereira.hunter.domain.settings.GetAlternativeSourceJsonUrlUseCase import br.alexandregpereira.hunter.domain.settings.GetMonsterImageJsonUrlUseCase @@ -33,6 +34,7 @@ import br.alexandregpereira.hunter.settings.domain.ApplyAppearanceSettings import br.alexandregpereira.hunter.settings.domain.GetAppearanceSettingsFromMonsters import br.alexandregpereira.hunter.state.UiModel import br.alexandregpereira.hunter.sync.event.SyncEventDispatcher +import br.alexandregpereira.hunter.ui.compose.AppImageContentScale import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow @@ -154,6 +156,10 @@ internal class SettingsStateHolder( forceLightImageBackground = appearanceState.forceLightImageBackground, defaultLightBackground = appearanceState.defaultLightBackground, defaultDarkBackground = appearanceState.defaultDarkBackground, + imageContentScale = when (appearanceState.monsterImageContentSelected) { + AppImageContentScale.Fit -> AppSettingsImageContentScale.Fit + AppImageContentScale.Crop -> AppSettingsImageContentScale.Crop + } ).let { appearance -> emit(appearance) } @@ -207,7 +213,8 @@ internal class SettingsStateHolder( appearanceState = AppearanceSettingsState( forceLightImageBackground = appearanceSettings.forceLightImageBackground, defaultLightBackground = appearanceSettings.defaultLightBackground, - defaultDarkBackground = appearanceSettings.defaultDarkBackground + defaultDarkBackground = appearanceSettings.defaultDarkBackground, + monsterImageContentSelectedOptionIndex = appearanceSettings.imageContentScale.ordinal ) ) } 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 6b298dcad..ab45e9fd1 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 @@ -17,6 +17,9 @@ interface SettingsStrings { val defaultLightBackground: String val defaultDarkBackground: String val importContent: String + val monsterImageContentScale: String + val imageContentScaleFit: String + val imageContentScaleCrop: String } internal data class SettingsEnStrings( @@ -34,6 +37,9 @@ internal data class SettingsEnStrings( override val defaultLightBackground: String = "Default Image Light Background Color", override val defaultDarkBackground: String = "Default Image Dark Background Color", override val importContent: String = "Import Shared Content", + override val monsterImageContentScale: String = "Monster Image Content Scale", + override val imageContentScaleFit: String = "Show entire image", + override val imageContentScaleCrop: String = "Expand the image", ) : SettingsStrings internal data class SettingsPtStrings( @@ -51,6 +57,9 @@ internal data class SettingsPtStrings( override val defaultLightBackground: String = "Cor Padrão de Fundo das Imagens Light", override val defaultDarkBackground: String = "Cor Padrão de Fundo das Imagens Dark", override val importContent: String = "Importar Conteúdo Compartilhado", + override val monsterImageContentScale: String = "Escala de Conteúdo de Imagem de Monstro", + override val imageContentScaleFit: String = "Mostrar imagem inteira", + override val imageContentScaleCrop: String = "Expandir a imagem", ) : SettingsStrings internal data class SettingsEmptyStrings( @@ -68,6 +77,9 @@ internal data class SettingsEmptyStrings( override val defaultLightBackground: String = "", override val defaultDarkBackground: String = "", override val importContent: String = "", + override val monsterImageContentScale: String = "", + override val imageContentScaleFit: String = "", + override val imageContentScaleCrop: String = "", ) : SettingsStrings internal fun getSettingsStrings(lang: Language): 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 d8ee8062e..f914609c2 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 @@ -16,6 +16,8 @@ package br.alexandregpereira.hunter.settings +import br.alexandregpereira.hunter.ui.compose.AppImageContentScale + internal data class SettingsViewState( val imageBaseUrl: String = "", val alternativeSourceBaseUrl: String = "", @@ -42,6 +44,10 @@ internal data class AppearanceSettingsState( val forceLightImageBackground: Boolean = false, val defaultLightBackground: String = "", val defaultDarkBackground: String = "", + val monsterImageContentScaleOptions: List = AppImageContentScale.entries, + val monsterImageContentSelectedOptionIndex: Int = 0, ) { val defaultDarkBackgroundEnabled: Boolean = forceLightImageBackground.not() + val monsterImageContentSelected: AppImageContentScale + get() = monsterImageContentScaleOptions[monsterImageContentSelectedOptionIndex] } diff --git a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/ui/AppearenceSettings.kt b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/ui/AppearenceSettings.kt index 11622c5f3..d688aaec6 100644 --- a/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/ui/AppearenceSettings.kt +++ b/feature/settings/compose/src/commonMain/kotlin/br/alexandregpereira/hunter/settings/ui/AppearenceSettings.kt @@ -19,15 +19,18 @@ package br.alexandregpereira.hunter.settings.ui import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import br.alexandregpereira.hunter.settings.AppearanceSettingsState import br.alexandregpereira.hunter.settings.SettingsStrings import br.alexandregpereira.hunter.ui.compose.AppButton +import br.alexandregpereira.hunter.ui.compose.AppImageContentScale import br.alexandregpereira.hunter.ui.compose.AppSwitch import br.alexandregpereira.hunter.ui.compose.BottomSheet import br.alexandregpereira.hunter.ui.compose.ColorTextField import br.alexandregpereira.hunter.ui.compose.Form +import br.alexandregpereira.hunter.ui.compose.PickerField @Composable internal fun AppearanceSettingsBottomSheet( @@ -72,6 +75,18 @@ internal fun AppearanceSettingsBottomSheet( }, ) + val monsterImageContentScaleOptions = state.monsterImageContentScaleOptions + PickerField( + label = strings.monsterImageContentScale, + options = remember(monsterImageContentScaleOptions, strings) { + monsterImageContentScaleOptions.map { it.asString(strings) } + }, + value = state.monsterImageContentSelected.asString(strings), + onValueChange = { + onStateChange(state.copy(monsterImageContentSelectedOptionIndex = it)) + }, + ) + AppButton( text = strings.save, onClick = onSaveButtonClick, @@ -79,3 +94,8 @@ internal fun AppearanceSettingsBottomSheet( ) } } + +private fun AppImageContentScale.asString(strings: SettingsStrings): String = when (this) { + AppImageContentScale.Fit -> strings.imageContentScaleFit + AppImageContentScale.Crop -> strings.imageContentScaleCrop +} diff --git a/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/CircleImage.kt b/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/CircleImage.kt index a385071c7..633814c33 100644 --- a/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/CircleImage.kt +++ b/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/CircleImage.kt @@ -22,7 +22,6 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -41,7 +40,7 @@ fun CircleImage( contentDescription = contentDescription, shape = CircleShape, backgroundColor = backgroundColor, - contentScale = ContentScale.Crop, + contentScale = AppImageContentScale.Crop, modifier = modifier .size(size) .animatePressed( diff --git a/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/CoilImage.kt b/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/CoilImage.kt index e35a6469a..c62c02d27 100644 --- a/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/CoilImage.kt +++ b/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/CoilImage.kt @@ -38,14 +38,17 @@ fun CoilImage( modifier: Modifier = Modifier, shape: Shape = RectangleShape, backgroundColor: Color? = null, - contentScale: ContentScale = ContentScale.Fit, + contentScale: AppImageContentScale, graphicsLayerBlock: GraphicsLayerScope.() -> Unit = {}, ) = AsyncImage( model = ImageRequest.Builder(LocalPlatformContext.current) .data(data = imageUrl) .crossfade(durationMillis = 300) .build(), - contentScale = contentScale, + contentScale = when (contentScale) { + AppImageContentScale.Fit -> ContentScale.Fit + AppImageContentScale.Crop -> ContentScale.Crop + }, contentDescription = contentDescription, modifier = modifier .run { @@ -59,3 +62,8 @@ fun CoilImage( .clip(shape = shape) .graphicsLayer(graphicsLayerBlock) ) + +enum class AppImageContentScale { + Fit, + Crop, +} diff --git a/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/MonsterCard.kt b/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/MonsterCard.kt index 0a5be94d1..bc305d13d 100644 --- a/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/MonsterCard.kt +++ b/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/MonsterCard.kt @@ -46,6 +46,7 @@ fun MonsterCard( icon: DrawableResource, backgroundColor: String, challengeRating: String, + contentScale: AppImageContentScale, isHorizontal: Boolean = false, modifier: Modifier = Modifier, onCLick: () -> Unit = {}, @@ -62,6 +63,7 @@ fun MonsterCard( icon = icon, backgroundColor = backgroundColor, challengeRating = challengeRating, + contentScale = contentScale, ) } @@ -130,7 +132,8 @@ private fun MonsterCardPreview() { url = "asdasdas", backgroundColor = "#ffe3ee", challengeRating = "18", - icon = Res.drawable.ic_aberration + icon = Res.drawable.ic_aberration, + contentScale = AppImageContentScale.Crop, ) } } diff --git a/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/MonsterCoilImage.kt b/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/MonsterCoilImage.kt index 54dea9d04..5716d8f5a 100644 --- a/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/MonsterCoilImage.kt +++ b/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/MonsterCoilImage.kt @@ -24,7 +24,6 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.GraphicsLayerScope import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.layout.ContentScale import br.alexandregpereira.hunter.ui.util.toColor @Composable @@ -34,7 +33,7 @@ fun MonsterCoilImage( shape: Shape = RectangleShape, modifier: Modifier = Modifier, backgroundColor: String, - contentScale: ContentScale = ContentScale.Crop, + contentScale: AppImageContentScale, graphicsLayerBlock: GraphicsLayerScope.() -> Unit = {}, ) = MonsterCoilImage( imageUrl = imageUrl, @@ -53,7 +52,7 @@ fun MonsterCoilImage( shape: Shape = RectangleShape, modifier: Modifier = Modifier, backgroundColor: Color? = null, - contentScale: ContentScale = ContentScale.Crop, + contentScale: AppImageContentScale, graphicsLayerBlock: GraphicsLayerScope.() -> Unit = {}, ) { CoilImage( diff --git a/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/MonsterImage.kt b/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/MonsterImage.kt index 5ed57a135..5f5a6353a 100644 --- a/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/MonsterImage.kt +++ b/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/MonsterImage.kt @@ -27,7 +27,6 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -43,6 +42,7 @@ fun MonsterImage( icon: DrawableResource, backgroundColor: String, challengeRating: String, + contentScale: AppImageContentScale, modifier: Modifier = Modifier, borderColor: Color = MaterialTheme.colors.surface, contentDescription: String = "", @@ -55,7 +55,7 @@ fun MonsterImage( imageUrl = url, contentDescription = contentDescription, backgroundColor = backgroundColor, - contentScale = ContentScale.Crop, + contentScale = contentScale, ) ChallengeRatingCircle( @@ -113,7 +113,8 @@ fun MonsterImagePreview() = HunterTheme { backgroundColor = "#ffe3ee", contentDescription = "Anything", challengeRating = "18", - icon = Res.drawable.ic_aberration + icon = Res.drawable.ic_aberration, + contentScale = AppImageContentScale.Fit, ) } @@ -125,6 +126,7 @@ fun MonsterImageBlackBackgroundPreview() = HunterTheme { backgroundColor = "#000000", contentDescription = "Anything", challengeRating = "18", - icon = Res.drawable.ic_aberration + icon = Res.drawable.ic_aberration, + contentScale = AppImageContentScale.Fit, ) } diff --git a/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/PickerField.kt b/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/PickerField.kt index acfe9449b..0bc85efb7 100644 --- a/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/PickerField.kt +++ b/ui/core/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compose/PickerField.kt @@ -82,7 +82,7 @@ fun PickerField( @Preview @Composable -fun PickerFieldPreview() = Window { +private fun PickerFieldPreview() = Window { val text = remember { mutableStateOf("") } val options = remember { listOf("Option 1", "Option 2", "Option 3") } PickerField( diff --git a/ui/monster-compendium/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compendium/monster/MonterCompendium.kt b/ui/monster-compendium/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compendium/monster/MonterCompendium.kt index 8fd96a90a..b1b155cf2 100644 --- a/ui/monster-compendium/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compendium/monster/MonterCompendium.kt +++ b/ui/monster-compendium/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compendium/monster/MonterCompendium.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.unit.dp import br.alexandregpereira.hunter.ui.compendium.Compendium import br.alexandregpereira.hunter.ui.compendium.CompendiumColumns import br.alexandregpereira.hunter.ui.compendium.CompendiumItemState +import br.alexandregpereira.hunter.ui.compose.AppImageContentScale import br.alexandregpereira.hunter.ui.compose.LocalScreenSize import br.alexandregpereira.hunter.ui.compose.MonsterCard import br.alexandregpereira.hunter.ui.compose.ScreenSizeType @@ -78,6 +79,7 @@ fun MonsterCompendium( ), isHorizontal = enableHorizontalImage && monsterCardState.imageState.isHorizontal, challengeRating = monsterCardState.imageState.challengeRating, + contentScale = monsterCardState.imageState.contentScale, onCLick = { onItemCLick(monsterCardState.index) }, onLongCLick = { onItemLongCLick(monsterCardState.index) } ) @@ -97,7 +99,8 @@ private fun MonsterCompendiumPreview() = Window { backgroundColor = ColorState( light = "#ffe0e0", dark = "#ffe0e0" - ) + ), + contentScale = AppImageContentScale.Fit, ) MonsterCompendium( items = mutableListOf( diff --git a/ui/monster-compendium/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compendium/monster/State.kt b/ui/monster-compendium/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compendium/monster/State.kt index 50e9a796d..dddd298e8 100644 --- a/ui/monster-compendium/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compendium/monster/State.kt +++ b/ui/monster-compendium/src/commonMain/kotlin/br/alexandregpereira/hunter/ui/compendium/monster/State.kt @@ -16,6 +16,7 @@ package br.alexandregpereira.hunter.ui.compendium.monster +import br.alexandregpereira.hunter.ui.compose.AppImageContentScale import br.alexandregpereira.hunter.ui.resources.Res import br.alexandregpereira.hunter.ui.resources.ic_aberration import br.alexandregpereira.hunter.ui.resources.ic_beast @@ -44,8 +45,9 @@ data class MonsterImageState( val type: MonsterTypeState, val backgroundColor: ColorState, val challengeRating: String, + val contentScale: AppImageContentScale, val isHorizontal: Boolean = false, - val contentDescription: String = "" + val contentDescription: String = "", ) data class ColorState(