mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-03-17 13:21:50 +01:00
Caches video and image aspect ratios to recompose with the correct size
This commit is contained in:
parent
4d4c7d5b72
commit
311964ce33
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.model
|
||||
|
||||
import android.util.LruCache
|
||||
|
||||
object MediaAspectRatioCache {
|
||||
val mediaAspectRatioCacheByUrl = LruCache<String, Float>(1000)
|
||||
|
||||
fun get(url: String) = mediaAspectRatioCacheByUrl.get(url)
|
||||
|
||||
fun add(
|
||||
url: String,
|
||||
width: Int,
|
||||
height: Int,
|
||||
) {
|
||||
if (height > 1) {
|
||||
mediaAspectRatioCacheByUrl.put(url, width.toFloat() / height.toFloat())
|
||||
}
|
||||
}
|
||||
}
|
@ -30,9 +30,11 @@ import androidx.media3.common.Player
|
||||
import androidx.media3.common.Player.PositionInfo
|
||||
import androidx.media3.common.Player.STATE_IDLE
|
||||
import androidx.media3.common.Player.STATE_READY
|
||||
import androidx.media3.common.VideoSize
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.session.MediaSession
|
||||
import com.vitorpamplona.amethyst.model.MediaAspectRatioCache
|
||||
import com.vitorpamplona.amethyst.ui.MainActivity
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -113,6 +115,10 @@ class MultiPlayerPlaybackManager(
|
||||
// avoids saving positions for live streams otherwise caching goes crazy
|
||||
val mustCachePositions = !uri.contains(".m3u8", true)
|
||||
|
||||
override fun onVideoSizeChanged(videoSize: VideoSize) {
|
||||
MediaAspectRatioCache.add(uri, videoSize.width, videoSize.height)
|
||||
}
|
||||
|
||||
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
||||
if (isPlaying) {
|
||||
player.setWakeMode(C.WAKE_MODE_NETWORK)
|
||||
|
@ -98,6 +98,7 @@ import com.linc.audiowaveform.infiniteLinearGradient
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.compose.GenericBaseCache
|
||||
import com.vitorpamplona.amethyst.commons.compose.produceCachedState
|
||||
import com.vitorpamplona.amethyst.model.MediaAspectRatioCache
|
||||
import com.vitorpamplona.amethyst.service.okhttp.HttpClientManager
|
||||
import com.vitorpamplona.amethyst.service.playback.PlaybackClientController
|
||||
import com.vitorpamplona.amethyst.ui.actions.MediaSaverToDisk
|
||||
@ -261,7 +262,8 @@ fun VideoView(
|
||||
}
|
||||
|
||||
if (blurhash == null) {
|
||||
val ratio = dimensions?.aspectRatio()
|
||||
val ratio = dimensions?.aspectRatio() ?: MediaAspectRatioCache.get(videoUri)
|
||||
|
||||
val modifier =
|
||||
if (ratio != null && automaticallyStartPlayback.value) {
|
||||
Modifier.aspectRatio(ratio)
|
||||
@ -295,7 +297,7 @@ fun VideoView(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val ratio = dimensions?.aspectRatio()
|
||||
val ratio = dimensions?.aspectRatio() ?: MediaAspectRatioCache.get(videoUri)
|
||||
|
||||
val modifier =
|
||||
if (ratio != null) {
|
||||
|
@ -43,6 +43,7 @@ import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@ -77,6 +78,7 @@ import com.vitorpamplona.amethyst.commons.richtext.MediaPreloadedContent
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlContent
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo
|
||||
import com.vitorpamplona.amethyst.model.MediaAspectRatioCache
|
||||
import com.vitorpamplona.amethyst.service.Blurhash
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.actions.InformationDialog
|
||||
@ -87,6 +89,7 @@ import com.vitorpamplona.amethyst.ui.note.DownloadForOfflineIcon
|
||||
import com.vitorpamplona.amethyst.ui.note.HashCheckFailedIcon
|
||||
import com.vitorpamplona.amethyst.ui.note.HashCheckIcon
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.gallery.UrlImageView
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size20dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size24dp
|
||||
@ -235,7 +238,7 @@ fun LocalImageView(
|
||||
)
|
||||
}
|
||||
|
||||
val ratio = remember(content) { aspectRatio(content.dim) }
|
||||
val ratio = remember(content) { content.dim?.aspectRatio() ?: MediaAspectRatioCache.get(content.localFile.toString()) }
|
||||
CrossfadeIfEnabled(targetState = showImage.value, contentAlignment = Alignment.Center, accountViewModel = accountViewModel) {
|
||||
if (it) {
|
||||
SubcomposeAsyncImage(
|
||||
@ -276,6 +279,11 @@ fun LocalImageView(
|
||||
is AsyncImagePainter.State.Success -> {
|
||||
SubcomposeAsyncImageContent(loadedImageModifier)
|
||||
|
||||
SideEffect {
|
||||
val drawable = (state as AsyncImagePainter.State.Success).result.image
|
||||
MediaAspectRatioCache.add(content.localFile.toString(), drawable.width, drawable.height)
|
||||
}
|
||||
|
||||
content.isVerified?.let {
|
||||
AnimatedVisibility(
|
||||
visible = controllerVisible.value,
|
||||
@ -328,7 +336,7 @@ fun UrlImageView(
|
||||
accountViewModel: AccountViewModel,
|
||||
alwayShowImage: Boolean = false,
|
||||
) {
|
||||
val ratio = content.dim?.aspectRatio()
|
||||
val ratio = content.dim?.aspectRatio() ?: MediaAspectRatioCache.get(content.url)
|
||||
|
||||
val showImage =
|
||||
remember {
|
||||
@ -385,6 +393,11 @@ fun UrlImageView(
|
||||
SubcomposeAsyncImageContent(loadedImageModifier)
|
||||
|
||||
ShowHashAnimated(content, controllerVisible, Modifier.align(Alignment.TopEnd))
|
||||
|
||||
SideEffect {
|
||||
val drawable = (state as AsyncImagePainter.State.Success).result.image
|
||||
MediaAspectRatioCache.add(content.url, drawable.width, drawable.height)
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
@ -519,12 +532,6 @@ fun ShowHash(content: MediaUrlContent) {
|
||||
verifiedHash?.let { HashVerificationSymbol(it) }
|
||||
}
|
||||
|
||||
fun aspectRatio(dim: DimensionTag?): Float? {
|
||||
if (dim == null) return null
|
||||
|
||||
return dim.width.toFloat() / dim.height.toFloat()
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun WaitAndDisplay(
|
||||
content:
|
||||
|
Loading…
x
Reference in New Issue
Block a user