Forces aspect ratio of when loading an image to minimize resizing of the UI after the image is loaded.

This commit is contained in:
Vitor Pamplona
2025-03-14 10:27:13 -04:00
parent de2b1a6c95
commit d76de0123a
7 changed files with 40 additions and 22 deletions
@@ -59,6 +59,7 @@ val DefaultAnimationColors =
@Composable
fun LoadingAnimation(
indicatorSize: Dp = 20.dp,
circleWidth: Dp = 4.dp,
circleColors: ImmutableList<Color> = DefaultAnimationColors,
animationDuration: Int = 1000,
) {
@@ -86,7 +87,7 @@ fun LoadingAnimation(
.size(size = indicatorSize)
.rotate(degrees = rotateAnimation)
.border(
width = 4.dp,
width = circleWidth,
brush = Brush.sweepGradient(circleColors),
shape = CircleShape,
),
@@ -94,6 +94,8 @@ import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.Size20dp
import com.vitorpamplona.amethyst.ui.theme.Size24dp
import com.vitorpamplona.amethyst.ui.theme.Size30dp
import com.vitorpamplona.amethyst.ui.theme.Size40dp
import com.vitorpamplona.amethyst.ui.theme.Size6dp
import com.vitorpamplona.amethyst.ui.theme.Size75dp
import com.vitorpamplona.amethyst.ui.theme.hashVerifierMark
import com.vitorpamplona.amethyst.ui.theme.imageModifier
@@ -135,7 +137,6 @@ fun ZoomableContentView(
.fillMaxWidth()
.clickable { dialogOpen = true }
val loadedImageModifier = if (roundedCorner) MaterialTheme.colorScheme.imageModifier else Modifier.fillMaxWidth()
UrlImageView(content, contentScale, mainImageModifier, loadedImageModifier, controllerVisible, accountViewModel = accountViewModel)
}
}
@@ -268,8 +269,14 @@ fun LocalImageView(
)
}
} else {
WaitAndDisplay {
DisplayUrlWithLoadingSymbol(content)
if (ratio != null) {
Box(loadedImageModifier.aspectRatio(ratio), contentAlignment = Alignment.Center) {
LoadingAnimation(Size40dp, Size6dp)
}
} else {
WaitAndDisplay {
DisplayUrlWithLoadingSymbol(content)
}
}
}
}
@@ -381,8 +388,14 @@ fun UrlImageView(
)
}
} else {
WaitAndDisplay {
DisplayUrlWithLoadingSymbol(content)
if (ratio != null) {
Box(loadedImageModifier.aspectRatio(ratio), contentAlignment = Alignment.Center) {
LoadingAnimation(Size40dp, Size6dp)
}
} else {
WaitAndDisplay {
DisplayUrlWithLoadingSymbol(content)
}
}
}
}
@@ -53,6 +53,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.gallery.UrlImageVie
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
import com.vitorpamplona.amethyst.ui.theme.Size10dp
import com.vitorpamplona.amethyst.ui.theme.Size40Modifier
import com.vitorpamplona.quartz.nip01Core.tags.addressables.taggedAddresses
import com.vitorpamplona.quartz.nip30CustomEmoji.selection.EmojiPackSelectionEvent
import kotlinx.collections.immutable.toImmutableList
@@ -108,11 +109,11 @@ fun ShowEmojiSuggestionList(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = spacedBy(Size10dp),
) {
Box(Modifier.size(40.dp)) {
Box(Size40Modifier) {
UrlImageView(it.url, accountViewModel)
}
Text(it.code, fontWeight = FontWeight.Bold, modifier = Modifier.weight(1f))
Box(Modifier.size(40.dp), contentAlignment = Alignment.Center) {
Box(Size40Modifier, contentAlignment = Alignment.Center) {
IconButton(
onClick = {
onFullSize(it)
@@ -47,12 +47,12 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.feeds.FeedContentState
import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.Size40dp
import com.vitorpamplona.amethyst.ui.theme.TabRowHeight
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import kotlinx.coroutines.launch
@@ -93,7 +93,7 @@ fun MessagesTabHeader(
IconButton(
modifier =
Modifier
.size(40.dp)
.size(Size40dp)
.align(Alignment.CenterEnd),
onClick = { moreActionsExpanded = true },
) {
@@ -56,12 +56,11 @@ import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
import com.vitorpamplona.amethyst.ui.components.AutoNonlazyGrid
import com.vitorpamplona.amethyst.ui.components.ClickableUrl
import com.vitorpamplona.amethyst.ui.components.DisplayBlurHash
import com.vitorpamplona.amethyst.ui.components.DisplayUrlWithLoadingSymbol
import com.vitorpamplona.amethyst.ui.components.GetMediaItem
import com.vitorpamplona.amethyst.ui.components.GetVideoController
import com.vitorpamplona.amethyst.ui.components.ImageUrlWithDownloadButton
import com.vitorpamplona.amethyst.ui.components.LoadingAnimation
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
import com.vitorpamplona.amethyst.ui.components.WaitAndDisplay
import com.vitorpamplona.amethyst.ui.navigation.INav
import com.vitorpamplona.amethyst.ui.note.DownloadForOfflineIcon
import com.vitorpamplona.amethyst.ui.note.WatchAuthor
@@ -217,8 +216,8 @@ fun UrlImageView(
defaultModifier,
)
} else {
WaitAndDisplay {
DisplayUrlWithLoadingSymbol(content)
Box(defaultModifier, contentAlignment = Alignment.Center) {
LoadingAnimation()
}
}
}
@@ -99,9 +99,12 @@ import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.SimpleQrCodeScanner
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
import com.vitorpamplona.amethyst.ui.theme.Size0dp
import com.vitorpamplona.amethyst.ui.theme.Size10dp
import com.vitorpamplona.amethyst.ui.theme.Size20dp
import com.vitorpamplona.amethyst.ui.theme.Size35dp
import com.vitorpamplona.amethyst.ui.theme.Size40dp
import com.vitorpamplona.amethyst.ui.theme.Size50dp
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonRow
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.amethyst.ui.tor.TorSettings
@@ -200,7 +203,7 @@ fun LoginPage(
contentScale = ContentScale.Inside,
)
Spacer(modifier = Modifier.height(40.dp))
Spacer(modifier = Modifier.height(Size40dp))
KeyTextField(
value = key.value,
@@ -334,9 +337,9 @@ fun LoginPage(
}
}
Spacer(modifier = Modifier.height(10.dp))
Spacer(modifier = Modifier.height(Size10dp))
Box(modifier = Modifier.padding(40.dp, 0.dp, 40.dp, 0.dp)) {
Box(modifier = Modifier.padding(Size40dp, 0.dp, Size40dp, 0.dp)) {
LoginButton(
enabled = acceptedTerms.value,
processingLogin = processingLogin,
@@ -371,7 +374,7 @@ fun LoginPage(
}
if (PackageUtils.isExternalSignerInstalled(context)) {
Box(modifier = Modifier.padding(40.dp, 20.dp, 40.dp, 0.dp)) {
Box(modifier = Modifier.padding(Size40dp, Size20dp, Size40dp, Size0dp)) {
LoginWithAmberButton(
enabled = acceptedTerms.value,
onClick = {
@@ -777,11 +780,11 @@ fun LoginWithAmberButton(
enabled = enabled,
onClick = onClick,
shape = RoundedCornerShape(Size35dp),
modifier = Modifier.height(50.dp),
modifier = Modifier.height(Size50dp),
) {
Text(
text = stringRes(R.string.login_with_external_signer),
modifier = Modifier.padding(horizontal = 40.dp),
modifier = Modifier.padding(horizontal = Size40dp),
)
}
}
@@ -796,9 +799,9 @@ fun LoginButton(
enabled = enabled,
onClick = onClick,
shape = RoundedCornerShape(Size35dp),
modifier = Modifier.height(50.dp),
modifier = Modifier.height(Size50dp),
) {
Row(modifier = Modifier.padding(horizontal = 40.dp)) {
Row(modifier = Modifier.padding(horizontal = Size40dp)) {
if (processingLogin) {
LoadingAnimation()
Spacer(modifier = DoubleHorzSpacer)
@@ -84,6 +84,7 @@ val TopBarSize = 50.dp - 64.dp
val Size0dp = 0.dp
val Size5dp = 5.dp
val Size6dp = 6.dp
val Size10dp = 10.dp
val Size12dp = 12.dp
val Size13dp = 13.dp