11package org.mrlem.composesample.features.library.ui.list
22
3+ import androidx.compose.animation.AnimatedVisibility
4+ import androidx.compose.animation.fadeIn
5+ import androidx.compose.animation.fadeOut
6+ import androidx.compose.foundation.background
37import androidx.compose.foundation.layout.Box
48import androidx.compose.foundation.layout.Column
59import androidx.compose.foundation.layout.fillMaxSize
610import androidx.compose.foundation.layout.fillMaxWidth
11+ import androidx.compose.foundation.layout.height
712import androidx.compose.foundation.layout.padding
813import androidx.compose.foundation.lazy.LazyColumn
914import androidx.compose.foundation.lazy.items
15+ import androidx.compose.foundation.lazy.rememberLazyListState
1016import androidx.compose.foundation.shape.CircleShape
1117import androidx.compose.material.icons.Icons
1218import androidx.compose.material.icons.filled.Add
1319import androidx.compose.material3.FloatingActionButton
1420import androidx.compose.material3.Icon
21+ import androidx.compose.material3.MaterialTheme
1522import androidx.compose.material3.SnackbarHostState
1623import androidx.compose.material3.Surface
24+ import androidx.compose.material3.Text
1725import androidx.compose.material3.TextField
26+ import androidx.compose.material3.TextFieldDefaults
1827import androidx.compose.runtime.Composable
1928import androidx.compose.runtime.LaunchedEffect
2029import androidx.compose.runtime.collectAsState
30+ import androidx.compose.runtime.derivedStateOf
2131import androidx.compose.runtime.getValue
2232import androidx.compose.runtime.mutableStateOf
2333import androidx.compose.runtime.remember
2434import androidx.compose.runtime.setValue
2535import androidx.compose.ui.Alignment
2636import androidx.compose.ui.Modifier
37+ import androidx.compose.ui.graphics.Brush
38+ import androidx.compose.ui.graphics.Color
2739import androidx.compose.ui.text.input.TextFieldValue
2840import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
2941import org.mrlem.android.core.feature.ui.UiModePreviews
@@ -43,6 +55,7 @@ internal fun ListScreen(
4355 when (effect) {
4456 is ListViewEffect .GoToItem ->
4557 onItemSelect(effect.id)
58+
4659 is ListViewEffect .ShowError ->
4760 snackbarHostState.showSnackbar(" Failed to retrieve data" )
4861 }
@@ -53,25 +66,51 @@ internal fun ListScreen(
5366 viewModel.handleRedirections()
5467 }
5568
69+ ListScreen (
70+ state = state,
71+ onAction = viewModel::onAction,
72+ )
73+ }
74+
75+ @Composable
76+ private fun ListScreen (
77+ state : ListViewState ,
78+ onAction : (ListViewAction ) -> Unit ,
79+ ) {
5680 Column {
5781 var fieldValue by remember {
5882 mutableStateOf(TextFieldValue (state.filter))
5983 }
84+
6085 TextField (
6186 value = fieldValue,
87+ singleLine = true ,
6288 onValueChange = {
6389 fieldValue = it
64- viewModel. onAction(ListViewAction .FilterChange (it.text))
90+ onAction(ListViewAction .FilterChange (it.text))
6591 },
92+ shape = MaterialTheme .shapes.medium,
93+ colors = TextFieldDefaults .colors(
94+ focusedIndicatorColor = Color .Transparent ,
95+ unfocusedIndicatorColor = Color .Transparent ,
96+ disabledIndicatorColor = Color .Transparent ,
97+ errorIndicatorColor = Color .Transparent ,
98+ ),
99+ placeholder = { Text (" Filter articles" ) },
66100 modifier = Modifier
67- .fillMaxWidth(),
101+ .fillMaxWidth()
102+ .padding(
103+ start = Theme .size.medium,
104+ top = Theme .size.medium,
105+ end = Theme .size.medium,
106+ ),
68107 )
69108
70109 List (
71110 state = state,
72111 modifier = Modifier
73112 .fillMaxSize(),
74- onAction = viewModel:: onAction,
113+ onAction = onAction,
75114 )
76115 }
77116}
@@ -85,14 +124,47 @@ private fun List(
85124 Box (
86125 modifier = modifier,
87126 ) {
88- LazyColumn (
127+ val listState = rememberLazyListState()
128+
129+ val showShadow by remember {
130+ derivedStateOf { listState.canScrollBackward }
131+ }
132+
133+ Box (
89134 modifier = Modifier
90- .fillMaxSize (),
135+ .fillMaxWidth (),
91136 ) {
92- items(state.items) {
93- ListItem (
94- viewState = it,
95- onAction = onAction,
137+ LazyColumn (
138+ state = listState,
139+ modifier = Modifier
140+ .fillMaxSize(),
141+ ) {
142+ items(state.items) {
143+ ListItem (
144+ viewState = it,
145+ onAction = onAction,
146+ )
147+ }
148+ }
149+
150+ AnimatedVisibility (
151+ visible = showShadow,
152+ enter = fadeIn(),
153+ exit = fadeOut(),
154+ modifier = Modifier .align(Alignment .TopCenter ),
155+ ) {
156+ Box (
157+ modifier = Modifier
158+ .fillMaxWidth()
159+ .height(Theme .size.medium)
160+ .background(
161+ brush = Brush .verticalGradient(
162+ colors = listOf (
163+ MaterialTheme .colorScheme.background,
164+ Color .Transparent ,
165+ ),
166+ ),
167+ ),
96168 )
97169 }
98170 }
@@ -102,7 +174,7 @@ private fun List(
102174 shape = CircleShape ,
103175 modifier = Modifier
104176 .padding(Theme .size.medium)
105- .align(Alignment .TopEnd ),
177+ .align(Alignment .BottomEnd ),
106178 ) {
107179 Icon (imageVector = Icons .Filled .Add , contentDescription = " Import random bookmark" )
108180 }
@@ -114,7 +186,7 @@ private fun List(
114186private fun Preview () {
115187 Theme {
116188 Surface {
117- List (
189+ ListScreen (
118190 state = ListViewState (
119191 items = listOf (
120192 ListItemViewState (
@@ -128,6 +200,7 @@ private fun Preview() {
128200 ),
129201 ),
130202 ),
203+ onAction = {},
131204 )
132205 }
133206 }
0 commit comments