Skip to content

Commit

Permalink
Merge pull request #181 from DroidKaigi/yamada-ika/add-sponsors-screen
Browse files Browse the repository at this point in the history
add sponsors screen
  • Loading branch information
takahirom authored Aug 4, 2024
2 parents 35d0d4a + 07b3774 commit 0cb1dfe
Show file tree
Hide file tree
Showing 23 changed files with 727 additions and 13 deletions.
1 change: 1 addition & 0 deletions app-android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ dependencies {
implementation(projects.feature.eventmap)
implementation(projects.feature.profilecard)
implementation(projects.feature.about)
implementation(projects.feature.sponsors)
implementation(projects.feature.staff)
implementation(projects.core.model)
implementation(projects.core.data)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ import io.github.droidkaigi.confsched.sessions.nestedSessionScreens
import io.github.droidkaigi.confsched.sessions.sessionScreens
import io.github.droidkaigi.confsched.sessions.timetableScreenRoute
import io.github.droidkaigi.confsched.share.ShareNavigator
import io.github.droidkaigi.confsched.sponsors.sponsorsScreenRoute
import io.github.droidkaigi.confsched.sponsors.sponsorsScreens
import io.github.droidkaigi.confsched.staff.staffScreenRoute
import io.github.droidkaigi.confsched.staff.staffScreens
import io.github.droidkaigi.confsched.ui.NavHostWithSharedAxisX
Expand Down Expand Up @@ -110,6 +112,11 @@ private fun KaigiNavHost(
onNavigationIconClick = navController::popBackStack,
onStaffItemClick = externalNavController::navigate,
)

sponsorsScreens(
onNavigationIconClick = navController::popBackStack,
onSponsorsItemClick = externalNavController::navigate,
)
}
}

Expand Down Expand Up @@ -141,7 +148,7 @@ private fun NavGraphBuilder.mainScreen(
"https://portal.droidkaigi.jp/en"
}
when (aboutItem) {
AboutItem.Sponsors -> TODO()
AboutItem.Sponsors -> navController.navigate(sponsorsScreenRoute)
AboutItem.CodeOfConduct -> {
externalNavController.navigate(
url = "$portalBaseUrl/about/code-of-conduct",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
package io.github.droidkaigi.confsched.data.sponsors

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.SponsorsRepository
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
public class SponsorsRepositoryModule {
@Provides
@Singleton
public fun provideSponsorsRepository(
sponsorsApi: SponsorsApiClient,
): SponsorsRepository {
return DefaultSponsorsRepository(
sponsorsApi = sponsorsApi,
)
public abstract class SponsorsRepositoryModule {
@Binds
@RepositoryQualifier
@IntoMap
@ClassKey(SponsorsRepository::class)
public abstract fun bind(repository: SponsorsRepository): Any

public companion object {
@Provides
@Singleton
public fun provideSponsorsRepository(
sponsorsApi: SponsorsApiClient,
): SponsorsRepository {
return DefaultSponsorsRepository(
sponsorsApi = sponsorsApi,
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package io.github.droidkaigi.confsched.data.sponsors

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import io.github.droidkaigi.confsched.compose.SafeLaunchedEffect
import io.github.droidkaigi.confsched.compose.safeCollectAsRetainedState
import io.github.droidkaigi.confsched.model.Sponsor
import io.github.droidkaigi.confsched.model.SponsorsRepository
import kotlinx.collections.immutable.PersistentList
Expand All @@ -15,7 +19,7 @@ public class DefaultSponsorsRepository(
private val sponsorsStateFlow =
MutableStateFlow<PersistentList<Sponsor>>(persistentListOf())

override fun sponsors(): Flow<PersistentList<Sponsor>> {
override fun getSponsorStream(): Flow<PersistentList<Sponsor>> {
return sponsorsStateFlow.onStart {
if (sponsorsStateFlow.value.isEmpty()) {
refresh()
Expand All @@ -28,4 +32,15 @@ public class DefaultSponsorsRepository(
.sponsors()
.toPersistentList()
}

@Composable
override fun sponsors(): PersistentList<Sponsor> {
val sponsors by sponsorsStateFlow.safeCollectAsRetainedState()
SafeLaunchedEffect(Unit) {
if (sponsors.isEmpty()) {
refresh()
}
}
return sponsors
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
package io.github.droidkaigi.confsched.model

import androidx.compose.runtime.Composable
import io.github.droidkaigi.confsched.model.compositionlocal.LocalRepositories
import kotlinx.collections.immutable.PersistentList
import kotlinx.coroutines.flow.Flow
import kotlin.coroutines.cancellation.CancellationException

public interface SponsorsRepository {
public fun sponsors(): Flow<PersistentList<Sponsor>>
public fun getSponsorStream(): Flow<PersistentList<Sponsor>>

@Throws(CancellationException::class)
public suspend fun refresh()

@Composable
fun sponsors(): PersistentList<Sponsor>
}

@Composable
fun localSponsorsRepository(): SponsorsRepository {
return LocalRepositories.current[SponsorsRepository::class] as SponsorsRepository
}
1 change: 1 addition & 0 deletions core/testing/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ dependencies {
implementation(projects.feature.profilecard)
implementation(projects.feature.about)
implementation(projects.feature.staff)
implementation(projects.feature.sponsors)
implementation(libs.daggerHiltAndroidTesting)
implementation(libs.roborazzi)
implementation(libs.kermit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ 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.data.sponsors.FakeSponsorsApiClient
import io.github.droidkaigi.confsched.data.sponsors.SponsorsApiClient
import io.github.droidkaigi.confsched.data.staff.FakeStaffApiClient
import io.github.droidkaigi.confsched.data.staff.StaffApiClient
import io.github.droidkaigi.confsched.testing.SponsorsServerRobot.ServerStatus
import io.github.droidkaigi.confsched.testing.SponsorsServerRobot.ServerStatus.Error
import io.github.droidkaigi.confsched.testing.SponsorsServerRobot.ServerStatus.Operational
import io.github.droidkaigi.confsched.testing.coroutines.runTestWithLogging
import kotlinx.coroutines.test.TestDispatcher
import org.robolectric.RuntimeEnvironment
Expand Down Expand Up @@ -219,3 +224,24 @@ class DefaultStaffServerRobot @Inject constructor(staffApiClient: StaffApiClient
)
}
}

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

fun setupSponsorsServer(sererStatus: ServerStatus)
}

class DefaultSponsorsServerRobot @Inject constructor(sponsorsApiClient: SponsorsApiClient) : SponsorsServerRobot {
private val fakeSponsorsApiClient = sponsorsApiClient as FakeSponsorsApiClient
override fun setupSponsorsServer(sererStatus: ServerStatus) {
fakeSponsorsApiClient.setup(
when (sererStatus) {
Operational -> FakeSponsorsApiClient.Status.Operational
Error -> FakeSponsorsApiClient.Status.Error
},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.github.droidkaigi.confsched.testing.robot

import io.github.droidkaigi.confsched.designsystem.theme.KaigiTheme
import io.github.droidkaigi.confsched.sponsors.SponsorsScreen
import io.github.droidkaigi.confsched.testing.DefaultScreenRobot
import io.github.droidkaigi.confsched.testing.DefaultSponsorsServerRobot
import io.github.droidkaigi.confsched.testing.ScreenRobot
import io.github.droidkaigi.confsched.testing.SponsorsServerRobot
import javax.inject.Inject

class SponsorsScreenRobot @Inject constructor(
private val screenRobot: DefaultScreenRobot,
private val sponsorsServerRobot: DefaultSponsorsServerRobot,
) : ScreenRobot by screenRobot,
SponsorsServerRobot by sponsorsServerRobot {
fun setupScreenContent() {
robotTestRule.setContent {
KaigiTheme {
SponsorsScreen(
onNavigationIconClick = {},
onSponsorsItemClick = {},
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import conference_app_2024.feature.about.generated.resources.contributor
import conference_app_2024.feature.about.generated.resources.credits_title
import conference_app_2024.feature.about.generated.resources.sponsor
import conference_app_2024.feature.about.generated.resources.staff
import io.github.droidkaigi.confsched.about.AboutRes
import io.github.droidkaigi.confsched.about.component.AboutContentColumn
Expand Down Expand Up @@ -66,7 +67,7 @@ fun LazyListScope.aboutCredits(
item {
AboutContentColumn(
leadingIcon = Outlined.Apartment,
label = stringResource(AboutRes.string.staff),
label = stringResource(AboutRes.string.sponsor),
testTag = AboutCreditsSponsorsItemTestTag,
onClickAction = onSponsorsItemClick,
modifier = modifier
Expand Down
1 change: 1 addition & 0 deletions feature/sponsors/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
24 changes: 24 additions & 0 deletions feature/sponsors/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
plugins {
id("droidkaigi.convention.kmpfeature")
}

android.namespace = "io.github.droidkaigi.confsched.feature.sponsors"
roborazzi.generateComposePreviewRobolectricTests.packages = listOf("io.github.droidkaigi.confsched.sponsors")
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/sponsors/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,76 @@
package io.github.droidkaigi.confsched.sponsors

import dagger.hilt.android.testing.BindValue
import dagger.hilt.android.testing.HiltAndroidTest
import io.github.droidkaigi.confsched.testing.DescribedBehavior
import io.github.droidkaigi.confsched.testing.RobotTestRule
import io.github.droidkaigi.confsched.testing.SponsorsServerRobot.ServerStatus
import io.github.droidkaigi.confsched.testing.describeBehaviors
import io.github.droidkaigi.confsched.testing.execute
import io.github.droidkaigi.confsched.testing.robot.SponsorsScreenRobot
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 org.robolectric.ParameterizedRobolectricTestRunner
import javax.inject.Inject

@RunWith(ParameterizedRobolectricTestRunner::class)
@HiltAndroidTest
class SponsorsScreenTest(
private val testCase: DescribedBehavior<SponsorsScreenRobot>,
) {
@get:Rule
@BindValue val robotTestRule: RobotTestRule = RobotTestRule(testInstance = this)

@Inject
lateinit var sponsorsScreenRobot: SponsorsScreenRobot

@Test
fun runTest() {
runRobot(sponsorsScreenRobot) {
testCase.execute(sponsorsScreenRobot)
}
}

companion object {
@JvmStatic
@ParameterizedRobolectricTestRunner.Parameters(name = "{0}")
fun behaviors(): List<DescribedBehavior<SponsorsScreenRobot>> {
return describeBehaviors<SponsorsScreenRobot>(name = "SponsorsScreen") {
describe("when server is operational") {
run {
setupSponsorsServer(ServerStatus.Operational)
}
describe("when launch") {
run {
setupScreenContent()
}
itShould("display sponsors") {
captureScreenWithChecks(
checks = todoChecks("This screen is still empty now. Please add some checks."),
)
}
}
}

describe("when server is down") {
run {
setupSponsorsServer(ServerStatus.Error)
}
describe("when launch") {
run {
setupScreenContent()
}
itShould("show error message") {
captureScreenWithChecks(
checks = todoChecks("This screen is still empty now. Please add some checks."),
)
}
}
}
}
}
}
}
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="sponsor">スポンサー</string>
<string name="platinum_sponsor">プラチナスポンサー</string>
<string name="gold_sponsor">ゴールドスポンサー</string>
<string name="supporters">サポーター</string>
<string name="content_description_back">戻る</string>
<string name="content_description_sponsor_logo">スポンサーロゴ</string>
</resources>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="sponsor">Sponsor</string>
<string name="platinum_sponsor">PLATINUM SPONSORS</string>
<string name="gold_sponsor">GOLD SPONSORS</string>
<string name="supporters">SUPPORTERS</string>
<string name="content_description_back">Back</string>
<string name="content_description_sponsor_logo">sponsor logo</string>
</resources>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.github.droidkaigi.confsched.sponsors

import conference_app_2024.feature.sponsors.generated.resources.Res

object SponsorsRes {
val string = Res.string
val drawable = Res.drawable
}
Loading

0 comments on commit 0cb1dfe

Please sign in to comment.