From 76af67ea26fce6b03ee2380ca97b626fab3d465f Mon Sep 17 00:00:00 2001 From: todayama_r <13657682+Corvus400@users.noreply.github.com> Date: Wed, 4 Sep 2024 04:01:52 +0900 Subject: [PATCH 01/18] :recycle: Added loading indicator since it is missing. --- .../confsched/sponsors/SponsorsScreen.kt | 60 +++++++- .../sponsors/SponsorsScreenPresenter.kt | 50 +++++- .../sponsors/section/SponsorsList.kt | 143 +++++++++++++----- 3 files changed, 204 insertions(+), 49 deletions(-) diff --git a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt index 16ddee39c..588af712e 100644 --- a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt +++ b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt @@ -54,11 +54,50 @@ data class SponsorsScreenUiState( ) data class SponsorsListUiState( - val platinumSponsors: PersistentList, - val goldSponsors: PersistentList, - val supporters: PersistentList, + val platinumSponsorsUiState: PlatinumSponsorsUiState, + val goldSponsorsUiState: GoldSponsorsUiState, + val supportersUiState: SupportersUiState, ) +sealed interface PlatinumSponsorsUiState { + val userMessageStateHolder: UserMessageStateHolder + + data class Loading( + override val userMessageStateHolder: UserMessageStateHolder, + ) : PlatinumSponsorsUiState + + data class Exists( + override val userMessageStateHolder: UserMessageStateHolder, + val platinumSponsors: PersistentList, + ) : PlatinumSponsorsUiState +} + +sealed interface GoldSponsorsUiState { + val userMessageStateHolder: UserMessageStateHolder + + data class Loading( + override val userMessageStateHolder: UserMessageStateHolder, + ) : GoldSponsorsUiState + + data class Exists( + override val userMessageStateHolder: UserMessageStateHolder, + val goldSponsors: PersistentList, + ) : GoldSponsorsUiState +} + +sealed interface SupportersUiState { + val userMessageStateHolder: UserMessageStateHolder + + data class Loading( + override val userMessageStateHolder: UserMessageStateHolder, + ) : SupportersUiState + + data class Exists( + override val userMessageStateHolder: UserMessageStateHolder, + val supporters: PersistentList, + ) : SupportersUiState +} + @Composable fun SponsorsScreen( onNavigationIconClick: () -> Unit, @@ -135,9 +174,18 @@ fun SponsorsScreenPreview() { SponsorsScreen( uiState = SponsorsScreenUiState( sponsorsListUiState = SponsorsListUiState( - platinumSponsors = Sponsor.fakes().filter { it.plan == PLATINUM }.toPersistentList(), - goldSponsors = Sponsor.fakes().filter { it.plan == GOLD }.toPersistentList(), - supporters = Sponsor.fakes().filter { it.plan == SUPPORTER }.toPersistentList(), + platinumSponsorsUiState = PlatinumSponsorsUiState.Exists( + userMessageStateHolder = UserMessageStateHolderImpl(), + platinumSponsors = Sponsor.fakes().filter { it.plan == PLATINUM }.toPersistentList(), + ), + goldSponsorsUiState = GoldSponsorsUiState.Exists( + userMessageStateHolder = UserMessageStateHolderImpl(), + goldSponsors = Sponsor.fakes().filter { it.plan == GOLD }.toPersistentList(), + ), + supportersUiState = SupportersUiState.Exists( + userMessageStateHolder = UserMessageStateHolderImpl(), + supporters = Sponsor.fakes().filter { it.plan == SUPPORTER }.toPersistentList(), + ), ), userMessageStateHolder = UserMessageStateHolderImpl(), ), diff --git a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt index 98b2a6378..e3edf6f85 100644 --- a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt +++ b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt @@ -5,6 +5,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberUpdatedState import io.github.droidkaigi.confsched.compose.EventEffect import io.github.droidkaigi.confsched.compose.EventFlow +import io.github.droidkaigi.confsched.droidkaigiui.UserMessageStateHolder import io.github.droidkaigi.confsched.droidkaigiui.providePresenterDefaults import io.github.droidkaigi.confsched.model.Plan.GOLD import io.github.droidkaigi.confsched.model.Plan.PLATINUM @@ -24,7 +25,10 @@ fun sponsorsScreenPresenter( ): SponsorsScreenUiState = providePresenterDefaults { userMessageStateHolder -> val sponsors by rememberUpdatedState(sponsorsRepository.sponsors()) val sponsorListUiState by rememberUpdatedState( - sponsorList(sponsors = sponsors), + sponsorList( + userMessageStateHolder = userMessageStateHolder, + sponsors = sponsors, + ), ) EventEffect(events) { event -> } @@ -37,10 +41,48 @@ fun sponsorsScreenPresenter( @Composable private fun sponsorList( sponsors: PersistentList, + userMessageStateHolder: UserMessageStateHolder, ): SponsorsListUiState { + val platinumSponsors = sponsors.filter { it.plan == PLATINUM }.toPersistentList() + val goldSponsors = sponsors.filter { it.plan == GOLD }.toPersistentList() + val supporters = sponsors.filter { it.plan == SUPPORTER }.toPersistentList() + + val platinumSponsorsUiState = if (platinumSponsors.isNotEmpty()) { + PlatinumSponsorsUiState.Exists( + userMessageStateHolder = userMessageStateHolder, + platinumSponsors = platinumSponsors, + ) + } else { + PlatinumSponsorsUiState.Loading( + userMessageStateHolder = userMessageStateHolder, + ) + } + + val goldSponsorsUiState = if (goldSponsors.isNotEmpty()) { + GoldSponsorsUiState.Exists( + userMessageStateHolder = userMessageStateHolder, + goldSponsors = goldSponsors, + ) + } else { + GoldSponsorsUiState.Loading( + userMessageStateHolder = userMessageStateHolder, + ) + } + + val supportersUiState = if (supporters.isNotEmpty()) { + SupportersUiState.Exists( + userMessageStateHolder = userMessageStateHolder, + supporters = supporters, + ) + } else { + SupportersUiState.Loading( + userMessageStateHolder = userMessageStateHolder, + ) + } + return SponsorsListUiState( - platinumSponsors = sponsors.filter { it.plan == PLATINUM }.toPersistentList(), - goldSponsors = sponsors.filter { it.plan == GOLD }.toPersistentList(), - supporters = sponsors.filter { it.plan == SUPPORTER }.toPersistentList(), + platinumSponsorsUiState = platinumSponsorsUiState, + goldSponsorsUiState = goldSponsorsUiState, + supportersUiState = supportersUiState, ) } diff --git a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt index 36979b1ab..0bc29ce5d 100644 --- a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt +++ b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt @@ -1,18 +1,22 @@ package io.github.droidkaigi.confsched.sponsors.section import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.GridItemSpan import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items +import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Surface import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.testTag @@ -21,13 +25,17 @@ import conference_app_2024.feature.sponsors.generated.resources.gold_sponsor import conference_app_2024.feature.sponsors.generated.resources.platinum_sponsor import conference_app_2024.feature.sponsors.generated.resources.supporters import io.github.droidkaigi.confsched.designsystem.theme.KaigiTheme +import io.github.droidkaigi.confsched.droidkaigiui.UserMessageStateHolderImpl import io.github.droidkaigi.confsched.model.Plan.GOLD import io.github.droidkaigi.confsched.model.Plan.PLATINUM import io.github.droidkaigi.confsched.model.Plan.SUPPORTER import io.github.droidkaigi.confsched.model.Sponsor import io.github.droidkaigi.confsched.model.fakes +import io.github.droidkaigi.confsched.sponsors.GoldSponsorsUiState +import io.github.droidkaigi.confsched.sponsors.PlatinumSponsorsUiState import io.github.droidkaigi.confsched.sponsors.SponsorsListUiState import io.github.droidkaigi.confsched.sponsors.SponsorsRes +import io.github.droidkaigi.confsched.sponsors.SupportersUiState import io.github.droidkaigi.confsched.sponsors.component.SponsorHeader import io.github.droidkaigi.confsched.sponsors.component.SponsorItem import kotlinx.collections.immutable.toPersistentList @@ -77,18 +85,34 @@ fun SponsorsList( ), ) } - items( - items = uiState.platinumSponsors, - span = { GridItemSpan(maxLineSpan) }, - ) { sponsor -> - SponsorItem( - modifier = Modifier - .fillMaxWidth() - .height(110.dp) - .testTag(SponsorsListSponsorItemTestTagPrefix.plus(sponsor.name)), - sponsor = sponsor, - onSponsorsItemClick = onSponsorsItemClick, - ) + when (uiState.platinumSponsorsUiState) { + is PlatinumSponsorsUiState.Exists -> { + items( + items = uiState.platinumSponsorsUiState.platinumSponsors, + span = { GridItemSpan(maxLineSpan) }, + ) { sponsor -> + SponsorItem( + modifier = Modifier + .fillMaxWidth() + .height(110.dp) + .testTag(SponsorsListSponsorItemTestTagPrefix.plus(sponsor.name)), + sponsor = sponsor, + onSponsorsItemClick = onSponsorsItemClick, + ) + } + } + is PlatinumSponsorsUiState.Loading -> { + item( + span = { GridItemSpan(maxLineSpan) }, + ) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.padding(contentPadding).fillMaxWidth(), + ) { + CircularProgressIndicator() + } + } + } } item(span = { GridItemSpan(maxLineSpan) }) { @@ -106,18 +130,34 @@ fun SponsorsList( ), ) } - items( - items = uiState.goldSponsors, - span = { GridItemSpan(3) }, - ) { sponsor -> - SponsorItem( - modifier = Modifier - .fillMaxWidth() - .height(77.dp) - .testTag(SponsorsListSponsorItemTestTagPrefix.plus(sponsor.name)), - sponsor = sponsor, - onSponsorsItemClick = onSponsorsItemClick, - ) + when (uiState.goldSponsorsUiState) { + is GoldSponsorsUiState.Exists -> { + items( + items = uiState.goldSponsorsUiState.goldSponsors, + span = { GridItemSpan(3) }, + ) { sponsor -> + SponsorItem( + modifier = Modifier + .fillMaxWidth() + .height(77.dp) + .testTag(SponsorsListSponsorItemTestTagPrefix.plus(sponsor.name)), + sponsor = sponsor, + onSponsorsItemClick = onSponsorsItemClick, + ) + } + } + is GoldSponsorsUiState.Loading -> { + item( + span = { GridItemSpan(maxLineSpan) }, + ) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.padding(contentPadding).fillMaxWidth(), + ) { + CircularProgressIndicator() + } + } + } } item(span = { GridItemSpan(maxLineSpan) }) { @@ -135,18 +175,34 @@ fun SponsorsList( ), ) } - items( - items = uiState.supporters, - span = { GridItemSpan(2) }, - ) { sponsor -> - SponsorItem( - modifier = Modifier - .fillMaxWidth() - .height(77.dp) - .testTag(SponsorsListSponsorItemTestTagPrefix.plus(sponsor.name)), - sponsor = sponsor, - onSponsorsItemClick = onSponsorsItemClick, - ) + when (uiState.supportersUiState) { + is SupportersUiState.Exists -> { + items( + items = uiState.supportersUiState.supporters, + span = { GridItemSpan(2) }, + ) { sponsor -> + SponsorItem( + modifier = Modifier + .fillMaxWidth() + .height(77.dp) + .testTag(SponsorsListSponsorItemTestTagPrefix.plus(sponsor.name)), + sponsor = sponsor, + onSponsorsItemClick = onSponsorsItemClick, + ) + } + } + is SupportersUiState.Loading -> { + item( + span = { GridItemSpan(maxLineSpan) }, + ) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.padding(contentPadding).fillMaxWidth(), + ) { + CircularProgressIndicator() + } + } + } } } } @@ -159,9 +215,18 @@ fun SponsorsListPreview() { Surface { SponsorsList( uiState = SponsorsListUiState( - platinumSponsors = Sponsor.fakes().filter { it.plan == PLATINUM }.toPersistentList(), - goldSponsors = Sponsor.fakes().filter { it.plan == GOLD }.toPersistentList(), - supporters = Sponsor.fakes().filter { it.plan == SUPPORTER }.toPersistentList(), + platinumSponsorsUiState = PlatinumSponsorsUiState.Exists( + userMessageStateHolder = UserMessageStateHolderImpl(), + platinumSponsors = Sponsor.fakes().filter { it.plan == PLATINUM }.toPersistentList(), + ), + goldSponsorsUiState = GoldSponsorsUiState.Exists( + userMessageStateHolder = UserMessageStateHolderImpl(), + goldSponsors = Sponsor.fakes().filter { it.plan == GOLD }.toPersistentList(), + ), + supportersUiState = SupportersUiState.Exists( + userMessageStateHolder = UserMessageStateHolderImpl(), + supporters = Sponsor.fakes().filter { it.plan == SUPPORTER }.toPersistentList(), + ), ), onSponsorsItemClick = {}, scrollBehavior = null, From 4e35fa554c8e9de55ac53f4c6e6e2e28af2e44b6 Mon Sep 17 00:00:00 2001 From: todayama_r <13657682+Corvus400@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:01:52 +0900 Subject: [PATCH 02/18] :sparkles: Since ScreenPreview was not implemented, it was implemented. --- .../droidkaigi/confsched/about/AboutScreen.kt | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/feature/about/src/commonMain/kotlin/io/github/droidkaigi/confsched/about/AboutScreen.kt b/feature/about/src/commonMain/kotlin/io/github/droidkaigi/confsched/about/AboutScreen.kt index 0a59750e6..5dc54d44c 100644 --- a/feature/about/src/commonMain/kotlin/io/github/droidkaigi/confsched/about/AboutScreen.kt +++ b/feature/about/src/commonMain/kotlin/io/github/droidkaigi/confsched/about/AboutScreen.kt @@ -8,6 +8,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Surface import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.remember @@ -24,12 +25,14 @@ import io.github.droidkaigi.confsched.about.section.AboutDroidKaigiDetail import io.github.droidkaigi.confsched.about.section.AboutFooterLinks import io.github.droidkaigi.confsched.about.section.aboutCredits import io.github.droidkaigi.confsched.about.section.aboutOthers +import io.github.droidkaigi.confsched.designsystem.theme.KaigiTheme import io.github.droidkaigi.confsched.droidkaigiui.component.AnimatedTextTopAppBar import io.github.droidkaigi.confsched.model.AboutItem import io.github.droidkaigi.confsched.model.AboutItem.Medium import io.github.droidkaigi.confsched.model.AboutItem.X import io.github.droidkaigi.confsched.model.AboutItem.YouTube import org.jetbrains.compose.resources.stringResource +import org.jetbrains.compose.ui.tooling.preview.Preview const val aboutScreenRoute = "about" @@ -65,16 +68,32 @@ data class AboutUiState( val versionName: String, ) -@OptIn(ExperimentalMaterial3Api::class) @Composable fun AboutScreen( - modifier: Modifier = Modifier, - contentPadding: PaddingValues = PaddingValues(), onAboutItemClick: (AboutItem) -> Unit, + contentPadding: PaddingValues = PaddingValues(), ) { val uiState = aboutScreenPresenter() - val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() val snackbarHostState = remember { SnackbarHostState() } + + AboutScreen( + uiState = uiState, + snackbarHostState = snackbarHostState, + contentPadding = contentPadding, + onAboutItemClick = onAboutItemClick, + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun AboutScreen( + uiState: AboutUiState, + snackbarHostState: SnackbarHostState, + contentPadding: PaddingValues, + onAboutItemClick: (AboutItem) -> Unit, + modifier: Modifier = Modifier, +) { + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() val layoutDirection = LocalLayoutDirection.current val lazyListState = rememberLazyListState() @@ -151,3 +170,20 @@ fun AboutScreen( } } } + +@Preview +@Composable +fun AboutScreenPreview() { + KaigiTheme { + Surface { + AboutScreen( + uiState = AboutUiState( + versionName = "1.0", + ), + snackbarHostState = SnackbarHostState(), + contentPadding = PaddingValues(), + onAboutItemClick = {}, + ) + } + } +} From d80ba13165f04f3c2f6898661e515acba599ff05 Mon Sep 17 00:00:00 2001 From: todayama_r <13657682+Corvus400@users.noreply.github.com> Date: Thu, 5 Sep 2024 21:10:10 +0900 Subject: [PATCH 03/18] :memo: Instead of having a UiState for each category, it was changed so that they are all held as a single UiState. --- .../confsched/sponsors/SponsorsScreen.kt | 63 ++++--------------- .../sponsors/SponsorsScreenPresenter.kt | 53 ++++------------ .../sponsors/section/SponsorsList.kt | 51 +++++++-------- 3 files changed, 44 insertions(+), 123 deletions(-) diff --git a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt index 588af712e..6f9e04598 100644 --- a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt +++ b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt @@ -53,49 +53,14 @@ data class SponsorsScreenUiState( val userMessageStateHolder: UserMessageStateHolder, ) -data class SponsorsListUiState( - val platinumSponsorsUiState: PlatinumSponsorsUiState, - val goldSponsorsUiState: GoldSponsorsUiState, - val supportersUiState: SupportersUiState, -) - -sealed interface PlatinumSponsorsUiState { - val userMessageStateHolder: UserMessageStateHolder - - data class Loading( - override val userMessageStateHolder: UserMessageStateHolder, - ) : PlatinumSponsorsUiState - +sealed interface SponsorsListUiState { data class Exists( - override val userMessageStateHolder: UserMessageStateHolder, val platinumSponsors: PersistentList, - ) : PlatinumSponsorsUiState -} - -sealed interface GoldSponsorsUiState { - val userMessageStateHolder: UserMessageStateHolder - - data class Loading( - override val userMessageStateHolder: UserMessageStateHolder, - ) : GoldSponsorsUiState - - data class Exists( - override val userMessageStateHolder: UserMessageStateHolder, val goldSponsors: PersistentList, - ) : GoldSponsorsUiState -} - -sealed interface SupportersUiState { - val userMessageStateHolder: UserMessageStateHolder - - data class Loading( - override val userMessageStateHolder: UserMessageStateHolder, - ) : SupportersUiState - - data class Exists( - override val userMessageStateHolder: UserMessageStateHolder, val supporters: PersistentList, - ) : SupportersUiState + ) : SponsorsListUiState + + data object Loading : SponsorsListUiState } @Composable @@ -173,19 +138,13 @@ fun SponsorsScreenPreview() { Surface { SponsorsScreen( uiState = SponsorsScreenUiState( - sponsorsListUiState = SponsorsListUiState( - platinumSponsorsUiState = PlatinumSponsorsUiState.Exists( - userMessageStateHolder = UserMessageStateHolderImpl(), - platinumSponsors = Sponsor.fakes().filter { it.plan == PLATINUM }.toPersistentList(), - ), - goldSponsorsUiState = GoldSponsorsUiState.Exists( - userMessageStateHolder = UserMessageStateHolderImpl(), - goldSponsors = Sponsor.fakes().filter { it.plan == GOLD }.toPersistentList(), - ), - supportersUiState = SupportersUiState.Exists( - userMessageStateHolder = UserMessageStateHolderImpl(), - supporters = Sponsor.fakes().filter { it.plan == SUPPORTER }.toPersistentList(), - ), + sponsorsListUiState = SponsorsListUiState.Exists( + platinumSponsors = Sponsor.fakes().filter { it.plan == PLATINUM } + .toPersistentList(), + goldSponsors = Sponsor.fakes().filter { it.plan == GOLD } + .toPersistentList(), + supporters = Sponsor.fakes().filter { it.plan == SUPPORTER } + .toPersistentList(), ), userMessageStateHolder = UserMessageStateHolderImpl(), ), diff --git a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt index e3edf6f85..69641fac7 100644 --- a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt +++ b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt @@ -5,7 +5,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberUpdatedState import io.github.droidkaigi.confsched.compose.EventEffect import io.github.droidkaigi.confsched.compose.EventFlow -import io.github.droidkaigi.confsched.droidkaigiui.UserMessageStateHolder import io.github.droidkaigi.confsched.droidkaigiui.providePresenterDefaults import io.github.droidkaigi.confsched.model.Plan.GOLD import io.github.droidkaigi.confsched.model.Plan.PLATINUM @@ -25,10 +24,7 @@ fun sponsorsScreenPresenter( ): SponsorsScreenUiState = providePresenterDefaults { userMessageStateHolder -> val sponsors by rememberUpdatedState(sponsorsRepository.sponsors()) val sponsorListUiState by rememberUpdatedState( - sponsorList( - userMessageStateHolder = userMessageStateHolder, - sponsors = sponsors, - ), + sponsorList(sponsors = sponsors), ) EventEffect(events) { event -> } @@ -41,48 +37,21 @@ fun sponsorsScreenPresenter( @Composable private fun sponsorList( sponsors: PersistentList, - userMessageStateHolder: UserMessageStateHolder, ): SponsorsListUiState { val platinumSponsors = sponsors.filter { it.plan == PLATINUM }.toPersistentList() val goldSponsors = sponsors.filter { it.plan == GOLD }.toPersistentList() val supporters = sponsors.filter { it.plan == SUPPORTER }.toPersistentList() - val platinumSponsorsUiState = if (platinumSponsors.isNotEmpty()) { - PlatinumSponsorsUiState.Exists( - userMessageStateHolder = userMessageStateHolder, - platinumSponsors = platinumSponsors, - ) - } else { - PlatinumSponsorsUiState.Loading( - userMessageStateHolder = userMessageStateHolder, - ) + if ( + platinumSponsors.isEmpty() || + goldSponsors.isEmpty() || + supporters.isEmpty() + ) { + return SponsorsListUiState.Loading } - - val goldSponsorsUiState = if (goldSponsors.isNotEmpty()) { - GoldSponsorsUiState.Exists( - userMessageStateHolder = userMessageStateHolder, - goldSponsors = goldSponsors, - ) - } else { - GoldSponsorsUiState.Loading( - userMessageStateHolder = userMessageStateHolder, - ) - } - - val supportersUiState = if (supporters.isNotEmpty()) { - SupportersUiState.Exists( - userMessageStateHolder = userMessageStateHolder, - supporters = supporters, - ) - } else { - SupportersUiState.Loading( - userMessageStateHolder = userMessageStateHolder, - ) - } - - return SponsorsListUiState( - platinumSponsorsUiState = platinumSponsorsUiState, - goldSponsorsUiState = goldSponsorsUiState, - supportersUiState = supportersUiState, + return SponsorsListUiState.Exists( + platinumSponsors = platinumSponsors, + goldSponsors = goldSponsors, + supporters = supporters, ) } diff --git a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt index 0bc29ce5d..3b2fa15eb 100644 --- a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt +++ b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt @@ -25,17 +25,13 @@ import conference_app_2024.feature.sponsors.generated.resources.gold_sponsor import conference_app_2024.feature.sponsors.generated.resources.platinum_sponsor import conference_app_2024.feature.sponsors.generated.resources.supporters import io.github.droidkaigi.confsched.designsystem.theme.KaigiTheme -import io.github.droidkaigi.confsched.droidkaigiui.UserMessageStateHolderImpl import io.github.droidkaigi.confsched.model.Plan.GOLD import io.github.droidkaigi.confsched.model.Plan.PLATINUM import io.github.droidkaigi.confsched.model.Plan.SUPPORTER import io.github.droidkaigi.confsched.model.Sponsor import io.github.droidkaigi.confsched.model.fakes -import io.github.droidkaigi.confsched.sponsors.GoldSponsorsUiState -import io.github.droidkaigi.confsched.sponsors.PlatinumSponsorsUiState import io.github.droidkaigi.confsched.sponsors.SponsorsListUiState import io.github.droidkaigi.confsched.sponsors.SponsorsRes -import io.github.droidkaigi.confsched.sponsors.SupportersUiState import io.github.droidkaigi.confsched.sponsors.component.SponsorHeader import io.github.droidkaigi.confsched.sponsors.component.SponsorItem import kotlinx.collections.immutable.toPersistentList @@ -85,10 +81,10 @@ fun SponsorsList( ), ) } - when (uiState.platinumSponsorsUiState) { - is PlatinumSponsorsUiState.Exists -> { + when (uiState) { + is SponsorsListUiState.Exists -> { items( - items = uiState.platinumSponsorsUiState.platinumSponsors, + items = uiState.platinumSponsors, span = { GridItemSpan(maxLineSpan) }, ) { sponsor -> SponsorItem( @@ -101,7 +97,8 @@ fun SponsorsList( ) } } - is PlatinumSponsorsUiState.Loading -> { + + is SponsorsListUiState.Loading -> { item( span = { GridItemSpan(maxLineSpan) }, ) { @@ -130,10 +127,10 @@ fun SponsorsList( ), ) } - when (uiState.goldSponsorsUiState) { - is GoldSponsorsUiState.Exists -> { + when (uiState) { + is SponsorsListUiState.Exists -> { items( - items = uiState.goldSponsorsUiState.goldSponsors, + items = uiState.goldSponsors, span = { GridItemSpan(3) }, ) { sponsor -> SponsorItem( @@ -146,7 +143,8 @@ fun SponsorsList( ) } } - is GoldSponsorsUiState.Loading -> { + + is SponsorsListUiState.Loading -> { item( span = { GridItemSpan(maxLineSpan) }, ) { @@ -175,10 +173,10 @@ fun SponsorsList( ), ) } - when (uiState.supportersUiState) { - is SupportersUiState.Exists -> { + when (uiState) { + is SponsorsListUiState.Exists -> { items( - items = uiState.supportersUiState.supporters, + items = uiState.supporters, span = { GridItemSpan(2) }, ) { sponsor -> SponsorItem( @@ -191,7 +189,8 @@ fun SponsorsList( ) } } - is SupportersUiState.Loading -> { + + is SponsorsListUiState.Loading -> { item( span = { GridItemSpan(maxLineSpan) }, ) { @@ -214,19 +213,13 @@ fun SponsorsListPreview() { KaigiTheme { Surface { SponsorsList( - uiState = SponsorsListUiState( - platinumSponsorsUiState = PlatinumSponsorsUiState.Exists( - userMessageStateHolder = UserMessageStateHolderImpl(), - platinumSponsors = Sponsor.fakes().filter { it.plan == PLATINUM }.toPersistentList(), - ), - goldSponsorsUiState = GoldSponsorsUiState.Exists( - userMessageStateHolder = UserMessageStateHolderImpl(), - goldSponsors = Sponsor.fakes().filter { it.plan == GOLD }.toPersistentList(), - ), - supportersUiState = SupportersUiState.Exists( - userMessageStateHolder = UserMessageStateHolderImpl(), - supporters = Sponsor.fakes().filter { it.plan == SUPPORTER }.toPersistentList(), - ), + uiState = SponsorsListUiState.Exists( + platinumSponsors = Sponsor.fakes().filter { it.plan == PLATINUM } + .toPersistentList(), + goldSponsors = Sponsor.fakes().filter { it.plan == GOLD } + .toPersistentList(), + supporters = Sponsor.fakes().filter { it.plan == SUPPORTER } + .toPersistentList(), ), onSponsorsItemClick = {}, scrollBehavior = null, From 576583bc060998f2eb9676fec51917bb4dc8243b Mon Sep 17 00:00:00 2001 From: vixer93 Date: Fri, 6 Sep 2024 01:08:08 +0900 Subject: [PATCH 04/18] Add logic to open sponsor page --- .../SponsorFeature/SponsorReducer.swift | 23 ++++++++++++++++--- .../Sources/SponsorFeature/SponsorView.swift | 21 ++++++++++------- .../SponsorFeatureTests.swift | 13 ++++++++++- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/app-ios/Sources/SponsorFeature/SponsorReducer.swift b/app-ios/Sources/SponsorFeature/SponsorReducer.swift index e377073e7..42cfe359e 100644 --- a/app-ios/Sources/SponsorFeature/SponsorReducer.swift +++ b/app-ios/Sources/SponsorFeature/SponsorReducer.swift @@ -14,21 +14,29 @@ public struct SponsorReducer : Sendable { var platinums = [Sponsor]() var golds = [Sponsor]() var supporters = [Sponsor]() + var url: IdentifiableURL? public init() { } } - public enum Action : Sendable { - case onAppear + public enum Action : Sendable, BindableAction { + case binding(BindingAction) case response(Result<[Sponsor], any Error>) + case view(View) + + public enum View: Sendable { + case onAppear + case sponsorTapped(URL) + } } public var body: some ReducerOf { + BindingReducer() Reduce { state, action in enum CancelID { case connection } switch action { - case .onAppear: + case .view(.onAppear): return .run { send in do { for try await sponsors in try sponsorsData.streamSponsors() { @@ -39,6 +47,11 @@ public struct SponsorReducer : Sendable { } } .cancellable(id: CancelID.connection) + + case let .view(.sponsorTapped(url)): + state.url = IdentifiableURL(url) + return .none + case .response(.success(let sponsors)): var platinums = [Sponsor]() var golds = [Sponsor]() @@ -59,9 +72,13 @@ public struct SponsorReducer : Sendable { state.golds = golds state.supporters = supporters return .none + case .response(.failure(let error)): print(error) return .none + + case .binding: + return .none } } } diff --git a/app-ios/Sources/SponsorFeature/SponsorView.swift b/app-ios/Sources/SponsorFeature/SponsorView.swift index d0e4a7240..052482c79 100644 --- a/app-ios/Sources/SponsorFeature/SponsorView.swift +++ b/app-ios/Sources/SponsorFeature/SponsorView.swift @@ -2,10 +2,10 @@ import ComposableArchitecture import SwiftUI import Theme import Model +import CommonComponents public struct SponsorView: View { - private let store: StoreOf - @State private var selectedSponsorData: Sponsor? + @Bindable private var store: StoreOf public init(store: StoreOf) { self.store = store @@ -39,10 +39,14 @@ public struct SponsorView: View { } .background(AssetColors.Surface.surface.swiftUIColor) .onAppear { - store.send(.onAppear) + store.send(.view(.onAppear)) } .navigationBarTitleDisplayMode(.large) .navigationTitle(String(localized: "Sponsor", bundle: .module)) + .sheet(item: $store.url, content: { url in + SafariView(url: url.id) + .ignoresSafeArea() + }) } @ViewBuilder @@ -53,15 +57,16 @@ public struct SponsorView: View { } LazyVGrid(columns: gridItems, spacing: 12) { ForEach(items) { item in - Button { - selectedSponsorData = item - } label: { - ZStack { - Color.white.clipShape(RoundedRectangle(cornerRadius: 12)) + ZStack { + Color.white.clipShape(RoundedRectangle(cornerRadius: 12)) + Button { + store.send(.view(.sponsorTapped(item.link))) + } label: { AsyncImage(url: item.logo) { $0.image? .resizable() .scaledToFit() + .frame(maxWidth: .infinity, maxHeight: .infinity) } .frame(height: imageHeight) .padding(.vertical, 6) diff --git a/app-ios/Tests/SponsorFeatureTests/SponsorFeatureTests.swift b/app-ios/Tests/SponsorFeatureTests/SponsorFeatureTests.swift index f22b5344a..31e81a259 100644 --- a/app-ios/Tests/SponsorFeatureTests/SponsorFeatureTests.swift +++ b/app-ios/Tests/SponsorFeatureTests/SponsorFeatureTests.swift @@ -1,5 +1,6 @@ import XCTest import ComposableArchitecture +import Model @testable import SponsorFeature final class SponsorFeatureTests: XCTestCase { @@ -20,7 +21,7 @@ final class SponsorFeatureTests: XCTestCase { } } } - await store.send(.onAppear) + await store.send(.view(.onAppear)) await store.receive(\.response.success) { $0.platinums = [ .init(id: "Hoge", logo: .init(string: "https://avatars.githubusercontent.com/u/10727543?s=200&v=4")!, link: .init(string: "https://2024.droidkaigi.jp/")!, plan: .platinum) @@ -34,4 +35,14 @@ final class SponsorFeatureTests: XCTestCase { } } + @MainActor + func testSponsorTapped() async throws { + let url = URL(string: "https://github.com/DroidKaigi/conference-app-2024")! + let store = TestStore(initialState: SponsorReducer.State()) { + SponsorReducer() + } + await store.send(.view(.sponsorTapped(url))) { + $0.url = IdentifiableURL(url) + } + } } From 10daa0af487ba38bbcd34d406d7c8638fc85c951 Mon Sep 17 00:00:00 2001 From: vixer93 Date: Fri, 6 Sep 2024 02:01:30 +0900 Subject: [PATCH 05/18] Resolve package dependency --- app-ios/Package.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app-ios/Package.swift b/app-ios/Package.swift index 79e27a49d..4d56e83f3 100644 --- a/app-ios/Package.swift +++ b/app-ios/Package.swift @@ -209,7 +209,8 @@ let package = Package( dependencies: [ .tca, .kmpClient, - .theme + .theme, + .commonComponents, ] ), .testTarget( From 463e3129e64a05afba657a560bdfae2eac64d83c Mon Sep 17 00:00:00 2001 From: vixer93 Date: Fri, 6 Sep 2024 02:07:12 +0900 Subject: [PATCH 06/18] Resolve package dependency --- app-ios/Package.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/app-ios/Package.swift b/app-ios/Package.swift index 4d56e83f3..a5b03b265 100644 --- a/app-ios/Package.swift +++ b/app-ios/Package.swift @@ -210,6 +210,7 @@ let package = Package( .tca, .kmpClient, .theme, + .model, .commonComponents, ] ), From cc810d38fb150cc7ade0967ffa59fe54969db37b Mon Sep 17 00:00:00 2001 From: todayama_r <13657682+Corvus400@users.noreply.github.com> Date: Fri, 6 Sep 2024 09:44:48 +0900 Subject: [PATCH 07/18] :wrench: I forgot to add the Modifier to the arguments, so I added it. --- .../kotlin/io/github/droidkaigi/confsched/about/AboutScreen.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feature/about/src/commonMain/kotlin/io/github/droidkaigi/confsched/about/AboutScreen.kt b/feature/about/src/commonMain/kotlin/io/github/droidkaigi/confsched/about/AboutScreen.kt index 5dc54d44c..c38635958 100644 --- a/feature/about/src/commonMain/kotlin/io/github/droidkaigi/confsched/about/AboutScreen.kt +++ b/feature/about/src/commonMain/kotlin/io/github/droidkaigi/confsched/about/AboutScreen.kt @@ -72,6 +72,7 @@ data class AboutUiState( fun AboutScreen( onAboutItemClick: (AboutItem) -> Unit, contentPadding: PaddingValues = PaddingValues(), + modifier: Modifier = Modifier, ) { val uiState = aboutScreenPresenter() val snackbarHostState = remember { SnackbarHostState() } @@ -81,6 +82,7 @@ fun AboutScreen( snackbarHostState = snackbarHostState, contentPadding = contentPadding, onAboutItemClick = onAboutItemClick, + modifier = modifier, ) } From 73cc6d00d1b782b56b71705c51562ff2a852bb2b Mon Sep 17 00:00:00 2001 From: todayama_r <13657682+Corvus400@users.noreply.github.com> Date: Fri, 6 Sep 2024 09:47:18 +0900 Subject: [PATCH 08/18] :wrench: ./gradlew detekt --auto-correct --- .../io/github/droidkaigi/confsched/about/AboutScreen.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feature/about/src/commonMain/kotlin/io/github/droidkaigi/confsched/about/AboutScreen.kt b/feature/about/src/commonMain/kotlin/io/github/droidkaigi/confsched/about/AboutScreen.kt index c38635958..cfd2a717e 100644 --- a/feature/about/src/commonMain/kotlin/io/github/droidkaigi/confsched/about/AboutScreen.kt +++ b/feature/about/src/commonMain/kotlin/io/github/droidkaigi/confsched/about/AboutScreen.kt @@ -71,8 +71,8 @@ data class AboutUiState( @Composable fun AboutScreen( onAboutItemClick: (AboutItem) -> Unit, - contentPadding: PaddingValues = PaddingValues(), modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(), ) { val uiState = aboutScreenPresenter() val snackbarHostState = remember { SnackbarHostState() } @@ -91,8 +91,8 @@ fun AboutScreen( fun AboutScreen( uiState: AboutUiState, snackbarHostState: SnackbarHostState, - contentPadding: PaddingValues, onAboutItemClick: (AboutItem) -> Unit, + contentPadding: PaddingValues, modifier: Modifier = Modifier, ) { val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() From be7818b0d74a457fe23cc8a7ab91deaf46f62b23 Mon Sep 17 00:00:00 2001 From: todayama_r <13657682+Corvus400@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:19:06 +0900 Subject: [PATCH 09/18] Revert ":memo: Instead of having a UiState for each category, it was changed so that they are all held as a single UiState." This reverts commit d80ba13165f04f3c2f6898661e515acba599ff05. --- .../confsched/sponsors/SponsorsScreen.kt | 63 +++++++++++++++---- .../sponsors/SponsorsScreenPresenter.kt | 53 ++++++++++++---- .../sponsors/section/SponsorsList.kt | 51 ++++++++------- 3 files changed, 123 insertions(+), 44 deletions(-) diff --git a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt index 6f9e04598..588af712e 100644 --- a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt +++ b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt @@ -53,14 +53,49 @@ data class SponsorsScreenUiState( val userMessageStateHolder: UserMessageStateHolder, ) -sealed interface SponsorsListUiState { +data class SponsorsListUiState( + val platinumSponsorsUiState: PlatinumSponsorsUiState, + val goldSponsorsUiState: GoldSponsorsUiState, + val supportersUiState: SupportersUiState, +) + +sealed interface PlatinumSponsorsUiState { + val userMessageStateHolder: UserMessageStateHolder + + data class Loading( + override val userMessageStateHolder: UserMessageStateHolder, + ) : PlatinumSponsorsUiState + data class Exists( + override val userMessageStateHolder: UserMessageStateHolder, val platinumSponsors: PersistentList, + ) : PlatinumSponsorsUiState +} + +sealed interface GoldSponsorsUiState { + val userMessageStateHolder: UserMessageStateHolder + + data class Loading( + override val userMessageStateHolder: UserMessageStateHolder, + ) : GoldSponsorsUiState + + data class Exists( + override val userMessageStateHolder: UserMessageStateHolder, val goldSponsors: PersistentList, - val supporters: PersistentList, - ) : SponsorsListUiState + ) : GoldSponsorsUiState +} + +sealed interface SupportersUiState { + val userMessageStateHolder: UserMessageStateHolder - data object Loading : SponsorsListUiState + data class Loading( + override val userMessageStateHolder: UserMessageStateHolder, + ) : SupportersUiState + + data class Exists( + override val userMessageStateHolder: UserMessageStateHolder, + val supporters: PersistentList, + ) : SupportersUiState } @Composable @@ -138,13 +173,19 @@ fun SponsorsScreenPreview() { Surface { SponsorsScreen( uiState = SponsorsScreenUiState( - sponsorsListUiState = SponsorsListUiState.Exists( - platinumSponsors = Sponsor.fakes().filter { it.plan == PLATINUM } - .toPersistentList(), - goldSponsors = Sponsor.fakes().filter { it.plan == GOLD } - .toPersistentList(), - supporters = Sponsor.fakes().filter { it.plan == SUPPORTER } - .toPersistentList(), + sponsorsListUiState = SponsorsListUiState( + platinumSponsorsUiState = PlatinumSponsorsUiState.Exists( + userMessageStateHolder = UserMessageStateHolderImpl(), + platinumSponsors = Sponsor.fakes().filter { it.plan == PLATINUM }.toPersistentList(), + ), + goldSponsorsUiState = GoldSponsorsUiState.Exists( + userMessageStateHolder = UserMessageStateHolderImpl(), + goldSponsors = Sponsor.fakes().filter { it.plan == GOLD }.toPersistentList(), + ), + supportersUiState = SupportersUiState.Exists( + userMessageStateHolder = UserMessageStateHolderImpl(), + supporters = Sponsor.fakes().filter { it.plan == SUPPORTER }.toPersistentList(), + ), ), userMessageStateHolder = UserMessageStateHolderImpl(), ), diff --git a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt index 69641fac7..e3edf6f85 100644 --- a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt +++ b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt @@ -5,6 +5,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberUpdatedState import io.github.droidkaigi.confsched.compose.EventEffect import io.github.droidkaigi.confsched.compose.EventFlow +import io.github.droidkaigi.confsched.droidkaigiui.UserMessageStateHolder import io.github.droidkaigi.confsched.droidkaigiui.providePresenterDefaults import io.github.droidkaigi.confsched.model.Plan.GOLD import io.github.droidkaigi.confsched.model.Plan.PLATINUM @@ -24,7 +25,10 @@ fun sponsorsScreenPresenter( ): SponsorsScreenUiState = providePresenterDefaults { userMessageStateHolder -> val sponsors by rememberUpdatedState(sponsorsRepository.sponsors()) val sponsorListUiState by rememberUpdatedState( - sponsorList(sponsors = sponsors), + sponsorList( + userMessageStateHolder = userMessageStateHolder, + sponsors = sponsors, + ), ) EventEffect(events) { event -> } @@ -37,21 +41,48 @@ fun sponsorsScreenPresenter( @Composable private fun sponsorList( sponsors: PersistentList, + userMessageStateHolder: UserMessageStateHolder, ): SponsorsListUiState { val platinumSponsors = sponsors.filter { it.plan == PLATINUM }.toPersistentList() val goldSponsors = sponsors.filter { it.plan == GOLD }.toPersistentList() val supporters = sponsors.filter { it.plan == SUPPORTER }.toPersistentList() - if ( - platinumSponsors.isEmpty() || - goldSponsors.isEmpty() || - supporters.isEmpty() - ) { - return SponsorsListUiState.Loading + val platinumSponsorsUiState = if (platinumSponsors.isNotEmpty()) { + PlatinumSponsorsUiState.Exists( + userMessageStateHolder = userMessageStateHolder, + platinumSponsors = platinumSponsors, + ) + } else { + PlatinumSponsorsUiState.Loading( + userMessageStateHolder = userMessageStateHolder, + ) } - return SponsorsListUiState.Exists( - platinumSponsors = platinumSponsors, - goldSponsors = goldSponsors, - supporters = supporters, + + val goldSponsorsUiState = if (goldSponsors.isNotEmpty()) { + GoldSponsorsUiState.Exists( + userMessageStateHolder = userMessageStateHolder, + goldSponsors = goldSponsors, + ) + } else { + GoldSponsorsUiState.Loading( + userMessageStateHolder = userMessageStateHolder, + ) + } + + val supportersUiState = if (supporters.isNotEmpty()) { + SupportersUiState.Exists( + userMessageStateHolder = userMessageStateHolder, + supporters = supporters, + ) + } else { + SupportersUiState.Loading( + userMessageStateHolder = userMessageStateHolder, + ) + } + + return SponsorsListUiState( + platinumSponsorsUiState = platinumSponsorsUiState, + goldSponsorsUiState = goldSponsorsUiState, + supportersUiState = supportersUiState, ) } diff --git a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt index 3b2fa15eb..0bc29ce5d 100644 --- a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt +++ b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt @@ -25,13 +25,17 @@ import conference_app_2024.feature.sponsors.generated.resources.gold_sponsor import conference_app_2024.feature.sponsors.generated.resources.platinum_sponsor import conference_app_2024.feature.sponsors.generated.resources.supporters import io.github.droidkaigi.confsched.designsystem.theme.KaigiTheme +import io.github.droidkaigi.confsched.droidkaigiui.UserMessageStateHolderImpl import io.github.droidkaigi.confsched.model.Plan.GOLD import io.github.droidkaigi.confsched.model.Plan.PLATINUM import io.github.droidkaigi.confsched.model.Plan.SUPPORTER import io.github.droidkaigi.confsched.model.Sponsor import io.github.droidkaigi.confsched.model.fakes +import io.github.droidkaigi.confsched.sponsors.GoldSponsorsUiState +import io.github.droidkaigi.confsched.sponsors.PlatinumSponsorsUiState import io.github.droidkaigi.confsched.sponsors.SponsorsListUiState import io.github.droidkaigi.confsched.sponsors.SponsorsRes +import io.github.droidkaigi.confsched.sponsors.SupportersUiState import io.github.droidkaigi.confsched.sponsors.component.SponsorHeader import io.github.droidkaigi.confsched.sponsors.component.SponsorItem import kotlinx.collections.immutable.toPersistentList @@ -81,10 +85,10 @@ fun SponsorsList( ), ) } - when (uiState) { - is SponsorsListUiState.Exists -> { + when (uiState.platinumSponsorsUiState) { + is PlatinumSponsorsUiState.Exists -> { items( - items = uiState.platinumSponsors, + items = uiState.platinumSponsorsUiState.platinumSponsors, span = { GridItemSpan(maxLineSpan) }, ) { sponsor -> SponsorItem( @@ -97,8 +101,7 @@ fun SponsorsList( ) } } - - is SponsorsListUiState.Loading -> { + is PlatinumSponsorsUiState.Loading -> { item( span = { GridItemSpan(maxLineSpan) }, ) { @@ -127,10 +130,10 @@ fun SponsorsList( ), ) } - when (uiState) { - is SponsorsListUiState.Exists -> { + when (uiState.goldSponsorsUiState) { + is GoldSponsorsUiState.Exists -> { items( - items = uiState.goldSponsors, + items = uiState.goldSponsorsUiState.goldSponsors, span = { GridItemSpan(3) }, ) { sponsor -> SponsorItem( @@ -143,8 +146,7 @@ fun SponsorsList( ) } } - - is SponsorsListUiState.Loading -> { + is GoldSponsorsUiState.Loading -> { item( span = { GridItemSpan(maxLineSpan) }, ) { @@ -173,10 +175,10 @@ fun SponsorsList( ), ) } - when (uiState) { - is SponsorsListUiState.Exists -> { + when (uiState.supportersUiState) { + is SupportersUiState.Exists -> { items( - items = uiState.supporters, + items = uiState.supportersUiState.supporters, span = { GridItemSpan(2) }, ) { sponsor -> SponsorItem( @@ -189,8 +191,7 @@ fun SponsorsList( ) } } - - is SponsorsListUiState.Loading -> { + is SupportersUiState.Loading -> { item( span = { GridItemSpan(maxLineSpan) }, ) { @@ -213,13 +214,19 @@ fun SponsorsListPreview() { KaigiTheme { Surface { SponsorsList( - uiState = SponsorsListUiState.Exists( - platinumSponsors = Sponsor.fakes().filter { it.plan == PLATINUM } - .toPersistentList(), - goldSponsors = Sponsor.fakes().filter { it.plan == GOLD } - .toPersistentList(), - supporters = Sponsor.fakes().filter { it.plan == SUPPORTER } - .toPersistentList(), + uiState = SponsorsListUiState( + platinumSponsorsUiState = PlatinumSponsorsUiState.Exists( + userMessageStateHolder = UserMessageStateHolderImpl(), + platinumSponsors = Sponsor.fakes().filter { it.plan == PLATINUM }.toPersistentList(), + ), + goldSponsorsUiState = GoldSponsorsUiState.Exists( + userMessageStateHolder = UserMessageStateHolderImpl(), + goldSponsors = Sponsor.fakes().filter { it.plan == GOLD }.toPersistentList(), + ), + supportersUiState = SupportersUiState.Exists( + userMessageStateHolder = UserMessageStateHolderImpl(), + supporters = Sponsor.fakes().filter { it.plan == SUPPORTER }.toPersistentList(), + ), ), onSponsorsItemClick = {}, scrollBehavior = null, From 4f8af9941d5685f3859f6b33d3db789609e19023 Mon Sep 17 00:00:00 2001 From: Dreamwalker Date: Fri, 6 Sep 2024 11:36:35 +0900 Subject: [PATCH 10/18] Update TimetableRoom model fix floor information --- .../droidkaigi/confsched/model/TimetableRoom.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/TimetableRoom.kt b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/TimetableRoom.kt index 4445d55d1..215f0e907 100644 --- a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/TimetableRoom.kt +++ b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/TimetableRoom.kt @@ -22,14 +22,15 @@ data class TimetableRoom( val TimetableRoom.nameAndFloor: String get() { val basementFloorString = MultiLangText(jaTitle = "地下1階", enTitle = "B1F") + val floor1FString = MultiLangText(jaTitle = "1階", enTitle = "1F") val floor = when (type) { - RoomType.RoomF -> basementFloorString.currentLangTitle - RoomType.RoomG -> basementFloorString.currentLangTitle + RoomType.RoomF -> floor1FString.currentLangTitle + RoomType.RoomG -> floor1FString.currentLangTitle RoomType.RoomH -> basementFloorString.currentLangTitle - RoomType.RoomI -> "1F" - RoomType.RoomJ -> "1F" + RoomType.RoomI -> basementFloorString.currentLangTitle + RoomType.RoomJ -> basementFloorString.currentLangTitle // Assume the room on the first day. - RoomType.RoomIJ -> "1F" + RoomType.RoomIJ -> basementFloorString.currentLangTitle } return "${name.currentLangTitle} ($floor)" } From 35d9ae6838905746737aab3d46c74a54d96e5b73 Mon Sep 17 00:00:00 2001 From: todayama_r <13657682+Corvus400@users.noreply.github.com> Date: Fri, 6 Sep 2024 12:12:39 +0900 Subject: [PATCH 11/18] :wrench: Redundant processes have been standardized. --- .../confsched/sponsors/SponsorsScreen.kt | 52 ++--- .../sponsors/SponsorsScreenPresenter.kt | 18 +- .../sponsors/section/SponsorsList.kt | 214 +++++++----------- 3 files changed, 107 insertions(+), 177 deletions(-) diff --git a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt index 588af712e..93e79f7d3 100644 --- a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt +++ b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreen.kt @@ -54,48 +54,22 @@ data class SponsorsScreenUiState( ) data class SponsorsListUiState( - val platinumSponsorsUiState: PlatinumSponsorsUiState, - val goldSponsorsUiState: GoldSponsorsUiState, - val supportersUiState: SupportersUiState, + val platinumSponsorsUiState: SponsorsByPlanUiState, + val goldSponsorsUiState: SponsorsByPlanUiState, + val supportersUiState: SponsorsByPlanUiState, ) -sealed interface PlatinumSponsorsUiState { +sealed interface SponsorsByPlanUiState { val userMessageStateHolder: UserMessageStateHolder data class Loading( override val userMessageStateHolder: UserMessageStateHolder, - ) : PlatinumSponsorsUiState + ) : SponsorsByPlanUiState data class Exists( override val userMessageStateHolder: UserMessageStateHolder, - val platinumSponsors: PersistentList, - ) : PlatinumSponsorsUiState -} - -sealed interface GoldSponsorsUiState { - val userMessageStateHolder: UserMessageStateHolder - - data class Loading( - override val userMessageStateHolder: UserMessageStateHolder, - ) : GoldSponsorsUiState - - data class Exists( - override val userMessageStateHolder: UserMessageStateHolder, - val goldSponsors: PersistentList, - ) : GoldSponsorsUiState -} - -sealed interface SupportersUiState { - val userMessageStateHolder: UserMessageStateHolder - - data class Loading( - override val userMessageStateHolder: UserMessageStateHolder, - ) : SupportersUiState - - data class Exists( - override val userMessageStateHolder: UserMessageStateHolder, - val supporters: PersistentList, - ) : SupportersUiState + val sponsors: PersistentList, + ) : SponsorsByPlanUiState } @Composable @@ -174,17 +148,17 @@ fun SponsorsScreenPreview() { SponsorsScreen( uiState = SponsorsScreenUiState( sponsorsListUiState = SponsorsListUiState( - platinumSponsorsUiState = PlatinumSponsorsUiState.Exists( + platinumSponsorsUiState = SponsorsByPlanUiState.Exists( userMessageStateHolder = UserMessageStateHolderImpl(), - platinumSponsors = Sponsor.fakes().filter { it.plan == PLATINUM }.toPersistentList(), + sponsors = Sponsor.fakes().filter { it.plan == PLATINUM }.toPersistentList(), ), - goldSponsorsUiState = GoldSponsorsUiState.Exists( + goldSponsorsUiState = SponsorsByPlanUiState.Exists( userMessageStateHolder = UserMessageStateHolderImpl(), - goldSponsors = Sponsor.fakes().filter { it.plan == GOLD }.toPersistentList(), + sponsors = Sponsor.fakes().filter { it.plan == GOLD }.toPersistentList(), ), - supportersUiState = SupportersUiState.Exists( + supportersUiState = SponsorsByPlanUiState.Exists( userMessageStateHolder = UserMessageStateHolderImpl(), - supporters = Sponsor.fakes().filter { it.plan == SUPPORTER }.toPersistentList(), + sponsors = Sponsor.fakes().filter { it.plan == SUPPORTER }.toPersistentList(), ), ), userMessageStateHolder = UserMessageStateHolderImpl(), diff --git a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt index e3edf6f85..d0300c88e 100644 --- a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt +++ b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/SponsorsScreenPresenter.kt @@ -48,34 +48,34 @@ private fun sponsorList( val supporters = sponsors.filter { it.plan == SUPPORTER }.toPersistentList() val platinumSponsorsUiState = if (platinumSponsors.isNotEmpty()) { - PlatinumSponsorsUiState.Exists( + SponsorsByPlanUiState.Exists( userMessageStateHolder = userMessageStateHolder, - platinumSponsors = platinumSponsors, + sponsors = platinumSponsors, ) } else { - PlatinumSponsorsUiState.Loading( + SponsorsByPlanUiState.Loading( userMessageStateHolder = userMessageStateHolder, ) } val goldSponsorsUiState = if (goldSponsors.isNotEmpty()) { - GoldSponsorsUiState.Exists( + SponsorsByPlanUiState.Exists( userMessageStateHolder = userMessageStateHolder, - goldSponsors = goldSponsors, + sponsors = goldSponsors, ) } else { - GoldSponsorsUiState.Loading( + SponsorsByPlanUiState.Loading( userMessageStateHolder = userMessageStateHolder, ) } val supportersUiState = if (supporters.isNotEmpty()) { - SupportersUiState.Exists( + SponsorsByPlanUiState.Exists( userMessageStateHolder = userMessageStateHolder, - supporters = supporters, + sponsors = supporters, ) } else { - SupportersUiState.Loading( + SponsorsByPlanUiState.Loading( userMessageStateHolder = userMessageStateHolder, ) } diff --git a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt index 0bc29ce5d..48735340e 100644 --- a/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt +++ b/feature/sponsors/src/commonMain/kotlin/io/github/droidkaigi/confsched/sponsors/section/SponsorsList.kt @@ -9,6 +9,8 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.GridItemSpan +import androidx.compose.foundation.lazy.grid.LazyGridItemSpanScope +import androidx.compose.foundation.lazy.grid.LazyGridScope import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items import androidx.compose.material3.CircularProgressIndicator @@ -20,6 +22,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.testTag +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import conference_app_2024.feature.sponsors.generated.resources.gold_sponsor import conference_app_2024.feature.sponsors.generated.resources.platinum_sponsor @@ -31,14 +34,13 @@ import io.github.droidkaigi.confsched.model.Plan.PLATINUM import io.github.droidkaigi.confsched.model.Plan.SUPPORTER import io.github.droidkaigi.confsched.model.Sponsor import io.github.droidkaigi.confsched.model.fakes -import io.github.droidkaigi.confsched.sponsors.GoldSponsorsUiState -import io.github.droidkaigi.confsched.sponsors.PlatinumSponsorsUiState +import io.github.droidkaigi.confsched.sponsors.SponsorsByPlanUiState import io.github.droidkaigi.confsched.sponsors.SponsorsListUiState import io.github.droidkaigi.confsched.sponsors.SponsorsRes -import io.github.droidkaigi.confsched.sponsors.SupportersUiState import io.github.droidkaigi.confsched.sponsors.component.SponsorHeader import io.github.droidkaigi.confsched.sponsors.component.SponsorItem import kotlinx.collections.immutable.toPersistentList +import org.jetbrains.compose.resources.StringResource import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.ui.tooling.preview.Preview @@ -74,136 +76,88 @@ fun SponsorsList( bottom = 48.dp + contentPadding.calculateBottomPadding(), ), ) { - item(span = { GridItemSpan(maxLineSpan) }) { - SponsorHeader( - text = stringResource(SponsorsRes.string.platinum_sponsor), - modifier = Modifier - .fillMaxWidth() - .testTag( - SponsorsListSponsorHeaderTestTagPrefix - .plus(stringResource(SponsorsRes.string.platinum_sponsor)), - ), - ) - } - when (uiState.platinumSponsorsUiState) { - is PlatinumSponsorsUiState.Exists -> { - items( - items = uiState.platinumSponsorsUiState.platinumSponsors, - span = { GridItemSpan(maxLineSpan) }, - ) { sponsor -> - SponsorItem( - modifier = Modifier - .fillMaxWidth() - .height(110.dp) - .testTag(SponsorsListSponsorItemTestTagPrefix.plus(sponsor.name)), - sponsor = sponsor, - onSponsorsItemClick = onSponsorsItemClick, - ) - } - } - is PlatinumSponsorsUiState.Loading -> { - item( - span = { GridItemSpan(maxLineSpan) }, - ) { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier.padding(contentPadding).fillMaxWidth(), - ) { - CircularProgressIndicator() - } - } - } - } + sponsorsByPlanSection( + headerStringResource = SponsorsRes.string.platinum_sponsor, + sponsorsByPlanUiState = uiState.platinumSponsorsUiState, + onSponsorsItemClick = onSponsorsItemClick, + contentPadding = contentPadding, + sponsorItemSpan = { GridItemSpan(maxLineSpan) }, + sponsorItemHeight = 110.dp, + ) - item(span = { GridItemSpan(maxLineSpan) }) { - Spacer(modifier = Modifier.height(24.dp)) - } + sponsorsByPlanSection( + headerStringResource = SponsorsRes.string.gold_sponsor, + sponsorsByPlanUiState = uiState.goldSponsorsUiState, + onSponsorsItemClick = onSponsorsItemClick, + contentPadding = contentPadding, + sponsorItemSpan = { GridItemSpan(3) }, + sponsorItemHeight = 77.dp, + ) - item(span = { GridItemSpan(maxLineSpan) }) { - SponsorHeader( - text = stringResource(SponsorsRes.string.gold_sponsor), - modifier = Modifier - .fillMaxWidth() - .testTag( - SponsorsListSponsorHeaderTestTagPrefix - .plus(stringResource(SponsorsRes.string.gold_sponsor)), - ), - ) - } - when (uiState.goldSponsorsUiState) { - is GoldSponsorsUiState.Exists -> { - items( - items = uiState.goldSponsorsUiState.goldSponsors, - span = { GridItemSpan(3) }, - ) { sponsor -> - SponsorItem( - modifier = Modifier - .fillMaxWidth() - .height(77.dp) - .testTag(SponsorsListSponsorItemTestTagPrefix.plus(sponsor.name)), - sponsor = sponsor, - onSponsorsItemClick = onSponsorsItemClick, - ) - } + sponsorsByPlanSection( + headerStringResource = SponsorsRes.string.supporters, + sponsorsByPlanUiState = uiState.supportersUiState, + onSponsorsItemClick = onSponsorsItemClick, + contentPadding = contentPadding, + sponsorItemSpan = { GridItemSpan(2) }, + sponsorItemHeight = 77.dp, + isLastSection = true, + ) + } +} + +private fun LazyGridScope.sponsorsByPlanSection( + headerStringResource: StringResource, + sponsorsByPlanUiState: SponsorsByPlanUiState, + contentPadding: PaddingValues, + sponsorItemSpan: LazyGridItemSpanScope.() -> GridItemSpan, + sponsorItemHeight: Dp, + onSponsorsItemClick: (url: String) -> Unit, + isLastSection: Boolean = false, +) { + item(span = { GridItemSpan(maxLineSpan) }) { + val headerText = stringResource(headerStringResource) + SponsorHeader( + text = headerText, + modifier = Modifier + .fillMaxWidth() + .testTag(SponsorsListSponsorHeaderTestTagPrefix.plus(headerText)), + ) + } + when (sponsorsByPlanUiState) { + is SponsorsByPlanUiState.Exists -> { + items( + items = sponsorsByPlanUiState.sponsors, + span = { sponsorItemSpan() }, + ) { sponsor -> + SponsorItem( + modifier = Modifier + .fillMaxWidth() + .height(sponsorItemHeight) + .testTag(SponsorsListSponsorItemTestTagPrefix.plus(sponsor.name)), + sponsor = sponsor, + onSponsorsItemClick = onSponsorsItemClick, + ) } - is GoldSponsorsUiState.Loading -> { - item( - span = { GridItemSpan(maxLineSpan) }, + } + + is SponsorsByPlanUiState.Loading -> { + item( + span = { GridItemSpan(maxLineSpan) }, + ) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.padding(contentPadding).fillMaxWidth(), ) { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier.padding(contentPadding).fillMaxWidth(), - ) { - CircularProgressIndicator() - } + CircularProgressIndicator() } } } - + } + if (isLastSection.not()) { item(span = { GridItemSpan(maxLineSpan) }) { Spacer(modifier = Modifier.height(24.dp)) } - - item(span = { GridItemSpan(maxLineSpan) }) { - SponsorHeader( - text = stringResource(SponsorsRes.string.supporters), - modifier = Modifier - .fillMaxWidth() - .testTag( - SponsorsListSponsorHeaderTestTagPrefix - .plus(stringResource(SponsorsRes.string.supporters)), - ), - ) - } - when (uiState.supportersUiState) { - is SupportersUiState.Exists -> { - items( - items = uiState.supportersUiState.supporters, - span = { GridItemSpan(2) }, - ) { sponsor -> - SponsorItem( - modifier = Modifier - .fillMaxWidth() - .height(77.dp) - .testTag(SponsorsListSponsorItemTestTagPrefix.plus(sponsor.name)), - sponsor = sponsor, - onSponsorsItemClick = onSponsorsItemClick, - ) - } - } - is SupportersUiState.Loading -> { - item( - span = { GridItemSpan(maxLineSpan) }, - ) { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier.padding(contentPadding).fillMaxWidth(), - ) { - CircularProgressIndicator() - } - } - } - } } } @@ -215,17 +169,19 @@ fun SponsorsListPreview() { Surface { SponsorsList( uiState = SponsorsListUiState( - platinumSponsorsUiState = PlatinumSponsorsUiState.Exists( + platinumSponsorsUiState = SponsorsByPlanUiState.Exists( userMessageStateHolder = UserMessageStateHolderImpl(), - platinumSponsors = Sponsor.fakes().filter { it.plan == PLATINUM }.toPersistentList(), + sponsors = Sponsor.fakes().filter { it.plan == PLATINUM } + .toPersistentList(), ), - goldSponsorsUiState = GoldSponsorsUiState.Exists( + goldSponsorsUiState = SponsorsByPlanUiState.Exists( userMessageStateHolder = UserMessageStateHolderImpl(), - goldSponsors = Sponsor.fakes().filter { it.plan == GOLD }.toPersistentList(), + sponsors = Sponsor.fakes().filter { it.plan == GOLD }.toPersistentList(), ), - supportersUiState = SupportersUiState.Exists( + supportersUiState = SponsorsByPlanUiState.Exists( userMessageStateHolder = UserMessageStateHolderImpl(), - supporters = Sponsor.fakes().filter { it.plan == SUPPORTER }.toPersistentList(), + sponsors = Sponsor.fakes().filter { it.plan == SUPPORTER } + .toPersistentList(), ), ), onSponsorsItemClick = {}, From 8d189aca612b51a567117ef73c192f514e62b907 Mon Sep 17 00:00:00 2001 From: todayama_r <13657682+Corvus400@users.noreply.github.com> Date: Fri, 6 Sep 2024 15:32:36 +0900 Subject: [PATCH 12/18] :wrench: Because the bug cannot be fixed, the following PR content will be reverted. https://github.com/DroidKaigi/conference-app-2024/pull/919 --- .../sessions/section/TimetableGrid.kt | 3 +- .../sessions/section/TimetableList.kt | 3 ++ .../sessions/section/TimetableSheet.kt | 34 ++++++------------- 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/section/TimetableGrid.kt b/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/section/TimetableGrid.kt index 5ef9b74e3..c0f74e210 100644 --- a/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/section/TimetableGrid.kt +++ b/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/section/TimetableGrid.kt @@ -139,7 +139,7 @@ fun TimetableGrid( val animatedScope = LocalAnimatedVisibilityScope.current Row( - modifier = modifier + modifier = Modifier .testTag(TimetableGridTestTag) .padding( top = contentPadding.calculateTopPadding(), @@ -171,6 +171,7 @@ fun TimetableGrid( timetableState = timetableState, timeLine = timeLine, selectedDay = selectedDay, + modifier = modifier, contentPadding = PaddingValues( top = 16.dp + contentPadding.calculateTopPadding(), bottom = 16.dp + 80.dp + contentPadding.calculateBottomPadding(), diff --git a/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/section/TimetableList.kt b/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/section/TimetableList.kt index 9d735709b..12bede6e0 100644 --- a/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/section/TimetableList.kt +++ b/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/section/TimetableList.kt @@ -93,6 +93,9 @@ internal fun TimetableList( LazyColumn( modifier = modifier.testTag(TimetableListTestTag) + .offset { + IntOffset(x = 0, y = nestedScrollStateHolder.uiState.dayTabOffsetY.toInt()) + } .nestedScroll(nestedScrollConnection), state = scrollState, verticalArrangement = Arrangement.spacedBy(32.dp), diff --git a/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/section/TimetableSheet.kt b/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/section/TimetableSheet.kt index 5b3d8cca9..edf842438 100644 --- a/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/section/TimetableSheet.kt +++ b/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/section/TimetableSheet.kt @@ -1,7 +1,7 @@ package io.github.droidkaigi.confsched.sessions.section -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.calculateEndPadding import androidx.compose.foundation.layout.calculateStartPadding @@ -20,9 +20,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.onGloballyPositioned -import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp @@ -31,7 +29,6 @@ import io.github.droidkaigi.confsched.model.DroidKaigi2024Day import io.github.droidkaigi.confsched.model.TimeLine import io.github.droidkaigi.confsched.model.TimetableItem import io.github.droidkaigi.confsched.sessions.component.TimetableDayTab -import io.github.droidkaigi.confsched.sessions.component.TimetableNestedScrollStateHolder import io.github.droidkaigi.confsched.sessions.component.rememberTimetableNestedScrollStateHolder import io.github.droidkaigi.confsched.sessions.section.TimetableUiState.Empty import io.github.droidkaigi.confsched.sessions.section.TimetableUiState.GridTimetable @@ -74,8 +71,9 @@ fun Timetable( Surface( modifier = modifier.padding(contentPadding.calculateTopPadding()), ) { - Box( - modifier = Modifier.fillMaxSize(), + Column( + modifier = Modifier + .fillMaxSize(), ) { TimetableDayTab( selectedDay = selectedDay, @@ -102,7 +100,9 @@ fun Timetable( scrollState = scrollStates.getValue(selectedDay), onTimetableItemClick = onTimetableItemClick, onBookmarkClick = onFavoriteClick, - modifier = timetableModifier(nestedScrollStateHolder), + modifier = Modifier + .fillMaxSize() + .weight(1f), contentPadding = PaddingValues( bottom = contentPadding.calculateBottomPadding(), start = contentPadding.calculateStartPadding(layoutDirection), @@ -119,7 +119,9 @@ fun Timetable( timeLine = uiState.timeLine, selectedDay = selectedDay, onTimetableItemClick = onTimetableItemClick, - modifier = timetableModifier(nestedScrollStateHolder), + modifier = Modifier + .fillMaxSize() + .weight(1f), contentPadding = PaddingValues( bottom = contentPadding.calculateBottomPadding(), start = contentPadding.calculateStartPadding(layoutDirection), @@ -158,19 +160,3 @@ private fun rememberGridTimetableStates(): Map Date: Fri, 6 Sep 2024 22:12:58 +0900 Subject: [PATCH 13/18] 1.2.0 --- app-android/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app-android/build.gradle.kts b/app-android/build.gradle.kts index f20b4c71b..2842d8fb0 100644 --- a/app-android/build.gradle.kts +++ b/app-android/build.gradle.kts @@ -25,8 +25,8 @@ android { buildConfig = true } defaultConfig { - versionCode = 4 - versionName = "1.1.0" + versionCode = 5 + versionName = "1.2.0" } signingConfigs { create("dev") { From cf0c69e44a6029e9ae2f6b2620b1b2a6f96f2b2c Mon Sep 17 00:00:00 2001 From: takahirom Date: Fri, 6 Sep 2024 23:06:04 +0900 Subject: [PATCH 14/18] Increment version code --- app-android/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app-android/build.gradle.kts b/app-android/build.gradle.kts index 2842d8fb0..741f9f1d9 100644 --- a/app-android/build.gradle.kts +++ b/app-android/build.gradle.kts @@ -25,7 +25,7 @@ android { buildConfig = true } defaultConfig { - versionCode = 5 + versionCode = 6 versionName = "1.2.0" } signingConfigs { From 71c7728ffbc7547ef65c88e674b3022de52bb2b6 Mon Sep 17 00:00:00 2001 From: Aniokrait Date: Fri, 6 Sep 2024 23:22:50 +0900 Subject: [PATCH 15/18] Fix to show message for special session --- .../data/sessions/DefaultSessionsApiClient.kt | 1 + .../component/TimetableItemCard.kt | 41 ++++++++++--------- .../droidkaigi/confsched/model/Timetable.kt | 5 +++ .../confsched/model/TimetableItem.kt | 1 + .../sessions/component/TimetableGridItem.kt | 1 + 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/core/data/src/commonMain/kotlin/io/github/droidkaigi/confsched/data/sessions/DefaultSessionsApiClient.kt b/core/data/src/commonMain/kotlin/io/github/droidkaigi/confsched/data/sessions/DefaultSessionsApiClient.kt index 313c3d199..66ac715d7 100644 --- a/core/data/src/commonMain/kotlin/io/github/droidkaigi/confsched/data/sessions/DefaultSessionsApiClient.kt +++ b/core/data/src/commonMain/kotlin/io/github/droidkaigi/confsched/data/sessions/DefaultSessionsApiClient.kt @@ -156,6 +156,7 @@ public fun SessionsAllResponse.toTimetable(): Timetable { } else { apiSession.i18nDesc.toMultiLangText() }, + message = apiSession.message?.toMultiLangText(), ) } } diff --git a/core/droidkaigiui/src/commonMain/kotlin/io/github/droidkaigi/confsched/droidkaigiui/component/TimetableItemCard.kt b/core/droidkaigiui/src/commonMain/kotlin/io/github/droidkaigi/confsched/droidkaigiui/component/TimetableItemCard.kt index b6404facc..e3ea41859 100644 --- a/core/droidkaigiui/src/commonMain/kotlin/io/github/droidkaigi/confsched/droidkaigiui/component/TimetableItemCard.kt +++ b/core/droidkaigiui/src/commonMain/kotlin/io/github/droidkaigi/confsched/droidkaigiui/component/TimetableItemCard.kt @@ -61,6 +61,7 @@ import io.github.droidkaigi.confsched.droidkaigiui.animation.LocalFavoriteAnimat import io.github.droidkaigi.confsched.droidkaigiui.previewOverride import io.github.droidkaigi.confsched.model.TimetableItem import io.github.droidkaigi.confsched.model.TimetableItem.Session +import io.github.droidkaigi.confsched.model.TimetableItem.Special import org.jetbrains.compose.resources.stringResource const val TimetableItemCardBookmarkButtonTestTag = "TimetableItemCardBookmarkButton" @@ -170,25 +171,27 @@ fun TimetableItemCard( } } } - if (timetableItem is Session) { - timetableItem.message?.let { - Row( - modifier = Modifier - .padding(top = 8.dp) - .height(IntrinsicSize.Min), - horizontalArrangement = Arrangement.spacedBy(12.dp), - ) { - Icon( - Icons.Filled.Info, - contentDescription = stringResource(DroidKaigiUiRes.string.image), - tint = MaterialTheme.colorScheme.error, - ) - Text( - text = it.currentLangTitle, - fontSize = 16.sp, - color = MaterialTheme.colorScheme.error, - ) - } + + when (timetableItem) { + is Session -> timetableItem.message + is Special -> timetableItem.message + }?.let { + Row( + modifier = Modifier + .padding(top = 8.dp) + .height(IntrinsicSize.Min), + horizontalArrangement = Arrangement.spacedBy(12.dp), + ) { + Icon( + Icons.Filled.Info, + contentDescription = stringResource(DroidKaigiUiRes.string.image), + tint = MaterialTheme.colorScheme.error, + ) + Text( + text = it.currentLangTitle, + fontSize = 16.sp, + color = MaterialTheme.colorScheme.error, + ) } } } diff --git a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/Timetable.kt b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/Timetable.kt index 89f155aa2..d86547d79 100644 --- a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/Timetable.kt +++ b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/Timetable.kt @@ -161,6 +161,7 @@ public fun Timetable.Companion.fake(): Timetable { enTitle = "This is a description\nThis is a description\nThis is a description\n" + "This is a description\nThis is a description\nThis is a description\n", ), + message = null, ), ) for (day in -1..1) { @@ -229,6 +230,10 @@ public fun Timetable.Companion.fake(): Timetable { enTitle = "This is a description\nThis is a description\nThis is a description\n" + "This is a description\nThis is a description\nThis is a description\n", ), + message = MultiLangText( + jaTitle = "このセッションは事情により中止となりました", + enTitle = "This session has been cancelled due to circumstances.", + ), ), ) } diff --git a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/TimetableItem.kt b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/TimetableItem.kt index 843f62cb1..5790ba60f 100644 --- a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/TimetableItem.kt +++ b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/TimetableItem.kt @@ -62,6 +62,7 @@ public sealed class TimetableItem { override val levels: PersistentList, override val speakers: PersistentList, val description: MultiLangText, + val message: MultiLangText?, ) : TimetableItem() private val startsDateString: String by lazy { diff --git a/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/component/TimetableGridItem.kt b/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/component/TimetableGridItem.kt index a79837759..3d6cf38c9 100644 --- a/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/component/TimetableGridItem.kt +++ b/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/component/TimetableGridItem.kt @@ -587,6 +587,7 @@ fun TimetableGridItemWelcomeTalkPreview() { enTitle = "This is a description\nThis is a description\nThis is a description\n" + "This is a description\nThis is a description\nThis is a description\n", ), + message = null, ), onTimetableItemClick = {}, gridItemHeightPx = 154, From 50b7f66e6f7c567e231b2ec056d64c318a453b1c Mon Sep 17 00:00:00 2001 From: Aniokrait Date: Sat, 7 Sep 2024 00:25:00 +0900 Subject: [PATCH 16/18] Fix to show cancel icon on grid --- .../confsched/sessions/component/TimetableGridItem.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/component/TimetableGridItem.kt b/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/component/TimetableGridItem.kt index 3d6cf38c9..c7f003704 100644 --- a/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/component/TimetableGridItem.kt +++ b/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/component/TimetableGridItem.kt @@ -59,6 +59,7 @@ import io.github.droidkaigi.confsched.model.TimetableAsset import io.github.droidkaigi.confsched.model.TimetableCategory import io.github.droidkaigi.confsched.model.TimetableItem import io.github.droidkaigi.confsched.model.TimetableItem.Session +import io.github.droidkaigi.confsched.model.TimetableItem.Special import io.github.droidkaigi.confsched.model.TimetableItemId import io.github.droidkaigi.confsched.model.TimetableLanguage import io.github.droidkaigi.confsched.model.TimetableRoom @@ -226,7 +227,10 @@ fun TimetableGridItem( }, ) - val shouldShowError = timetableItem is Session && timetableItem.message != null + val shouldShowError = when (timetableItem) { + is Session -> timetableItem.message + is Special -> timetableItem.message + } != null if (isShowingAllContent && (speakers.isNotEmpty() || shouldShowError)) { Row( From 67002c6895c9895fefe3d78b0da6cd78e88938db Mon Sep 17 00:00:00 2001 From: Aniokrait Date: Sat, 7 Sep 2024 00:27:11 +0900 Subject: [PATCH 17/18] Fix icon color --- .../confsched/sessions/component/TimetableGridItem.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/component/TimetableGridItem.kt b/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/component/TimetableGridItem.kt index c7f003704..2b7e884f3 100644 --- a/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/component/TimetableGridItem.kt +++ b/feature/sessions/src/commonMain/kotlin/io/github/droidkaigi/confsched/sessions/component/TimetableGridItem.kt @@ -267,7 +267,7 @@ fun TimetableGridItem( .size(TimetableGridItemSizes.errorHeight), imageVector = Icons.Default.Error, contentDescription = stringResource(SessionsRes.string.content_description_error_icon), - tint = MaterialTheme.colorScheme.errorContainer, + tint = MaterialTheme.colorScheme.error, ) } } From f0f0fa37f176fcc3b65238a84bc33af2318c08ce Mon Sep 17 00:00:00 2001 From: woxtu Date: Sat, 7 Sep 2024 01:05:16 +0900 Subject: [PATCH 18/18] Add exception that may be thrown --- .../github/droidkaigi/confsched/model/ContributorsRepository.kt | 2 +- .../io/github/droidkaigi/confsched/model/EventMapRepository.kt | 2 +- .../io/github/droidkaigi/confsched/model/SponsorsRepository.kt | 2 +- .../io/github/droidkaigi/confsched/model/StaffRepository.kt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/ContributorsRepository.kt b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/ContributorsRepository.kt index 66c78ee10..a1509c9b5 100644 --- a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/ContributorsRepository.kt +++ b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/ContributorsRepository.kt @@ -8,7 +8,7 @@ import kotlin.coroutines.cancellation.CancellationException interface ContributorsRepository { - @Throws(CancellationException::class) + @Throws(AppError::class, CancellationException::class) suspend fun refresh() @Composable diff --git a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/EventMapRepository.kt b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/EventMapRepository.kt index 5ca1b38b9..3ce0276ef 100644 --- a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/EventMapRepository.kt +++ b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/EventMapRepository.kt @@ -8,7 +8,7 @@ import kotlin.coroutines.cancellation.CancellationException interface EventMapRepository { - @Throws(CancellationException::class) + @Throws(AppError::class, CancellationException::class) suspend fun refresh() @Composable diff --git a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/SponsorsRepository.kt b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/SponsorsRepository.kt index bea88cb6e..4e2780059 100644 --- a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/SponsorsRepository.kt +++ b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/SponsorsRepository.kt @@ -9,7 +9,7 @@ import kotlin.coroutines.cancellation.CancellationException public interface SponsorsRepository { public fun getSponsorStream(): Flow> - @Throws(CancellationException::class) + @Throws(AppError::class, CancellationException::class) public suspend fun refresh() @Composable diff --git a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/StaffRepository.kt b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/StaffRepository.kt index b088b477c..542db9cf6 100644 --- a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/StaffRepository.kt +++ b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/StaffRepository.kt @@ -10,7 +10,7 @@ interface StaffRepository { public fun staffs(): Flow> - @Throws(CancellationException::class) + @Throws(AppError::class, CancellationException::class) public suspend fun refresh() @Composable