@@ -29,8 +29,6 @@ import androidx.compose.foundation.layout.Spacer
2929import androidx.compose.foundation.layout.WindowInsets
3030import androidx.compose.foundation.layout.WindowInsetsSides
3131import androidx.compose.foundation.layout.asPaddingValues
32- import androidx.compose.foundation.layout.calculateEndPadding
33- import androidx.compose.foundation.layout.calculateStartPadding
3432import androidx.compose.foundation.layout.only
3533import androidx.compose.foundation.layout.padding
3634import androidx.compose.foundation.layout.safeDrawing
@@ -50,23 +48,25 @@ import androidx.compose.material3.minimumInteractiveComponentSize
5048import androidx.compose.runtime.Composable
5149import androidx.compose.runtime.getValue
5250import androidx.compose.ui.Modifier
51+ import androidx.compose.ui.platform.LocalDensity
5352import androidx.compose.ui.platform.LocalFocusManager
5453import androidx.compose.ui.platform.LocalLayoutDirection
5554import androidx.compose.ui.platform.LocalSoftwareKeyboardController
5655import androidx.compose.ui.res.stringResource
5756import androidx.compose.ui.text.style.TextOverflow
57+ import ovh.plrapps.mapcompose.utils.lerp
5858import ru.spbu.depnav.R
5959import ru.spbu.depnav.ui.theme.DEFAULT_PADDING
6060import ru.spbu.depnav.ui.theme.ON_MAP_SURFACE_ALPHA
6161import ru.spbu.depnav.ui.viewmodel.SearchResults
6262
6363// These are basically copied from SearchBar implementation
64- private val ACTIVATION_ENTER_SPEC = tween<Float >(
64+ private val EXPANSION_ENTER_SPEC = tween<Float >(
6565 durationMillis = 600 ,
6666 delayMillis = 100 ,
6767 easing = CubicBezierEasing (0.05f , 0.7f , 0.1f , 1.0f )
6868)
69- private val ACTIVATION_EXIT_SPEC = tween<Float >(
69+ private val EXPANSION_EXIT_SPEC = tween<Float >(
7070 durationMillis = 350 ,
7171 delayMillis = 100 ,
7272 easing = CubicBezierEasing (0.0f , 1.0f , 0.0f , 1.0f )
@@ -76,106 +76,97 @@ private val ACTIVATION_EXIT_SPEC = tween<Float>(
7676 * Search bar for querying map markers on [ru.spbu.depnav.ui.screen.MapScreen].
7777 */
7878@Composable
79- @Suppress(
80- " LongMethod" , // No point in further shrinking
81- " LongParameterList" // Considered OK for a composable
82- )
79+ @Suppress(" LongParameterList" ) // Considered OK for a composable
8380@OptIn(ExperimentalMaterial3Api ::class )
8481fun MapSearchBar (
8582 query : String ,
8683 onQueryChange : (String ) -> Unit ,
8784 mapTitle : String ,
88- active : Boolean ,
89- onActiveChange : (Boolean ) -> Unit ,
85+ expanded : Boolean ,
86+ onExpandedChange : (Boolean ) -> Unit ,
9087 results : SearchResults ,
9188 onResultClick : (Int ) -> Unit ,
9289 onMenuClick : () -> Unit ,
9390 modifier : Modifier = Modifier
9491) {
95- val activationAnimationProgress by animateFloatAsState(
96- targetValue = if (active ) 1f else 0f ,
97- animationSpec = if (active) ACTIVATION_ENTER_SPEC else ACTIVATION_EXIT_SPEC ,
92+ val expansionAnimationProgress by animateFloatAsState(
93+ targetValue = if (expanded ) 1f else 0f ,
94+ animationSpec = if (expanded) EXPANSION_ENTER_SPEC else EXPANSION_EXIT_SPEC ,
9895 label = " Map search bar activation animation progress"
9996 )
10097
101- val (insetsStartPadding, insetsEndPadding) = with (WindowInsets .safeDrawing.asPaddingValues()) {
102- val layoutDirection = LocalLayoutDirection .current
103- calculateStartPadding(layoutDirection) to calculateEndPadding(layoutDirection)
104- }
105-
106- val outerStartPadding = insetsStartPadding * (1 - activationAnimationProgress)
107- val outerEndPadding = insetsEndPadding * (1 - activationAnimationProgress)
108- val innerStartPadding = insetsStartPadding * activationAnimationProgress
109- val innerEndPadding = insetsEndPadding * activationAnimationProgress
110-
111- val focusManager = LocalFocusManager .current
112-
113- val containerColorAlpha =
114- ON_MAP_SURFACE_ALPHA + (1 - ON_MAP_SURFACE_ALPHA ) * activationAnimationProgress
115-
11698 SearchBar (
117- query = query,
118- onQueryChange = onQueryChange,
119- onSearch = { focusManager.clearFocus() } ,
120- active = active ,
121- onActiveChange = onActiveChange ,
122- modifier = Modifier
123- . run {
124- if (active) padding(start = outerStartPadding, end = outerEndPadding)
125- else windowInsetsPadding( WindowInsets .safeDrawing.only(WindowInsetsSides .Horizontal ))
126- }
127- .then(modifier ),
128- placeholder = {
129- Text (
130- stringResource(R .string.search_on_map, mapTitle),
131- overflow = TextOverflow .Ellipsis ,
132- maxLines = 1
133- )
134- },
135- leadingIcon = {
136- AnimatedLeadingIcon (
137- active ,
138- onMenuClick = onMenuClick,
139- modifier = Modifier .padding(start = innerStartPadding),
140- onNavigateBackClick = { onActiveChange( false ) }
141- )
142- },
143- trailingIcon = {
144- AnimatedTrailingIcon (
145- active ,
146- query.isEmpty(),
147- onClearClick = { onQueryChange( " " ) },
148- modifier = Modifier .padding(end = innerEndPadding)
99+ inputField = {
100+ SearchBarDefaults . InputField (
101+ query = query ,
102+ onQueryChange = onQueryChange ,
103+ onSearch = with ( LocalFocusManager .current) { { clearFocus() } } ,
104+ expanded = expanded,
105+ onExpandedChange = onExpandedChange,
106+ modifier = Modifier .windowInsetsPadding(
107+ WindowInsets .safeDrawing.only(WindowInsetsSides .Horizontal ) *
108+ expansionAnimationProgress
109+ ),
110+ placeholder = {
111+ Text (
112+ stringResource(R .string.search_on_map, mapTitle),
113+ overflow = TextOverflow .Ellipsis ,
114+ maxLines = 1
115+ )
116+ },
117+ leadingIcon = {
118+ AnimatedLeadingIcon (
119+ expanded ,
120+ onMenuClick = onMenuClick,
121+ onNavigateBackClick = { onExpandedChange( false ) }
122+ )
123+ },
124+ trailingIcon = {
125+ AnimatedTrailingIcon (
126+ expanded,
127+ queryEmpty = query.isEmpty() ,
128+ onClearClick = { onQueryChange( " " ) }
129+ )
130+ }
149131 )
150132 },
133+ expanded = expanded,
134+ onExpandedChange = onExpandedChange,
135+ modifier = modifier,
151136 colors = SearchBarDefaults .colors(
152137 containerColor = MaterialTheme .colorScheme.surfaceVariant.copy(
153- alpha = containerColorAlpha
138+ alpha = lerp( ON_MAP_SURFACE_ALPHA , 1f , expansionAnimationProgress)
154139 )
155- )
140+ ),
156141 ) {
157142 val keyboard = LocalSoftwareKeyboardController .current
158143
159144 SearchResultsView (
160145 results,
161146 onScroll = { onTop -> keyboard?.apply { if (onTop) show() else hide() } },
162147 onResultClick = {
163- onActiveChange (false )
148+ onExpandedChange (false )
164149 onResultClick(it)
165150 },
166151 modifier = Modifier
152+ .windowInsetsPadding(WindowInsets .safeDrawing)
167153 .padding(horizontal = DEFAULT_PADDING * 1.5f )
168- .padding(
169- start = innerStartPadding,
170- end = innerEndPadding,
171- bottom = WindowInsets .safeDrawing
172- .asPaddingValues()
173- .calculateBottomPadding()
174- )
175154 )
176155 }
177156}
178157
158+ @Composable
159+ private operator fun WindowInsets.times (num : Float ): WindowInsets {
160+ val paddings = asPaddingValues(LocalDensity .current)
161+ val layoutDirection = LocalLayoutDirection .current
162+ return WindowInsets (
163+ paddings.calculateLeftPadding(layoutDirection) * num,
164+ paddings.calculateTopPadding() * num,
165+ paddings.calculateRightPadding(layoutDirection) * num,
166+ paddings.calculateBottomPadding() * num
167+ )
168+ }
169+
179170@Composable
180171private fun AnimatedLeadingIcon (
181172 searchBarActive : Boolean ,
0 commit comments