@@ -52,11 +52,16 @@ import androidx.core.view.WindowInsetsCompat
5252import androidx.core.view.WindowInsetsControllerCompat
5353import androidx.navigation3.runtime.NavKey
5454import coil3.EventListener
55+ import coil3.ImageLoader
5556import coil3.compose.AsyncImagePainter
5657import coil3.compose.rememberAsyncImagePainter
5758import coil3.decode.Decoder
59+ import coil3.disk.DiskCache
5860import coil3.fetch.Fetcher
61+ import coil3.gif.AnimatedImageDecoder
62+ import coil3.gif.GifDecoder
5963import coil3.imageLoader
64+ import coil3.network.okhttp.OkHttpNetworkFetcherFactory
6065import coil3.request.CachePolicy
6166import coil3.request.ErrorResult
6267import coil3.request.ImageRequest
@@ -68,14 +73,21 @@ import kotlinx.coroutines.awaitAll
6873import kotlinx.coroutines.flow.MutableStateFlow
6974import kotlinx.serialization.Serializable
7075import li.songe.gkd.MainActivity
76+ import li.songe.gkd.app
7177import li.songe.gkd.ui.component.PerfIcon
7278import li.songe.gkd.ui.component.PerfIconButton
7379import li.songe.gkd.ui.component.PerfTopAppBar
7480import li.songe.gkd.ui.share.LocalMainViewModel
81+ import li.songe.gkd.util.AndroidTarget
82+ import li.songe.gkd.util.coilCacheDir
7583import li.songe.gkd.util.throttle
7684import me.saket.telephoto.zoomable.ZoomableContentLocation
7785import me.saket.telephoto.zoomable.rememberZoomableState
7886import me.saket.telephoto.zoomable.zoomable
87+ import okhttp3.OkHttpClient
88+ import okio.Path.Companion.toOkioPath
89+ import kotlin.time.Duration.Companion.seconds
90+ import kotlin.time.toJavaDuration
7991
8092@Serializable
8193data class ImagePreviewItem (
@@ -92,21 +104,45 @@ data class ImagePreviewRoute(
92104 val items : List <ImagePreviewItem > = emptyList(),
93105) : NavKey
94106
107+ private val imageLoader by lazy {
108+ ImageLoader .Builder (app)
109+ .diskCache {
110+ DiskCache .Builder ()
111+ .directory(coilCacheDir.toOkioPath())
112+ .maxSizePercent(0.1 )
113+ .build()
114+ }
115+ .components {
116+ if (AndroidTarget .P ) {
117+ add(AnimatedImageDecoder .Factory ())
118+ } else {
119+ add(GifDecoder .Factory ())
120+ }
121+ add(
122+ OkHttpNetworkFetcherFactory (
123+ callFactory = {
124+ OkHttpClient .Builder ()
125+ .connectTimeout(30 .seconds.toJavaDuration())
126+ .readTimeout(30 .seconds.toJavaDuration())
127+ .writeTimeout(30 .seconds.toJavaDuration())
128+ .build()
129+ }
130+ ))
131+ }
132+ .build()
133+ }
134+
95135@Composable
96136fun ImagePreviewPage (route : ImagePreviewRoute ) {
97137 val mainVm = LocalMainViewModel .current
98138 val context = LocalActivity .current as MainActivity
99- val imageLoader = context.imageLoader
100139 var showBars by remember { mutableStateOf(true ) }
101140
102141 // 路由同时兼容旧的 uri/uris 和新的 items,预览页内部统一按图片项处理。
103- val previewItems = remember(route.uri, route.uris, route.items ) {
142+ val previewItems = remember(route) {
104143 when {
105144 route.items.isNotEmpty() -> route.items
106- route.uris.isNotEmpty() -> route.uris.map { uri ->
107- ImagePreviewItem (uri = uri)
108- }
109-
145+ route.uris.isNotEmpty() -> route.uris.map { ImagePreviewItem (it) }
110146 route.uri != null -> listOf (ImagePreviewItem (uri = route.uri))
111147 else -> emptyList()
112148 }
0 commit comments