From 756b070bfc4a1f407b62100a6bfc6e22d3717b2a Mon Sep 17 00:00:00 2001 From: michaelbel Date: Tue, 21 Nov 2023 11:30:58 +0300 Subject: [PATCH] Update project --- .../movies/gallery/ui/GalleryLoading.kt | 36 +++ .../movies/gallery/ui/GalleryScreenContent.kt | 291 +++++++++--------- 2 files changed, 185 insertions(+), 142 deletions(-) create mode 100644 feature/gallery-impl/src/main/kotlin/org/michaelbel/movies/gallery/ui/GalleryLoading.kt diff --git a/feature/gallery-impl/src/main/kotlin/org/michaelbel/movies/gallery/ui/GalleryLoading.kt b/feature/gallery-impl/src/main/kotlin/org/michaelbel/movies/gallery/ui/GalleryLoading.kt new file mode 100644 index 000000000..d29b01a62 --- /dev/null +++ b/feature/gallery-impl/src/main/kotlin/org/michaelbel/movies/gallery/ui/GalleryLoading.kt @@ -0,0 +1,36 @@ +package org.michaelbel.movies.gallery.ui + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.LinearProgressIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import org.michaelbel.movies.ui.preview.DevicePreviews +import org.michaelbel.movies.ui.theme.MoviesTheme + +@Composable +fun GalleryLoading( + modifier: Modifier = Modifier +) { + Box( + modifier = modifier, + contentAlignment = Alignment.Center + ) { + LinearProgressIndicator( + modifier = Modifier, + trackColor = MaterialTheme.colorScheme.inversePrimary + ) + } +} + +@Composable +@DevicePreviews +private fun GalleryLoadingPreview() { + MoviesTheme { + GalleryLoading( + modifier = Modifier.fillMaxSize() + ) + } +} \ No newline at end of file diff --git a/feature/gallery-impl/src/main/kotlin/org/michaelbel/movies/gallery/ui/GalleryScreenContent.kt b/feature/gallery-impl/src/main/kotlin/org/michaelbel/movies/gallery/ui/GalleryScreenContent.kt index 87f0346ac..5a4262b82 100644 --- a/feature/gallery-impl/src/main/kotlin/org/michaelbel/movies/gallery/ui/GalleryScreenContent.kt +++ b/feature/gallery-impl/src/main/kotlin/org/michaelbel/movies/gallery/ui/GalleryScreenContent.kt @@ -150,176 +150,183 @@ private fun GalleryScreenContent( }, containerColor = MaterialTheme.colorScheme.primaryContainer ) { paddingValues -> - ConstraintLayout( - modifier = Modifier.fillMaxSize() - ) { - val (pager, backIcon, title) = createRefs() + when { + movieImages.isEmpty() -> { + GalleryLoading( + modifier = Modifier.fillMaxSize() + ) + } + else -> { + ConstraintLayout( + modifier = Modifier.fillMaxSize() + ) { + val (pager, backIcon, title) = createRefs() - val initialPage = 0 - val pagerState = rememberPagerState( - initialPage = initialPage, - initialPageOffsetFraction = 0F, - pageCount = { movieImages.size } - ) + val initialPage = 0 + val pagerState = rememberPagerState( + initialPage = initialPage, + initialPageOffsetFraction = 0F, + pageCount = { movieImages.size } + ) - var currentPage: Int by remember { mutableStateOf(0) } - LaunchedEffect(pagerState) { - snapshotFlow { pagerState.currentPage }.collect { page -> - if (currentPage != page) { - hapticFeedback.performHapticFeedback(hapticFeedbackType = HapticFeedbackType.LongPress) - currentPage = page + var currentPage: Int by remember { mutableStateOf(0) } + LaunchedEffect(pagerState) { + snapshotFlow { pagerState.currentPage }.collect { page -> + if (currentPage != page) { + hapticFeedback.performHapticFeedback(hapticFeedbackType = HapticFeedbackType.LongPress) + currentPage = page + } + } } - } - } - LoopHorizontalPager( - pagerState = pagerState, - modifier = Modifier.constrainAs(pager) { - width = Dimension.fillToConstraints - height = Dimension.wrapContent - start.linkTo(parent.start) - top.linkTo(parent.top) - end.linkTo(parent.end) - bottom.linkTo(parent.bottom) - } - ) { page -> - currentPage = page + LoopHorizontalPager( + pagerState = pagerState, + modifier = Modifier.constrainAs(pager) { + width = Dimension.fillToConstraints + height = Dimension.wrapContent + start.linkTo(parent.start) + top.linkTo(parent.top) + end.linkTo(parent.end) + bottom.linkTo(parent.bottom) + } + ) { page -> + currentPage = page - val imageDb: ImageDb = movieImages[page] - var imageDiskCacheKey: String? by remember { mutableStateOf(null) } + val imageDb: ImageDb = movieImages[page] + var imageDiskCacheKey: String? by remember { mutableStateOf(null) } - var image: String by remember { mutableStateOf("") } - image = imageDb.original + var image: String by remember { mutableStateOf("") } + image = imageDb.original - var loading: Boolean by remember { mutableStateOf(true) } + var loading: Boolean by remember { mutableStateOf(true) } - ConstraintLayout( - modifier = Modifier.fillMaxSize() - ) { - val (asyncImage, progressBar, downloadIcon) = createRefs() + ConstraintLayout( + modifier = Modifier.fillMaxSize() + ) { + val (asyncImage, progressBar, downloadIcon) = createRefs() - val zoomState = rememberZoomState() + val zoomState = rememberZoomState() - AsyncImage( - model = ImageRequest.Builder(context) - .data(image) - .crossfade(true) - .placeholderMemoryCacheKey(imageDiskCacheKey) - .build(), - contentDescription = null, - modifier = Modifier - .constrainAs(asyncImage) { - width = Dimension.fillToConstraints - height = Dimension.fillToConstraints - start.linkTo(parent.start) - top.linkTo(parent.top) - end.linkTo(parent.end) - bottom.linkTo(parent.bottom) + AsyncImage( + model = ImageRequest.Builder(context) + .data(image) + .crossfade(true) + .placeholderMemoryCacheKey(imageDiskCacheKey) + .build(), + contentDescription = null, + modifier = Modifier + .constrainAs(asyncImage) { + width = Dimension.fillToConstraints + height = Dimension.fillToConstraints + start.linkTo(parent.start) + top.linkTo(parent.top) + end.linkTo(parent.end) + bottom.linkTo(parent.bottom) + } + .zoomable(zoomState), + transform = { state -> + loading = state is AsyncImagePainter.State.Loading + + if (state is AsyncImagePainter.State.Success) { + zoomState.setContentSize(state.painter.intrinsicSize) + imageDiskCacheKey = state.result.diskCacheKey + if (image.isNotOriginal) { + image = imageDb.original + } + } + + state + }, + contentScale = ContentScale.Fit + ) + + if (loading) { + LinearProgressIndicator( + modifier = Modifier + .constrainAs(progressBar) { + width = Dimension.wrapContent + height = Dimension.wrapContent + start.linkTo(parent.start) + top.linkTo(parent.top) + end.linkTo(parent.end) + bottom.linkTo(parent.bottom) + } + .zoomable(zoomState), + trackColor = MaterialTheme.colorScheme.inversePrimary + ) } - .zoomable(zoomState), - transform = { state -> - loading = state is AsyncImagePainter.State.Loading - if (state is AsyncImagePainter.State.Success) { - zoomState.setContentSize(state.painter.intrinsicSize) - imageDiskCacheKey = state.result.diskCacheKey - if (image.isNotOriginal) { - image = imageDb.original + AnimatedVisibility( + visible = !loading, + modifier = Modifier + .constrainAs(downloadIcon) { + width = Dimension.wrapContent + height = Dimension.wrapContent + end.linkTo(parent.end, 4.dp) + top.linkTo(parent.top, 8.dp) + } + .statusBarsPadding(), + enter = fadeIn() + ) { + IconButton( + onClick = { onDownloadClick(imageDb) }, + modifier = Modifier.windowInsetsPadding(displayCutoutWindowInsets) + ) { + Image( + imageVector = MoviesIcons.FileDownload, + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onPrimaryContainer) + ) } } - state - }, - contentScale = ContentScale.Fit - ) - - if (loading) { - LinearProgressIndicator( - modifier = Modifier - .constrainAs(progressBar) { - width = Dimension.wrapContent - height = Dimension.wrapContent - start.linkTo(parent.start) - top.linkTo(parent.top) - end.linkTo(parent.end) - bottom.linkTo(parent.bottom) - } - .zoomable(zoomState), - trackColor = MaterialTheme.colorScheme.inversePrimary - ) + BackHandler(zoomState.isScaled) { + coroutineScope.launch { zoomState.reset() } + } + } } - AnimatedVisibility( - visible = !loading, + IconButton( + onClick = onBackClick, modifier = Modifier - .constrainAs(downloadIcon) { + .constrainAs(backIcon) { width = Dimension.wrapContent height = Dimension.wrapContent - end.linkTo(parent.end, 4.dp) + start.linkTo(parent.start, 4.dp) top.linkTo(parent.top, 8.dp) } - .statusBarsPadding(), - enter = fadeIn() + .statusBarsPadding() + .windowInsetsPadding(displayCutoutWindowInsets) ) { - IconButton( - onClick = { onDownloadClick(imageDb) }, - modifier = Modifier.windowInsetsPadding(displayCutoutWindowInsets) - ) { - Image( - imageVector = MoviesIcons.FileDownload, - contentDescription = null, - colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onPrimaryContainer) - ) - } + Image( + imageVector = MoviesIcons.ArrowBack, + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onPrimaryContainer) + ) } - BackHandler(zoomState.isScaled) { - coroutineScope.launch { zoomState.reset() } - } + Text( + text = "", + modifier = Modifier + .constrainAs(title) { + width = Dimension.wrapContent + height = Dimension.wrapContent + start.linkTo(backIcon.end, 4.dp) + top.linkTo(backIcon.top) + end.linkTo(parent.end, 4.dp) + bottom.linkTo(backIcon.bottom) + } + .statusBarsPadding(), + overflow = TextOverflow.Ellipsis, + maxLines = 1, + textAlign = TextAlign.Start, + style = MaterialTheme.typography.titleLarge.copy( + color = MaterialTheme.colorScheme.onPrimaryContainer + ) + ) } } - - IconButton( - onClick = onBackClick, - modifier = Modifier - .constrainAs(backIcon) { - width = Dimension.wrapContent - height = Dimension.wrapContent - start.linkTo(parent.start, 4.dp) - top.linkTo(parent.top, 8.dp) - } - .statusBarsPadding() - .windowInsetsPadding(displayCutoutWindowInsets) - ) { - Image( - imageVector = MoviesIcons.ArrowBack, - contentDescription = null, - colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onPrimaryContainer) - ) - } - - Text( - text = "", - modifier = Modifier - .constrainAs(title) { - width = Dimension.wrapContent - height = Dimension.wrapContent - start.linkTo(backIcon.end, 4.dp) - top.linkTo(backIcon.top) - end.linkTo(parent.end, 4.dp) - bottom.linkTo(backIcon.bottom) - } - .statusBarsPadding(), - overflow = TextOverflow.Ellipsis, - maxLines = 1, - textAlign = TextAlign.Start, - style = MaterialTheme.typography.titleLarge.copy( - color = MaterialTheme.colorScheme.onPrimaryContainer - ) - ) } - - paddingValues.toString() } }