-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4899 from sjudd:compose_gallery_sample
PiperOrigin-RevId: 476430507
- Loading branch information
Showing
4 changed files
with
149 additions
and
197 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
120 changes: 85 additions & 35 deletions
120
...les/gallery/src/main/java/com/bumptech/glide/samples/gallery/HorizontalGalleryFragment.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,101 @@ | ||
package com.bumptech.glide.samples.gallery | ||
|
||
import android.os.Bundle | ||
import androidx.fragment.app.Fragment | ||
import android.view.LayoutInflater | ||
import android.view.View | ||
import android.view.ViewGroup | ||
import androidx.fragment.app.Fragment | ||
import androidx.compose.foundation.layout.Arrangement | ||
import androidx.compose.foundation.lazy.LazyRow | ||
import androidx.compose.foundation.lazy.items | ||
import androidx.compose.foundation.lazy.rememberLazyListState | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.collectAsState | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.geometry.Size | ||
import androidx.compose.ui.platform.ComposeView | ||
import androidx.compose.ui.platform.LocalContext | ||
import androidx.compose.ui.unit.dp | ||
import androidx.fragment.app.viewModels | ||
import androidx.lifecycle.Lifecycle | ||
import androidx.lifecycle.lifecycleScope | ||
import androidx.lifecycle.repeatOnLifecycle | ||
import androidx.recyclerview.widget.RecyclerView | ||
import androidx.recyclerview.widget.GridLayoutManager | ||
import com.bumptech.glide.Glide | ||
import com.bumptech.glide.integration.recyclerview.RecyclerViewPreloader | ||
import kotlinx.coroutines.launch | ||
import com.bumptech.glide.RequestManager | ||
import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi | ||
import com.bumptech.glide.integration.compose.GlideImage | ||
import com.bumptech.glide.integration.compose.GlideLazyListPreloader | ||
import com.bumptech.glide.signature.MediaStoreSignature | ||
|
||
/** Displays media store data in a recycler view. */ | ||
/** Displays media store data in a recycler view. */ | ||
@OptIn(ExperimentalGlideComposeApi::class) | ||
class HorizontalGalleryFragment : Fragment() { | ||
private lateinit var adapter: RecyclerAdapter | ||
private lateinit var recyclerView: RecyclerView | ||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
|
||
override fun onCreateView( | ||
inflater: LayoutInflater, | ||
container: ViewGroup?, | ||
savedInstanceState: Bundle?, | ||
): View { | ||
val galleryViewModel: GalleryViewModel by viewModels() | ||
lifecycleScope.launch { | ||
repeatOnLifecycle(Lifecycle.State.STARTED) { | ||
galleryViewModel.mediaStoreData.collect { data -> | ||
adapter.setData(data) | ||
} | ||
return ComposeView(requireContext()).apply { | ||
setContent { LoadableDeviceMedia(galleryViewModel) } | ||
} | ||
} | ||
|
||
@Composable | ||
fun LoadableDeviceMedia(viewModel: GalleryViewModel) { | ||
val mediaStoreData = viewModel.mediaStoreData.collectAsState() | ||
DeviceMedia(mediaStoreData.value) | ||
} | ||
|
||
@Composable | ||
fun DeviceMedia(mediaStoreData: List<MediaStoreData>) { | ||
val state = rememberLazyListState() | ||
val requestManager = rememberRequestManager() | ||
LazyRow(horizontalArrangement = Arrangement.spacedBy(10.dp), state = state) { | ||
items(mediaStoreData) { mediaStoreItem -> | ||
MediaStoreView(mediaStoreItem, requestManager, Modifier.fillParentMaxSize()) | ||
} | ||
} | ||
|
||
GlideLazyListPreloader( | ||
state = state, | ||
data = mediaStoreData, | ||
size = THUMBNAIL_SIZE, | ||
numberOfItemsToPreload = 15, | ||
fixedVisibleItemCount = 2, | ||
) { item, requestBuilder -> | ||
requestBuilder.load(item.uri).signature(item.signature()) | ||
} | ||
} | ||
|
||
override fun onCreateView( | ||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, | ||
): View? { | ||
val result = inflater.inflate(R.layout.recycler_view, container, false) | ||
recyclerView = result.findViewById<View>(R.id.recycler_view) as RecyclerView | ||
val layoutManager = GridLayoutManager(activity, 1) | ||
layoutManager.orientation = RecyclerView.HORIZONTAL | ||
recyclerView.layoutManager = layoutManager | ||
recyclerView.setHasFixedSize(true) | ||
|
||
val glideRequests = Glide.with(this) | ||
adapter = RecyclerAdapter(requireContext(), glideRequests) | ||
val preloader = RecyclerViewPreloader(glideRequests, adapter, adapter, 3) | ||
recyclerView.addOnScrollListener(preloader) | ||
recyclerView.adapter = adapter | ||
return result | ||
@Composable | ||
private fun rememberRequestManager() = | ||
LocalContext.current.let { remember(it) { Glide.with(it) } } | ||
|
||
private fun MediaStoreData.signature() = MediaStoreSignature(mimeType, dateModified, orientation) | ||
|
||
@Composable | ||
fun MediaStoreView(item: MediaStoreData, requestManager: RequestManager, modifier: Modifier) { | ||
val signature = item.signature() | ||
|
||
GlideImage( | ||
model = item.uri, | ||
contentDescription = item.displayName, | ||
modifier = modifier, | ||
) { | ||
it | ||
.thumbnail( | ||
requestManager | ||
.asDrawable() | ||
.load(item.uri) | ||
.signature(signature) | ||
.override(THUMBNAIL_DIMENSION) | ||
) | ||
.signature(signature) | ||
} | ||
} | ||
|
||
companion object { | ||
private const val THUMBNAIL_DIMENSION = 50 | ||
private val THUMBNAIL_SIZE = Size(THUMBNAIL_DIMENSION.toFloat(), THUMBNAIL_DIMENSION.toFloat()) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.