Last active
November 17, 2019 05:44
-
-
Save Judrummer/bcceab5498251ab2a8dfd90ea921c99e to your computer and use it in GitHub Desktop.
Kotlin Multiplatform Workshop
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.kithub.core.data | |
import android.content.Context.MODE_PRIVATE | |
import androidx.core.content.edit | |
import com.kithub.core.AndroidAppContext | |
actual class UserPreferenceImpl : UserPreference { | |
private val sharedPreference | |
get() = AndroidAppContext.app.getSharedPreferences("UserPreference", MODE_PRIVATE) | |
override var username: String | |
get() = sharedPreference.getString("username", "").orEmpty() | |
set(value) { | |
sharedPreference.edit { | |
putString("username", value) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.kithub.core.data | |
import platform.Foundation.NSUserDefaults | |
import platform.Foundation.setValue | |
actual class UserPreferenceImpl : UserPreference { | |
private val userDefaults get() = NSUserDefaults(suiteName = "UserPreference") | |
override var username: String | |
get() = userDefaults.stringForKey("username").orEmpty() | |
set(value) { | |
userDefaults.setValue(value, forKey = "username") | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.kithub.core.viewmodel.repodetail | |
import com.kithub.core.data.GithubApi | |
import com.kithub.core.data.UserPreference | |
import com.kithub.core.viewmodel.KViewModel | |
import kotlinx.coroutines.launch | |
data class RepoDetailViewState( | |
val loading: Boolean = true, | |
val name: String = "", | |
val descriptionText: String = "", | |
val language: String = "", | |
val sshUrl: String = "", | |
val starCount: Int = 0, | |
val contributors: List<ContributorItem> = emptyList() | |
) | |
data class ContributorItem( | |
val name: String = "", | |
val contributions: Int = 0, | |
val avatarUrl: String = "" | |
) | |
class RepoDetailViewModel( | |
private val userPreference: UserPreference, | |
private val githubApi: GithubApi | |
) : KViewModel<RepoDetailViewState>(RepoDetailViewState()) { | |
fun refresh(repoName: String) { | |
launch { | |
try { | |
setState { copy(loading = true) } | |
val contributors = githubApi.getContributors(userPreference.username, repoName) | |
val repoDetail = githubApi.getUserRepoDetail(userPreference.username, repoName) | |
setState { | |
copy(loading = false, | |
name = repoDetail.name.orEmpty(), | |
descriptionText = repoDetail.description.orEmpty(), | |
language = repoDetail.language.orEmpty(), | |
starCount = repoDetail.stargazersCount ?: 0, | |
sshUrl = repoDetail.sshUrl.orEmpty(), | |
contributors = contributors.map { | |
ContributorItem( | |
name = it.login.orEmpty(), | |
avatarUrl = it.avatarUrl.orEmpty(), | |
contributions = it.contributions ?: 0 | |
) | |
}) | |
} | |
} catch (e: Throwable) { | |
setState { copy(loading = false) } | |
setError(e) | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.kithub.core.viewmodel.repodetail | |
import com.kithub.core.assertState | |
import com.kithub.core.common.coroutine.ApplicationDispatcher | |
import com.kithub.core.common.coroutine.TestDispatcher | |
import com.kithub.core.common.kreactive.test | |
import com.kithub.core.data.ContributorEntity | |
import com.kithub.core.data.GithubApi | |
import com.kithub.core.data.RepoDetailEntity | |
import com.kithub.core.data.UserPreference | |
import io.mockk.coEvery | |
import io.mockk.every | |
import io.mockk.mockk | |
import kotlinx.coroutines.InternalCoroutinesApi | |
import org.junit.Test | |
import kotlin.test.assertTrue | |
@UseExperimental(InternalCoroutinesApi::class) | |
class RepoDetailViewModelTest { | |
val userPreference = mockk<UserPreference>(relaxed = true) | |
val githubApi = mockk<GithubApi>(relaxed = true) | |
val viewModel = RepoDetailViewModel(userPreference, githubApi) | |
val state = viewModel.state.test() | |
val error = viewModel.error.test() | |
init { | |
ApplicationDispatcher = TestDispatcher | |
} | |
@Test | |
fun refresh() { | |
val repoDetailEntity = RepoDetailEntity( | |
name = "ktor", | |
description = "http library", | |
language = "kotlin", | |
sshUrl = "ssh.url", | |
stargazersCount = 2000 | |
) | |
val contributorEntities = listOf( | |
ContributorEntity( | |
login = "alice", | |
contributions = 120, | |
avatarUrl = "avatar.url" | |
) | |
) | |
every { userPreference.username } returns "kotlin" | |
coEvery { githubApi.getContributors("kotlin", "ktor") } returns contributorEntities | |
coEvery { githubApi.getUserRepoDetail("kotlin", "ktor") } returns repoDetailEntity | |
viewModel.refresh("ktor") | |
assertTrue { error.values.isEmpty() } | |
state.assertState( | |
RepoDetailViewState(), | |
{ copy(loading = true) }, | |
{ | |
copy( | |
loading = false, | |
name = "ktor", | |
descriptionText = "http library", | |
starCount = 2000, | |
sshUrl = "ssh.url", | |
language = "kotlin", | |
contributors = listOf( | |
ContributorItem( | |
name = "alice", | |
contributions = 120, | |
avatarUrl = "avatar.url" | |
) | |
) | |
) | |
} | |
) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.kithub.core.viewmodel.repolist | |
import com.kithub.core.data.GithubApi | |
import com.kithub.core.data.UserPreference | |
import com.kithub.core.viewmodel.KViewModel | |
import kotlinx.coroutines.launch | |
data class RepoListViewState( | |
val loading: Boolean = true, | |
val username: String = "", | |
val displayName: String = "", | |
val avatarUrl: String = "", | |
val repos: List<RepoItem> = emptyList() | |
) | |
data class RepoItem( | |
val name: String, | |
val descriptionText: String, // Don't use val description: String because iOS can't see it | |
val starCount: Int | |
) | |
class RepoListViewModel( | |
private val userPreference: UserPreference, | |
private val githubApi: GithubApi | |
) : KViewModel<RepoListViewState>(RepoListViewState()) { | |
fun refresh() { | |
launch { | |
try { | |
setState { copy(loading = true) } | |
val userEntity = githubApi.getUser(username = userPreference.username) | |
val repoEntities = githubApi.getUserRepos(username = userPreference.username) | |
setState { | |
copy( | |
loading = false, | |
username = userEntity.login ?: "", | |
displayName = userEntity.name.orEmpty(), | |
avatarUrl = userEntity.avatarUrl.orEmpty(), | |
repos = repoEntities.map { | |
RepoItem( | |
name = it.name.orEmpty(), | |
descriptionText = it.description.orEmpty(), | |
starCount = it.stargazersCount ?: 0 | |
) | |
} | |
) | |
} | |
} catch (e: Throwable) { | |
setState { copy(loading = false) } | |
setError(e) | |
} | |
} | |
} | |
fun logout() { | |
userPreference.username = "" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.kithub.core.viewmodel.repolist | |
import com.kithub.core.assertState | |
import com.kithub.core.common.coroutine.ApplicationDispatcher | |
import com.kithub.core.common.coroutine.TestDispatcher | |
import com.kithub.core.common.kreactive.test | |
import com.kithub.core.data.GithubApi | |
import com.kithub.core.data.RepoEntity | |
import com.kithub.core.data.UserEntity | |
import com.kithub.core.data.UserPreference | |
import io.mockk.coEvery | |
import io.mockk.every | |
import io.mockk.mockk | |
import io.mockk.verify | |
import kotlinx.coroutines.InternalCoroutinesApi | |
import kotlin.test.Test | |
import kotlin.test.assertTrue | |
@UseExperimental(InternalCoroutinesApi::class) | |
class RepoListViewModelTest { | |
val userPreference = mockk<UserPreference>(relaxed = true) | |
val githubApi = mockk<GithubApi>(relaxed = true) | |
val viewModel = RepoListViewModel(userPreference, githubApi) | |
val state = viewModel.state.test() | |
val error = viewModel.error.test() | |
init { | |
ApplicationDispatcher = TestDispatcher | |
} | |
@Test | |
fun refresh() { | |
val userEntity = UserEntity( | |
login = "kotlin", | |
name = "Kotlin Lang", | |
avatarUrl = "www.google.com" | |
) | |
val repoEntities = listOf( | |
RepoEntity( | |
name = "ktor", | |
description = "Http library", | |
stargazersCount = 9999 | |
) | |
) | |
every { userPreference.username } returns "kotlin" | |
coEvery { githubApi.getUser("kotlin") } returns userEntity | |
coEvery { githubApi.getUserRepos("kotlin") } returns repoEntities | |
viewModel.refresh() | |
assertTrue { error.values.isEmpty() } | |
state.assertState(RepoListViewState(), | |
{ copy(loading = true) }, | |
{ | |
copy( | |
loading = false, | |
username = "kotlin", | |
avatarUrl = "www.google.com", | |
displayName = "Kotlin Lang", | |
repos = listOf( | |
RepoItem( | |
name = "ktor", | |
descriptionText = "Http library", | |
starCount = 9999 | |
) | |
) | |
) | |
} | |
) | |
} | |
@Test | |
fun logout() { | |
viewModel.logout() | |
verify { userPreference.username = "" } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment