diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d036848..5d2c1bf 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -15,45 +15,45 @@
limitations under the License.
-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+xmlns:tools="http://schemas.android.com/tools">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/database/schemas/com.skydoves.pokedex.compose.core.database.PokedexDatabase/3.json b/core/database/schemas/com.skydoves.pokedex.compose.core.database.PokedexDatabase/3.json
new file mode 100644
index 0000000..ca4d915
--- /dev/null
+++ b/core/database/schemas/com.skydoves.pokedex.compose.core.database.PokedexDatabase/3.json
@@ -0,0 +1,108 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 3,
+ "identityHash": "2ce2c0e046fdc408aab83eb7e475bf26",
+ "entities": [
+ {
+ "tableName": "PokemonEntity",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`page` INTEGER NOT NULL, `name` TEXT NOT NULL, `url` TEXT NOT NULL, PRIMARY KEY(`name`))",
+ "fields": [
+ {
+ "fieldPath": "page",
+ "columnName": "page",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "name"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "PokemonInfoEntity",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT NOT NULL, `height` INTEGER NOT NULL, `weight` INTEGER NOT NULL, `experience` INTEGER NOT NULL, `types` TEXT NOT NULL, `exp` INTEGER NOT NULL, `stats` TEXT NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "height",
+ "columnName": "height",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "experience",
+ "columnName": "experience",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "types",
+ "columnName": "types",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exp",
+ "columnName": "exp",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "stats",
+ "columnName": "stats",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '2ce2c0e046fdc408aab83eb7e475bf26')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/core/database/schemas/com.skydoves.pokedex.compose.core.database.PokedexDatabase/4.json b/core/database/schemas/com.skydoves.pokedex.compose.core.database.PokedexDatabase/4.json
new file mode 100644
index 0000000..d24909b
--- /dev/null
+++ b/core/database/schemas/com.skydoves.pokedex.compose.core.database.PokedexDatabase/4.json
@@ -0,0 +1,108 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 4,
+ "identityHash": "2ce2c0e046fdc408aab83eb7e475bf26",
+ "entities": [
+ {
+ "tableName": "PokemonEntity",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`page` INTEGER NOT NULL, `name` TEXT NOT NULL, `url` TEXT NOT NULL, PRIMARY KEY(`name`))",
+ "fields": [
+ {
+ "fieldPath": "page",
+ "columnName": "page",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "name"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "PokemonInfoEntity",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT NOT NULL, `height` INTEGER NOT NULL, `weight` INTEGER NOT NULL, `experience` INTEGER NOT NULL, `types` TEXT NOT NULL, `exp` INTEGER NOT NULL, `stats` TEXT NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "height",
+ "columnName": "height",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "experience",
+ "columnName": "experience",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "types",
+ "columnName": "types",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "exp",
+ "columnName": "exp",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "stats",
+ "columnName": "stats",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '2ce2c0e046fdc408aab83eb7e475bf26')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/PokedexDatabase.kt b/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/PokedexDatabase.kt
index 40143e5..1c5f3b3 100644
--- a/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/PokedexDatabase.kt
+++ b/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/PokedexDatabase.kt
@@ -24,10 +24,10 @@ import com.skydoves.pokedex.compose.core.database.entitiy.PokemonInfoEntity
@Database(
entities = [PokemonEntity::class, PokemonInfoEntity::class],
- version = 2,
+ version = 4,
exportSchema = true,
)
-@TypeConverters(value = [TypeResponseConverter::class])
+@TypeConverters(value = [TypeResponseConverter::class, StatsResponseConverter::class])
abstract class PokedexDatabase : RoomDatabase() {
abstract fun pokemonDao(): PokemonDao
diff --git a/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/StatsResponseConverter.kt b/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/StatsResponseConverter.kt
new file mode 100644
index 0000000..df23bbe
--- /dev/null
+++ b/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/StatsResponseConverter.kt
@@ -0,0 +1,47 @@
+/*
+ * Designed and developed by 2024 skydoves (Jaewoong Eum)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.skydoves.pokedex.compose.core.database
+
+import androidx.room.ProvidedTypeConverter
+import androidx.room.TypeConverter
+import com.skydoves.pokedex.compose.core.model.PokemonInfo
+import com.squareup.moshi.JsonAdapter
+import com.squareup.moshi.Moshi
+import com.squareup.moshi.Types
+import javax.inject.Inject
+
+@ProvidedTypeConverter
+class StatsResponseConverter @Inject constructor(
+ private val moshi: Moshi,
+) {
+
+ @TypeConverter
+ fun fromString(value: String): List? {
+ val listType =
+ Types.newParameterizedType(List::class.java, PokemonInfo.StatsResponse::class.java)
+ val adapter: JsonAdapter> = moshi.adapter(listType)
+ return adapter.fromJson(value)
+ }
+
+ @TypeConverter
+ fun fromInfoType(type: List?): String {
+ val listType =
+ Types.newParameterizedType(List::class.java, PokemonInfo.StatsResponse::class.java)
+ val adapter: JsonAdapter> = moshi.adapter(listType)
+ return adapter.toJson(type)
+ }
+}
diff --git a/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/di/DatabaseModule.kt b/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/di/DatabaseModule.kt
index 571cca4..4a3ae79 100644
--- a/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/di/DatabaseModule.kt
+++ b/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/di/DatabaseModule.kt
@@ -21,6 +21,7 @@ import androidx.room.Room
import com.skydoves.pokedex.compose.core.database.PokedexDatabase
import com.skydoves.pokedex.compose.core.database.PokemonDao
import com.skydoves.pokedex.compose.core.database.PokemonInfoDao
+import com.skydoves.pokedex.compose.core.database.StatsResponseConverter
import com.skydoves.pokedex.compose.core.database.TypeResponseConverter
import com.squareup.moshi.Moshi
import dagger.Module
@@ -45,11 +46,13 @@ internal object DatabaseModule {
fun provideAppDatabase(
application: Application,
typeResponseConverter: TypeResponseConverter,
+ statsResponseConverter: StatsResponseConverter,
): PokedexDatabase {
return Room
.databaseBuilder(application, PokedexDatabase::class.java, "Pokedex.db")
.fallbackToDestructiveMigration()
.addTypeConverter(typeResponseConverter)
+ .addTypeConverter(statsResponseConverter)
.build()
}
diff --git a/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/entitiy/PokemonInfoEntity.kt b/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/entitiy/PokemonInfoEntity.kt
index e368f62..f242314 100644
--- a/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/entitiy/PokemonInfoEntity.kt
+++ b/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/entitiy/PokemonInfoEntity.kt
@@ -28,9 +28,6 @@ data class PokemonInfoEntity(
val weight: Int,
val experience: Int,
val types: List,
- val hp: Int,
- val attack: Int,
- val defense: Int,
- val speed: Int,
val exp: Int,
+ val stats: List,
)
diff --git a/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/entitiy/mapper/PokemonInfoEntityMapper.kt b/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/entitiy/mapper/PokemonInfoEntityMapper.kt
index a09a800..85ed405 100644
--- a/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/entitiy/mapper/PokemonInfoEntityMapper.kt
+++ b/core/database/src/main/kotlin/com/skydoves/pokedex/compose/core/database/entitiy/mapper/PokemonInfoEntityMapper.kt
@@ -29,11 +29,8 @@ object PokemonInfoEntityMapper : EntityMapper {
weight = domain.weight,
experience = domain.experience,
types = domain.types,
- hp = domain.hp,
- attack = domain.attack,
- defense = domain.defense,
- speed = domain.speed,
exp = domain.exp,
+ stats = domain.stats,
)
}
@@ -45,11 +42,8 @@ object PokemonInfoEntityMapper : EntityMapper {
weight = entity.weight,
experience = entity.experience,
types = entity.types,
- hp = entity.hp,
- attack = entity.attack,
- defense = entity.defense,
- speed = entity.speed,
exp = entity.exp,
+ stats = entity.stats,
)
}
}
diff --git a/core/model/src/main/kotlin/com/skydoves/pokedex/compose/core/model/PokemonInfo.kt b/core/model/src/main/kotlin/com/skydoves/pokedex/compose/core/model/PokemonInfo.kt
index ff9c6b7..f650120 100644
--- a/core/model/src/main/kotlin/com/skydoves/pokedex/compose/core/model/PokemonInfo.kt
+++ b/core/model/src/main/kotlin/com/skydoves/pokedex/compose/core/model/PokemonInfo.kt
@@ -31,12 +31,21 @@ data class PokemonInfo(
@field:Json(name = "weight") val weight: Int,
@field:Json(name = "base_experience") val experience: Int,
@field:Json(name = "types") val types: List,
- val hp: Int = Random.nextInt(MAX_HP),
- val attack: Int = Random.nextInt(MAX_ATTACK),
- val defense: Int = Random.nextInt(MAX_DEFENSE),
- val speed: Int = Random.nextInt(MAX_SPEED),
+ @field:Json(name = "stats") val stats: List,
val exp: Int = Random.nextInt(MAX_EXP),
) {
+ val hp: Int by lazy {
+ stats.firstOrNull { it.stat.name == "hp" }?.baseStat ?: Random.nextInt(MAX_HP)
+ }
+ val attack: Int by lazy {
+ stats.firstOrNull { it.stat.name == "attack" }?.baseStat ?: Random.nextInt(MAX_ATTACK)
+ }
+ val defense: Int by lazy {
+ stats.firstOrNull { it.stat.name == "defense" }?.baseStat ?: Random.nextInt(MAX_DEFENSE)
+ }
+ val speed: Int by lazy {
+ stats.firstOrNull { it.stat.name == "speed" }?.baseStat ?: Random.nextInt(MAX_SPEED)
+ }
fun getIdString(): String = String.format("#%03d", id)
fun getWeightString(): String = String.format("%.1f KG", weight.toFloat() / 10)
@@ -53,6 +62,18 @@ data class PokemonInfo(
@field:Json(name = "type") val type: Type,
)
+ @JsonClass(generateAdapter = true)
+ data class StatsResponse(
+ @field:Json(name = "base_stat") val baseStat: Int,
+ @field:Json(name = "effort") val effort: Int,
+ @field:Json(name = "stat") val stat: Stat,
+ )
+
+ @JsonClass(generateAdapter = true)
+ data class Stat(
+ @field:Json(name = "name") val name: String,
+ )
+
@JsonClass(generateAdapter = true)
data class Type(
@field:Json(name = "name") val name: String,
diff --git a/core/preview/src/main/kotlin/com/skydoves/pokedex/compose/core/preview/PreviewUtils.kt b/core/preview/src/main/kotlin/com/skydoves/pokedex/compose/core/preview/PreviewUtils.kt
index b3d6038..51a0753 100644
--- a/core/preview/src/main/kotlin/com/skydoves/pokedex/compose/core/preview/PreviewUtils.kt
+++ b/core/preview/src/main/kotlin/com/skydoves/pokedex/compose/core/preview/PreviewUtils.kt
@@ -41,5 +41,11 @@ object PreviewUtils {
PokemonInfo.TypeResponse(slot = 0, type = PokemonInfo.Type("grass")),
PokemonInfo.TypeResponse(slot = 0, type = PokemonInfo.Type("poison")),
),
+ stats = listOf(
+ PokemonInfo.StatsResponse(baseStat = 20, effort = 0, stat = PokemonInfo.Stat("hp")),
+ PokemonInfo.StatsResponse(baseStat = 40, effort = 0, stat = PokemonInfo.Stat("attack")),
+ PokemonInfo.StatsResponse(baseStat = 60, effort = 0, stat = PokemonInfo.Stat("defense")),
+ PokemonInfo.StatsResponse(baseStat = 80, effort = 0, stat = PokemonInfo.Stat("attack")),
+ ),
)
}
diff --git a/core/test/src/main/kotlin/com/skydoves/pokedex/compose/core/test/MockUtil.kt b/core/test/src/main/kotlin/com/skydoves/pokedex/compose/core/test/MockUtil.kt
index 0ec3fd6..d26cc5e 100644
--- a/core/test/src/main/kotlin/com/skydoves/pokedex/compose/core/test/MockUtil.kt
+++ b/core/test/src/main/kotlin/com/skydoves/pokedex/compose/core/test/MockUtil.kt
@@ -36,5 +36,6 @@ object MockUtil {
weight = 69,
experience = 60,
types = emptyList(),
+ stats = emptyList(),
)
}