Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add image content scale to appearance settings #329

Merged
merged 1 commit into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion domain/monster-folder/core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ plugins {

multiplatform {
commonMain {
implementation(project(":domain:monster:core"))
implementation(libs.koin.core)
implementation(libs.kotlin.coroutines.core)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
1 change: 1 addition & 0 deletions domain/monster-folder/data/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,37 @@ 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<String>): Flow<Unit> {
return monsterFolderLocalDataSource.addMonsters(folderName, monsterIndexes = indexes)
}

override fun getMonsterFolders(): Flow<List<MonsterFolder>> {
return monsterFolderLocalDataSource.getMonsterFolders().map { it.asDomain() }
return monsterFolderLocalDataSource.getMonsterFolders().map {
it.asDomain(getImageContentScale())
}
}

override fun getMonstersFromFolder(folderName: String): Flow<MonsterFolder?> {
return monsterFolderLocalDataSource.getMonstersFromFolder(folderName).map { it?.asDomain() }
return monsterFolderLocalDataSource.getMonstersFromFolder(folderName).map {
it?.asDomain(getImageContentScale())
}
}

override fun getMonstersFromFolders(foldersName: List<String>): Flow<List<MonsterPreviewFolder>> {
return monsterFolderLocalDataSource.getMonstersFromFolders(foldersName)
.map { it.asDomainMonsterPreviewFolderEntity() }
.map { it.asDomainMonsterPreviewFolderEntity(getImageContentScale()) }
}

override fun removeMonsters(folderName: String, indexes: List<String>): Flow<Unit> {
Expand All @@ -53,10 +62,19 @@ internal class DefaultFolderRepository(
indexes: List<String>
): Flow<List<MonsterPreviewFolder>> {
return monsterFolderLocalDataSource.getFolderMonsterPreviewsByIds(indexes)
.map { it.asDomainMonsterPreviewFolderEntity() }
.map { it.asDomainMonsterPreviewFolderEntity(getImageContentScale()) }
}

override fun removeMonsterFolders(folderNames: List<String>): Flow<Unit> {
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
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<MonsterFolderCompleteEntity>.asDomain(): List<MonsterFolder> {
return this.map { it.asDomain() }
internal fun List<MonsterFolderCompleteEntity>.asDomain(
monsterImageContentScale: MonsterPreviewFolderImageContentScale
): List<MonsterFolder> {
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<MonsterEntity>.asDomainMonsterPreviewFolderEntity(): List<MonsterPreviewFolder> {
internal fun List<MonsterEntity>.asDomainMonsterPreviewFolderEntity(
monsterImageContentScale: MonsterPreviewFolderImageContentScale
): List<MonsterPreviewFolder> {
return map {
it.run {
MonsterPreviewFolder(
Expand All @@ -45,6 +52,7 @@ internal fun List<MonsterEntity>.asDomainMonsterPreviewFolderEntity(): List<Mons
backgroundColorLight = backgroundColorLight,
backgroundColorDark = backgroundColorDark,
isHorizontalImage = isHorizontalImage,
imageContentScale = monsterImageContentScale,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ import org.koin.dsl.module
val monsterFolderDataModule = module {
factory<MonsterFolderLocalDataSource> { DefaultMonsterFolderLocalDataSource(get(), get()) }
factory {
createMonsterFolderRepository() ?: DefaultFolderRepository(get())
createMonsterFolderRepository() ?: DefaultFolderRepository(get(), get())
}
factory {
createFolderMonsterPreviewRepository() ?: DefaultFolderRepository(get())
createFolderMonsterPreviewRepository() ?: DefaultFolderRepository(get(), get())
}
}.apply { includes(getAdditionalModule()) }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,41 +22,52 @@ 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<Monster>, isSync: Boolean): Flow<Unit> {
return localDataSource.saveMonsters(monsters.toEntity(), isSync)
}

override fun getMonsterPreviews(): Flow<List<Monster>> {
return localDataSource.getMonsterPreviews().map { it.toDomainMonsterEntity() }
return localDataSource.getMonsterPreviews().map {
it.toDomainMonsterEntity(getImageContentScale())
}
}

override fun getMonsterPreviewsEdited(): Flow<List<Monster>> {
return localDataSource.getMonsterPreviewsEdited().map { it.toDomainMonsterEntity() }
return localDataSource.getMonsterPreviewsEdited().map {
it.toDomainMonsterEntity(getImageContentScale())
}
}

override fun getMonsters(): Flow<List<Monster>> {
return localDataSource.getMonsters().map { it.toDomain() }
return localDataSource.getMonsters().map { it.toDomain(getImageContentScale()) }
}

override fun getMonsters(indexes: List<String>): Flow<List<Monster>> {
return localDataSource.getMonsters(indexes).map { it.toDomain() }
return localDataSource.getMonsters(indexes).map { it.toDomain(getImageContentScale()) }
}

override fun getMonster(index: String): Flow<Monster> {
return localDataSource.getMonster(index).map { it.toDomain() }
return localDataSource.getMonster(index).map { it.toDomain(getImageContentScale()) }
}

override fun getMonstersByQuery(query: String): Flow<List<Monster>> {
return localDataSource.getMonstersByQuery(query).map { it.toDomainMonsterEntity() }
return localDataSource.getMonstersByQuery(query).map {
it.toDomainMonsterEntity(getImageContentScale())
}
}

override fun deleteMonster(index: String): Flow<Unit> {
Expand All @@ -65,6 +76,15 @@ internal class DefaultMonsterLocalRepository(

override fun getMonstersByStatus(status: Set<MonsterStatus>): Flow<List<Monster>> {
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
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ val monsterDataModule = module {
single { MonsterCacheDataSource() }
factory<MonsterRepository> { MonsterRepositoryImpl(get(), get()) }
factory {
createMonsterLocalRepository() ?: DefaultMonsterLocalRepository(get())
createMonsterLocalRepository() ?: DefaultMonsterLocalRepository(get(), get())
}
factory<MonsterRemoteRepository> { MonsterRemoteRepositoryImpl(get(), get()) }
factory<MonsterCacheRepository> { MonsterCacheRepositoryImpl(get()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<MonsterCompleteEntity>.toDomain(): List<Monster> {
fun List<MonsterCompleteEntity>.toDomain(
monsterImageContentScale: MonsterImageContentScale,
): List<Monster> {
return this.map {
it.toDomain()
it.toDomain(monsterImageContentScale)
}
}

fun List<MonsterEntity>.toDomainMonsterEntity(): List<Monster> {
fun List<MonsterEntity>.toDomainMonsterEntity(
monsterImageContentScale: MonsterImageContentScale,
): List<Monster> {
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(),
Expand Down Expand Up @@ -114,7 +121,9 @@ internal fun List<Monster>.toEntity(): List<MonsterCompleteEntity> {
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,
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
)
)
}
Expand All @@ -32,18 +36,32 @@ 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)
}
}
}

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,
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -71,7 +73,11 @@ private fun List<MonsterPreviewFolder>.asState(): List<MonsterCardState> = map {
),
challengeRating = challengeRating,
isHorizontal = isHorizontalImage,
contentDescription = name
contentDescription = name,
contentScale = when (imageContentScale) {
MonsterPreviewFolderImageContentScale.Fit -> AppImageContentScale.Fit
MonsterPreviewFolderImageContentScale.Crop -> AppImageContentScale.Crop
}
)
)
}
Expand Down
Loading
Loading