From d68ca761fc416c4eca1a3252c6e47ab3dfb3fd3a Mon Sep 17 00:00:00 2001 From: kenken <43767445+tkhs0604@users.noreply.github.com> Date: Sat, 16 Sep 2023 00:10:04 +0900 Subject: [PATCH 01/10] add clock parameter --- .../confsched2023/model/DroidKaigi2023Day.kt | 7 ++----- .../confsched2023/sessions/TimetableScreen.kt | 7 ++++++- .../sessions/TimetableScreenViewModel.kt | 2 +- .../sessions/section/TimetableSheet.kt | 14 +++++++++++--- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched2023/model/DroidKaigi2023Day.kt b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched2023/model/DroidKaigi2023Day.kt index ac3feab49..0648b9948 100644 --- a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched2023/model/DroidKaigi2023Day.kt +++ b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched2023/model/DroidKaigi2023Day.kt @@ -81,14 +81,11 @@ public enum class DroidKaigi2023Day( /** * @return appropriate initial day for now */ - fun initialSelectedDay(isTest: Boolean = false): DroidKaigi2023Day { - // Timetable tab set initial tab with current date. - // To get the consistent test result, fix selected timetable tab to Day1 here. - if (isTest) return Day1 + fun initialSelectedDay(clock: Clock): DroidKaigi2023Day { val reversedEntries = entries.sortedByDescending { it.day } var selectedDay = reversedEntries.last() for (entry in reversedEntries) { - if (Clock.System.now() <= entry.end) selectedDay = entry + if (clock.now() <= entry.end) selectedDay = entry } return selectedDay } diff --git a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt index 545dc4330..677b37d0b 100644 --- a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt +++ b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt @@ -52,6 +52,8 @@ import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheet import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheetUiState import io.github.droidkaigi.confsched2023.ui.SnackbarMessageEffect import kotlinx.collections.immutable.toPersistentMap +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant import kotlin.math.roundToInt const val timetableScreenRoute = "timetable" @@ -253,7 +255,7 @@ fun PreviewTimetableScreenDark() { TimetableScreen( uiState = TimetableScreenUiState( contentUiState = TimetableSheetUiState.ListTimetable( - mapOf( + timetableListUiStates = mapOf( DroidKaigi2023Day.Day1 to TimetableListUiState( mapOf>().toPersistentMap(), Timetable(), @@ -263,6 +265,9 @@ fun PreviewTimetableScreenDark() { Timetable(), ), ), + clock = object : Clock { + override fun now(): Instant = Instant.parse("2023-09-14T00:00:00Z") + }, ), timetableUiType = TimetableUiType.Grid, onBookmarkIconClickStatus = false, diff --git a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreenViewModel.kt b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreenViewModel.kt index b9457d1f5..a3393fb86 100644 --- a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreenViewModel.kt +++ b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreenViewModel.kt @@ -52,7 +52,7 @@ class TimetableScreenViewModel @Inject constructor( timetableUiTypeStateFlow, ) { sessionTimetable, uiType -> if (sessionTimetable.timetableItems.isEmpty()) { - return@buildUiState TimetableSheetUiState.Empty + return@buildUiState TimetableSheetUiState.Empty() } if (uiType == TimetableUiType.List) { TimetableSheetUiState.ListTimetable( diff --git a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableSheet.kt b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableSheet.kt index f2e208f73..0c00f3b07 100644 --- a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableSheet.kt +++ b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableSheet.kt @@ -36,18 +36,26 @@ import io.github.droidkaigi.confsched2023.sessions.component.rememberTimetableTa import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheetUiState.Empty import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheetUiState.GridTimetable import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheetUiState.ListTimetable -import io.github.droidkaigi.confsched2023.ui.isTest +import kotlinx.datetime.Clock const val TimetableTabTestTag = "TimetableTab" sealed interface TimetableSheetUiState { - data object Empty : TimetableSheetUiState + + val clock: Clock + + data class Empty( + override val clock: Clock = Clock.System, + ) : TimetableSheetUiState + data class ListTimetable( val timetableListUiStates: Map, + override val clock: Clock = Clock.System, ) : TimetableSheetUiState data class GridTimetable( val timetableGridUiState: Map, + override val clock: Clock = Clock.System, ) : TimetableSheetUiState } @@ -60,7 +68,7 @@ fun TimetableSheet( contentPadding: PaddingValues, modifier: Modifier = Modifier, ) { - var selectedDay by rememberSaveable { mutableStateOf(DroidKaigi2023Day.initialSelectedDay(isTest())) } + var selectedDay by rememberSaveable { mutableStateOf(DroidKaigi2023Day.initialSelectedDay(uiState.clock)) } val corner by animateIntAsState( if (timetableScreenScrollState.isScreenLayoutCalculating || timetableScreenScrollState.isSheetExpandable) 40 else 0, label = "Timetable corner state", From eb10b89001d3b75fb0b5e9b0c30dae1069f3444a Mon Sep 17 00:00:00 2001 From: kenken <43767445+tkhs0604@users.noreply.github.com> Date: Sat, 16 Sep 2023 11:27:50 +0900 Subject: [PATCH 02/10] add LocalClockProvider --- .../droidkaigi/confsched2023/PreviewTest.kt | 12 +++- core/ui/build.gradle.kts | 1 + .../ui/compositionlocal/LocalClockProvider.kt | 8 +++ .../confsched2023/sessions/TimetableScreen.kt | 59 ++++++++++--------- .../sessions/TimetableScreenViewModel.kt | 2 +- .../sessions/section/TimetableSheet.kt | 15 ++--- 6 files changed, 57 insertions(+), 40 deletions(-) create mode 100644 core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt diff --git a/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt b/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt index c7868b878..94ffa839d 100644 --- a/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt +++ b/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt @@ -14,6 +14,9 @@ import io.github.droidkaigi.confsched2023.designsystem.preview.MultiLanguagePrev import io.github.droidkaigi.confsched2023.designsystem.preview.MultiThemePreviewDefinition import io.github.droidkaigi.confsched2023.designsystem.preview.ShowkaseMultiplePreviewsWorkaround import io.github.droidkaigi.confsched2023.testing.category.ScreenshotTests +import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClockProvider +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant import org.junit.Test import org.junit.experimental.categories.Category import org.junit.runner.RunWith @@ -70,7 +73,10 @@ class PreviewTest( val newConfiguration = appliers.fold(LocalConfiguration.current) { c, a -> c.apply(a) } - CompositionLocalProvider(LocalConfiguration provides newConfiguration) { + CompositionLocalProvider( + LocalConfiguration provides newConfiguration, + LocalClockProvider provides FakeClock, + ) { // Notify locale changes to lang() through the following invocation. LocaleList.setDefault(LocalConfiguration.current.locales) @@ -150,3 +156,7 @@ class PreviewTest( } } } + +private object FakeClock : Clock { + override fun now(): Instant = Instant.parse("2023-09-14T10:00:00.000Z") +} diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index a396e8521..48e34b842 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -18,6 +18,7 @@ kotlin { implementation(libs.kermit) api(projects.core.common) api(libs.composeImageLoader) + api(libs.kotlinxDatetime) } } } diff --git a/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt b/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt new file mode 100644 index 000000000..f55be1745 --- /dev/null +++ b/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt @@ -0,0 +1,8 @@ +package io.github.droidkaigi.confsched2023.ui.compositionlocal + +import androidx.compose.runtime.compositionLocalOf +import kotlinx.datetime.Clock + +val LocalClockProvider = compositionLocalOf { + Clock.System +} diff --git a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt index 677b37d0b..ea77896a1 100644 --- a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt +++ b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt @@ -16,6 +16,7 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -51,6 +52,7 @@ import io.github.droidkaigi.confsched2023.sessions.section.TimetableListUiState import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheet import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheetUiState import io.github.droidkaigi.confsched2023.ui.SnackbarMessageEffect +import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClockProvider import kotlinx.collections.immutable.toPersistentMap import kotlinx.datetime.Clock import kotlinx.datetime.Instant @@ -251,35 +253,38 @@ private fun TimetableScreen( @MultiThemePreviews @Composable fun PreviewTimetableScreenDark() { - KaigiTheme { - TimetableScreen( - uiState = TimetableScreenUiState( - contentUiState = TimetableSheetUiState.ListTimetable( - timetableListUiStates = mapOf( - DroidKaigi2023Day.Day1 to TimetableListUiState( - mapOf>().toPersistentMap(), - Timetable(), - ), - DroidKaigi2023Day.Day2 to TimetableListUiState( - mapOf>().toPersistentMap(), - Timetable(), + CompositionLocalProvider( + LocalClockProvider provides object : Clock { + override fun now(): Instant = Instant.parse("2023-09-14T00:00:00Z") + }, + ) { + KaigiTheme { + TimetableScreen( + uiState = TimetableScreenUiState( + contentUiState = TimetableSheetUiState.ListTimetable( + mapOf( + DroidKaigi2023Day.Day1 to TimetableListUiState( + mapOf>().toPersistentMap(), + Timetable(), + ), + DroidKaigi2023Day.Day2 to TimetableListUiState( + mapOf>().toPersistentMap(), + Timetable(), + ), ), ), - clock = object : Clock { - override fun now(): Instant = Instant.parse("2023-09-14T00:00:00Z") - }, + timetableUiType = TimetableUiType.Grid, + onBookmarkIconClickStatus = false, ), - timetableUiType = TimetableUiType.Grid, - onBookmarkIconClickStatus = false, - ), - snackbarHostState = SnackbarHostState(), - onTimetableItemClick = {}, - onBookmarkClick = { _, _ -> }, - onBookmarkIconClick = {}, - onSearchClick = {}, - onTimetableUiChangeClick = {}, - onReachAnimationEnd = {}, - modifier = Modifier.statusBarsPadding(), - ) + snackbarHostState = SnackbarHostState(), + onTimetableItemClick = {}, + onBookmarkClick = { _, _ -> }, + onBookmarkIconClick = {}, + onSearchClick = {}, + onTimetableUiChangeClick = {}, + onReachAnimationEnd = {}, + modifier = Modifier.statusBarsPadding(), + ) + } } } diff --git a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreenViewModel.kt b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreenViewModel.kt index a3393fb86..b9457d1f5 100644 --- a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreenViewModel.kt +++ b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreenViewModel.kt @@ -52,7 +52,7 @@ class TimetableScreenViewModel @Inject constructor( timetableUiTypeStateFlow, ) { sessionTimetable, uiType -> if (sessionTimetable.timetableItems.isEmpty()) { - return@buildUiState TimetableSheetUiState.Empty() + return@buildUiState TimetableSheetUiState.Empty } if (uiType == TimetableUiType.List) { TimetableSheetUiState.ListTimetable( diff --git a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableSheet.kt b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableSheet.kt index 0c00f3b07..9825983ef 100644 --- a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableSheet.kt +++ b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableSheet.kt @@ -36,26 +36,18 @@ import io.github.droidkaigi.confsched2023.sessions.component.rememberTimetableTa import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheetUiState.Empty import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheetUiState.GridTimetable import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheetUiState.ListTimetable -import kotlinx.datetime.Clock +import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClockProvider const val TimetableTabTestTag = "TimetableTab" sealed interface TimetableSheetUiState { - - val clock: Clock - - data class Empty( - override val clock: Clock = Clock.System, - ) : TimetableSheetUiState - + data object Empty : TimetableSheetUiState data class ListTimetable( val timetableListUiStates: Map, - override val clock: Clock = Clock.System, ) : TimetableSheetUiState data class GridTimetable( val timetableGridUiState: Map, - override val clock: Clock = Clock.System, ) : TimetableSheetUiState } @@ -68,7 +60,8 @@ fun TimetableSheet( contentPadding: PaddingValues, modifier: Modifier = Modifier, ) { - var selectedDay by rememberSaveable { mutableStateOf(DroidKaigi2023Day.initialSelectedDay(uiState.clock)) } + val clock = LocalClockProvider.current + var selectedDay by rememberSaveable { mutableStateOf(DroidKaigi2023Day.initialSelectedDay(clock)) } val corner by animateIntAsState( if (timetableScreenScrollState.isScreenLayoutCalculating || timetableScreenScrollState.isSheetExpandable) 40 else 0, label = "Timetable corner state", From c6787c2855f871b0a4a193b918c5ba678777a1cf Mon Sep 17 00:00:00 2001 From: kenken <43767445+tkhs0604@users.noreply.github.com> Date: Sat, 16 Sep 2023 14:14:39 +0900 Subject: [PATCH 03/10] suppress CompositionLocalAllowList --- .../confsched2023/ui/compositionlocal/LocalClockProvider.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt b/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt index f55be1745..afe440fa8 100644 --- a/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt +++ b/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt @@ -3,6 +3,7 @@ package io.github.droidkaigi.confsched2023.ui.compositionlocal import androidx.compose.runtime.compositionLocalOf import kotlinx.datetime.Clock +@Suppress("CompositionLocalAllowList") val LocalClockProvider = compositionLocalOf { Clock.System } From 9c90ff80177dedf71cfb5af4ba8404411ee9df02 Mon Sep 17 00:00:00 2001 From: kenken <43767445+tkhs0604@users.noreply.github.com> Date: Sat, 16 Sep 2023 17:17:40 +0900 Subject: [PATCH 04/10] replace with staticCompositionLocalOf --- .../confsched2023/ui/compositionlocal/LocalClockProvider.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt b/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt index afe440fa8..db1fed646 100644 --- a/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt +++ b/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt @@ -1,9 +1,9 @@ package io.github.droidkaigi.confsched2023.ui.compositionlocal -import androidx.compose.runtime.compositionLocalOf +import androidx.compose.runtime.staticCompositionLocalOf import kotlinx.datetime.Clock @Suppress("CompositionLocalAllowList") -val LocalClockProvider = compositionLocalOf { +val LocalClockProvider = staticCompositionLocalOf { Clock.System } From 518615bbf0ad7002b159e908500d69c1f798a466 Mon Sep 17 00:00:00 2001 From: kenken <43767445+tkhs0604@users.noreply.github.com> Date: Sat, 16 Sep 2023 17:24:54 +0900 Subject: [PATCH 05/10] fix format --- .../confsched2023/ui/compositionlocal/LocalClockProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt b/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt index db1fed646..8e1945ee6 100644 --- a/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt +++ b/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt @@ -3,7 +3,7 @@ package io.github.droidkaigi.confsched2023.ui.compositionlocal import androidx.compose.runtime.staticCompositionLocalOf import kotlinx.datetime.Clock -@Suppress("CompositionLocalAllowList") +@Suppress("CompositionLocalAllowlist") val LocalClockProvider = staticCompositionLocalOf { Clock.System } From 3d0f9c5d9c898a5087d40a5cb9d2d2cda8c6bde0 Mon Sep 17 00:00:00 2001 From: kenken <43767445+tkhs0604@users.noreply.github.com> Date: Sat, 16 Sep 2023 20:53:30 +0900 Subject: [PATCH 06/10] rename to LocalClock --- .../java/io/github/droidkaigi/confsched2023/PreviewTest.kt | 4 ++-- .../compositionlocal/{LocalClockProvider.kt => LocalClock.kt} | 2 +- .../droidkaigi/confsched2023/sessions/TimetableScreen.kt | 4 ++-- .../confsched2023/sessions/section/TimetableSheet.kt | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) rename core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/{LocalClockProvider.kt => LocalClock.kt} (78%) diff --git a/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt b/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt index 94ffa839d..227b73694 100644 --- a/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt +++ b/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt @@ -14,7 +14,7 @@ import io.github.droidkaigi.confsched2023.designsystem.preview.MultiLanguagePrev import io.github.droidkaigi.confsched2023.designsystem.preview.MultiThemePreviewDefinition import io.github.droidkaigi.confsched2023.designsystem.preview.ShowkaseMultiplePreviewsWorkaround import io.github.droidkaigi.confsched2023.testing.category.ScreenshotTests -import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClockProvider +import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClock import kotlinx.datetime.Clock import kotlinx.datetime.Instant import org.junit.Test @@ -75,7 +75,7 @@ class PreviewTest( CompositionLocalProvider( LocalConfiguration provides newConfiguration, - LocalClockProvider provides FakeClock, + LocalClock provides FakeClock, ) { // Notify locale changes to lang() through the following invocation. LocaleList.setDefault(LocalConfiguration.current.locales) diff --git a/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt b/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClock.kt similarity index 78% rename from core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt rename to core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClock.kt index 8e1945ee6..5ec1ad96f 100644 --- a/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClockProvider.kt +++ b/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClock.kt @@ -4,6 +4,6 @@ import androidx.compose.runtime.staticCompositionLocalOf import kotlinx.datetime.Clock @Suppress("CompositionLocalAllowlist") -val LocalClockProvider = staticCompositionLocalOf { +val LocalClock = staticCompositionLocalOf { Clock.System } diff --git a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt index ea77896a1..3d307f732 100644 --- a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt +++ b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt @@ -52,7 +52,7 @@ import io.github.droidkaigi.confsched2023.sessions.section.TimetableListUiState import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheet import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheetUiState import io.github.droidkaigi.confsched2023.ui.SnackbarMessageEffect -import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClockProvider +import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClock import kotlinx.collections.immutable.toPersistentMap import kotlinx.datetime.Clock import kotlinx.datetime.Instant @@ -254,7 +254,7 @@ private fun TimetableScreen( @Composable fun PreviewTimetableScreenDark() { CompositionLocalProvider( - LocalClockProvider provides object : Clock { + LocalClock provides object : Clock { override fun now(): Instant = Instant.parse("2023-09-14T00:00:00Z") }, ) { diff --git a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableSheet.kt b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableSheet.kt index 9825983ef..71925d7b3 100644 --- a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableSheet.kt +++ b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableSheet.kt @@ -36,7 +36,7 @@ import io.github.droidkaigi.confsched2023.sessions.component.rememberTimetableTa import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheetUiState.Empty import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheetUiState.GridTimetable import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheetUiState.ListTimetable -import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClockProvider +import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClock const val TimetableTabTestTag = "TimetableTab" @@ -60,7 +60,7 @@ fun TimetableSheet( contentPadding: PaddingValues, modifier: Modifier = Modifier, ) { - val clock = LocalClockProvider.current + val clock = LocalClock.current var selectedDay by rememberSaveable { mutableStateOf(DroidKaigi2023Day.initialSelectedDay(clock)) } val corner by animateIntAsState( if (timetableScreenScrollState.isScreenLayoutCalculating || timetableScreenScrollState.isSheetExpandable) 40 else 0, From 21728765933fac8f38ed332021d996c0b3023e4b Mon Sep 17 00:00:00 2001 From: kenken <43767445+tkhs0604@users.noreply.github.com> Date: Sun, 17 Sep 2023 12:11:10 +0900 Subject: [PATCH 07/10] move FakeClock --- .../java/io/github/droidkaigi/confsched2023/PreviewTest.kt | 5 +---- .../confsched2023/ui/compositionlocal/LocalClock.kt | 5 +++++ .../droidkaigi/confsched2023/sessions/TimetableScreen.kt | 7 ++----- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt b/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt index 227b73694..f6694c8be 100644 --- a/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt +++ b/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt @@ -14,6 +14,7 @@ import io.github.droidkaigi.confsched2023.designsystem.preview.MultiLanguagePrev import io.github.droidkaigi.confsched2023.designsystem.preview.MultiThemePreviewDefinition import io.github.droidkaigi.confsched2023.designsystem.preview.ShowkaseMultiplePreviewsWorkaround import io.github.droidkaigi.confsched2023.testing.category.ScreenshotTests +import io.github.droidkaigi.confsched2023.ui.compositionlocal.FakeClock import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClock import kotlinx.datetime.Clock import kotlinx.datetime.Instant @@ -156,7 +157,3 @@ class PreviewTest( } } } - -private object FakeClock : Clock { - override fun now(): Instant = Instant.parse("2023-09-14T10:00:00.000Z") -} diff --git a/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClock.kt b/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClock.kt index 5ec1ad96f..0cb30ce7f 100644 --- a/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClock.kt +++ b/core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched2023/ui/compositionlocal/LocalClock.kt @@ -2,8 +2,13 @@ package io.github.droidkaigi.confsched2023.ui.compositionlocal import androidx.compose.runtime.staticCompositionLocalOf import kotlinx.datetime.Clock +import kotlinx.datetime.Instant @Suppress("CompositionLocalAllowlist") val LocalClock = staticCompositionLocalOf { Clock.System } + +object FakeClock : Clock { + override fun now(): Instant = Instant.parse("2023-09-14T10:00:00.000Z") +} diff --git a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt index 3d307f732..97d2a7c5f 100644 --- a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt +++ b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt @@ -52,6 +52,7 @@ import io.github.droidkaigi.confsched2023.sessions.section.TimetableListUiState import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheet import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheetUiState import io.github.droidkaigi.confsched2023.ui.SnackbarMessageEffect +import io.github.droidkaigi.confsched2023.ui.compositionlocal.FakeClock import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClock import kotlinx.collections.immutable.toPersistentMap import kotlinx.datetime.Clock @@ -253,11 +254,7 @@ private fun TimetableScreen( @MultiThemePreviews @Composable fun PreviewTimetableScreenDark() { - CompositionLocalProvider( - LocalClock provides object : Clock { - override fun now(): Instant = Instant.parse("2023-09-14T00:00:00Z") - }, - ) { + CompositionLocalProvider(LocalClock provides FakeClock) { KaigiTheme { TimetableScreen( uiState = TimetableScreenUiState( From 046fba6f5131ce117f82435edd9c7607486886de Mon Sep 17 00:00:00 2001 From: kenken <43767445+tkhs0604@users.noreply.github.com> Date: Sun, 17 Sep 2023 12:24:59 +0900 Subject: [PATCH 08/10] fix tests --- .../droidkaigi/confsched2023/PreviewTest.kt | 9 +-------- core/testing/build.gradle.kts | 1 + .../testing/robot/TimetableScreenRobot.kt | 17 +++++++++++------ .../confsched2023/sessions/TimetableScreen.kt | 2 -- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt b/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt index f6694c8be..c7868b878 100644 --- a/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt +++ b/app-android/src/test/java/io/github/droidkaigi/confsched2023/PreviewTest.kt @@ -14,10 +14,6 @@ import io.github.droidkaigi.confsched2023.designsystem.preview.MultiLanguagePrev import io.github.droidkaigi.confsched2023.designsystem.preview.MultiThemePreviewDefinition import io.github.droidkaigi.confsched2023.designsystem.preview.ShowkaseMultiplePreviewsWorkaround import io.github.droidkaigi.confsched2023.testing.category.ScreenshotTests -import io.github.droidkaigi.confsched2023.ui.compositionlocal.FakeClock -import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClock -import kotlinx.datetime.Clock -import kotlinx.datetime.Instant import org.junit.Test import org.junit.experimental.categories.Category import org.junit.runner.RunWith @@ -74,10 +70,7 @@ class PreviewTest( val newConfiguration = appliers.fold(LocalConfiguration.current) { c, a -> c.apply(a) } - CompositionLocalProvider( - LocalConfiguration provides newConfiguration, - LocalClock provides FakeClock, - ) { + CompositionLocalProvider(LocalConfiguration provides newConfiguration) { // Notify locale changes to lang() through the following invocation. LocaleList.setDefault(LocalConfiguration.current.locales) diff --git a/core/testing/build.gradle.kts b/core/testing/build.gradle.kts index 8016717c1..2d65923e5 100644 --- a/core/testing/build.gradle.kts +++ b/core/testing/build.gradle.kts @@ -12,6 +12,7 @@ dependencies { implementation(projects.core.model) implementation(projects.core.designsystem) implementation(projects.core.data) + implementation(projects.core.ui) implementation(projects.feature.main) implementation(projects.feature.sessions) implementation(projects.feature.about) diff --git a/core/testing/src/main/java/io/github/droidkaigi/confsched2023/testing/robot/TimetableScreenRobot.kt b/core/testing/src/main/java/io/github/droidkaigi/confsched2023/testing/robot/TimetableScreenRobot.kt index 1bea2ec3e..e68f65f2a 100644 --- a/core/testing/src/main/java/io/github/droidkaigi/confsched2023/testing/robot/TimetableScreenRobot.kt +++ b/core/testing/src/main/java/io/github/droidkaigi/confsched2023/testing/robot/TimetableScreenRobot.kt @@ -1,5 +1,6 @@ package io.github.droidkaigi.confsched2023.testing.robot +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.isRoot @@ -25,6 +26,8 @@ import io.github.droidkaigi.confsched2023.sessions.component.TimetableUiTypeChan import io.github.droidkaigi.confsched2023.sessions.section.TimetableTabTestTag import io.github.droidkaigi.confsched2023.testing.RobotTestRule import io.github.droidkaigi.confsched2023.testing.coroutines.runTestWithLogging +import io.github.droidkaigi.confsched2023.ui.compositionlocal.FakeClock +import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClock import kotlinx.coroutines.test.TestDispatcher import javax.inject.Inject import kotlin.time.Duration.Companion.seconds @@ -50,12 +53,14 @@ class TimetableScreenRobot @Inject constructor( fun setupTimetableScreenContent() { composeTestRule.setContent { - KaigiTheme { - TimetableScreen( - onSearchClick = { }, - onTimetableItemClick = { }, - onBookmarkIconClick = { }, - ) + CompositionLocalProvider(LocalClock provides FakeClock) { + KaigiTheme { + TimetableScreen( + onSearchClick = { }, + onTimetableItemClick = { }, + onBookmarkIconClick = { }, + ) + } } } waitUntilIdle() diff --git a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt index 97d2a7c5f..1a48a09d1 100644 --- a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt +++ b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/TimetableScreen.kt @@ -55,8 +55,6 @@ import io.github.droidkaigi.confsched2023.ui.SnackbarMessageEffect import io.github.droidkaigi.confsched2023.ui.compositionlocal.FakeClock import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClock import kotlinx.collections.immutable.toPersistentMap -import kotlinx.datetime.Clock -import kotlinx.datetime.Instant import kotlin.math.roundToInt const val timetableScreenRoute = "timetable" From 051d5b8f89c7769f870511077bf15f0249a569ef Mon Sep 17 00:00:00 2001 From: kenken <43767445+tkhs0604@users.noreply.github.com> Date: Tue, 19 Sep 2023 23:07:31 +0900 Subject: [PATCH 09/10] inject clock provider --- .../droidkaigi/confsched2023/AppModule.kt | 11 +++++++++ .../droidkaigi/confsched2023/MainActivity.kt | 17 +++++++++---- .../droidkaigi/confsched2023/FakeAppModule.kt | 24 +++++++++++++++++++ .../testing/robot/TimetableScreenRobot.kt | 17 +++++-------- 4 files changed, 54 insertions(+), 15 deletions(-) create mode 100644 app-android/src/test/java/io/github/droidkaigi/confsched2023/FakeAppModule.kt diff --git a/app-android/src/main/java/io/github/droidkaigi/confsched2023/AppModule.kt b/app-android/src/main/java/io/github/droidkaigi/confsched2023/AppModule.kt index 06b477e0d..1b555fd33 100644 --- a/app-android/src/main/java/io/github/droidkaigi/confsched2023/AppModule.kt +++ b/app-android/src/main/java/io/github/droidkaigi/confsched2023/AppModule.kt @@ -6,6 +6,7 @@ import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import io.github.droidkaigi.confsched2023.data.di.AppAndroidBuildConfig import io.github.droidkaigi.confsched2023.model.BuildConfigProvider +import kotlinx.datetime.Clock import javax.inject.Singleton @InstallIn(SingletonComponent::class) @@ -15,9 +16,19 @@ class AppModule { @Singleton @AppAndroidBuildConfig fun provideBuildConfigProvider(): BuildConfigProvider = AppBuildConfigProvider() + + @Provides + @Singleton + fun provideClockProvider(): ClockProvider = object : ClockProvider { + override fun clock(): Clock = Clock.System + } } class AppBuildConfigProvider( override val versionName: String = BuildConfig.VERSION_NAME, override val debugBuild: Boolean = BuildConfig.DEBUG, ) : BuildConfigProvider + +interface ClockProvider { + fun clock(): Clock +} diff --git a/app-android/src/main/java/io/github/droidkaigi/confsched2023/MainActivity.kt b/app-android/src/main/java/io/github/droidkaigi/confsched2023/MainActivity.kt index 83aff3ba3..e7d5bb352 100644 --- a/app-android/src/main/java/io/github/droidkaigi/confsched2023/MainActivity.kt +++ b/app-android/src/main/java/io/github/droidkaigi/confsched2023/MainActivity.kt @@ -10,6 +10,7 @@ import androidx.activity.enableEdgeToEdge import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.getValue import androidx.compose.runtime.produceState import androidx.compose.runtime.remember @@ -19,12 +20,18 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.window.layout.DisplayFeature import androidx.window.layout.WindowInfoTracker import dagger.hilt.android.AndroidEntryPoint +import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClock import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList +import javax.inject.Inject @AndroidEntryPoint class MainActivity : ComponentActivity() { + + @Inject + lateinit var clockProvider: ClockProvider + @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) override fun onCreate(savedInstanceState: Bundle?) { installSplashScreen() @@ -55,10 +62,12 @@ class MainActivity : ComponentActivity() { setContent { val windowSize = calculateWindowSizeClass(this) val displayFeatures = calculateDisplayFeatures(this) - KaigiApp( - windowSize = windowSize, - displayFeatures = displayFeatures, - ) + CompositionLocalProvider(LocalClock provides clockProvider.clock()) { + KaigiApp( + windowSize = windowSize, + displayFeatures = displayFeatures, + ) + } } } } diff --git a/app-android/src/test/java/io/github/droidkaigi/confsched2023/FakeAppModule.kt b/app-android/src/test/java/io/github/droidkaigi/confsched2023/FakeAppModule.kt new file mode 100644 index 000000000..90ddc1f3b --- /dev/null +++ b/app-android/src/test/java/io/github/droidkaigi/confsched2023/FakeAppModule.kt @@ -0,0 +1,24 @@ +package io.github.droidkaigi.confsched2023 + +import dagger.Module +import dagger.Provides +import dagger.hilt.components.SingletonComponent +import dagger.hilt.testing.TestInstallIn +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import javax.inject.Singleton + +@TestInstallIn( + components = [SingletonComponent::class], + replaces = [AppModule::class], +) +@Module +class FakeAppModule { + @Provides + @Singleton + fun provideClockProvider(): ClockProvider = object : ClockProvider { + override fun clock(): Clock = object : Clock { + override fun now() = Instant.parse("2023-09-14T10:00:00.00Z") + } + } +} diff --git a/core/testing/src/main/java/io/github/droidkaigi/confsched2023/testing/robot/TimetableScreenRobot.kt b/core/testing/src/main/java/io/github/droidkaigi/confsched2023/testing/robot/TimetableScreenRobot.kt index e68f65f2a..1bea2ec3e 100644 --- a/core/testing/src/main/java/io/github/droidkaigi/confsched2023/testing/robot/TimetableScreenRobot.kt +++ b/core/testing/src/main/java/io/github/droidkaigi/confsched2023/testing/robot/TimetableScreenRobot.kt @@ -1,6 +1,5 @@ package io.github.droidkaigi.confsched2023.testing.robot -import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.isRoot @@ -26,8 +25,6 @@ import io.github.droidkaigi.confsched2023.sessions.component.TimetableUiTypeChan import io.github.droidkaigi.confsched2023.sessions.section.TimetableTabTestTag import io.github.droidkaigi.confsched2023.testing.RobotTestRule import io.github.droidkaigi.confsched2023.testing.coroutines.runTestWithLogging -import io.github.droidkaigi.confsched2023.ui.compositionlocal.FakeClock -import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClock import kotlinx.coroutines.test.TestDispatcher import javax.inject.Inject import kotlin.time.Duration.Companion.seconds @@ -53,14 +50,12 @@ class TimetableScreenRobot @Inject constructor( fun setupTimetableScreenContent() { composeTestRule.setContent { - CompositionLocalProvider(LocalClock provides FakeClock) { - KaigiTheme { - TimetableScreen( - onSearchClick = { }, - onTimetableItemClick = { }, - onBookmarkIconClick = { }, - ) - } + KaigiTheme { + TimetableScreen( + onSearchClick = { }, + onTimetableItemClick = { }, + onBookmarkIconClick = { }, + ) } } waitUntilIdle() From c06314b4ce8d856fbfad2bb1a6486a265df5b8fe Mon Sep 17 00:00:00 2001 From: kenken <43767445+tkhs0604@users.noreply.github.com> Date: Tue, 19 Sep 2023 23:17:18 +0900 Subject: [PATCH 10/10] wrap with composition local --- .../testing/robot/TimetableScreenRobot.kt | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/core/testing/src/main/java/io/github/droidkaigi/confsched2023/testing/robot/TimetableScreenRobot.kt b/core/testing/src/main/java/io/github/droidkaigi/confsched2023/testing/robot/TimetableScreenRobot.kt index 1bea2ec3e..e68f65f2a 100644 --- a/core/testing/src/main/java/io/github/droidkaigi/confsched2023/testing/robot/TimetableScreenRobot.kt +++ b/core/testing/src/main/java/io/github/droidkaigi/confsched2023/testing/robot/TimetableScreenRobot.kt @@ -1,5 +1,6 @@ package io.github.droidkaigi.confsched2023.testing.robot +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.isRoot @@ -25,6 +26,8 @@ import io.github.droidkaigi.confsched2023.sessions.component.TimetableUiTypeChan import io.github.droidkaigi.confsched2023.sessions.section.TimetableTabTestTag import io.github.droidkaigi.confsched2023.testing.RobotTestRule import io.github.droidkaigi.confsched2023.testing.coroutines.runTestWithLogging +import io.github.droidkaigi.confsched2023.ui.compositionlocal.FakeClock +import io.github.droidkaigi.confsched2023.ui.compositionlocal.LocalClock import kotlinx.coroutines.test.TestDispatcher import javax.inject.Inject import kotlin.time.Duration.Companion.seconds @@ -50,12 +53,14 @@ class TimetableScreenRobot @Inject constructor( fun setupTimetableScreenContent() { composeTestRule.setContent { - KaigiTheme { - TimetableScreen( - onSearchClick = { }, - onTimetableItemClick = { }, - onBookmarkIconClick = { }, - ) + CompositionLocalProvider(LocalClock provides FakeClock) { + KaigiTheme { + TimetableScreen( + onSearchClick = { }, + onTimetableItemClick = { }, + onBookmarkIconClick = { }, + ) + } } } waitUntilIdle()