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 2c741ab99..95105738c 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 @@ -14,6 +14,7 @@ import io.github.droidkaigi.confsched2023.designsystem.theme.KaigiTheme import io.github.droidkaigi.confsched2023.sessions.TimetableScreen import io.github.droidkaigi.confsched2023.sessions.TimetableScreenTestTag import io.github.droidkaigi.confsched2023.sessions.component.TimetableListItemTestTag +import io.github.droidkaigi.confsched2023.sessions.component.TimetableUiTypeChangeButtonTestTag import io.github.droidkaigi.confsched2023.testing.RobotTestRule import kotlinx.coroutines.test.TestDispatcher import javax.inject.Inject @@ -42,7 +43,7 @@ class TimetableScreenRobot @Inject constructor( waitUntilIdle() } - fun clickFirstSessionFavorite() { + fun clickFirstSessionBookmark() { composeTestRule .onAllNodes(hasText("☆")) .onFirst() @@ -50,6 +51,12 @@ class TimetableScreenRobot @Inject constructor( waitUntilIdle() } + fun clickTimetableUiTypeChangeButton() { + composeTestRule + .onNode(hasTestTag(TimetableUiTypeChangeButtonTestTag)) + .performClick() + } + fun scrollTimetable() { composeTestRule .onNode(hasTestTag(TimetableScreenTestTag)) 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 99334c288..8a9bf704d 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 @@ -1,32 +1,24 @@ package io.github.droidkaigi.confsched2023.sessions -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.layout -import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.testTag import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import io.github.droidkaigi.confsched2023.model.TimetableItem +import io.github.droidkaigi.confsched2023.sessions.component.TimetableTopArea import io.github.droidkaigi.confsched2023.sessions.component.rememberTimetableScreenScrollState import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheet import io.github.droidkaigi.confsched2023.sessions.section.TimetableSheetUiState @@ -51,7 +43,8 @@ fun TimetableScreen( uiState = uiState, snackbarHostState = snackbarHostState, onContributorsClick = onContributorsClick, - onFavoriteClick = viewModel::onBookmarkClick, + onBookmarkClick = viewModel::onBookmarkClick, + onTimetableUiChangeClick = viewModel::onUiTypeChange, ) } @@ -65,7 +58,8 @@ private fun TimetableScreen( uiState: TimetableScreenUiState, snackbarHostState: SnackbarHostState, onContributorsClick: () -> Unit, - onFavoriteClick: (TimetableItem.Session) -> Unit, + onBookmarkClick: (TimetableItem.Session) -> Unit, + onTimetableUiChangeClick: () -> Unit, ) { val state = rememberTimetableScreenScrollState() @@ -79,27 +73,7 @@ private fun TimetableScreen( ) }, topBar = { - Column { - // TODO: Implement TopAppBar design - TopAppBar( - title = { - Text(text = "KaigiApp") - }, - colors = TopAppBarDefaults.largeTopAppBarColors( - containerColor = MaterialTheme.colorScheme.surfaceVariant, - ), - ) - Row( - modifier = Modifier - .fillMaxWidth() - .onGloballyPositioned { coordinates -> - state.onHeaderPositioned(coordinates.size.height.toFloat()) - }, - ) { - // TODO: Implement header desing(title and image etc..) - Spacer(modifier = Modifier.height(130.dp)) - } - } + TimetableTopArea(state, onTimetableUiChangeClick) }, containerColor = MaterialTheme.colorScheme.surfaceVariant, contentWindowInsets = WindowInsets(0.dp), @@ -119,7 +93,7 @@ private fun TimetableScreen( onContributorsClick = onContributorsClick, uiState = uiState.contentUiState, timetableScreenScrollState = state, - onFavoriteClick = onFavoriteClick, + onFavoriteClick = onBookmarkClick, ) } } 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 814091304..ee438e0fb 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 @@ -71,8 +71,13 @@ class TimetableScreenViewModel @Inject constructor( ) } - fun onUiTypeChange(uiType: TimetableUiType) { - timetableUiTypeStateFlow.value = uiType + fun onUiTypeChange() { + timetableUiTypeStateFlow.value = + if (timetableUiTypeStateFlow.value == TimetableUiType.List) { + TimetableUiType.Grid + } else { + TimetableUiType.List + } } fun onBookmarkClick(session: TimetableItem.Session) { diff --git a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/component/TimetableTopArea.kt b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/component/TimetableTopArea.kt new file mode 100644 index 000000000..03ce3eeb8 --- /dev/null +++ b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/component/TimetableTopArea.kt @@ -0,0 +1,61 @@ +package io.github.droidkaigi.confsched2023.sessions.component + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.DateRange +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.unit.dp +import io.github.droidkaigi.confsched2023.sessions.strings.SessionsStrings.Timetable + +const val TimetableUiTypeChangeButtonTestTag = "TimetableUiTypeChangeButton" + +@Composable +@OptIn(ExperimentalMaterial3Api::class) +fun TimetableTopArea(state: TimetableScreenScrollState, onTimetableUiChangeClick: () -> Unit) { + Column { + // TODO: Implement TopAppBar design + TopAppBar( + title = { + Text(text = "KaigiApp") + }, + actions = { + IconButton( + modifier = Modifier.testTag(TimetableUiTypeChangeButtonTestTag), + onClick = { onTimetableUiChangeClick() }, + ) { + Icon( + imageVector = Icons.Default.DateRange, + contentDescription = Timetable.asString(), + ) + } + }, + colors = TopAppBarDefaults.largeTopAppBarColors( + containerColor = MaterialTheme.colorScheme.surfaceVariant, + ), + ) + Row( + modifier = Modifier + .fillMaxWidth() + .onGloballyPositioned { coordinates -> + state.onHeaderPositioned(coordinates.size.height.toFloat()) + }, + ) { + // TODO: Implement header desing(title and image etc..) + Spacer(modifier = Modifier.height(130.dp)) + } + } +} diff --git a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableGrid.kt b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableGrid.kt index 8cbf85b6a..34010cced 100644 --- a/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableGrid.kt +++ b/feature/sessions/src/main/java/io/github/droidkaigi/confsched2023/sessions/section/TimetableGrid.kt @@ -72,10 +72,10 @@ fun TimetableGrid( onBookmarked: (TimetableItem) -> Unit, modifier: Modifier = Modifier, ) { - val timetableState = rememberTimetableState() + val timetableGridState = rememberTimetableGridState() TimetableGrid( timetable = uiState.timetable, - timetableState = timetableState, + timetableState = timetableGridState, modifier = modifier, contentPadding = PaddingValues(16.dp), ) { timetableItem, isBookmarked -> @@ -119,9 +119,6 @@ fun TimetableGrid( val linePxSize = with(timetableState.density) { TimetableSizes.lineStrokeSize.toPx() } val layoutDirection = LocalLayoutDirection.current - val currentTimeLineColor = MaterialTheme.colorScheme.primary - val currentTimeCircleRadius = - with(timetableState.density) { TimetableSizes.currentTimeCircleRadius.toPx() } LazyLayout( modifier = modifier .padding( @@ -245,7 +242,7 @@ fun TimetableGrid( @Preview @Composable fun TimetablePreview() { - val timetableState = rememberTimetableState() + val timetableState = rememberTimetableGridState() TimetableGrid( modifier = Modifier.fillMaxSize(), timetable = Timetable.fake(), @@ -358,7 +355,7 @@ private data class TimetableLayout( } @Composable -fun rememberTimetableState( +fun rememberTimetableGridState( screenScrollState: ScreenScrollState = rememberScreenScrollState(), screenScaleState: ScreenScaleState = rememberScreenScaleState(), density: Density = LocalDensity.current, @@ -437,26 +434,6 @@ class ScreenScrollState( } } - suspend fun flingYIfPossible() = coroutineScope { - val velocity = velocityTracker.calculateVelocity() - launch { - _scrollY.animateDecay( - velocity.y / 2f, - exponentialDecay(), - ) - } - } - - suspend fun flingXIfPossible() = coroutineScope { - val velocity = velocityTracker.calculateVelocity() - launch { - _scrollX.animateDecay( - velocity.x / 2f, - exponentialDecay(), - ) - } - } - fun updateBounds(maxX: Float, maxY: Float) { _scrollX.updateBounds(maxX, 0f) _scrollY.updateBounds(maxY, 0f) diff --git a/feature/sessions/src/test/java/io/github/droidkaigi/confsched2023/TimetableScreenTest.kt b/feature/sessions/src/test/java/io/github/droidkaigi/confsched2023/TimetableScreenTest.kt index 5c7645279..5bd95fd60 100644 --- a/feature/sessions/src/test/java/io/github/droidkaigi/confsched2023/TimetableScreenTest.kt +++ b/feature/sessions/src/test/java/io/github/droidkaigi/confsched2023/TimetableScreenTest.kt @@ -53,9 +53,9 @@ class TimetableScreenTest { fun checkFavoriteToggleShot() { timetableScreenRobot(robotTestRule) { setupTimetableScreenContent() - clickFirstSessionFavorite() + clickFirstSessionBookmark() checkTimetableListCapture() - clickFirstSessionFavorite() + clickFirstSessionBookmark() checkTimetableListCapture() } } @@ -69,4 +69,25 @@ class TimetableScreenTest { checkTimetableListCapture() } } + + @Test + @Category(ScreenshotTests::class) + fun checkGridShot() { + timetableScreenRobot(robotTestRule) { + setupTimetableScreenContent() + clickTimetableUiTypeChangeButton() + checkTimetableListCapture() + } + } + + @Test + @Category(ScreenshotTests::class) + fun checkGridScrollShot() { + timetableScreenRobot(robotTestRule) { + setupTimetableScreenContent() + clickTimetableUiTypeChangeButton() + scrollTimetable() + checkTimetableListCapture() + } + } }