Skip to content

Commit

Permalink
Added shared feature homepage module, added store5 for caching
Browse files Browse the repository at this point in the history
  • Loading branch information
AshuTyagi16 committed Jan 7, 2024
1 parent be25713 commit fc57e1d
Show file tree
Hide file tree
Showing 31 changed files with 603 additions and 18 deletions.
11 changes: 11 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ build-konfig = "0.15.1"
koin = "3.5.3"
kmm-bridge = "0.5.1"
skie = "0.6.1"
kotlin-serialization = "1.6.2"
store5 = "5.0.0"
kotlin-atomicfu = "0.23.1"

[libraries]
## Core-Ktx
Expand Down Expand Up @@ -57,6 +60,8 @@ ktor-client-auth = { module = "io.ktor:ktor-client-auth", version.ref = "ktor" }
ktor-client-encoding = { module = "io.ktor:ktor-client-encoding", version.ref = "ktor" }

kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
kotlin-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlin-serialization" }
kotlin-atomicfu = { module = "org.jetbrains.kotlinx:atomicfu", version.ref = "kotlin-atomicfu" }

## Coroutine
coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
Expand All @@ -68,6 +73,8 @@ build-konfig = { module = "com.codingfeline.buildkonfig:buildkonfig-gradle-plugi
koin = { module = "io.insert-koin:koin-core", version.ref = "koin"}
koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin"}

store = { module = "org.mobilenativefoundation.store:store5", version.ref = "store5" }

## Testing
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
Expand Down Expand Up @@ -104,3 +111,7 @@ multiplatform-preferences = [
"multiplatform-settings",
"multiplatform-settings-couroutine"
]
store = [
"store",
"kotlin-atomicfu"
]
2 changes: 2 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ include(":shared")
include(":shared:core-network")
include(":shared:core-logger")
include(":shared:core-preferences")
include(":shared:feature-homepage")
include(":shared:core-base")
6 changes: 6 additions & 0 deletions shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ kotlin {

// Shared Core Logger Module
api(project(":shared:core-logger"))

// Shared Feature HomePage Module
api(project(":shared:feature-homepage"))
}
commonTest.dependencies {
implementation(libs.kotlin.test)
Expand All @@ -62,6 +65,9 @@ kotlin {
// Shared Core Logger Module
export(project(":shared:core-logger"))

// Shared Feature HomePage Module
export(project(":shared:feature-homepage"))

isStatic = true

binaryOption("bundleId", "com.spotify.app.shared")
Expand Down
44 changes: 44 additions & 0 deletions shared/core-base/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
plugins {
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.com.android.library)
alias(libs.plugins.kotlin.serialization)
}

kotlin {
androidTarget {
compilations.all {
kotlinOptions {
jvmTarget = libs.versions.jvmTargetVersion.get()
}
}
}

listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
it.binaries.framework {
baseName = "core-base"
isStatic = true
}
}

sourceSets {
commonMain.dependencies {
api(libs.kotlin.serialization)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
}
}
}

android {
namespace = "com.spotify.app.core_base.shared"
compileSdk = libs.versions.compileSdkVersion.get().toInt()
defaultConfig {
minSdk = libs.versions.minSdkVersion.get().toInt()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.spotify.app.core_base.shared.data.base

interface DtoMapper<Domain, DTO> {

fun asDto(domain: Domain): DTO

fun asDomain(dto: DTO): Domain
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.spotify.app.core_base.shared.data.dto

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ImageDTO(
@SerialName("url")
val url: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.spotify.app.core_base.shared.domain.mapper

import com.spotify.app.core_base.shared.data.base.DtoMapper
import com.spotify.app.core_base.shared.data.dto.ImageDTO
import com.spotify.app.core_base.shared.domain.model.Image

object ImageDtoMapper : DtoMapper<Image, ImageDTO> {
override fun asDto(domain: Image): ImageDTO {
return ImageDTO(
url = domain.url
)
}

override fun asDomain(dto: ImageDTO): Image {
return Image(
url = dto.url
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.spotify.app.core_base.shared.domain.model

data class Image(
val url: String
)
37 changes: 20 additions & 17 deletions shared/core-network/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,22 +1,6 @@
import com.codingfeline.buildkonfig.compiler.FieldSpec.Type.BOOLEAN
import com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING

fun readTokenProperties(): Map<String, String> {
val items = HashMap<String, String>()

val fl = rootProject.file("token.properties")

if (fl.exists()) {
fl.forEachLine {
items[it.split("=")[0]] = it.split("=")[1]
}
}

return items
}

val tokenProperties = readTokenProperties()

@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
plugins {
alias(libs.plugins.kotlin.multiplatform)
Expand Down Expand Up @@ -55,11 +39,14 @@ kotlin {
implementation(libs.coroutines.core)

// Ktor
implementation(libs.bundles.ktor.common)
api(libs.bundles.ktor.common)

// Koin
implementation(libs.koin)

// Store5
implementation(libs.bundles.store)

// Core-Logger Module
implementation(project(":shared:core-logger"))

Expand All @@ -86,6 +73,22 @@ kotlin {

val modulePackageName = "com.spotify.app.core_network.shared"

fun readTokenProperties(): Map<String, String> {
val items = HashMap<String, String>()

val fl = rootProject.file("token.properties")

if (fl.exists()) {
fl.forEachLine {
items[it.split("=")[0]] = it.split("=")[1]
}
}

return items
}

val tokenProperties = readTokenProperties()

buildkonfig {
packageName = modulePackageName
exposeObjectWithName = "CoreNetworkBuildKonfig"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.spotify.app.core_network.shared.impl.util

import com.spotify.app.core_network.shared.impl.data.model.RestClientResult
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map
import org.mobilenativefoundation.store.store5.StoreReadResponse

suspend inline fun <DTO, Domain> RestClientResult<DTO>.mapFromDTO(
crossinline dataMapper: suspend (t: DTO?) -> Domain
): RestClientResult<Domain> {
return when (status) {
RestClientResult.Status.LOADING -> {
RestClientResult.loading()
}

RestClientResult.Status.SUCCESS -> {
RestClientResult.success(data = dataMapper.invoke(data))
}

RestClientResult.Status.ERROR -> {
RestClientResult.error(errorMessage = errorMessage.orEmpty(), errorCode = errorCode)
}
}
}

fun <T> Flow<StoreReadResponse<RestClientResult<T>>>.mapStoreResponseToRestClientResult(): Flow<RestClientResult<T?>> =
this.map {
when (it) {
is StoreReadResponse.Data -> {
when (it.value.status) {
RestClientResult.Status.SUCCESS -> {
RestClientResult.success(it.value.data)
}

RestClientResult.Status.ERROR -> {
RestClientResult.error(
errorMessage = it.value.errorMessage.orEmpty(),
errorCode = it.value.errorCode
)
}

RestClientResult.Status.LOADING -> {
RestClientResult.loading()
}
}
}

is StoreReadResponse.Error.Exception -> {
RestClientResult.error(errorMessage = it.errorMessageOrNull().orEmpty())
}

is StoreReadResponse.Error.Message -> {
RestClientResult.error(errorMessage = it.errorMessageOrNull().orEmpty())
}

is StoreReadResponse.Loading -> {
RestClientResult.loading()
}

is StoreReadResponse.NoNewData -> {
RestClientResult.error(errorMessage = it.errorMessageOrNull().orEmpty())
}
}
}

suspend fun <T> Flow<RestClientResult<T>>.collect(
onLoading: suspend () -> Unit,
onSuccess: suspend (data: T) -> Unit,
onError: suspend (errorMessage: String, errorCode: Int?) -> Unit
) {
this.collectLatest {
when (it.status) {
RestClientResult.Status.LOADING -> {
onLoading.invoke()
}

RestClientResult.Status.SUCCESS -> {
onSuccess.invoke(it.data!!)
}

RestClientResult.Status.ERROR -> {
onError.invoke(it.errorMessage.orEmpty(), it.errorCode)
}
}
}
}
58 changes: 58 additions & 0 deletions shared/feature-homepage/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
plugins {
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.com.android.library)
alias(libs.plugins.kotlin.serialization)
}

kotlin {
androidTarget {
compilations.all {
kotlinOptions {
jvmTarget = libs.versions.jvmTargetVersion.get()
}
}
}

listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
it.binaries.framework {
baseName = "feature-homepage"
isStatic = true
}
}

sourceSets {
commonMain.dependencies {

// Shared Core Base Module
implementation(project(":shared:core-base"))

// Shared Core Network Module
implementation(project(":shared:core-network"))

// Store5
implementation(libs.bundles.store)

// Koin
implementation(libs.koin)

}
commonTest.dependencies {
implementation(libs.kotlin.test)
}
}
}

val modulePackageName = "com.spotify.app.feature_homepage.shared"

android {
namespace = modulePackageName
compileSdk = libs.versions.compileSdkVersion.get().toInt()
defaultConfig {
minSdk = libs.versions.minSdkVersion.get().toInt()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.spotify.app.feature_homepage.shared.data.dto

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class FeaturedPlaylistsDTO(
@SerialName("message")
val message: String,

@SerialName("playlists")
val playlists: PlaylistDTO
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.spotify.app.feature_homepage.shared.data.dto

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class PlaylistDTO(
@SerialName("items")
val items: List<PlaylistItemDTO>,

@SerialName("total")
val total: Int
)
Loading

0 comments on commit fc57e1d

Please sign in to comment.