Skip to content

Commit

Permalink
Add desktop
Browse files Browse the repository at this point in the history
  • Loading branch information
MohamedRejeb committed Mar 12, 2023
1 parent a2f95ab commit e769262
Show file tree
Hide file tree
Showing 22 changed files with 356 additions and 94 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
//trick: for the same plugin versions in all sub-modules
kotlin("jvm") version "1.8.10" apply false
// kotlin("jvm") version "1.8.10" apply false
kotlin("android") version "1.8.10" apply false
kotlin("multiplatform") version "1.8.10" apply false
kotlin("plugin.serialization") version "1.8.10" apply false
Expand Down
5 changes: 2 additions & 3 deletions buildSrc/src/main/java/com/mocoding/pokedex/Deps.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ object Deps {
const val ktorClientContentNegotiation = "io.ktor:ktor-client-content-negotiation:${Versions.ktor}"
const val ktorClientLogging = "io.ktor:ktor-client-logging:${Versions.ktor}"

// Engines
const val ktorClientAndroid = "io.ktor:ktor-client-android:${Versions.ktor}"
const val ktorClientOkhttp = "io.ktor:ktor-client-okhttp:${Versions.ktor}"

const val ktorClientDarwin = "io.ktor:ktor-client-darwin:${Versions.ktor}"
const val ktorClientIos = "io.ktor:ktor-client-ios:${Versions.ktor}"
const val ktorClientJava = "io.ktor:ktor-client-java:${Versions.ktor}"
}
}

Expand Down
42 changes: 42 additions & 0 deletions desktop/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/

### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/

### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/

### VS Code ###
.vscode/

### Mac OS ###
.DS_Store
36 changes: 36 additions & 0 deletions desktop/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import org.jetbrains.compose.desktop.application.dsl.TargetFormat

plugins {
kotlin("multiplatform")
id("org.jetbrains.compose")
}

group = "com.mocoding"
version = "1.0-SNAPSHOT"

kotlin {
jvm {
jvmToolchain(11)
withJava()
}
sourceSets {
val jvmMain by getting {
dependencies {
implementation(project(":shared"))
implementation(compose.desktop.currentOs)
}
}
val jvmTest by getting
}
}

compose.desktop {
application {
mainClass = "MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "desktop"
packageVersion = "1.0.0"
}
}
}
48 changes: 48 additions & 0 deletions desktop/src/jvmMain/kotlin/Main.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import com.arkivanov.decompose.DefaultComponentContext
import com.arkivanov.essenty.lifecycle.LifecycleRegistry
import com.arkivanov.essenty.lifecycle.resume
import com.arkivanov.mvikotlin.core.utils.setMainThreadId
import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
import com.mocoding.pokedex.core.di.initKoin
import com.mocoding.pokedex.ui.ContentView
import com.mocoding.pokedex.ui.root.RootComponent
import javax.swing.SwingUtilities

fun main() {
initKoin(enableNetworkLogs = false)

// overrideSchedulers(main = Dispatchers.Main::asScheduler)

val rootComponent = invokeOnAwtSync {
setMainThreadId(Thread.currentThread().id)

val lifecycle = LifecycleRegistry()

val rootComponent = RootComponent(
componentContext = DefaultComponentContext(lifecycle = lifecycle),
storeFactory = DefaultStoreFactory(),
)

lifecycle.resume()

rootComponent
}

application {
Window(onCloseRequest = ::exitApplication) {
ContentView(
component = rootComponent
)
}
}
}

fun <T> invokeOnAwtSync(block: () -> T): T {
var result: T? = null
SwingUtilities.invokeAndWait { result = block() }

@Suppress("UNCHECKED_CAST")
return result as T
}
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ dependencyResolutionManagement {

rootProject.name = "Pokedex"
include(":android")
include(":desktop")
include(":shared")
17 changes: 14 additions & 3 deletions shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ plugins {

@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
kotlin {
jvm("desktop")
android()
ios()
iosSimulatorArm64()
Expand Down Expand Up @@ -107,14 +108,24 @@ kotlin {
}
val androidUnitTest by getting

val desktopMain by getting {
dependsOn(commonMain)

dependencies {
// Ktor
implementation(Deps.Io.Ktor.ktorClientJava)

// SqlDelight
implementation(Deps.CashApp.SQLDelight.sqliteDriver)
}
}

val iosMain by getting {
dependsOn(commonMain)

dependencies {
// Ktor
with(Deps.Io.Ktor) {
api(ktorClientDarwin)
}
implementation(Deps.Io.Ktor.ktorClientDarwin)

// SqlDelight
implementation(Deps.CashApp.SQLDelight.nativeDriver)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.mocoding.pokedex.core.database.dao

import app.cash.sqldelight.coroutines.asFlow
import com.mocoding.pokedex.core.database.PokemonDatabase
import com.mocoding.pokedex.pokedexDispatchers
import commocodingpokedex.PokemonInfoEntity
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext

class PokemonInfoDao(
Expand All @@ -15,7 +17,7 @@ class PokemonInfoDao(
}

suspend fun selectAllFavorite() = withContext(pokedexDispatchers.io) {
query.selectAllFavorite().executeAsList()
query.selectAllFavorite().asFlow().map { it.executeAsList() }
}

suspend fun insert(pokemonInfoEntity: PokemonInfoEntity) = withContext(pokedexDispatchers.io) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ package com.mocoding.pokedex.data.repository

import com.mocoding.pokedex.core.model.Pokemon
import com.mocoding.pokedex.core.model.PokemonInfo
import kotlinx.coroutines.flow.Flow

interface PokemonRepository {

suspend fun getPokemonList(page: Long): Result<List<Pokemon>>

suspend fun getPokemonByName(name: String): Result<PokemonInfo>
suspend fun getFavoritePokemonList(): List<Pokemon>
suspend fun getPokemonFlowByName(name: String): Result<PokemonInfo>
suspend fun getFavoritePokemonListFlow(): Flow<List<Pokemon>>
suspend fun updatePokemonFavoriteState(name: String, isFavorite: Boolean)

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import com.mocoding.pokedex.data.toPokemon
import com.mocoding.pokedex.data.toPokemonEntity
import com.mocoding.pokedex.data.toPokemonInfo
import com.mocoding.pokedex.data.toPokemonInfoEntity
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

Expand All @@ -33,11 +35,12 @@ class PokemonRepositoryImpl: PokemonRepository, KoinComponent {
Result.success(cachedPokemonList.map { it.toPokemon() })
}
} catch (e: Exception) {
e.printStackTrace()
Result.failure(e)
}
}

override suspend fun getPokemonByName(name: String): Result<PokemonInfo> {
override suspend fun getPokemonFlowByName(name: String): Result<PokemonInfo> {
return try {
val cachedPokemon = pokemonInfoDao.selectOneByName(name = name)

Expand All @@ -54,8 +57,10 @@ class PokemonRepositoryImpl: PokemonRepository, KoinComponent {
}
}

override suspend fun getFavoritePokemonList(): List<Pokemon> {
return pokemonInfoDao.selectAllFavorite().map { it.toPokemon() }
override suspend fun getFavoritePokemonListFlow(): Flow<List<Pokemon>> {
return pokemonInfoDao.selectAllFavorite().map { list ->
list.map { it.toPokemon() }
}
}

override suspend fun updatePokemonFavoriteState(name: String, isFavorite: Boolean) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@ internal fun DetailsContent(
onEvent: (DetailsStore.Intent) -> Unit,
onOutput: (DetailsComponent.Output) -> Unit,
) {
Box {
Box(contentAlignment = Alignment.TopCenter) {
state.pokemonInfo?.let { pokemonInfo ->
AsyncImage(
url = pokemonInfo.imageUrl,
contentDescription = pokemonInfo.name,
contentScale = ContentScale.FillWidth,
colorFilter = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(3f) }),
modifier = Modifier
.widthIn(max = 800.dp)
.fillMaxWidth(.9f)
.wrapContentHeight(Alignment.Top, true)
.scale(1f, 1.8f)
Expand Down Expand Up @@ -134,6 +135,7 @@ internal fun DetailsContent(
contentDescription = pokemonInfo.name,
contentScale = ContentScale.Fit,
modifier = Modifier
.widthIn(max = 500.dp)
.fillMaxWidth()
.aspectRatio(1.2f)
.fillMaxHeight()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ internal class DetailsStoreFactory(
dispatch(Msg.PokemonInfoLoading)

pokemonRepository
.getPokemonByName(name)
.getPokemonFlowByName(name)
.onSuccess { pokemonInfo ->
dispatch(Msg.PokemonInfoLoaded(pokemonInfo))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.mocoding.pokedex.core.model.Pokemon
import com.mocoding.pokedex.data.repository.PokemonRepository
import com.mocoding.pokedex.pokedexDispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
Expand Down Expand Up @@ -49,8 +50,9 @@ class FavoriteStoreFactory(
getFavoritePokemonListJob = scope.launch {
dispatch(Msg.PokemonListLoading)

val favoritePokemonList = pokemonRepository.getFavoritePokemonList()
dispatch(Msg.PokemonListLoaded(favoritePokemonList))
pokemonRepository.getFavoritePokemonListFlow().collectLatest { favoritePokemonList ->
dispatch(Msg.PokemonListLoaded(favoritePokemonList))
}
}
}
}
Expand All @@ -59,7 +61,7 @@ class FavoriteStoreFactory(
override fun FavoriteStore.State.reduce(msg: Msg): FavoriteStore.State =
when (msg) {
is Msg.PokemonListLoading -> copy(isLoading = true)
is Msg.PokemonListLoaded -> FavoriteStore.State(pokemonList = pokemonList + msg.pokemonList)
is Msg.PokemonListLoaded -> FavoriteStore.State(pokemonList = msg.pokemonList)
is Msg.PokemonListFailed -> copy(error = msg.error)
}
}
Expand Down
Loading

0 comments on commit e769262

Please sign in to comment.