From 7965fa19da32a94d3e8008f6eb6e6d1268ffe423 Mon Sep 17 00:00:00 2001 From: Sungyong An Date: Sun, 29 Dec 2024 20:52:05 +0900 Subject: [PATCH] Migrate from system toast to snackbar --- .../soup/movie/core/designsystem/Toast.kt | 28 ---- .../feature/detail/impl/DetailContent.kt | 35 ++++- .../feature/detail/impl/DetailEventModel.kt | 27 ---- .../movie/feature/detail/impl/DetailList.kt | 14 +- .../movie/feature/detail/impl/DetailScreen.kt | 9 -- .../feature/detail/impl/DetailViewModel.kt | 18 ++- .../movie/feature/home/impl/HomeNavGraph.kt | 37 ++--- .../movie/feature/home/impl/HomeScreen.kt | 17 +- .../home/impl/favorite/HomeFavoriteScreen.kt | 19 ++- .../movie/feature/search/impl/SearchScreen.kt | 148 ++++++++++-------- 10 files changed, 173 insertions(+), 179 deletions(-) delete mode 100644 core/designsystem/src/main/java/soup/movie/core/designsystem/Toast.kt delete mode 100644 feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailEventModel.kt diff --git a/core/designsystem/src/main/java/soup/movie/core/designsystem/Toast.kt b/core/designsystem/src/main/java/soup/movie/core/designsystem/Toast.kt deleted file mode 100644 index 8b9d11512..000000000 --- a/core/designsystem/src/main/java/soup/movie/core/designsystem/Toast.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2022 SOUP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package soup.movie.core.designsystem - -import android.content.Context -import android.widget.Toast -import androidx.annotation.StringRes - -fun Context.showToast(msg: CharSequence) { - Toast.makeText(this, msg, Toast.LENGTH_SHORT).show() -} - -fun Context.showToast(@StringRes msgId: Int) { - Toast.makeText(this, msgId, Toast.LENGTH_SHORT).show() -} diff --git a/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailContent.kt b/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailContent.kt index 79d9d00ad..82ac32eca 100644 --- a/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailContent.kt +++ b/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailContent.kt @@ -17,12 +17,20 @@ package soup.movie.feature.detail.impl import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Surface +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp +import kotlinx.coroutines.launch +import soup.movie.resources.R @Composable internal fun DetailContent( @@ -32,7 +40,14 @@ internal fun DetailContent( onItemClick: (ContentItemUiModel) -> Unit, modifier: Modifier = Modifier, ) { - Surface(modifier = modifier) { + val snackbarHostState = remember { SnackbarHostState() } + val coroutineScope = rememberCoroutineScope() + Scaffold( + modifier = modifier, + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, + ) { paddingValues -> when (uiModel) { is DetailUiModel.None -> {} is DetailUiModel.Success -> { @@ -57,6 +72,7 @@ internal fun DetailContent( }, items = uiModel.items, onItemClick = { item -> onItemClick(item) }, + modifier = Modifier.padding(paddingValues), ) } is DetailUiModel.Failure -> { @@ -64,9 +80,22 @@ internal fun DetailContent( onRetryClick = { viewModel.onRetryClick() }, - modifier = Modifier.fillMaxSize(), + modifier = Modifier.padding(paddingValues).fillMaxSize(), ) } } } + + val context = LocalContext.current + val showOpenDateAlarmMessage by viewModel.showOpenDateAlarmMessage.collectAsState() + LaunchedEffect(showOpenDateAlarmMessage) { + if (showOpenDateAlarmMessage) { + coroutineScope.launch { + snackbarHostState.showSnackbar( + message = context.getString(R.string.action_toast_opendate_alarm), + ) + viewModel.onOpenDateAlarmMessageShown() + } + } + } } diff --git a/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailEventModel.kt b/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailEventModel.kt deleted file mode 100644 index 1fce56abe..000000000 --- a/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailEventModel.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2021 SOUP - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package soup.movie.feature.detail.impl - -import androidx.annotation.Keep -import androidx.annotation.StringRes - -sealed class UiEvent - -@Keep -class ToastAction( - @StringRes - val resId: Int, -) : UiEvent() diff --git a/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailList.kt b/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailList.kt index 5594f12e6..d7f94bd84 100644 --- a/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailList.kt +++ b/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailList.kt @@ -75,8 +75,10 @@ internal fun DetailList( header: @Composable () -> Unit, items: List, onItemClick: (ContentItemUiModel) -> Unit, + modifier: Modifier = Modifier, ) { LazyColumn( + modifier = modifier, contentPadding = WindowInsets.systemBars.asPaddingValues(), ) { item { @@ -167,7 +169,9 @@ private fun Cgv( modifier = modifier.padding(start = 12.dp, end = 4.dp, bottom = 8.dp), ) { Column( - modifier = Modifier.fillMaxSize().padding(top = 4.dp, bottom = 6.dp), + modifier = Modifier + .fillMaxSize() + .padding(top = 4.dp, bottom = 6.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { AssistChip( @@ -213,7 +217,9 @@ private fun Lotte( modifier = modifier.padding(start = 4.dp, end = 4.dp, bottom = 8.dp), ) { Column( - modifier = Modifier.fillMaxSize().padding(top = 4.dp, bottom = 6.dp), + modifier = Modifier + .fillMaxSize() + .padding(top = 4.dp, bottom = 6.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { AssistChip( @@ -259,7 +265,9 @@ private fun Megabox( modifier = modifier.padding(start = 4.dp, end = 12.dp, bottom = 8.dp), ) { Column( - modifier = Modifier.fillMaxSize().padding(top = 4.dp, bottom = 6.dp), + modifier = Modifier + .fillMaxSize() + .padding(top = 4.dp, bottom = 6.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { AssistChip( diff --git a/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailScreen.kt b/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailScreen.kt index afead133a..0a1a68be9 100644 --- a/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailScreen.kt +++ b/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailScreen.kt @@ -22,7 +22,6 @@ import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -37,7 +36,6 @@ import androidx.compose.ui.text.TextLinkStyles import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.withLink -import soup.movie.core.designsystem.showToast import soup.movie.core.designsystem.theme.MovieTheme import soup.movie.core.external.YouTube import soup.movie.core.external.executeWeb @@ -51,13 +49,6 @@ fun DetailScreen( ) { val context = LocalContext.current val uiModel: DetailUiModel by viewModel.uiModel.collectAsState() - LaunchedEffect(Unit) { - viewModel.uiEvent.collect { event -> - when (event) { - is ToastAction -> context.showToast(event.resId) - } - } - } var showPrivacyDialog by remember { mutableStateOf(false) } DetailContent( diff --git a/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailViewModel.kt b/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailViewModel.kt index 9411e84cd..b4573e2dc 100644 --- a/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailViewModel.kt +++ b/feature/detail/impl/src/main/java/soup/movie/feature/detail/impl/DetailViewModel.kt @@ -20,11 +20,9 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import soup.movie.common.DefaultDispatcher @@ -35,7 +33,6 @@ import soup.movie.domain.movie.yesterday import soup.movie.log.Logger import soup.movie.model.MovieDetailModel import soup.movie.model.OpenDateAlarmModel -import soup.movie.resources.R import javax.inject.Inject @HiltViewModel @@ -53,8 +50,8 @@ class DetailViewModel @Inject constructor( private val _isFavorite = MutableStateFlow(false) val isFavorite: StateFlow = _isFavorite - private val _uiEvent = MutableSharedFlow() - val uiEvent: SharedFlow = _uiEvent.asSharedFlow() + private val _showOpenDateAlarmMessage = MutableStateFlow(false) + val showOpenDateAlarmMessage: StateFlow = _showOpenDateAlarmMessage init { viewModelScope.launch { @@ -179,7 +176,8 @@ class DetailViewModel @Inject constructor( } fun onFavoriteButtonClick(isFavorite: Boolean) { - val movie = (_uiModel.value as? DetailUiModel.Success)?.header?.movie ?: return + val uiModel = _uiModel.value as? DetailUiModel.Success ?: return + val movie = uiModel.header.movie viewModelScope.launch { if (isFavorite) { repository.addFavoriteMovie(movie) @@ -191,7 +189,7 @@ class DetailViewModel @Inject constructor( movie.openDate, ), ) - _uiEvent.emit(ToastAction(R.string.action_toast_opendate_alarm)) + _showOpenDateAlarmMessage.update { true } } } else { repository.removeFavoriteMovie(movie.id) @@ -200,6 +198,10 @@ class DetailViewModel @Inject constructor( } } + fun onOpenDateAlarmMessageShown() { + _showOpenDateAlarmMessage.update { false } + } + fun onRetryClick() { viewModelScope.launch { loadDetail(movieId) diff --git a/feature/home/impl/src/main/java/soup/movie/feature/home/impl/HomeNavGraph.kt b/feature/home/impl/src/main/java/soup/movie/feature/home/impl/HomeNavGraph.kt index 4a90509b6..d74ae6af0 100644 --- a/feature/home/impl/src/main/java/soup/movie/feature/home/impl/HomeNavGraph.kt +++ b/feature/home/impl/src/main/java/soup/movie/feature/home/impl/HomeNavGraph.kt @@ -19,7 +19,6 @@ import androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi import androidx.compose.animation.graphics.res.animatedVectorResource import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter import androidx.compose.animation.graphics.vector.AnimatedImageVector -import androidx.compose.foundation.layout.Box import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold @@ -27,11 +26,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.hilt.navigation.compose.hiltViewModel import soup.movie.core.designsystem.icon.MovieIcons -import soup.movie.core.designsystem.showToast import soup.movie.feature.home.impl.favorite.HomeFavoriteScreen import soup.movie.model.MovieModel import soup.movie.resources.R @@ -51,26 +48,20 @@ fun HomeNavGraph( viewModel.onMainTabSelected(mainTab) }, ) { - Box { - when (currentMainTab) { - MainTabUiModel.Home -> { - HomeScreen( - viewModel = viewModel, - onSearchClick = onSearchClick, - onMovieItemClick = onMovieItemClick, - ) - } - MainTabUiModel.Favorite -> { - val context = LocalContext.current - HomeFavoriteScreen( - viewModel = hiltViewModel(), - onSettingsClick = onSettingsClick, - onItemClick = onMovieItemClick, - onItemLongClick = { - context.showToast(it.title) - }, - ) - } + when (currentMainTab) { + MainTabUiModel.Home -> { + HomeScreen( + viewModel = viewModel, + onSearchClick = onSearchClick, + onMovieItemClick = onMovieItemClick, + ) + } + MainTabUiModel.Favorite -> { + HomeFavoriteScreen( + viewModel = hiltViewModel(), + onSettingsClick = onSettingsClick, + onItemClick = onMovieItemClick, + ) } } } diff --git a/feature/home/impl/src/main/java/soup/movie/feature/home/impl/HomeScreen.kt b/feature/home/impl/src/main/java/soup/movie/feature/home/impl/HomeScreen.kt index 737a80a37..20dbede49 100644 --- a/feature/home/impl/src/main/java/soup/movie/feature/home/impl/HomeScreen.kt +++ b/feature/home/impl/src/main/java/soup/movie/feature/home/impl/HomeScreen.kt @@ -43,13 +43,11 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import kotlinx.coroutines.launch import soup.movie.core.designsystem.icon.MovieIcons -import soup.movie.core.designsystem.showToast import soup.movie.core.designsystem.theme.MovieTheme import soup.movie.feature.home.impl.filter.HomeFilterScreen import soup.movie.feature.home.impl.now.HomeNowList @@ -64,7 +62,6 @@ fun HomeScreen( onSearchClick: () -> Unit, onMovieItemClick: (MovieModel) -> Unit, ) { - val context = LocalContext.current val coroutineScope = rememberCoroutineScope() val selectedTab by viewModel.selectedHomeTab.collectAsState() @@ -160,7 +157,11 @@ fun HomeScreen( ) }, ) { paddingValues -> - Box(modifier = Modifier.fillMaxSize().padding(paddingValues)) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues), + ) { when (selectedTab) { HomeTabUiModel.Now -> HomeNowList( viewModel = hiltViewModel(), @@ -169,7 +170,9 @@ fun HomeScreen( onMovieItemClick(it) }, onItemLongClick = { - context.showToast(it.title) + coroutineScope.launch { + bottomSheetScaffoldState.snackbarHostState.showSnackbar(message = it.title) + } }, ) HomeTabUiModel.Plan -> HomePlanList( @@ -179,7 +182,9 @@ fun HomeScreen( onMovieItemClick(it) }, onItemLongClick = { - context.showToast(it.title) + coroutineScope.launch { + bottomSheetScaffoldState.snackbarHostState.showSnackbar(message = it.title) + } }, ) } diff --git a/feature/home/impl/src/main/java/soup/movie/feature/home/impl/favorite/HomeFavoriteScreen.kt b/feature/home/impl/src/main/java/soup/movie/feature/home/impl/favorite/HomeFavoriteScreen.kt index f0b6ea9b1..c848a4070 100644 --- a/feature/home/impl/src/main/java/soup/movie/feature/home/impl/favorite/HomeFavoriteScreen.kt +++ b/feature/home/impl/src/main/java/soup/movie/feature/home/impl/favorite/HomeFavoriteScreen.kt @@ -25,6 +25,8 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton 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.runtime.Composable @@ -51,8 +53,8 @@ fun HomeFavoriteScreen( state: LazyGridState = rememberLazyGridState(), onSettingsClick: () -> Unit, onItemClick: (MovieModel) -> Unit, - onItemLongClick: (MovieModel) -> Unit, ) { + val snackbarHostState = remember { SnackbarHostState() } val coroutineScope = rememberCoroutineScope() val isTopAtCurrentTab by remember { derivedStateOf { @@ -83,8 +85,15 @@ fun HomeFavoriteScreen( }, ) }, + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, ) { paddingValues -> - Box(modifier = Modifier.fillMaxSize().padding(paddingValues)) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues), + ) { val movies by viewModel.movies.collectAsState() if (movies.isEmpty()) { NoMovieItems(modifier = Modifier.align(Alignment.Center)) @@ -93,7 +102,11 @@ fun HomeFavoriteScreen( state = state, movies = movies, onItemClick = onItemClick, - onLongItemClick = onItemLongClick, + onLongItemClick = { + coroutineScope.launch { + snackbarHostState.showSnackbar(message = it.title) + } + }, ) } } diff --git a/feature/search/impl/src/main/java/soup/movie/feature/search/impl/SearchScreen.kt b/feature/search/impl/src/main/java/soup/movie/feature/search/impl/SearchScreen.kt index e0472b829..71a12b312 100644 --- a/feature/search/impl/src/main/java/soup/movie/feature/search/impl/SearchScreen.kt +++ b/feature/search/impl/src/main/java/soup/movie/feature/search/impl/SearchScreen.kt @@ -16,7 +16,6 @@ package soup.movie.feature.search.impl import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -27,6 +26,8 @@ import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextField @@ -35,19 +36,20 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp +import kotlinx.coroutines.launch import soup.movie.core.designsystem.icon.MovieIcons -import soup.movie.core.designsystem.showToast import soup.movie.core.designsystem.theme.MovieTheme import soup.movie.feature.home.rememberHomeComposableFactory import soup.movie.model.MovieModel @@ -59,13 +61,24 @@ fun SearchScreen( upPress: () -> Unit, onItemClick: (MovieModel) -> Unit, ) { + val snackbarHostState = remember { SnackbarHostState() } + val coroutineScope = rememberCoroutineScope() val factory = rememberHomeComposableFactory() val query by viewModel.query.collectAsState() val uiModel by viewModel.uiModel.collectAsState() - SearchScaffold( - upPress = upPress, - query = query, - onQueryChanged = { viewModel.onQueryChanged(it) }, + + Scaffold( + modifier = Modifier.systemBarsPadding(), + topBar = { + SearchTopBar( + upPress = upPress, + query = query, + onQueryChanged = { viewModel.onQueryChanged(it) }, + ) + }, + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, ) { paddingValues -> Box( modifier = Modifier @@ -75,14 +88,18 @@ fun SearchScreen( if (uiModel.hasNoItem) { factory.NoMovieItems(modifier = Modifier.align(Alignment.Center)) } else { - val context = LocalContext.current + val focusManager = LocalFocusManager.current factory.MovieList( movies = uiModel.movies, onItemClick = { + focusManager.clearFocus() onItemClick(it) }, onLongItemClick = { - context.showToast(it.title) + coroutineScope.launch { + focusManager.clearFocus() + snackbarHostState.showSnackbar(message = it.title) + } }, modifier = Modifier, ) @@ -92,79 +109,72 @@ fun SearchScreen( } @Composable -private fun SearchScaffold( +private fun SearchTopBar( upPress: () -> Unit, query: String, onQueryChanged: (String) -> Unit, - content: @Composable (PaddingValues) -> Unit, + modifier: Modifier = Modifier, ) { - Scaffold( - modifier = Modifier.systemBarsPadding(), - topBar = { - Surface( - modifier = Modifier - .fillMaxWidth() - .height(56.dp), - color = MovieTheme.colorScheme.primary, - ) { - val focusManager = LocalFocusManager.current - val focusRequester = FocusRequester() - LaunchedEffect(Unit) { - focusRequester.requestFocus() - } + Surface( + modifier = modifier + .fillMaxWidth() + .height(56.dp), + color = MovieTheme.colorScheme.primary, + ) { + val focusManager = LocalFocusManager.current + val focusRequester = FocusRequester() + LaunchedEffect(Unit) { + focusRequester.requestFocus() + } - TextField( - value = query, - onValueChange = onQueryChanged, - modifier = Modifier - .fillMaxSize() - .focusRequester(focusRequester), - keyboardOptions = KeyboardOptions( - keyboardType = KeyboardType.Text, - imeAction = ImeAction.Search, - ), - keyboardActions = KeyboardActions( - onSearch = { - focusManager.clearFocus() - }, - ), - singleLine = true, - placeholder = { - Text(stringResource(R.string.search_hint)) - }, - leadingIcon = { - IconButton(onClick = upPress) { - Icon( - MovieIcons.ArrowBack, - contentDescription = null, - ) - } - }, - trailingIcon = { - IconButton(onClick = { onQueryChanged("") }) { - Icon( - MovieIcons.Close, - contentDescription = null, - ) - } - }, - colors = TextFieldDefaults.colors(), - ) - } - }, - ) { paddingValues -> - content(paddingValues) + TextField( + value = query, + onValueChange = onQueryChanged, + modifier = Modifier + .fillMaxSize() + .focusRequester(focusRequester), + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Text, + imeAction = ImeAction.Search, + ), + keyboardActions = KeyboardActions( + onSearch = { + focusManager.clearFocus() + }, + ), + singleLine = true, + placeholder = { + Text(stringResource(R.string.search_hint)) + }, + leadingIcon = { + IconButton(onClick = upPress) { + Icon( + MovieIcons.ArrowBack, + contentDescription = null, + ) + } + }, + trailingIcon = { + IconButton(onClick = { onQueryChanged("") }) { + Icon( + MovieIcons.Close, + contentDescription = null, + ) + } + }, + colors = TextFieldDefaults.colors(), + ) } } @PreviewLightDark @Composable -private fun SearchScaffoldPreview() { +private fun SearchTopBarPreview() { MovieTheme { - SearchScaffold( + SearchTopBar( upPress = {}, query = "", onQueryChanged = {}, - ) {} + ) } }