Skip to content

Commit

Permalink
Add empty eventmap module
Browse files Browse the repository at this point in the history
  • Loading branch information
takahirom committed Jun 15, 2024
1 parent 66dd855 commit d94fe4e
Show file tree
Hide file tree
Showing 20 changed files with 570 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.github.droidkaigi.confsched.data.eventmap

import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent

@Module
@InstallIn(SingletonComponent::class)
public class EventMapApiModule {
@Provides
public fun provideEventMapApi(): EventMapApiClient {
return FakeEventMapApiClient()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.github.droidkaigi.confsched.data.eventmap

import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
import io.github.droidkaigi.confsched.data.di.RepositoryQualifier
import io.github.droidkaigi.confsched.model.EventMapRepository
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
public abstract class EventMapRepositoryModule {
@Binds
@RepositoryQualifier
@IntoMap
@ClassKey(EventMapRepository::class)
public abstract fun bind(repository: EventMapRepository): Any

public companion object {
@Provides
@Singleton
public fun provideEventMapRepository(
eventMapApi: EventMapApiClient,
): EventMapRepository {
return DefaultEventMapRepository(
eventMapApi = eventMapApi,
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.github.droidkaigi.confsched.data.eventmap

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import io.github.droidkaigi.confsched.compose.SafeLaunchedEffect
import io.github.droidkaigi.confsched.compose.safeCollectAsState
import io.github.droidkaigi.confsched.model.EventMapEvent
import io.github.droidkaigi.confsched.model.EventMapRepository
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.flow.MutableStateFlow

public class DefaultEventMapRepository(
private val eventMapApi: EventMapApiClient,
) : EventMapRepository {
private val eventMapStateFlow =
MutableStateFlow<PersistentList<EventMapEvent>>(persistentListOf())

@Composable
override fun eventMapEvents(): PersistentList<EventMapEvent> {
val eventMap by eventMapStateFlow.safeCollectAsState()
SafeLaunchedEffect(Unit) {
if (eventMap.isEmpty()) {
refresh()
}
}
return eventMap
}

override suspend fun refresh() {
eventMapApi
.eventMapEvents()
.toPersistentList().also { eventMapStateFlow.value = it }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.github.droidkaigi.confsched.data.eventmap

import de.jensklingenberg.ktorfit.http.GET
import io.github.droidkaigi.confsched.data.eventmap.response.EventMapResponse
import io.github.droidkaigi.confsched.model.EventMapEvent
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList

internal interface EventMapApi {
@GET("/events/droidkaigi2023/eventmap")
suspend fun getEventMap(): EventMapResponse
}

public interface EventMapApiClient {

public suspend fun eventMapEvents(): PersistentList<EventMapEvent>
}

public fun EventMapResponse.toEventMapList(): PersistentList<EventMapEvent> {
return listOf(EventMapEvent()).toPersistentList()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.github.droidkaigi.confsched.data.eventmap

import io.github.droidkaigi.confsched.data.eventmap.response.EventMapResponse
import io.github.droidkaigi.confsched.model.EventMapEvent
import kotlinx.collections.immutable.PersistentList
import okio.IOException

public class FakeEventMapApiClient : EventMapApiClient {

public sealed class Status : EventMapApiClient {
public data object Operational : Status() {
override suspend fun eventMapEvents(): PersistentList<EventMapEvent> {
return EventMapResponse().toEventMapList()
}
}

public data object Error : Status() {
override suspend fun eventMapEvents(): PersistentList<EventMapEvent> {
throw IOException("Fake IO Exception")
}
}
}

private var status: Status = Status.Operational

public fun setup(status: Status) {
this.status = status
}

override suspend fun eventMapEvents(): PersistentList<EventMapEvent> {
return status.eventMapEvents()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package io.github.droidkaigi.confsched.data.eventmap.response

public class EventMapResponse
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package io.github.droidkaigi.confsched.model

class EventMapEvent
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.github.droidkaigi.confsched.model

import androidx.compose.runtime.Composable
import io.github.droidkaigi.confsched.model.compositionlocal.LocalRepositories
import kotlinx.collections.immutable.PersistentList

interface EventMapRepository {

suspend fun refresh()

@Composable
fun eventMapEvents(): PersistentList<EventMapEvent>
}

@Composable
fun localEventMapRepository(): EventMapRepository {
return LocalRepositories.current[EventMapRepository::class] as EventMapRepository
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package io.github.droidkaigi.confsched.testing
import androidx.compose.ui.test.junit4.ComposeTestRule
import io.github.droidkaigi.confsched.data.contributors.ContributorsApiClient
import io.github.droidkaigi.confsched.data.contributors.FakeContributorsApiClient
import io.github.droidkaigi.confsched.data.eventmap.EventMapApiClient
import io.github.droidkaigi.confsched.data.eventmap.FakeEventMapApiClient
import io.github.droidkaigi.confsched.data.sessions.FakeSessionsApiClient
import io.github.droidkaigi.confsched.data.sessions.SessionsApiClient
import io.github.droidkaigi.confsched.testing.coroutines.runTestWithLogging
Expand Down Expand Up @@ -136,3 +138,25 @@ class DefaultContributorsServerRobot @Inject constructor(contributorsApiClient:
)
}
}

interface EventMapServerRobot {
enum class ServerStatus {
Operational,
Error,
}

fun setupContributorServer(serverStatus: ServerStatus)
}

class DefaultEventMapServerRobot @Inject constructor(contributorsApiClient: EventMapApiClient) :
EventMapServerRobot {
private val fakeEventMapApiClient = contributorsApiClient as FakeEventMapApiClient
override fun setupContributorServer(serverStatus: EventMapServerRobot.ServerStatus) {
fakeEventMapApiClient.setup(
when (serverStatus) {
EventMapServerRobot.ServerStatus.Operational -> FakeEventMapApiClient.Status.Operational
EventMapServerRobot.ServerStatus.Error -> FakeEventMapApiClient.Status.Error
},
)
}
}
1 change: 1 addition & 0 deletions feature/eventmap/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
23 changes: 23 additions & 0 deletions feature/eventmap/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
plugins {
id("droidkaigi.convention.kmpfeature")
}

android.namespace = "io.github.droidkaigi.confsched.feature.eventMap"
kotlin {
sourceSets {
commonMain {
dependencies {
implementation(projects.core.model)
implementation(projects.core.ui)
implementation(libs.kotlinxCoroutinesCore)
implementation(projects.core.designsystem)
implementation(libs.moleculeRuntime)
}
}
androidUnitTest {
dependencies {
implementation(projects.core.testing)
}
}
}
}
21 changes: 21 additions & 0 deletions feature/eventmap/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.kts.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package io.github.droidkaigi.confsched.eventmap

import androidx.test.ext.junit.runners.AndroidJUnit4
import dagger.hilt.android.testing.BindValue
import dagger.hilt.android.testing.HiltAndroidTest
import io.github.droidkaigi.confsched.testing.DefaultEventMapServerRobot
import io.github.droidkaigi.confsched.testing.DefaultScreenRobot
import io.github.droidkaigi.confsched.testing.EventMapServerRobot
import io.github.droidkaigi.confsched.testing.RobotTestRule
import io.github.droidkaigi.confsched.testing.ScreenRobot
import io.github.droidkaigi.confsched.testing.runRobot
import io.github.droidkaigi.confsched.testing.todoChecks
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import javax.inject.Inject

@RunWith(AndroidJUnit4::class)
@HiltAndroidTest
class EventMapScreenTest {

@get:Rule
@BindValue val robotTestRule: RobotTestRule = RobotTestRule(this)

@Inject
lateinit var eventMapScreenRobot: EventMapScreenRobot

@Test
fun checkScreenContent() {
runRobot(eventMapScreenRobot) {
setupContributorServer(EventMapServerRobot.ServerStatus.Operational)
setupScreenContent()

captureScreenWithChecks(
checks = todoChecks("This screen is still empty now. Please add some checks."),
)
}
}

@Test
fun checkErrorScreenContent() {
runRobot(eventMapScreenRobot) {
setupContributorServer(EventMapServerRobot.ServerStatus.Error)
setupScreenContent()

captureScreenWithChecks(
checks = todoChecks("This screen is still empty now. Please add some checks."),
)
}
}
}

class EventMapScreenRobot @Inject constructor(
screenRobot: DefaultScreenRobot,
eventMapServerRobot: DefaultEventMapServerRobot,
) : ScreenRobot by screenRobot,
EventMapServerRobot by eventMapServerRobot {
fun setupScreenContent() {
robotTestRule.setContent {
EventMapScreen(
onNavigationIconClick = { },
onEventMapItemClick = { },
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
sdk=34
# RobolectricDeviceQualifiers.NexusOne
qualifiers=w320dp-h533dp-normal-long-notround-any-hdpi-keyshidden-trackball

application=dagger.hilt.android.testing.HiltTestApplication
# https://github.com/robolectric/robolectric/issues/6593
instrumentedPackages=androidx.loader.content
Loading

0 comments on commit d94fe4e

Please sign in to comment.