Skip to content

Commit

Permalink
Merge pull request #82 from subroh0508/add-common-viewmodel
Browse files Browse the repository at this point in the history
Add common ViewModel
  • Loading branch information
subroh0508 authored Oct 21, 2024
2 parents 3faabbc + 47b68f6 commit 09359ff
Show file tree
Hide file tree
Showing 55 changed files with 888 additions and 233 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import net.subroh0508.colormaster.model.auth.AuthRepository
internal class DefaultAuthRepository(
private val client: AuthClient,
) : AuthRepository {
override fun currentUser() = client.subscribeAuthState().map { it?.toEntity() }
override fun getCurrentUserStream() = client.subscribeAuthState().map { it?.toEntity() }
override suspend fun signOut() = client.signOut()

override suspend fun fetchCurrentUser() = client.currentUser?.toEntity()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package net.subroh0508.colormaster.data.extension

import net.subroh0508.colormaster.network.auth.AuthClient

actual suspend fun signInWithGoogle(
client: AuthClient,
) = client.signInWithGoogle("idToken")
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package net.subroh0508.colormaster.data.extension

import net.subroh0508.colormaster.network.auth.AuthClient
import net.subroh0508.colormaster.network.firestore.FirestoreClient
import net.subroh0508.colormaster.network.firestore.document.UserDocument

actual suspend fun setUserDocument(
auth: AuthClient,
firestore: FirestoreClient,
inChargeIds: List<String>,
favoriteIds: List<String>,
) {
auth.signInWithGoogle("idToken")
val uid = auth.currentUser?.uid ?: return

firestore.setUserDocument(uid, UserDocument(inChargeIds, favoriteIds))
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import net.subroh0508.colormaster.test.extension.flowToList
import net.subroh0508.colormaster.test.model.GoogleUser

class AndroidDefaultAuthRepositorySpec : FunSpec({
test("#currentUser: it should return current user") {
test("#getCurrentUserStream: it should return current user") {
val repository = buildAuthRepository()

val (instances, _) = flowToList(repository.currentUser())
val (instances, _) = flowToList(repository.getCurrentUserStream())

repository.signInWithGoogle("idToken")
repository.signOut()
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package net.subroh0508.colormaster.data
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.onStart
import net.subroh0508.colormaster.data.extension.toIdolColors
import net.subroh0508.colormaster.network.auth.AuthClient
import net.subroh0508.colormaster.network.firestore.FirestoreClient
import net.subroh0508.colormaster.network.imasparql.ImasparqlClient
Expand All @@ -11,7 +12,6 @@ import net.subroh0508.colormaster.network.imasparql.query.RandomQuery
import net.subroh0508.colormaster.network.imasparql.query.SearchByIdQuery
import net.subroh0508.colormaster.network.imasparql.query.SearchByLiveQuery
import net.subroh0508.colormaster.network.imasparql.query.SearchByNameQuery
import net.subroh0508.colormaster.network.imasparql.serializer.Response
import net.subroh0508.colormaster.model.*

internal class DefaultIdolColorsRepository(
Expand All @@ -23,24 +23,28 @@ internal class DefaultIdolColorsRepository(
private val inChargeOfIdolIdsStateFlow = MutableStateFlow<List<String>>(listOf())
private val favoriteIdolIdsStateFlow = MutableStateFlow<List<String>>(listOf())

override fun idols(limit: Int, lang: String): Flow<List<IdolColor>> {
override fun getIdolColorsStream(limit: Int, lang: String): Flow<List<IdolColor>> {
return idolsStateFlow.onStart {
rand(limit, lang)
}
}

override fun inChargeOfIdolIds(): Flow<List<String>> {
override fun getInChargeOfIdolIdsStream(): Flow<List<String>> {
return inChargeOfIdolIdsStateFlow.onStart {
getInChargeOfIdolIds()
}
}

override fun favoriteIdolIds(): Flow<List<String>> {
override fun getFavoriteIdolIdsStream(): Flow<List<String>> {
return favoriteIdolIdsStateFlow.onStart {
getFavoriteIdolIds()
}
}

override suspend fun refresh() {
idolsStateFlow.value = listOf()
}

override suspend fun rand(
limit: Int,
lang: String,
Expand Down Expand Up @@ -147,20 +151,4 @@ internal class DefaultIdolColorsRepository(
private val currentUser get() = authClient.currentUser

private suspend fun getUserDocument() = firestoreClient.getUserDocument(currentUser?.uid)

private fun Response<IdolColorJson>.toIdolColors() = results
.bindings
.mapNotNull { (idMap, nameMap, colorMap) ->
val id = idMap["value"] ?: return@mapNotNull null
val name = nameMap["value"] ?: return@mapNotNull null
val color = colorMap["value"] ?: return@mapNotNull null

val intColor = Triple(
color.substring(0, 2).toInt(16),
color.substring(2, 4).toInt(16),
color.substring(4, 6).toInt(16),
)

IdolColor(id, name, intColor)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ internal class DefaultLiveRepository(
) : LiveRepository {
private val names: MutableStateFlow<List<LiveName>> = MutableStateFlow(listOf())

override fun names() = names.onStart {
override fun getLiveNamesStream() = names.onStart {
refresh()
}

override suspend fun refresh() {
names.value = listOf()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package net.subroh0508.colormaster.data

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.onStart
import net.subroh0508.colormaster.data.extension.search
import net.subroh0508.colormaster.model.IdolColor
import net.subroh0508.colormaster.model.MyIdolsRepository
import net.subroh0508.colormaster.network.auth.AuthClient
import net.subroh0508.colormaster.network.firestore.FirestoreClient
import net.subroh0508.colormaster.network.imasparql.ImasparqlClient

internal class DefaultMyIdolsRepository(
private val imasparqlClient: ImasparqlClient,
private val firestoreClient: FirestoreClient,
private val authClient: AuthClient,
) : MyIdolsRepository {
private val inChargeOfIdolsStateFlow = MutableStateFlow<List<IdolColor>>(listOf())
private val favoriteIdolsStateFlow = MutableStateFlow<List<IdolColor>>(listOf())

override fun getInChargeOfIdolsStream(lang: String): Flow<List<IdolColor>> {
return inChargeOfIdolsStateFlow.onStart {
inChargeOfIdolsStateFlow.value = imasparqlClient.search(getUserDocument().inCharges, lang)
}
}

override fun getFavoriteIdolsStream(lang: String): Flow<List<IdolColor>> {
return favoriteIdolsStateFlow.onStart {
favoriteIdolsStateFlow.value = imasparqlClient.search(getUserDocument().favorites, lang)
}
}

private val currentUser get() = authClient.currentUser

private suspend fun getUserDocument() = firestoreClient.getUserDocument(currentUser?.uid)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package net.subroh0508.colormaster.data

import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.onStart
import net.subroh0508.colormaster.data.extension.search
import net.subroh0508.colormaster.model.IdolColor
import net.subroh0508.colormaster.model.PreviewRepository
import net.subroh0508.colormaster.network.imasparql.ImasparqlClient

internal class DefaultPreviewRepository(
private val imasparqlClient: ImasparqlClient,
) : PreviewRepository {
private val idolsStateFlow = MutableStateFlow<List<IdolColor>>(listOf())

override fun getPreviewColorsStream() = idolsStateFlow.onStart { clear() }

override fun clear() {
idolsStateFlow.value = listOf()
}

override suspend fun show(ids: List<String>, lang: String) {
idolsStateFlow.value = imasparqlClient.search(ids, lang)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ import net.subroh0508.colormaster.network.imasparql.di.Api
val DataModule get() = Api.Module() + Auth.Module + Firestore.Module +
AuthRepositories.Module +
IdolColorsRepositories.Module +
LiveRepositories.Module
LiveRepositories.Module +
MyIdolsRepositories.Module +
PreviewRepositories.Module
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package net.subroh0508.colormaster.data.di

import net.subroh0508.colormaster.data.DefaultMyIdolsRepository
import net.subroh0508.colormaster.model.MyIdolsRepository
import org.koin.dsl.module

object MyIdolsRepositories {
val Module get() = module {
single<MyIdolsRepository> { DefaultMyIdolsRepository(get(), get(), get()) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package net.subroh0508.colormaster.data.di

import net.subroh0508.colormaster.data.DefaultPreviewRepository
import net.subroh0508.colormaster.model.PreviewRepository
import org.koin.dsl.module

object PreviewRepositories {
val Module get() = module {
single<PreviewRepository> { DefaultPreviewRepository(get()) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package net.subroh0508.colormaster.data.extension

import net.subroh0508.colormaster.model.IdolColor
import net.subroh0508.colormaster.network.imasparql.json.IdolColorJson
import net.subroh0508.colormaster.network.imasparql.serializer.Response

internal fun Response<IdolColorJson>.toIdolColors() = results
.bindings
.mapNotNull { (idMap, nameMap, colorMap) ->
val id = idMap["value"] ?: return@mapNotNull null
val name = nameMap["value"] ?: return@mapNotNull null
val color = colorMap["value"] ?: return@mapNotNull null

val intColor = Triple(
color.substring(0, 2).toInt(16),
color.substring(2, 4).toInt(16),
color.substring(4, 6).toInt(16),
)

IdolColor(id, name, intColor)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package net.subroh0508.colormaster.data.extension

import net.subroh0508.colormaster.network.imasparql.ImasparqlClient
import net.subroh0508.colormaster.network.imasparql.json.IdolColorJson
import net.subroh0508.colormaster.network.imasparql.query.SearchByIdQuery

internal suspend fun ImasparqlClient.search(
ids: List<String>,
lang: String,
) = if (ids.isEmpty())
listOf()
else
search(
SearchByIdQuery(lang, ids).build(),
IdolColorJson.serializer(),
).toIdolColors()
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package net.subroh0508.colormaster.data.extension

import net.subroh0508.colormaster.network.auth.AuthClient

expect suspend fun signInWithGoogle(
client: AuthClient,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package net.subroh0508.colormaster.data.extension

import net.subroh0508.colormaster.network.auth.AuthClient
import net.subroh0508.colormaster.network.firestore.FirestoreClient

expect suspend fun setUserDocument(
auth: AuthClient,
firestore: FirestoreClient,
inChargeIds: List<String> = listOf(),
favoriteIds: List<String> = listOf(),
)
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import net.subroh0508.colormaster.model.LiveRepository
import net.subroh0508.colormaster.network.imasparql.di.Api
import org.koin.dsl.koinApplication

fun buildLiveRepository(
internal fun buildLiveRepository(
block: () -> HttpClient,
): LiveRepository = koinApplication {
modules(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package net.subroh0508.colormaster.data.module

import io.ktor.client.HttpClient
import net.subroh0508.colormaster.data.di.MyIdolsRepositories
import net.subroh0508.colormaster.model.MyIdolsRepository
import net.subroh0508.colormaster.network.auth.AuthClient
import net.subroh0508.colormaster.network.firestore.FirestoreClient
import net.subroh0508.colormaster.network.imasparql.di.Api
import net.subroh0508.colormaster.test.fake.FakeAuthClient
import net.subroh0508.colormaster.test.fake.FakeFirestoreClient
import org.koin.dsl.koinApplication
import org.koin.dsl.module

internal fun buildMyIdolsRepository(
block: () -> HttpClient,
): Triple<MyIdolsRepository, AuthClient, FirestoreClient> {
val authClient: AuthClient = FakeAuthClient()
val firestoreClient: FirestoreClient = FakeFirestoreClient()

val repository: MyIdolsRepository = koinApplication {
modules(
Api.Module(block()) + module {
single { authClient }
single { firestoreClient }
} + MyIdolsRepositories.Module
)
}.koin.get(MyIdolsRepository::class)

return Triple(repository, authClient, firestoreClient)
}
Loading

0 comments on commit 09359ff

Please sign in to comment.