@@ -15,6 +15,8 @@ import androidx.compose.foundation.pager.rememberPagerState
1515import androidx.compose.foundation.shape.CircleShape
1616import androidx.compose.foundation.shape.RoundedCornerShape
1717import androidx.compose.runtime.Composable
18+ import androidx.compose.runtime.CompositionLocalProvider
19+ import androidx.compose.runtime.LaunchedEffect
1820import androidx.compose.ui.Alignment
1921import androidx.compose.ui.Modifier
2022import androidx.compose.ui.draw.BlurredEdgeTreatment.Companion.Unbounded
@@ -23,7 +25,9 @@ import androidx.compose.ui.draw.clip
2325import androidx.compose.ui.draw.shadow
2426import androidx.compose.ui.graphics.graphicsLayer
2527import androidx.compose.ui.layout.ContentScale
28+ import androidx.compose.ui.platform.LocalLayoutDirection
2629import androidx.compose.ui.tooling.preview.Preview
30+ import androidx.compose.ui.unit.LayoutDirection
2731import androidx.compose.ui.unit.dp
2832import androidx.compose.ui.util.lerp
2933import androidx.compose.ui.zIndex
@@ -32,6 +36,7 @@ import com.madrid.detectImageContent.FilteredImage
3236import com.madrid.presentation.viewModel.homeViewModel.CategoryUiState
3337import com.madrid.presentation.viewModel.shared.MediaType
3438import com.madrid.presentation.viewModel.shared.MediaUiState
39+ import kotlinx.coroutines.delay
3540import kotlin.math.absoluteValue
3641
3742@Composable
@@ -43,11 +48,25 @@ fun MovioPager(
4348 onClickMediaButton : (Int ) -> Unit = {},
4449) {
4550 if (medias.isNotEmpty()) {
51+ val currentLayoutDirection = LocalLayoutDirection .current
52+ val isRtl = currentLayoutDirection == LayoutDirection .Rtl
4653 val pagerState = rememberPagerState(
47- initialPage = medias.size / 2 ,
54+ initialPage = if (isRtl) medias.size - 1 else 0 ,
4855 pageCount = { medias.size }
4956 )
5057
58+ LaunchedEffect (medias) {
59+ while (true ) {
60+ delay(6000 )
61+ val nextPage = if (isRtl) {
62+ if (pagerState.currentPage == 0 ) medias.size - 1 else pagerState.currentPage - 1
63+ } else {
64+ (pagerState.currentPage + 1 ) % medias.size
65+ }
66+ pagerState.animateScrollToPage(nextPage)
67+ }
68+ }
69+
5170 Box (
5271 modifier = modifier
5372 .fillMaxWidth()
@@ -68,87 +87,108 @@ fun MovioPager(
6887 modifier = Modifier .fillMaxWidth(),
6988 horizontalAlignment = Alignment .CenterHorizontally
7089 ) {
90+ CompositionLocalProvider (LocalLayoutDirection provides LayoutDirection .Ltr ) {
91+ HorizontalPager (
92+ modifier = Modifier .fillMaxWidth(),
93+ pageSpacing = (- 240 ).dp,
94+ state = pagerState,
95+ verticalAlignment = Alignment .CenterVertically ,
96+ ) { page ->
97+ val pageOffset =
98+ ((pagerState.currentPage - page) + pagerState.currentPageOffsetFraction)
7199
72- HorizontalPager (
73- modifier = Modifier .fillMaxWidth(),
74- pageSpacing = (- 240 ).dp,
75- state = pagerState,
76- verticalAlignment = Alignment .CenterVertically ,
77- ) { page ->
78- val pageOffset =
79- ((pagerState.currentPage - page) + pagerState.currentPageOffsetFraction)
100+ val absOffset = pageOffset.absoluteValue
80101
81- val absOffset = pageOffset.absoluteValue
102+ val scale = lerp(0.7f , 1f , 1f - absOffset.coerceIn(0f , 1f ))
103+ val rotation =
104+ lerp(
105+ 20f ,
106+ 0f ,
107+ 1f - absOffset.coerceIn(0f , 1f )
108+ ) * if (pageOffset < 0 ) 1f else - 1f
109+ val alphaa = lerp(0.4f , 1f , 1f - absOffset.coerceIn(0f , 1f ))
110+ val zIndex = if (page == pagerState.currentPage) {
111+ medias.size.toFloat()
112+ } else {
113+ medias.size - absOffset
114+ }
82115
83- val scale = lerp(0.7f , 1f , 1f - absOffset.coerceIn(0f , 1f ))
84- val rotation =
85- lerp(
86- 20f ,
87- 0f ,
88- 1f - absOffset.coerceIn(0f , 1f )
89- ) * if (pageOffset < 0 ) 1f else - 1f
90- val alphaa = lerp(0.4f , 1f , 1f - absOffset.coerceIn(0f , 1f ))
91- val zIndex = if (page == pagerState.currentPage) {
92- medias.size.toFloat()
93- } else {
94- medias.size - absOffset
95- }
96-
97- Box (
98- modifier = Modifier
99- .fillMaxWidth()
100- .then(
101- if (pagerState.currentPage == page) Modifier .zIndex(1f ) else Modifier
102- ),
103- contentAlignment = Alignment .Center
104- ) {
105- MovieHomeCard (
116+ Box (
106117 modifier = Modifier
107- .graphicsLayer {
108- scaleX = scale
109- scaleY = scale
110- rotationZ = rotation
111- alpha = alphaa
112- cameraDistance = 12 * density
113- }
114- .clip(RoundedCornerShape (8 .dp))
115- .size(width = 200 .dp, height = 260 .dp),
116- movieId = medias[page].imageUrl,
117- name = medias[page].title,
118- genres = medias[page].category.map { it.name },
119- onClick = { onClickMediaButton(page) },
120- )
118+ .fillMaxWidth()
119+ .then(
120+ if (pagerState.currentPage == page) Modifier .zIndex(1f ) else Modifier
121+ ),
122+ contentAlignment = Alignment .Center
123+ ) {
124+ MovieHomeCard (
125+ modifier = Modifier
126+ .graphicsLayer {
127+ scaleX = scale
128+ scaleY = scale
129+ rotationZ = rotation
130+ alpha = alphaa
131+ cameraDistance = 12 * density
132+ }
133+ .clip(RoundedCornerShape (8 .dp))
134+ .size(width = 200 .dp, height = 260 .dp),
135+ movieId = medias[page].imageUrl,
136+ name = medias[page].title,
137+ genres = medias[page].category.map { it.name },
138+ onClick = { onClickMediaButton(page) },
139+ )
140+ }
121141 }
122142 }
123143
124144 Spacer (modifier = Modifier .height(16 .dp))
125145
126- Row (
127- horizontalArrangement = Arrangement .Center ,
128- verticalAlignment = Alignment .CenterVertically ,
129- ) {
130- repeat(medias.size) { index ->
131- val isSelected = pagerState.currentPage == index
132- Box (
133- modifier = Modifier
134- .padding(horizontal = 4 .dp)
135- .size(if (isSelected) 15 .dp else 5 .dp, 5 .dp)
136- .clip(if (isSelected) RoundedCornerShape (50 ) else CircleShape )
137- .background(
138- if (isSelected)
139- Theme .color.surfaces.onSurfaceAt1
140- else
141- Theme .color.surfaces.onSurfaceAt2
142- )
143- )
144- }
145- }
146- Spacer (modifier = Modifier .height(4 .dp))
146+ MovioPagerIndicator (
147+ pageCount = medias.size,
148+ currentPage = pagerState.currentPage,
149+ isRtl = isRtl,
150+ modifier = Modifier .padding(bottom = 4 .dp)
151+ )
147152 }
148153 }
149154 }
155+
156+
150157}
151158
159+ @Composable
160+ private fun MovioPagerIndicator (
161+ pageCount : Int ,
162+ currentPage : Int ,
163+ isRtl : Boolean ,
164+ modifier : Modifier = Modifier
165+ ) {
166+ CompositionLocalProvider (LocalLayoutDirection provides LayoutDirection .Ltr ) {
167+ Row (
168+ horizontalArrangement = Arrangement .Center ,
169+ verticalAlignment = Alignment .CenterVertically ,
170+ modifier = modifier
171+ ) {
172+ val indicatorRange =
173+ if (isRtl) (pageCount - 1 ) downTo 0 else 0 until pageCount
174+ repeat(pageCount) { index ->
175+ val isSelected = currentPage == index
176+ Box (
177+ modifier = Modifier
178+ .padding(horizontal = 4 .dp)
179+ .size(if (isSelected) 15 .dp else 5 .dp, 5 .dp)
180+ .clip(if (isSelected) RoundedCornerShape (50 ) else CircleShape )
181+ .background(
182+ if (isSelected)
183+ Theme .color.surfaces.onSurfaceAt1
184+ else
185+ Theme .color.surfaces.onSurfaceAt2
186+ )
187+ )
188+ }
189+ }
190+ }
191+ }
152192@Preview(showBackground = true , showSystemUi = true )
153193@Composable
154194fun MovioSliderPreview () {
0 commit comments