From 34671ba09f1d1912d50d118cccea9791d67ecafe Mon Sep 17 00:00:00 2001 From: Fimkov <123477029+fimkov@users.noreply.github.com> Date: Thu, 2 Apr 2026 11:54:29 +0700 Subject: [PATCH 1/2] replaced CircularProgressIndicator with CircularWavyProgressIndicator or LoadingIndicator --- .../auth/components/CodeInputScreen.kt | 8 +- .../auth/components/PasswordInputScreen.kt | 2 +- .../auth/components/PhoneInputScreen.kt | 2 +- .../chatContent/ChatContentList.kt | 6 +- .../AdvancedCircularRecorderScreen.kt | 3 +- .../channels/ChannelAlbumMessageBubble.kt | 12 +- .../components/chats/AudioMessageBubble.kt | 7 +- .../components/chats/DocumentMessageBubble.kt | 7 +- .../components/chats/GifMessageBubble.kt | 117 ++++++++++-------- .../chats/MediaLoadingComponents.kt | 24 ++-- .../components/chats/PhotoMessageBubble.kt | 28 ++++- .../components/chats/PollVotersSheet.kt | 4 +- .../components/chats/StickerMessageBubble.kt | 27 ++-- .../components/chats/VideoMessageBubble.kt | 5 +- .../components/chats/VideoNoteBubble.kt | 14 ++- .../components/chats/VoiceMessageBubble.kt | 7 +- .../components/inputbar/InlineBotResults.kt | 3 +- .../editor/photo/PhotoEditorScreen.kt | 7 +- .../editor/video/VideoEditorScreen.kt | 9 +- .../features/chats/newChat/NewChatContent.kt | 5 +- .../gallery/components/GalleryMediaGrid.kt | 19 ++- .../features/instantview/InstantViewer.kt | 6 +- .../components/InstantViewComponents.kt | 40 ++++-- .../features/profile/ProfileContent.kt | 8 +- .../profile/admin/AdminManageContent.kt | 4 +- .../profile/admin/MemberListContent.kt | 6 +- .../profile/components/ProfileSections.kt | 21 ++-- .../profile/components/StatisticsViewer.kt | 13 +- .../profile/logs/ProfileLogsContent.kt | 6 +- .../stickers/ui/menu/MessageOptionsMenu.kt | 113 ++++++++++++++--- .../features/viewers/YouTubeViewer.kt | 3 +- .../components/ImageViewerComponents.kt | 6 +- .../components/VideoViewerComponents.kt | 116 +++++++++++++---- .../webapp/components/InvoiceDialog.kt | 18 +-- .../webapp/components/MiniAppButtons.kt | 12 +- .../webapp/components/MiniAppLoadingView.kt | 6 +- .../chatSettings/ChatSettingsContent.kt | 7 +- .../settings/folders/FoldersContent.kt | 4 +- .../networkUsage/NetworkUsageContent.kt | 4 +- .../NotificationsExceptionsContent.kt | 58 +++++++-- .../settings/privacy/BlockedUsersContent.kt | 43 ++++++- .../settings/privacy/PrivacyListContent.kt | 4 +- .../userSelection/UserSelectionContent.kt | 35 +++++- .../settings/profile/EditProfileContent.kt | 9 +- .../settings/proxy/ProxyContent.kt | 70 ++++++++--- .../settings/sessions/SessionsContent.kt | 4 +- .../settings/stickers/StickersContent.kt | 51 +++++--- .../settings/storage/StorageUsageContent.kt | 4 +- 48 files changed, 698 insertions(+), 289 deletions(-) diff --git a/presentation/src/main/java/org/monogram/presentation/features/auth/components/CodeInputScreen.kt b/presentation/src/main/java/org/monogram/presentation/features/auth/components/CodeInputScreen.kt index 0b0f6ef1..7e897666 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/auth/components/CodeInputScreen.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/auth/components/CodeInputScreen.kt @@ -310,7 +310,8 @@ fun CodeInputScreen( DropdownMenuItem( text = { Text(stringResource(R.string.paste_action)) }, onClick = { - val pastedText = nativeClipboard.primaryClip?.getItemAt(0)?.text?.toString() ?: "" + val pastedText = + nativeClipboard.primaryClip?.getItemAt(0)?.text?.toString() ?: "" val digits = pastedText.filter { it.isDigit() }.take(maxCodeLength) if (digits.isNotEmpty()) { code = digits @@ -327,7 +328,10 @@ fun CodeInputScreen( Spacer(modifier = Modifier.height(middleSpacerHeight)) if (isSubmitting) { - LoadingIndicator(modifier = Modifier.size(32.dp)) + LoadingIndicator( + modifier = Modifier.size(32.dp), + color = MaterialTheme.colorScheme.primary + ) } else { Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { Button( diff --git a/presentation/src/main/java/org/monogram/presentation/features/auth/components/PasswordInputScreen.kt b/presentation/src/main/java/org/monogram/presentation/features/auth/components/PasswordInputScreen.kt index ab190c6d..af664177 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/auth/components/PasswordInputScreen.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/auth/components/PasswordInputScreen.kt @@ -422,7 +422,7 @@ private fun PasswordContent( if (isSubmitting) { LoadingIndicator( modifier = Modifier.size(24.dp), - color = MaterialTheme.colorScheme.onPrimary + color = MaterialTheme.colorScheme.primary ) } else { Text(stringResource(R.string.unlock_button), fontSize = 18.sp, fontWeight = FontWeight.Bold) diff --git a/presentation/src/main/java/org/monogram/presentation/features/auth/components/PhoneInputScreen.kt b/presentation/src/main/java/org/monogram/presentation/features/auth/components/PhoneInputScreen.kt index 7e2875cc..258cfdf2 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/auth/components/PhoneInputScreen.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/auth/components/PhoneInputScreen.kt @@ -416,7 +416,7 @@ fun PhoneInputScreen( if (isSubmitting) { LoadingIndicator( modifier = Modifier.size(24.dp), - color = MaterialTheme.colorScheme.onPrimary + color = MaterialTheme.colorScheme.primary ) } else { Text( diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/chatContent/ChatContentList.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/chatContent/ChatContentList.kt index 3de70a0a..a4d06989 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/chatContent/ChatContentList.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/chatContent/ChatContentList.kt @@ -303,6 +303,7 @@ fun ChatContentList( } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable private fun PagingLoadingIndicator() { Box( @@ -321,9 +322,8 @@ private fun PagingLoadingIndicator() { verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp) ) { - CircularProgressIndicator( - modifier = Modifier.size(14.dp), - strokeWidth = 2.dp + LoadingIndicator( + modifier = Modifier.size(14.dp) ) Text( text = "Loading...", diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/AdvancedCircularRecorderScreen.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/AdvancedCircularRecorderScreen.kt index 344ae121..9941465c 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/AdvancedCircularRecorderScreen.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/AdvancedCircularRecorderScreen.kt @@ -119,6 +119,7 @@ fun AdvancedCircularRecorderScreen( } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @SuppressLint("MissingPermission", "RestrictedApi") @Composable fun NativeCircularCameraContent( @@ -605,7 +606,7 @@ fun NativeCircularCameraContent( .fillMaxSize() .background(Color.Black.copy(alpha = 0.8f)), contentAlignment = Alignment.Center) { Column(horizontalAlignment = Alignment.CenterHorizontally) { - CircularProgressIndicator(color = Color.White) + LoadingIndicator(color = Color.White) Text( stringResource(R.string.recorder_processing), color = Color.White, diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/channels/ChannelAlbumMessageBubble.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/channels/ChannelAlbumMessageBubble.kt index 7250c827..54c5c66d 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/channels/ChannelAlbumMessageBubble.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/channels/ChannelAlbumMessageBubble.kt @@ -16,9 +16,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.positionInWindow import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -284,6 +286,7 @@ fun ChannelAlbumMessageBubble( } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun ChannelDocumentAlbumBubble( messages: List, @@ -382,11 +385,11 @@ fun ChannelDocumentAlbumBubble( contentAlignment = Alignment.Center ) { if (content.isDownloading || content.isUploading) { - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { if (content.isDownloading) content.downloadProgress else content.uploadProgress }, modifier = Modifier.size(36.dp), color = MaterialTheme.colorScheme.onPrimary, - strokeWidth = 3.dp, + stroke = Stroke(width = with(LocalDensity.current) { 3.dp.toPx() }), trackColor = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.2f), ) Icon( @@ -486,6 +489,7 @@ fun ChannelDocumentAlbumBubble( } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun ChannelAudioAlbumBubble( messages: List, @@ -584,11 +588,11 @@ fun ChannelAudioAlbumBubble( contentAlignment = Alignment.Center ) { if (content.isDownloading || content.isUploading) { - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { if (content.isDownloading) content.downloadProgress else content.uploadProgress }, modifier = Modifier.size(36.dp), color = MaterialTheme.colorScheme.onPrimary, - strokeWidth = 3.dp, + stroke = Stroke(width = with(LocalDensity.current) { 3.dp.toPx() }), trackColor = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.2f), ) Icon( diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/AudioMessageBubble.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/AudioMessageBubble.kt index d618d279..62bfd592 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/AudioMessageBubble.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/AudioMessageBubble.kt @@ -15,8 +15,10 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.positionInWindow +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -192,6 +194,7 @@ fun AudioMessageBubble( } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun AudioRow( content: MessageContent.Audio, @@ -223,11 +226,11 @@ fun AudioRow( contentAlignment = Alignment.Center ) { if (content.isDownloading || content.isUploading) { - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { if (content.isDownloading) content.downloadProgress else content.uploadProgress }, modifier = Modifier.size(40.dp), color = MaterialTheme.colorScheme.onPrimary, - strokeWidth = 3.dp, + stroke = Stroke(width = with(LocalDensity.current) { 3.dp.toPx() }), trackColor = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.2f), ) Icon( diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/DocumentMessageBubble.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/DocumentMessageBubble.kt index 55709296..b68ad54d 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/DocumentMessageBubble.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/DocumentMessageBubble.kt @@ -16,8 +16,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.positionInWindow +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -212,6 +214,7 @@ fun DocumentMessageBubble( } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun DocumentRow( content: MessageContent.Document, @@ -245,11 +248,11 @@ fun DocumentRow( contentAlignment = Alignment.Center ) { if (content.isDownloading || content.isUploading) { - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { if (content.isDownloading) content.downloadProgress else content.uploadProgress }, modifier = Modifier.size(40.dp), color = MaterialTheme.colorScheme.onPrimary, - strokeWidth = 3.dp, + stroke = Stroke(width = with(LocalDensity.current) { 3.dp.toPx() }), trackColor = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.2f), ) Icon( diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/GifMessageBubble.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/GifMessageBubble.kt index e6ca5ed3..17d38c02 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/GifMessageBubble.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/GifMessageBubble.kt @@ -1,6 +1,5 @@ package org.monogram.presentation.features.chats.currentChat.components.chats -import androidx.annotation.OptIn import androidx.compose.animation.animateContentSize import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -36,7 +35,8 @@ import org.monogram.presentation.features.chats.currentChat.components.VideoPlay import org.monogram.presentation.features.chats.currentChat.components.VideoStickerPlayer import org.monogram.presentation.features.chats.currentChat.components.VideoType -@OptIn(UnstableApi::class) +@androidx.annotation.OptIn(UnstableApi::class) +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun GifMessageBubble( content: MessageContent.Gif, @@ -79,7 +79,13 @@ fun GifMessageBubble( } } - LaunchedEffect(content.path, content.isDownloading, autoDownloadMobile, autoDownloadWifi, autoDownloadRoaming) { + LaunchedEffect( + content.path, + content.isDownloading, + autoDownloadMobile, + autoDownloadWifi, + autoDownloadRoaming + ) { if (content.path.isNullOrBlank() && !content.isDownloading && !isAutoDownloadSuppressed && !AutoDownloadSuppression.isSuppressed( content.fileId ) @@ -124,9 +130,11 @@ fun GifMessageBubble( color = if (isOutgoing) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.surfaceContainerHigh, contentColor = if (isOutgoing) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSurfaceVariant, ) { - Column(modifier = Modifier - .widthIn(min = 160.dp, max = 320.dp) - .animateContentSize()) { + Column( + modifier = Modifier + .widthIn(min = 160.dp, max = 320.dp) + .animateContentSize() + ) { msg.forwardInfo?.let { forward -> Box( modifier = Modifier @@ -160,7 +168,10 @@ fun GifMessageBubble( .heightIn(min = 160.dp, max = 360.dp) .aspectRatio( if (content.width > 0 && content.height > 0) - (content.width.toFloat() / content.height.toFloat()).coerceIn(0.5f, 2f) + (content.width.toFloat() / content.height.toFloat()).coerceIn( + 0.5f, + 2f + ) else 1f ) .clipToBounds() @@ -185,53 +196,56 @@ fun GifMessageBubble( } ) { if (!stablePath.isNullOrBlank()) { - if (autoplayGifs) { - VideoStickerPlayer( - path = stablePath ?: "", - type = VideoType.Gif, - modifier = Modifier.fillMaxSize(), - contentScale = ContentScale.Fit, - animate = !isAnyViewerOpen, - videoPlayerPool = videoPlayerPool, - thumbnailData = content.minithumbnail - ) - } else { - Image( - painter = rememberAsyncImagePainter(stablePath), - contentDescription = content.caption, - modifier = Modifier.fillMaxSize(), - contentScale = ContentScale.Fit - ) - - Box( - modifier = Modifier - .align(Alignment.Center) - .size(48.dp) - .background(Color.Black.copy(alpha = 0.45f), CircleShape), - contentAlignment = Alignment.Center - ) { - Icon( - imageVector = Icons.Default.PlayArrow, - contentDescription = "Play", - tint = Color.White, - modifier = Modifier.size(32.dp) - ) - } - } + if (autoplayGifs) { + VideoStickerPlayer( + path = stablePath ?: "", + type = VideoType.Gif, + modifier = Modifier.fillMaxSize(), + contentScale = ContentScale.Fit, + animate = !isAnyViewerOpen, + videoPlayerPool = videoPlayerPool, + thumbnailData = content.minithumbnail + ) + } else { + Image( + painter = rememberAsyncImagePainter(stablePath), + contentDescription = content.caption, + modifier = Modifier.fillMaxSize(), + contentScale = ContentScale.Fit + ) Box( modifier = Modifier - .align(Alignment.TopStart) - .padding(8.dp) - .background(Color.Black.copy(alpha = 0.45f), RoundedCornerShape(6.dp)) - .padding(horizontal = 6.dp, vertical = 2.dp) + .align(Alignment.Center) + .size(48.dp) + .background(Color.Black.copy(alpha = 0.45f), CircleShape), + contentAlignment = Alignment.Center ) { - Text( - text = "GIF", - style = MaterialTheme.typography.labelSmall, - color = Color.White + Icon( + imageVector = Icons.Default.PlayArrow, + contentDescription = "Play", + tint = Color.White, + modifier = Modifier.size(32.dp) ) } + } + + Box( + modifier = Modifier + .align(Alignment.TopStart) + .padding(8.dp) + .background( + Color.Black.copy(alpha = 0.45f), + RoundedCornerShape(6.dp) + ) + .padding(horizontal = 6.dp, vertical = 2.dp) + ) { + Text( + text = "GIF", + style = MaterialTheme.typography.labelSmall, + color = Color.White + ) + } } else { Box( modifier = Modifier.fillMaxSize(), @@ -268,7 +282,7 @@ fun GifMessageBubble( .background(Color.Black.copy(alpha = 0.5f)), contentAlignment = Alignment.Center ) { - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { content.uploadProgress }, color = Color.White, trackColor = Color.White.copy(alpha = 0.3f), @@ -285,7 +299,10 @@ fun GifMessageBubble( modifier = Modifier .align(Alignment.BottomEnd) .padding(6.dp) - .background(Color.Black.copy(alpha = 0.45f), RoundedCornerShape(10.dp)) + .background( + Color.Black.copy(alpha = 0.45f), + RoundedCornerShape(10.dp) + ) .padding(horizontal = 6.dp, vertical = 2.dp) ) { Row(verticalAlignment = Alignment.CenterVertically) { diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/MediaLoadingComponents.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/MediaLoadingComponents.kt index 81aa4afa..8cb05913 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/MediaLoadingComponents.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/MediaLoadingComponents.kt @@ -1,6 +1,11 @@ package org.monogram.presentation.features.chats.currentChat.components.chats -import androidx.compose.animation.core.* +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.RepeatMode +import androidx.compose.animation.core.animateFloat +import androidx.compose.animation.core.infiniteRepeatable +import androidx.compose.animation.core.rememberInfiniteTransition +import androidx.compose.animation.core.tween import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -10,8 +15,10 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close -import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.CircularWavyProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon +import androidx.compose.material3.LoadingIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -19,8 +26,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import coil3.compose.rememberAsyncImagePainter @@ -70,6 +79,7 @@ fun MediaLoadingBackground( } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun MediaLoadingAction( isDownloading: Boolean, @@ -89,19 +99,17 @@ fun MediaLoadingAction( ) { if (isDownloading) { if (progress > 0f && progress < 1f) { - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { progress }, modifier = Modifier.size(36.dp), color = Color.White, trackColor = Color.White.copy(alpha = 0.25f), - strokeWidth = 2.5.dp + stroke = Stroke(width = with(LocalDensity.current) { 4.dp.toPx() }) ) } else { - CircularProgressIndicator( + LoadingIndicator( modifier = Modifier.size(36.dp), - color = Color.White, - trackColor = Color.White.copy(alpha = 0.25f), - strokeWidth = 2.5.dp + color = Color.White ) } diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/PhotoMessageBubble.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/PhotoMessageBubble.kt index 121216ab..272a9c6e 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/PhotoMessageBubble.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/PhotoMessageBubble.kt @@ -5,14 +5,31 @@ import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.gestures.detectTapGestures -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Download -import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.CircularWavyProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.LoadingIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clipToBounds @@ -36,6 +53,7 @@ import org.monogram.domain.models.MessageModel import org.monogram.presentation.core.util.IDownloadUtils import org.monogram.presentation.features.chats.currentChat.AutoDownloadSuppression +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun PhotoMessageBubble( content: MessageContent.Photo, @@ -263,13 +281,13 @@ fun PhotoMessageBubble( contentAlignment = Alignment.Center ) { if (content.uploadProgress > 0f) { - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { content.uploadProgress }, color = Color.White, trackColor = Color.White.copy(alpha = 0.3f), ) } else { - CircularProgressIndicator( + LoadingIndicator( color = Color.White ) } diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/PollVotersSheet.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/PollVotersSheet.kt index 747805f9..114c37d5 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/PollVotersSheet.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/PollVotersSheet.kt @@ -23,7 +23,7 @@ import org.monogram.presentation.core.ui.Avatar import org.monogram.presentation.features.chats.currentChat.components.VideoPlayerPool -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun PollVotersSheet( voters: List, @@ -57,7 +57,7 @@ fun PollVotersSheet( .height(200.dp), contentAlignment = Alignment.Center ) { - CircularProgressIndicator() + LoadingIndicator() } } else if (voters.isEmpty()) { Box( diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/StickerMessageBubble.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/StickerMessageBubble.kt index 751b6393..f3739abb 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/StickerMessageBubble.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/StickerMessageBubble.kt @@ -1,15 +1,27 @@ package org.monogram.presentation.features.chats.currentChat.components.chats import androidx.annotation.OptIn -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.combinedClickable -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Download import androidx.compose.material.icons.filled.Edit -import androidx.compose.material3.* +import androidx.compose.material3.CircularWavyProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -25,18 +37,19 @@ import org.monogram.presentation.features.stickers.ui.view.StickerImage import org.monogram.presentation.features.stickers.ui.view.StickerSkeleton import java.io.File -@OptIn(UnstableApi::class, ExperimentalFoundationApi::class) +@OptIn(UnstableApi::class) +@kotlin.OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun StickerMessageBubble( content: MessageContent.Sticker, msg: MessageModel, isOutgoing: Boolean, + modifier: Modifier = Modifier, onReplyClick: (MessageModel) -> Unit = {}, onReactionClick: (String) -> Unit = {}, onStickerClick: (Long) -> Unit = {}, onLongClick: () -> Unit = {}, - toProfile: (Long) -> Unit = {}, - modifier: Modifier = Modifier + toProfile: (Long) -> Unit = {} ) { Column( modifier = modifier, @@ -107,7 +120,7 @@ fun StickerMessageBubble( StickerSkeleton(modifier = Modifier.matchParentSize()) if (content.isDownloading) { - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { content.downloadProgress }, modifier = Modifier.size(48.dp), color = Color.White, diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/VideoMessageBubble.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/VideoMessageBubble.kt index 136741a0..63405db7 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/VideoMessageBubble.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/VideoMessageBubble.kt @@ -42,6 +42,7 @@ import org.monogram.presentation.features.chats.currentChat.components.VideoPlay import org.monogram.presentation.features.chats.currentChat.components.VideoStickerPlayer import org.monogram.presentation.features.chats.currentChat.components.VideoType +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun VideoMessageBubble( content: MessageContent.Video, @@ -341,13 +342,13 @@ fun VideoMessageBubble( contentAlignment = Alignment.Center ) { if (content.uploadProgress > 0f) { - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { content.uploadProgress }, color = Color.White, trackColor = Color.White.copy(alpha = 0.3f) ) } else { - CircularProgressIndicator( + LoadingIndicator( color = Color.White ) } diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/VideoNoteBubble.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/VideoNoteBubble.kt index 776a2680..bd0ef84f 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/VideoNoteBubble.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/VideoNoteBubble.kt @@ -22,11 +22,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.positionInWindow import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.viewinterop.AndroidView @@ -52,6 +54,7 @@ import java.io.File import java.io.FileNotFoundException @OptIn(UnstableApi::class) +@kotlin.OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun VideoNoteBubble( content: MessageContent.VideoNote, @@ -225,7 +228,7 @@ fun VideoNoteBubble( contentAlignment = Alignment.Center ) { if (content.isDownloading) { - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { content.downloadProgress }, color = Color.White, modifier = Modifier.size(48.dp) @@ -265,20 +268,19 @@ fun VideoNoteBubble( .background(Color.Black.copy(alpha = 0.5f), CircleShape), contentAlignment = Alignment.Center ) { - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { content.uploadProgress }, color = Color.White, - strokeWidth = 3.dp, + stroke = Stroke(width = with(LocalDensity.current) { 3.dp.toPx() }), modifier = Modifier.size(48.dp), trackColor = Color.White.copy(alpha = 0.3f) ) } } else if (content.path != null && !hasError) { - - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { progress }, color = Color.White, - strokeWidth = 2.dp, + stroke = Stroke(width = with(LocalDensity.current) { 2.dp.toPx() }), modifier = Modifier.matchParentSize(), trackColor = Color.Transparent ) diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/VoiceMessageBubble.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/VoiceMessageBubble.kt index bc90e0e7..7f421b4f 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/VoiceMessageBubble.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/chats/VoiceMessageBubble.kt @@ -20,8 +20,10 @@ import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.positionInWindow +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import org.monogram.domain.models.MessageContent @@ -161,6 +163,7 @@ fun VoiceMessageBubble( } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun VoiceRow( content: MessageContent.Voice, @@ -195,11 +198,11 @@ fun VoiceRow( contentAlignment = Alignment.Center ) { if (content.isDownloading || content.isUploading) { - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { if (content.isDownloading) content.downloadProgress else content.uploadProgress }, modifier = Modifier.size(32.dp), color = if (isOutgoing) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.onPrimary, - strokeWidth = 2.dp, + stroke = Stroke(width = with(LocalDensity.current) { 2.dp.toPx() }), trackColor = (if (isOutgoing) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.onPrimary).copy( alpha = 0.2f ), diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/inputbar/InlineBotResults.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/inputbar/InlineBotResults.kt index 04b6d668..4f7859b6 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/inputbar/InlineBotResults.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/components/inputbar/InlineBotResults.kt @@ -44,6 +44,7 @@ private enum class InlineResultsMode { List } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun InlineBotResults( inlineBotResults: InlineBotResultsModel?, @@ -123,7 +124,7 @@ fun InlineBotResults( .background(MaterialTheme.colorScheme.surface.copy(alpha = 0.25f)), contentAlignment = Alignment.Center ) { - CircularProgressIndicator(modifier = Modifier.size(30.dp)) + LoadingIndicator(modifier = Modifier.size(30.dp)) } } } diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/editor/photo/PhotoEditorScreen.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/editor/photo/PhotoEditorScreen.kt index 291b36c5..763058c6 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/editor/photo/PhotoEditorScreen.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/editor/photo/PhotoEditorScreen.kt @@ -48,7 +48,7 @@ enum class EditorTool(val labelRes: Int, val icon: ImageVector) { ERASER(R.string.photo_editor_tool_eraser, Icons.Rounded.CleaningServices) } -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun PhotoEditorScreen( imagePath: String, @@ -236,7 +236,8 @@ fun PhotoEditorScreen( indicatorColor = MaterialTheme.colorScheme.primaryContainer, selectedIconColor = MaterialTheme.colorScheme.onPrimaryContainer, unselectedIconColor = MaterialTheme.colorScheme.onSurfaceVariant, - unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant + unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant, + selectedTextColor = MaterialTheme.colorScheme.onPrimaryContainer ) ) } @@ -436,7 +437,7 @@ fun PhotoEditorScreen( .background(Color.Black.copy(0.6f)), contentAlignment = Alignment.Center ) { - CircularProgressIndicator() + LoadingIndicator() } } } diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/editor/video/VideoEditorScreen.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/editor/video/VideoEditorScreen.kt index eb8fb1f7..d3f6c1b1 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/editor/video/VideoEditorScreen.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/currentChat/editor/video/VideoEditorScreen.kt @@ -2,7 +2,6 @@ package org.monogram.presentation.features.chats.currentChat.editor.video import android.widget.Toast import androidx.activity.compose.BackHandler -import androidx.annotation.OptIn import androidx.annotation.StringRes import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.background @@ -57,7 +56,8 @@ enum class VideoEditorTool(@StringRes val labelRes: Int, val icon: ImageVector) COMPRESS(R.string.video_tool_compress, Icons.Rounded.Compress) } -@OptIn(UnstableApi::class) +@androidx.annotation.OptIn(UnstableApi::class) +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun VideoEditorScreen( videoPath: String, @@ -354,7 +354,8 @@ fun VideoEditorScreen( indicatorColor = MaterialTheme.colorScheme.primaryContainer, selectedIconColor = MaterialTheme.colorScheme.onPrimaryContainer, unselectedIconColor = MaterialTheme.colorScheme.onSurfaceVariant, - unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant + unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant, + selectedTextColor = MaterialTheme.colorScheme.onPrimaryContainer ) ) } @@ -463,7 +464,7 @@ fun VideoEditorScreen( .background(Color.Black.copy(0.6f)), contentAlignment = Alignment.Center ) { - CircularProgressIndicator() + LoadingIndicator() } } } diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/newChat/NewChatContent.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/newChat/NewChatContent.kt index 010bd129..aa823e47 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/newChat/NewChatContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/newChat/NewChatContent.kt @@ -50,7 +50,7 @@ import org.monogram.presentation.features.chats.chatList.components.SectionHeade import org.monogram.presentation.features.chats.chatList.components.SettingsTextField import org.monogram.presentation.features.chats.currentChat.components.VideoPlayerPool -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun NewChatContent(component: NewChatComponent) { val state by component.state.collectAsState() @@ -225,9 +225,8 @@ fun NewChatContent(component: NewChatComponent) { } ) { if (state.isCreating) { - CircularProgressIndicator( + LoadingIndicator( modifier = Modifier.size(22.dp), - strokeWidth = 2.dp, color = MaterialTheme.colorScheme.onSurfaceVariant ) } else { diff --git a/presentation/src/main/java/org/monogram/presentation/features/gallery/components/GalleryMediaGrid.kt b/presentation/src/main/java/org/monogram/presentation/features/gallery/components/GalleryMediaGrid.kt index 2111f014..1f1ec019 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/gallery/components/GalleryMediaGrid.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/gallery/components/GalleryMediaGrid.kt @@ -6,15 +6,25 @@ import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid -import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.itemsIndexed import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.CheckCircle -import androidx.compose.material3.* +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.Icon +import androidx.compose.material3.LoadingIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment @@ -26,6 +36,7 @@ import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage import org.monogram.presentation.features.gallery.GalleryMediaItem +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun GalleryGrid( media: List, @@ -35,7 +46,7 @@ fun GalleryGrid( ) { if (isLoading) { Box(modifier = modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { - CircularProgressIndicator() + LoadingIndicator() } return } diff --git a/presentation/src/main/java/org/monogram/presentation/features/instantview/InstantViewer.kt b/presentation/src/main/java/org/monogram/presentation/features/instantview/InstantViewer.kt index e7a94510..beb5519e 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/instantview/InstantViewer.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/instantview/InstantViewer.kt @@ -50,7 +50,9 @@ import org.monogram.presentation.features.viewers.components.ViewerSettingsDropd import java.text.SimpleDateFormat import java.util.* -@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class, + ExperimentalMaterial3ExpressiveApi::class +) @Composable fun InstantViewer( url: String, @@ -230,7 +232,7 @@ fun InstantViewer( .padding(padding) ) { if (isLoading) { - CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) + LoadingIndicator(modifier = Modifier.align(Alignment.Center)) } else if (instantView != null) { val blocks = remember(instantView, searchQuery) { if (searchQuery.isEmpty()) { diff --git a/presentation/src/main/java/org/monogram/presentation/features/instantview/components/InstantViewComponents.kt b/presentation/src/main/java/org/monogram/presentation/features/instantview/components/InstantViewComponents.kt index 0fef6671..6832edb3 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/instantview/components/InstantViewComponents.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/instantview/components/InstantViewComponents.kt @@ -1,17 +1,31 @@ package org.monogram.presentation.features.instantview.components import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.text.ClickableText -import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.CircularWavyProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.LoadingIndicator import androidx.compose.material3.MaterialTheme -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.blur import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.takeOrElse import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight @@ -72,17 +86,18 @@ fun RichTextView( ) } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun AsyncImageWithDownload( path: String?, fileId: Int, - minithumbnail: ByteArray? = null, modifier: Modifier = Modifier, + minithumbnail: ByteArray? = null, contentScale: ContentScale = ContentScale.Fit ) { val messageRepository = LocalMessageRepository.current var currentPath by remember(fileId) { mutableStateOf(path) } - var progress by remember { mutableStateOf(0f) } + var progress by remember { mutableFloatStateOf(0f) } LaunchedEffect(path, fileId) { if (!path.isNullOrEmpty()) { @@ -137,16 +152,15 @@ fun AsyncImageWithDownload( } if (progress > 0f && progress < 1f) { - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { progress }, modifier = Modifier.size(32.dp), - strokeWidth = 2.dp, + stroke = Stroke(width = with(LocalDensity.current) { 2.dp.toPx() }), color = MaterialTheme.colorScheme.primary ) } else { - CircularProgressIndicator( + LoadingIndicator( modifier = Modifier.size(24.dp), - strokeWidth = 2.dp, color = MaterialTheme.colorScheme.primary.copy(alpha = 0.3f) ) } @@ -154,6 +168,7 @@ fun AsyncImageWithDownload( } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun AsyncVideoWithDownload( path: String?, @@ -210,16 +225,15 @@ fun AsyncVideoWithDownload( contentAlignment = Alignment.Center ) { if (progress > 0f && progress < 1f) { - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { progress }, modifier = Modifier.size(32.dp), - strokeWidth = 2.dp, + stroke = Stroke(width = with(LocalDensity.current) { 2.dp.toPx() }), color = MaterialTheme.colorScheme.primary ) } else { - CircularProgressIndicator( + LoadingIndicator( modifier = Modifier.size(24.dp), - strokeWidth = 2.dp, color = MaterialTheme.colorScheme.primary.copy(alpha = 0.3f) ) } diff --git a/presentation/src/main/java/org/monogram/presentation/features/profile/ProfileContent.kt b/presentation/src/main/java/org/monogram/presentation/features/profile/ProfileContent.kt index b7c7e192..1a9cf256 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/profile/ProfileContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/profile/ProfileContent.kt @@ -36,8 +36,9 @@ import androidx.compose.material.icons.rounded.Edit import androidx.compose.material.icons.rounded.Person import androidx.compose.material3.BottomSheetDefaults import androidx.compose.material3.Button -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.LoadingIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.OutlinedButton @@ -91,7 +92,7 @@ import org.monogram.presentation.features.viewers.ImageViewer import org.monogram.presentation.features.viewers.VideoViewer import org.monogram.presentation.features.webapp.MiniAppViewer -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun ProfileContent(component: ProfileComponent) { val state by component.state.subscribeAsState() @@ -438,8 +439,7 @@ fun ProfileContent(component: ProfileComponent) { verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(10.dp) ) { - CircularProgressIndicator( - strokeWidth = 2.dp, + LoadingIndicator( modifier = Modifier.size(16.dp) ) Text( diff --git a/presentation/src/main/java/org/monogram/presentation/features/profile/admin/AdminManageContent.kt b/presentation/src/main/java/org/monogram/presentation/features/profile/admin/AdminManageContent.kt index c79d2286..43fb6f16 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/profile/admin/AdminManageContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/profile/admin/AdminManageContent.kt @@ -24,7 +24,7 @@ import org.monogram.presentation.features.chats.chatList.components.SettingsText import org.monogram.presentation.core.ui.ItemPosition import org.monogram.presentation.core.ui.SettingsSwitchTile -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun AdminManageContent(component: AdminManageComponent) { val state by component.state.subscribeAsState() @@ -72,7 +72,7 @@ fun AdminManageContent(component: AdminManageComponent) { ) { padding -> if (state.isLoading) { Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - CircularProgressIndicator() + LoadingIndicator() } } else { LazyColumn( diff --git a/presentation/src/main/java/org/monogram/presentation/features/profile/admin/MemberListContent.kt b/presentation/src/main/java/org/monogram/presentation/features/profile/admin/MemberListContent.kt index 698b8f14..ce7a3a7f 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/profile/admin/MemberListContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/profile/admin/MemberListContent.kt @@ -36,7 +36,7 @@ import com.arkivanov.decompose.extensions.compose.subscribeAsState import org.monogram.presentation.R import org.monogram.presentation.core.ui.Avatar -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun MemberListContent(component: MemberListComponent) { val state by component.state.subscribeAsState() @@ -135,7 +135,7 @@ fun MemberListContent(component: MemberListComponent) { ) { padding -> if (state.isLoading && state.members.isEmpty()) { Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - CircularProgressIndicator() + LoadingIndicator() } } else { LazyColumn( @@ -203,7 +203,7 @@ fun MemberListContent(component: MemberListComponent) { .fillMaxWidth() .padding(16.dp), contentAlignment = Alignment.Center ) { - CircularProgressIndicator(modifier = Modifier.size(24.dp)) + LoadingIndicator(modifier = Modifier.size(24.dp)) } } } diff --git a/presentation/src/main/java/org/monogram/presentation/features/profile/components/ProfileSections.kt b/presentation/src/main/java/org/monogram/presentation/features/profile/components/ProfileSections.kt index 54b5eeca..0a09a03e 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/profile/components/ProfileSections.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/profile/components/ProfileSections.kt @@ -60,13 +60,14 @@ import androidx.compose.material.icons.rounded.Timer import androidx.compose.material3.BottomSheetDefaults import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.ListItem import androidx.compose.material3.ListItemDefaults +import androidx.compose.material3.LoadingIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.OutlinedButton @@ -97,9 +98,14 @@ import androidx.compose.ui.unit.sp import androidx.core.net.toUri import org.monogram.domain.models.UserTypeEnum import org.monogram.presentation.R -import org.monogram.presentation.core.ui.* -import com.google.i18n.phonenumbers.PhoneNumberUtil -import org.koin.compose.koinInject +import org.monogram.presentation.core.ui.ItemPosition +import org.monogram.presentation.core.ui.SettingsSwitchTile +import org.monogram.presentation.core.ui.SettingsTile +import org.monogram.presentation.core.ui.StyledQRCode +import org.monogram.presentation.core.ui.generatePureBitmap +import org.monogram.presentation.core.ui.rememberShimmerBrush +import org.monogram.presentation.core.ui.saveBitmapToGallery +import org.monogram.presentation.core.ui.shareBitmap import org.monogram.presentation.core.util.CountryManager import org.monogram.presentation.core.util.OperatorManager import org.monogram.presentation.features.chats.currentChat.components.VideoPlayerPool @@ -1346,7 +1352,7 @@ fun ProfilePermissionsDialog( } } -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun ProfileTOSDialog( state: ProfileComponent.State, @@ -1398,10 +1404,9 @@ fun ProfileTOSDialog( label = "AcceptButtonContent" ) { accepting -> if (accepting) { - CircularProgressIndicator( + LoadingIndicator( modifier = Modifier.size(24.dp), - color = MaterialTheme.colorScheme.onPrimary, - strokeWidth = 2.dp + color = MaterialTheme.colorScheme.onPrimary ) } else { Text( diff --git a/presentation/src/main/java/org/monogram/presentation/features/profile/components/StatisticsViewer.kt b/presentation/src/main/java/org/monogram/presentation/features/profile/components/StatisticsViewer.kt index d272111a..b66ab5b5 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/profile/components/StatisticsViewer.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/profile/components/StatisticsViewer.kt @@ -42,7 +42,7 @@ import java.util.* import kotlin.math.abs import kotlin.math.roundToInt -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun StatisticsViewer( title: String, @@ -89,9 +89,7 @@ fun StatisticsViewer( .fillMaxWidth() .height(300.dp), contentAlignment = Alignment.Center) { Column(horizontalAlignment = Alignment.CenterHorizontally) { - CircularProgressIndicator( - strokeWidth = 4.dp, - strokeCap = StrokeCap.Round, + LoadingIndicator( color = MaterialTheme.colorScheme.primary ) Spacer(modifier = Modifier.height(16.dp)) @@ -765,6 +763,7 @@ private fun RevenueMetricCard(modifier: Modifier = Modifier, label: String, valu } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun GraphSection(title: String, graph: StatisticsGraphModel, color: Color, onLoadGraph: (String) -> Unit) { if (graph is StatisticsGraphModel.Error) return @@ -804,11 +803,9 @@ fun GraphSection(title: String, graph: StatisticsGraphModel, color: Color, onLoa } Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) { Column(horizontalAlignment = Alignment.CenterHorizontally) { - CircularProgressIndicator( + LoadingIndicator( modifier = Modifier.size(48.dp), - strokeWidth = 4.dp, - color = color, - strokeCap = StrokeCap.Round + color = color ) Spacer(modifier = Modifier.height(16.dp)) Text( diff --git a/presentation/src/main/java/org/monogram/presentation/features/profile/logs/ProfileLogsContent.kt b/presentation/src/main/java/org/monogram/presentation/features/profile/logs/ProfileLogsContent.kt index d9288233..7f5f70c5 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/profile/logs/ProfileLogsContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/profile/logs/ProfileLogsContent.kt @@ -36,7 +36,7 @@ import org.monogram.presentation.features.viewers.VideoViewer import java.text.SimpleDateFormat import java.util.* -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun ProfileLogsContent(component: ProfileLogsComponent) { val state by component.state.subscribeAsState() @@ -98,7 +98,7 @@ fun ProfileLogsContent(component: ProfileLogsComponent) { ) { Box(modifier = Modifier.fillMaxSize()) { if (state.isLoading) { - CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) + LoadingIndicator(modifier = Modifier.align(Alignment.Center)) } else if (state.logs.isEmpty()) { Column( modifier = Modifier.align(Alignment.Center), @@ -159,7 +159,7 @@ fun ProfileLogsContent(component: ProfileLogsComponent) { .padding(16.dp), contentAlignment = Alignment.Center ) { - CircularProgressIndicator(modifier = Modifier.size(24.dp)) + LoadingIndicator(modifier = Modifier.size(24.dp)) } } } diff --git a/presentation/src/main/java/org/monogram/presentation/features/stickers/ui/menu/MessageOptionsMenu.kt b/presentation/src/main/java/org/monogram/presentation/features/stickers/ui/menu/MessageOptionsMenu.kt index 4ed7401a..53203ed6 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/stickers/ui/menu/MessageOptionsMenu.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/stickers/ui/menu/MessageOptionsMenu.kt @@ -1,29 +1,107 @@ package org.monogram.presentation.features.stickers.ui.menu -import androidx.compose.animation.* -import androidx.compose.animation.core.* -import androidx.compose.foundation.* +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.AnimatedContentTransitionScope +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.SizeTransform +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.FastOutLinearInEasing +import androidx.compose.animation.core.FastOutSlowInEasing +import androidx.compose.animation.core.LinearOutSlowInEasing +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.animateFloat +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.spring +import androidx.compose.animation.core.tween +import androidx.compose.animation.core.updateTransition +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.scaleIn +import androidx.compose.animation.scaleOut +import androidx.compose.animation.togetherWith +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.ime +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.union +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.rounded.ArrowBack import androidx.compose.material.icons.automirrored.rounded.Chat import androidx.compose.material.icons.automirrored.rounded.Forward import androidx.compose.material.icons.automirrored.rounded.Reply -import androidx.compose.material.icons.rounded.* -import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.material.icons.rounded.AutoAwesome +import androidx.compose.material.icons.rounded.Block +import androidx.compose.material.icons.rounded.CheckCircle +import androidx.compose.material.icons.rounded.ChevronRight +import androidx.compose.material.icons.rounded.ContentCopy +import androidx.compose.material.icons.rounded.Delete +import androidx.compose.material.icons.rounded.DoneAll +import androidx.compose.material.icons.rounded.Download +import androidx.compose.material.icons.rounded.Edit +import androidx.compose.material.icons.rounded.Gavel +import androidx.compose.material.icons.rounded.Link +import androidx.compose.material.icons.rounded.MoreHoriz +import androidx.compose.material.icons.rounded.PushPin +import androidx.compose.material.icons.rounded.Report +import androidx.compose.material.icons.rounded.Translate +import androidx.compose.material.icons.rounded.Undo +import androidx.compose.material.icons.rounded.Visibility +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.LoadingIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.listSaver import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawWithContent -import androidx.compose.ui.geometry.* -import androidx.compose.ui.graphics.* +import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Rect +import androidx.compose.ui.geometry.RoundRect +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.BlendMode +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.CompositingStrategy +import androidx.compose.ui.graphics.Path +import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.graphics.drawscope.clipRect +import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.layout.onGloballyPositioned @@ -34,7 +112,11 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.* +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.coerceAtLeast +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import androidx.compose.ui.zIndex import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -52,8 +134,10 @@ import org.monogram.presentation.features.chats.currentChat.components.VideoPlay import org.monogram.presentation.features.chats.currentChat.components.chats.getEmojiFontFamily import org.monogram.presentation.features.stickers.ui.view.StickerImage import java.text.SimpleDateFormat -import java.util.* +import java.util.Date +import java.util.Locale +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun MessageOptionsMenu( message: MessageModel, @@ -511,9 +595,8 @@ fun MessageOptionsMenu( text = "${viewers.size} ${stringResource(R.string.info_views)}", trailingContent = { if (isLoadingViewers) { - CircularProgressIndicator( - modifier = Modifier.size(16.dp), - strokeWidth = 2.dp + LoadingIndicator( + modifier = Modifier.size(16.dp) ) } else { Icon( @@ -756,7 +839,7 @@ fun MessageOptionsMenu( .padding(vertical = 24.dp), contentAlignment = Alignment.Center ) { - CircularProgressIndicator() + LoadingIndicator() } } diff --git a/presentation/src/main/java/org/monogram/presentation/features/viewers/YouTubeViewer.kt b/presentation/src/main/java/org/monogram/presentation/features/viewers/YouTubeViewer.kt index a8ef6270..4c39d41d 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/viewers/YouTubeViewer.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/viewers/YouTubeViewer.kt @@ -57,6 +57,7 @@ import java.util.* import java.util.regex.Pattern import kotlin.math.max +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun YouTubeViewer( videoUrl: String, @@ -449,7 +450,7 @@ fun YouTubeViewer( } ) { if (playerState.isLoading) { - CircularProgressIndicator( + LoadingIndicator( color = MaterialTheme.colorScheme.primary, modifier = Modifier.align(Alignment.Center) ) diff --git a/presentation/src/main/java/org/monogram/presentation/features/viewers/components/ImageViewerComponents.kt b/presentation/src/main/java/org/monogram/presentation/features/viewers/components/ImageViewerComponents.kt index 00b8f3f4..7348c0d9 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/viewers/components/ImageViewerComponents.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/viewers/components/ImageViewerComponents.kt @@ -29,6 +29,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.TransformOrigin +import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.ContentScale @@ -410,6 +411,7 @@ fun PageIndicator(modifier: Modifier = Modifier, current: Int, total: Int) { } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun ZoomableImage( data: Any, @@ -482,10 +484,10 @@ fun ZoomableImage( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(12.dp) ) { - CircularProgressIndicator( + CircularWavyProgressIndicator( modifier = Modifier.size(48.dp), color = Color.White, - strokeWidth = 3.dp, + stroke = Stroke(width = with(LocalDensity.current) { 3.dp.toPx() }), progress = { if (isDownloading && downloadProgress in 0f..1f) { downloadProgress diff --git a/presentation/src/main/java/org/monogram/presentation/features/viewers/components/VideoViewerComponents.kt b/presentation/src/main/java/org/monogram/presentation/features/viewers/components/VideoViewerComponents.kt index 7521bcf0..1c181200 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/viewers/components/VideoViewerComponents.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/viewers/components/VideoViewerComponents.kt @@ -58,6 +58,7 @@ import kotlin.math.max private const val TAG = "VideoPage" @OptIn(UnstableApi::class) +@kotlin.OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun VideoPage( path: String, @@ -147,9 +148,19 @@ fun VideoPage( } if (dataSourceFactory != null) { - playerBuilder.setMediaSourceFactory(DefaultMediaSourceFactory(dataSourceFactory, extractorsFactory)) + playerBuilder.setMediaSourceFactory( + DefaultMediaSourceFactory( + dataSourceFactory, + extractorsFactory + ) + ) } else { - playerBuilder.setMediaSourceFactory(DefaultMediaSourceFactory(context, extractorsFactory)) + playerBuilder.setMediaSourceFactory( + DefaultMediaSourceFactory( + context, + extractorsFactory + ) + ) } playerBuilder.build().apply { @@ -332,7 +343,8 @@ fun VideoPage( }, update = { view -> view.player = exoPlayer - view.resizeMode = if (isInPipMode) AspectRatioFrameLayout.RESIZE_MODE_FIT else resizeMode + view.resizeMode = + if (isInPipMode) AspectRatioFrameLayout.RESIZE_MODE_FIT else resizeMode view.setOnClickListener { currentOnToggleControls() } playerView = view }, @@ -341,10 +353,11 @@ fun VideoPage( } if (!isInPipMode) { - if (isBuffering) CircularProgressIndicator( - color = MaterialTheme.colorScheme.primary, - modifier = Modifier.align(Alignment.Center) - ) + if (isBuffering) + LoadingIndicator( + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.align(Alignment.Center) + ) SeekFeedback( rewindSeekFeedback, @@ -362,7 +375,12 @@ fun VideoPage( .align(Alignment.CenterEnd) .padding(end = 64.dp) ) - GestureOverlay(showGestureOverlay, gestureIcon, gestureText, Modifier.align(Alignment.Center)) + GestureOverlay( + showGestureOverlay, + gestureIcon, + gestureText, + Modifier.align(Alignment.Center) + ) if (isLocked) { AnimatedVisibility( @@ -381,7 +399,13 @@ fun VideoPage( .windowInsetsPadding(WindowInsets.statusBars) .padding(16.dp) .background(MaterialTheme.colorScheme.surfaceContainer, CircleShape) - ) { Icon(Icons.Rounded.Lock, stringResource(R.string.action_unlock), tint = MaterialTheme.colorScheme.onSurface) } + ) { + Icon( + Icons.Rounded.Lock, + stringResource(R.string.action_unlock), + tint = MaterialTheme.colorScheme.onSurface + ) + } } } } else { @@ -418,11 +442,16 @@ fun VideoPage( AnimatedVisibility( visible = showSettingsMenu && showControls, enter = fadeIn(tween(150)) + scaleIn( - animationSpec = spring(dampingRatio = 0.8f, stiffness = Spring.StiffnessMedium), + animationSpec = spring( + dampingRatio = 0.8f, + stiffness = Spring.StiffnessMedium + ), initialScale = 0.8f, transformOrigin = TransformOrigin(1f, 0f) ), exit = fadeOut(tween(150)) + scaleOut( - animationSpec = tween(150), targetScale = 0.9f, transformOrigin = TransformOrigin(1f, 0f) + animationSpec = tween(150), + targetScale = 0.9f, + transformOrigin = TransformOrigin(1f, 0f) ), modifier = Modifier .fillMaxSize() @@ -476,12 +505,18 @@ fun VideoPage( val view = playerView ?: return@VideoSettingsMenu if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val surfaceView = - view.videoSurfaceView as? android.view.SurfaceView ?: return@VideoSettingsMenu + view.videoSurfaceView as? android.view.SurfaceView + ?: return@VideoSettingsMenu val bitmap = - androidx.core.graphics.createBitmap(surfaceView.width, surfaceView.height) + androidx.core.graphics.createBitmap( + surfaceView.width, + surfaceView.height + ) android.view.PixelCopy.request(surfaceView, bitmap, { result -> if (result == android.view.PixelCopy.SUCCESS) { - if (toClipboard) downloadUtils.copyBitmapToClipboard(bitmap) else downloadUtils.saveBitmapToGallery( + if (toClipboard) downloadUtils.copyBitmapToClipboard( + bitmap + ) else downloadUtils.saveBitmapToGallery( bitmap ) } @@ -549,7 +584,11 @@ fun VideoPlayerControls( exit = slideOutVertically(targetOffsetY = { -it }) + fadeOut(), modifier = Modifier.align(Alignment.TopCenter) ) { - ViewerTopBar(onBack = onBack, onActionClick = onSettingsToggle, isActionActive = isSettingsOpen) + ViewerTopBar( + onBack = onBack, + onActionClick = onSettingsToggle, + isActionActive = isSettingsOpen + ) } AnimatedVisibility( @@ -558,14 +597,25 @@ fun VideoPlayerControls( exit = scaleOut() + fadeOut(), modifier = Modifier.align(Alignment.Center) ) { - Row(horizontalArrangement = Arrangement.spacedBy(48.dp), verticalAlignment = Alignment.CenterVertically) { + Row( + horizontalArrangement = Arrangement.spacedBy(48.dp), + verticalAlignment = Alignment.CenterVertically + ) { IconButton(onClick = onRewind, modifier = Modifier.size(56.dp)) { - Icon(Icons.Rounded.Replay10, stringResource(R.string.viewer_seek_rewind_cd), tint = Color.White, modifier = Modifier.fillMaxSize()) + Icon( + Icons.Rounded.Replay10, + stringResource(R.string.viewer_seek_rewind_cd), + tint = Color.White, + modifier = Modifier.fillMaxSize() + ) } val interactionSource = remember { MutableInteractionSource() } val isPressed by interactionSource.collectIsPressedAsState() - val scale by animateFloatAsState(targetValue = if (isPressed) 0.9f else 1f, label = "scale") + val scale by animateFloatAsState( + targetValue = if (isPressed) 0.9f else 1f, + label = "scale" + ) Box( modifier = Modifier @@ -573,7 +623,10 @@ fun VideoPlayerControls( .size(84.dp) .clip(CircleShape) .background(MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.9f)) - .clickable(interactionSource = interactionSource, indication = null) { onPlayPauseToggle() }, + .clickable( + interactionSource = interactionSource, + indication = null + ) { onPlayPauseToggle() }, contentAlignment = Alignment.Center ) { Icon( @@ -593,7 +646,12 @@ fun VideoPlayerControls( } IconButton(onClick = onForward, modifier = Modifier.size(56.dp)) { - Icon(Icons.Rounded.Forward10, stringResource(R.string.viewer_seek_forward_cd), tint = Color.White, modifier = Modifier.fillMaxSize()) + Icon( + Icons.Rounded.Forward10, + stringResource(R.string.viewer_seek_forward_cd), + tint = Color.White, + modifier = Modifier.fillMaxSize() + ) } } } @@ -747,7 +805,9 @@ fun VideoSettingsMenu( MenuOptionRow( icon = if (resizeMode == AspectRatioFrameLayout.RESIZE_MODE_FIT) Icons.Rounded.AspectRatio else Icons.Rounded.FitScreen, title = stringResource(R.string.settings_scale_mode), - value = if (resizeMode == AspectRatioFrameLayout.RESIZE_MODE_FIT) stringResource(R.string.settings_scale_fit) else stringResource(R.string.settings_scale_zoom), + value = if (resizeMode == AspectRatioFrameLayout.RESIZE_MODE_FIT) stringResource( + R.string.settings_scale_fit + ) else stringResource(R.string.settings_scale_zoom), onClick = onResizeToggle ) } @@ -787,7 +847,11 @@ fun VideoSettingsMenu( modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp), color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.1f) ) - MenuOptionRow(icon = Icons.Rounded.Download, title = stringResource(R.string.action_download_video), onClick = onDownload) + MenuOptionRow( + icon = Icons.Rounded.Download, + title = stringResource(R.string.action_download_video), + onClick = onDownload + ) if (onSaveGif != null) MenuOptionRow( icon = Icons.Rounded.Gif, title = stringResource(R.string.action_save_gifs), @@ -803,7 +867,11 @@ fun VideoSettingsMenu( title = stringResource(R.string.action_copy_link), onClick = onCopyLink ) - MenuOptionRow(icon = Icons.AutoMirrored.Rounded.Forward, title = stringResource(R.string.action_forward), onClick = onForward) + MenuOptionRow( + icon = Icons.AutoMirrored.Rounded.Forward, + title = stringResource(R.string.action_forward), + onClick = onForward + ) MenuOptionRow( icon = Icons.Rounded.Lock, title = stringResource(R.string.settings_lock_controls), @@ -826,6 +894,7 @@ fun VideoSettingsMenu( } } } + SettingsScreen.SPEED -> { Column(modifier = Modifier.padding(vertical = 4.dp)) { Row( @@ -857,6 +926,7 @@ fun VideoSettingsMenu( } } } + SettingsScreen.SCREENSHOT -> { Column(modifier = Modifier.padding(vertical = 4.dp)) { Row( diff --git a/presentation/src/main/java/org/monogram/presentation/features/webapp/components/InvoiceDialog.kt b/presentation/src/main/java/org/monogram/presentation/features/webapp/components/InvoiceDialog.kt index ba031206..fb991d0c 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/webapp/components/InvoiceDialog.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/webapp/components/InvoiceDialog.kt @@ -8,7 +8,9 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -19,7 +21,7 @@ import kotlinx.coroutines.launch import org.monogram.domain.models.webapp.InvoiceModel import org.monogram.domain.repository.MessageRepository -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun InvoiceDialog( slug: String? = null, @@ -77,7 +79,7 @@ fun InvoiceDialog( horizontalAlignment = Alignment.CenterHorizontally ) { if (isLoading) { - CircularProgressIndicator(modifier = Modifier.padding(32.dp)) + LoadingIndicator(modifier = Modifier.padding(32.dp)) } else if (invoice == null) { Text("Failed to load invoice", color = MaterialTheme.colorScheme.error) Spacer(Modifier.height(16.dp)) @@ -108,13 +110,12 @@ fun InvoiceDialog( .background(MaterialTheme.colorScheme.surfaceVariant), contentAlignment = Alignment.Center ) { - CircularProgressIndicator( + CircularWavyProgressIndicator( progress = { progress }, modifier = Modifier, color = ProgressIndicatorDefaults.circularColor, - strokeWidth = 4.dp, - trackColor = ProgressIndicatorDefaults.circularIndeterminateTrackColor, - strokeCap = ProgressIndicatorDefaults.CircularDeterminateStrokeCap, + stroke = Stroke(width = with(LocalDensity.current) { 4.dp.toPx() }, cap = ProgressIndicatorDefaults.CircularDeterminateStrokeCap), + trackColor = ProgressIndicatorDefaults.circularIndeterminateTrackColor ) } } @@ -181,10 +182,9 @@ fun InvoiceDialog( shape = RoundedCornerShape(16.dp) ) { if (isPaying) { - CircularProgressIndicator( + LoadingIndicator( modifier = Modifier.size(20.dp), - color = MaterialTheme.colorScheme.onPrimary, - strokeWidth = 2.dp + color = MaterialTheme.colorScheme.onPrimary ) } else { Text( diff --git a/presentation/src/main/java/org/monogram/presentation/features/webapp/components/MiniAppButtons.kt b/presentation/src/main/java/org/monogram/presentation/features/webapp/components/MiniAppButtons.kt index e0565230..a656e52e 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/webapp/components/MiniAppButtons.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/webapp/components/MiniAppButtons.kt @@ -73,6 +73,7 @@ private fun CustomEmojiIcon( } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun MainButton( state: MainButtonState, @@ -103,10 +104,9 @@ fun MainButton( shape = MaterialTheme.shapes.medium ) { if (state.isProgressVisible) { - CircularProgressIndicator( + LoadingIndicator( modifier = Modifier.size(20.dp), - color = state.textColor ?: defaultTextColor, - strokeWidth = 2.dp + color = state.textColor ?: defaultTextColor ) } else { if (state.iconCustomEmojiId?.toLongOrNull() != null) { @@ -121,6 +121,7 @@ fun MainButton( } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun SecondaryButton( state: SecondaryButtonState, @@ -151,10 +152,9 @@ fun SecondaryButton( shape = MaterialTheme.shapes.medium ) { if (state.isProgressVisible) { - CircularProgressIndicator( + LoadingIndicator( modifier = Modifier.size(20.dp), - color = state.textColor ?: defaultTextColor, - strokeWidth = 2.dp + color = state.textColor ?: defaultTextColor ) } else { if (state.iconCustomEmojiId?.toLongOrNull() != null) { diff --git a/presentation/src/main/java/org/monogram/presentation/features/webapp/components/MiniAppLoadingView.kt b/presentation/src/main/java/org/monogram/presentation/features/webapp/components/MiniAppLoadingView.kt index a20e11bd..338d2867 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/webapp/components/MiniAppLoadingView.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/webapp/components/MiniAppLoadingView.kt @@ -4,8 +4,9 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.LinearProgressIndicator +import androidx.compose.material3.LoadingIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable @@ -14,6 +15,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun MiniAppLoadingView( isInitializing: Boolean, @@ -27,7 +29,7 @@ fun MiniAppLoadingView( color = backgroundColor ?: MaterialTheme.colorScheme.surface ) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - CircularProgressIndicator() + LoadingIndicator() } } } diff --git a/presentation/src/main/java/org/monogram/presentation/settings/chatSettings/ChatSettingsContent.kt b/presentation/src/main/java/org/monogram/presentation/settings/chatSettings/ChatSettingsContent.kt index 5c2aac11..9484307d 100644 --- a/presentation/src/main/java/org/monogram/presentation/settings/chatSettings/ChatSettingsContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/settings/chatSettings/ChatSettingsContent.kt @@ -1171,7 +1171,7 @@ private fun nightModeLabel(mode: NightMode): String = when (mode) { NightMode.BRIGHTNESS -> stringResource(R.string.night_mode_brightness) } -@OptIn(ExperimentalFoundationApi::class) +@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3ExpressiveApi::class) @Composable private fun EmojiStyleItem( style: EmojiStyle, @@ -1259,10 +1259,9 @@ private fun EmojiStyleItem( contentAlignment = Alignment.Center ) { if (isDownloading) { - CircularProgressIndicator( + LoadingIndicator( modifier = Modifier.size(24.dp), - color = Color.White, - strokeWidth = 2.dp + color = Color.White ) } else { Icon( diff --git a/presentation/src/main/java/org/monogram/presentation/settings/folders/FoldersContent.kt b/presentation/src/main/java/org/monogram/presentation/settings/folders/FoldersContent.kt index ac2c096e..36e7a20a 100644 --- a/presentation/src/main/java/org/monogram/presentation/settings/folders/FoldersContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/settings/folders/FoldersContent.kt @@ -33,7 +33,7 @@ import org.monogram.domain.models.FolderModel import org.monogram.presentation.R import org.monogram.presentation.core.ui.ItemPosition -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun FoldersContent(component: FoldersComponent) { val state by component.state.subscribeAsState() @@ -88,7 +88,7 @@ fun FoldersContent(component: FoldersComponent) { .padding(top = padding.calculateTopPadding()) ) { if (state.isLoading) { - CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) + LoadingIndicator(modifier = Modifier.align(Alignment.Center)) } else { FolderList( systemFolders = systemFolders, diff --git a/presentation/src/main/java/org/monogram/presentation/settings/networkUsage/NetworkUsageContent.kt b/presentation/src/main/java/org/monogram/presentation/settings/networkUsage/NetworkUsageContent.kt index 5aea294f..1b8ab12f 100644 --- a/presentation/src/main/java/org/monogram/presentation/settings/networkUsage/NetworkUsageContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/settings/networkUsage/NetworkUsageContent.kt @@ -45,7 +45,7 @@ private enum class NetworkTab(val titleRes: Int, val icon: ImageVector) { Other(R.string.other_tab, Icons.Rounded.DevicesOther) } -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun NetworkUsageContent(component: NetworkUsageComponent) { val state by component.state.subscribeAsState() @@ -101,7 +101,7 @@ fun NetworkUsageContent(component: NetworkUsageComponent) { .padding(padding), contentAlignment = Alignment.Center ) { - CircularProgressIndicator() + LoadingIndicator() } } else { Column( diff --git a/presentation/src/main/java/org/monogram/presentation/settings/notifications/NotificationsExceptionsContent.kt b/presentation/src/main/java/org/monogram/presentation/settings/notifications/NotificationsExceptionsContent.kt index 3688c70b..7c2855c8 100644 --- a/presentation/src/main/java/org/monogram/presentation/settings/notifications/NotificationsExceptionsContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/settings/notifications/NotificationsExceptionsContent.kt @@ -1,18 +1,60 @@ package org.monogram.presentation.settings.notifications -import androidx.compose.animation.* +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically +import androidx.compose.animation.togetherWith import androidx.compose.foundation.background import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBarsPadding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.rounded.ArrowBack -import androidx.compose.material.icons.rounded.* -import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.material.icons.rounded.Close +import androidx.compose.material.icons.rounded.Delete +import androidx.compose.material.icons.rounded.Notifications +import androidx.compose.material.icons.rounded.NotificationsOff +import androidx.compose.material.icons.rounded.Search +import androidx.compose.material3.BottomSheetDefaults +import androidx.compose.material3.Button +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.ListItem +import androidx.compose.material3.ListItemDefaults +import androidx.compose.material3.LoadingIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SearchBar +import androidx.compose.material3.SearchBarDefaults +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -25,10 +67,10 @@ import com.arkivanov.decompose.extensions.compose.subscribeAsState import org.monogram.domain.models.ChatModel import org.monogram.domain.repository.SettingsRepository.TdNotificationScope import org.monogram.presentation.core.ui.Avatar -import org.monogram.presentation.features.chats.currentChat.components.VideoPlayerPool import org.monogram.presentation.core.ui.ItemPosition +import org.monogram.presentation.features.chats.currentChat.components.VideoPlayerPool -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun NotificationsExceptionsContent( component: NotificationsComponent, @@ -162,7 +204,7 @@ fun NotificationsExceptionsContent( .padding(padding), contentAlignment = Alignment.Center ) { - CircularProgressIndicator() + LoadingIndicator() } } diff --git a/presentation/src/main/java/org/monogram/presentation/settings/privacy/BlockedUsersContent.kt b/presentation/src/main/java/org/monogram/presentation/settings/privacy/BlockedUsersContent.kt index e6e93a78..58b87fe9 100644 --- a/presentation/src/main/java/org/monogram/presentation/settings/privacy/BlockedUsersContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/settings/privacy/BlockedUsersContent.kt @@ -1,11 +1,25 @@ package org.monogram.presentation.settings.privacy -import androidx.compose.animation.* +import androidx.compose.animation.AnimatedContent import androidx.compose.animation.core.EaseIn import androidx.compose.animation.core.EaseOut import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.scaleIn +import androidx.compose.animation.togetherWith import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons @@ -14,8 +28,25 @@ import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.rounded.Add import androidx.compose.material.icons.rounded.MoreVert import androidx.compose.material.icons.rounded.Verified -import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.LoadingIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -31,7 +62,7 @@ import org.monogram.presentation.core.ui.Avatar import org.monogram.presentation.core.ui.ItemPosition import org.monogram.presentation.features.chats.currentChat.components.VideoPlayerPool -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun BlockedUsersContent(component: BlockedUsersComponent) { val state by component.state.subscribeAsState() @@ -99,7 +130,7 @@ fun BlockedUsersContent(component: BlockedUsersComponent) { modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { - CircularProgressIndicator() + LoadingIndicator() } } diff --git a/presentation/src/main/java/org/monogram/presentation/settings/privacy/PrivacyListContent.kt b/presentation/src/main/java/org/monogram/presentation/settings/privacy/PrivacyListContent.kt index 36db9983..151c7a77 100644 --- a/presentation/src/main/java/org/monogram/presentation/settings/privacy/PrivacyListContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/settings/privacy/PrivacyListContent.kt @@ -35,7 +35,7 @@ import org.monogram.presentation.core.ui.ItemPosition import org.monogram.presentation.core.ui.SettingsSwitchTile import org.monogram.presentation.core.ui.SettingsTile -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun PrivacyListContent(component: PrivacyListComponent) { val state by component.state.subscribeAsState() @@ -103,7 +103,7 @@ fun PrivacyListContent(component: PrivacyListComponent) { modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { - CircularProgressIndicator() + LoadingIndicator() } } else { LazyColumn( diff --git a/presentation/src/main/java/org/monogram/presentation/settings/privacy/userSelection/UserSelectionContent.kt b/presentation/src/main/java/org/monogram/presentation/settings/privacy/userSelection/UserSelectionContent.kt index 0d6d2cf3..20d46de7 100644 --- a/presentation/src/main/java/org/monogram/presentation/settings/privacy/userSelection/UserSelectionContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/settings/privacy/userSelection/UserSelectionContent.kt @@ -1,17 +1,42 @@ package org.monogram.presentation.settings.privacy.userSelection -import androidx.compose.animation.* +import androidx.compose.animation.AnimatedContent import androidx.compose.animation.core.EaseIn import androidx.compose.animation.core.EaseOut import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.scaleIn +import androidx.compose.animation.togetherWith import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.consumeWindowInsets +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.rounded.ArrowBack import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.rounded.Verified -import androidx.compose.material3.* +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.ListItem +import androidx.compose.material3.ListItemDefaults +import androidx.compose.material3.LoadingIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember @@ -27,7 +52,7 @@ import org.monogram.presentation.core.ui.Avatar import org.monogram.presentation.core.ui.SettingsGroup import org.monogram.presentation.features.chats.currentChat.components.VideoPlayerPool -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun UserSelectionContent(component: UserSelectionComponent) { val state by component.state.subscribeAsState() @@ -83,7 +108,7 @@ fun UserSelectionContent(component: UserSelectionComponent) { modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { - CircularProgressIndicator() + LoadingIndicator() } } diff --git a/presentation/src/main/java/org/monogram/presentation/settings/profile/EditProfileContent.kt b/presentation/src/main/java/org/monogram/presentation/settings/profile/EditProfileContent.kt index 953b88da..c40e6d45 100644 --- a/presentation/src/main/java/org/monogram/presentation/settings/profile/EditProfileContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/settings/profile/EditProfileContent.kt @@ -54,7 +54,7 @@ import java.util.* private const val MAP_STYLE = "https://tiles.openfreemap.org/styles/bright" -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun EditProfileContent(component: EditProfileComponent) { val state by component.state.subscribeAsState() @@ -767,11 +767,10 @@ fun EditProfileContent(component: EditProfileComponent) { }, actions = { if (state.isLoading) { - CircularProgressIndicator( + LoadingIndicator( modifier = Modifier .size(24.dp) - .padding(end = 16.dp), - strokeWidth = 2.dp + .padding(end = 16.dp) ) } else if (state.user != null) { IconButton(onClick = component::onSave) { @@ -794,7 +793,7 @@ fun EditProfileContent(component: EditProfileComponent) { .padding(padding), contentAlignment = Alignment.Center ) { - CircularProgressIndicator() + LoadingIndicator() } } else { LazyColumn( diff --git a/presentation/src/main/java/org/monogram/presentation/settings/proxy/ProxyContent.kt b/presentation/src/main/java/org/monogram/presentation/settings/proxy/ProxyContent.kt index 4a846879..aa1c5a9b 100644 --- a/presentation/src/main/java/org/monogram/presentation/settings/proxy/ProxyContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/settings/proxy/ProxyContent.kt @@ -38,7 +38,10 @@ import org.monogram.presentation.core.ui.ItemPosition import org.monogram.presentation.core.ui.SettingsSwitchTile import org.monogram.presentation.core.ui.SettingsTile -@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) +@OptIn( + ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class, + ExperimentalMaterial3ExpressiveApi::class +) @Composable fun ProxyContent(component: ProxyComponent) { val state by component.state.subscribeAsState() @@ -73,7 +76,10 @@ fun ProxyContent(component: ProxyComponent) { }, actions = { IconButton(onClick = component::onPingAll) { - Icon(Icons.Rounded.Refresh, contentDescription = stringResource(R.string.refresh_pings_cd)) + Icon( + Icons.Rounded.Refresh, + contentDescription = stringResource(R.string.refresh_pings_cd) + ) } }, colors = TopAppBarDefaults.topAppBarColors( @@ -135,7 +141,8 @@ fun ProxyContent(component: ProxyComponent) { onCheckedChange = component::onPreferIpv6Toggled ) - val isDirect = state.proxies.none { it.isEnabled } && state.telegaProxies.none { it.isEnabled } + val isDirect = + state.proxies.none { it.isEnabled } && state.telegaProxies.none { it.isEnabled } SettingsTile( icon = Icons.Rounded.LinkOff, title = stringResource(R.string.disable_proxy_title), @@ -147,7 +154,11 @@ fun ProxyContent(component: ProxyComponent) { onClick = { component.onDisableProxy() }, trailingContent = { if (isDirect) { - Icon(Icons.Rounded.Check, contentDescription = null, tint = Color(0xFF34A853)) + Icon( + Icons.Rounded.Check, + contentDescription = null, + tint = Color(0xFF34A853) + ) } } ) @@ -165,7 +176,8 @@ fun ProxyContent(component: ProxyComponent) { text = stringResource(R.string.telega_proxy_header), subtitle = stringResource(R.string.telega_proxy_subtitle), onSubtitleClick = { - val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://t.me/telegaru")) + val intent = + Intent(Intent.ACTION_VIEW, Uri.parse("https://t.me/telegaru")) context.startActivity(intent) } ) @@ -200,9 +212,8 @@ fun ProxyContent(component: ProxyComponent) { onClick = { component.onFetchTelegaProxies() }, trailingContent = { if (state.isFetchingExternal) { - CircularProgressIndicator( - modifier = Modifier.size(20.dp), - strokeWidth = 2.dp + LoadingIndicator( + modifier = Modifier.size(20.dp) ) } } @@ -346,7 +357,14 @@ fun ProxyContent(component: ProxyComponent) { AlertDialog( onDismissRequest = component::onDismissDeleteConfirmation, title = { Text(stringResource(R.string.delete_proxy_title)) }, - text = { Text(stringResource(R.string.delete_proxy_confirmation_format, proxy.server)) }, + text = { + Text( + stringResource( + R.string.delete_proxy_confirmation_format, + proxy.server + ) + ) + }, confirmButton = { TextButton( onClick = component::onConfirmDelete, @@ -496,7 +514,10 @@ fun ProxyItem( style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier - .background(MaterialTheme.colorScheme.surfaceVariant, RoundedCornerShape(4.dp)) + .background( + MaterialTheme.colorScheme.surfaceVariant, + RoundedCornerShape(4.dp) + ) .padding(horizontal = 4.dp, vertical = 1.dp) ) Spacer(Modifier.width(8.dp)) @@ -607,7 +628,7 @@ private fun SectionHeader( } } -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun ProxyAddEditSheet( proxy: ProxyModel?, @@ -631,7 +652,11 @@ fun ProxyAddEditSheet( ) } - var secret by remember { mutableStateOf((proxy?.type as? ProxyTypeModel.Mtproto)?.secret ?: "") } + var secret by remember { + mutableStateOf( + (proxy?.type as? ProxyTypeModel.Mtproto)?.secret ?: "" + ) + } var username by remember { mutableStateOf( when (val t = proxy?.type) { @@ -659,7 +684,8 @@ fun ProxyAddEditSheet( } } - val isInputValid = server.isNotBlank() && port.isNotBlank() && (type != "MTProto" || secret.isNotBlank()) + val isInputValid = + server.isNotBlank() && port.isNotBlank() && (type != "MTProto" || secret.isNotBlank()) ModalBottomSheet( onDismissRequest = onDismiss, @@ -675,7 +701,9 @@ fun ProxyAddEditSheet( .padding(bottom = 32.dp) ) { Text( - text = if (proxy == null) stringResource(R.string.new_proxy_title) else stringResource(R.string.edit_proxy_title), + text = if (proxy == null) stringResource(R.string.new_proxy_title) else stringResource( + R.string.edit_proxy_title + ), style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold ) @@ -686,7 +714,10 @@ fun ProxyAddEditSheet( Modifier .selectableGroup() .fillMaxWidth() - .background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f), RoundedCornerShape(50)) + .background( + MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f), + RoundedCornerShape(50) + ) .padding(4.dp), horizontalArrangement = Arrangement.SpaceBetween ) { @@ -811,10 +842,7 @@ fun ProxyAddEditSheet( shape = RoundedCornerShape(16.dp) ) { if (isTesting) { - CircularProgressIndicator( - modifier = Modifier.size(18.dp), - strokeWidth = 2.dp - ) + LoadingIndicator(modifier = Modifier.size(18.dp)) } else { Text(stringResource(R.string.test_proxy_button)) } @@ -832,7 +860,9 @@ fun ProxyAddEditSheet( shape = RoundedCornerShape(16.dp) ) { Text( - if (proxy == null) stringResource(R.string.add_proxy_button) else stringResource(R.string.save_changes_button), + if (proxy == null) stringResource(R.string.add_proxy_button) else stringResource( + R.string.save_changes_button + ), fontSize = 16.sp, fontWeight = FontWeight.Bold ) diff --git a/presentation/src/main/java/org/monogram/presentation/settings/sessions/SessionsContent.kt b/presentation/src/main/java/org/monogram/presentation/settings/sessions/SessionsContent.kt index 958d7a70..f2c10575 100644 --- a/presentation/src/main/java/org/monogram/presentation/settings/sessions/SessionsContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/settings/sessions/SessionsContent.kt @@ -32,7 +32,7 @@ import org.monogram.presentation.R import org.monogram.presentation.core.ui.IntegratedQRScanner import org.monogram.presentation.core.ui.ItemPosition -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun SessionsContent(component: SessionsComponent) { val state by component.state.subscribeAsState() @@ -218,7 +218,7 @@ fun SessionsContent(component: SessionsComponent) { } if (state.isLoading) { - CircularProgressIndicator(Modifier.align(Alignment.Center)) + LoadingIndicator(Modifier.align(Alignment.Center)) } } } diff --git a/presentation/src/main/java/org/monogram/presentation/settings/stickers/StickersContent.kt b/presentation/src/main/java/org/monogram/presentation/settings/stickers/StickersContent.kt index 56495a1a..423af990 100644 --- a/presentation/src/main/java/org/monogram/presentation/settings/stickers/StickersContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/settings/stickers/StickersContent.kt @@ -60,7 +60,7 @@ private enum class StickerTab(val titleRes: Int, val icon: ImageVector) { Emoji(R.string.emoji_tab, Icons.Rounded.EmojiEmotions) } -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun StickersContent(component: StickersComponent) { val state by component.state.subscribeAsState() @@ -123,7 +123,8 @@ fun StickersContent(component: StickersComponent) { ) { StickerTab.entries.forEachIndexed { index, tab -> val selected = (state.selectedTabIndex == index) - val count = if (index == 0) state.stickerSets.size else state.emojiSets.size + val count = + if (index == 0) state.stickerSets.size else state.emojiSets.size val backgroundColor by animateColorAsState( if (selected) MaterialTheme.colorScheme.primary else Color.Transparent, @@ -197,20 +198,21 @@ fun StickersContent(component: StickersComponent) { .padding(32.dp), contentAlignment = Alignment.Center ) { - CircularProgressIndicator() + LoadingIndicator() } } else { when (tabIndex) { 0 -> { - val filteredSets = remember(state.stickerSets, debouncedSearchQuery) { - if (debouncedSearchQuery.isEmpty()) state.stickerSets - else state.stickerSets.filter { - it.title.contains( - debouncedSearchQuery, - ignoreCase = true - ) + val filteredSets = + remember(state.stickerSets, debouncedSearchQuery) { + if (debouncedSearchQuery.isEmpty()) state.stickerSets + else state.stickerSets.filter { + it.title.contains( + debouncedSearchQuery, + ignoreCase = true + ) + } } - } GenericStickerList( sets = filteredSets, archivedSets = state.archivedStickerSets, @@ -382,12 +384,18 @@ private fun GenericStickerList( onActiveChange = { }, placeholder = { Text(stringResource(R.string.search_packs_placeholder)) }, leadingIcon = { - Icon(Icons.Rounded.Search, contentDescription = stringResource(R.string.action_search)) + Icon( + Icons.Rounded.Search, + contentDescription = stringResource(R.string.action_search) + ) }, trailingIcon = { if (searchQuery.isNotEmpty()) { IconButton(onClick = { onSearchQueryChange("") }) { - Icon(Icons.Rounded.Close, contentDescription = stringResource(R.string.action_clear)) + Icon( + Icons.Rounded.Close, + contentDescription = stringResource(R.string.action_clear) + ) } } }, @@ -479,7 +487,8 @@ private fun GenericStickerList( totalDragDistance += dragAmount.y val currentItemInfo = listState.layoutInfo.visibleItemsInfo - .firstOrNull { it.key == set.id } ?: return@detectDragGesturesAfterLongPress + .firstOrNull { it.key == set.id } + ?: return@detectDragGesturesAfterLongPress val targetY = initialDragStartOffset + totalDragDistance dragOffset = targetY - currentItemInfo.offset @@ -501,17 +510,25 @@ private fun GenericStickerList( } } - val viewPortHeight = listState.layoutInfo.viewportSize.height + val viewPortHeight = + listState.layoutInfo.viewportSize.height val topThreshold = 100.dp.toPx() val bottomThreshold = viewPortHeight - 100.dp.toPx() val pointerY = initialPointerY + totalDragDistance if (pointerY < topThreshold) { - val intensity = ((topThreshold - pointerY) / topThreshold).coerceIn(0f, 1f) + val intensity = + ((topThreshold - pointerY) / topThreshold).coerceIn( + 0f, + 1f + ) autoScrollVelocity = -(6f + (18f * intensity)) } else if (pointerY > bottomThreshold) { val intensity = - ((pointerY - bottomThreshold) / topThreshold).coerceIn(0f, 1f) + ((pointerY - bottomThreshold) / topThreshold).coerceIn( + 0f, + 1f + ) autoScrollVelocity = 6f + (18f * intensity) } else { autoScrollVelocity = 0f diff --git a/presentation/src/main/java/org/monogram/presentation/settings/storage/StorageUsageContent.kt b/presentation/src/main/java/org/monogram/presentation/settings/storage/StorageUsageContent.kt index dd716414..3e3ba052 100644 --- a/presentation/src/main/java/org/monogram/presentation/settings/storage/StorageUsageContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/settings/storage/StorageUsageContent.kt @@ -56,7 +56,7 @@ private val ChartColors = listOf( Color(0xFF90A4AE) // Blue Grey ) -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun StorageUsageContent(component: StorageUsageComponent) { val state by component.state.subscribeAsState() @@ -96,7 +96,7 @@ fun StorageUsageContent(component: StorageUsageComponent) { Box(modifier = Modifier .fillMaxSize() .padding(padding), contentAlignment = Alignment.Center) { - CircularProgressIndicator() + LoadingIndicator() } } else { val usage = state.usage From 5f64af24a303c6a0de64df87a6fbd4972acbc5f5 Mon Sep 17 00:00:00 2001 From: Fimkov <123477029+fimkov@users.noreply.github.com> Date: Fri, 3 Apr 2026 19:30:23 +0700 Subject: [PATCH 2/2] replaced LinearProgressIndicator with LinearWavyProgressIndicator where it looks good --- .../features/chats/chatList/components/AccountMenu.kt | 6 ++++-- .../features/profile/components/StatisticsViewer.kt | 4 ++-- .../presentation/features/webview/InternalWebView.kt | 4 ++-- .../monogram/presentation/settings/about/AboutContent.kt | 6 +++--- .../settings/networkUsage/NetworkUsageContent.kt | 3 ++- .../presentation/settings/storage/StorageUsageContent.kt | 3 ++- 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/presentation/src/main/java/org/monogram/presentation/features/chats/chatList/components/AccountMenu.kt b/presentation/src/main/java/org/monogram/presentation/features/chats/chatList/components/AccountMenu.kt index 99958a5d..5bc512d1 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/chats/chatList/components/AccountMenu.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/chats/chatList/components/AccountMenu.kt @@ -51,7 +51,8 @@ import androidx.compose.material.icons.rounded.SystemUpdate import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.LinearProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.LinearWavyProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -100,6 +101,7 @@ import org.monogram.presentation.core.util.CountryManager import org.monogram.presentation.features.chats.currentChat.components.VideoPlayerPool import kotlin.math.roundToInt +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun AccountMenu( user: UserModel?, @@ -426,7 +428,7 @@ fun AccountMenu( } ) if (updateState is UpdateState.Downloading) { - LinearProgressIndicator( + LinearWavyProgressIndicator( progress = { updateState.progress }, modifier = Modifier .fillMaxWidth() diff --git a/presentation/src/main/java/org/monogram/presentation/features/profile/components/StatisticsViewer.kt b/presentation/src/main/java/org/monogram/presentation/features/profile/components/StatisticsViewer.kt index b66ab5b5..4fac5f4e 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/profile/components/StatisticsViewer.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/profile/components/StatisticsViewer.kt @@ -339,6 +339,7 @@ fun ChannelStatistics(stats: ChatStatisticsModel, onLoadGraph: (String) -> Unit) } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun InteractionItem(interaction: ChatInteractionInfoModel) { var expanded by remember { mutableStateOf(false) } @@ -419,7 +420,7 @@ fun InteractionItem(interaction: ChatInteractionInfoModel) { InteractionStat(Icons.Rounded.EmojiEmotions, interaction.reactionCount) } Spacer(modifier = Modifier.height(10.dp)) - LinearProgressIndicator( + LinearWavyProgressIndicator( progress = { (interaction.viewCount.toFloat() / dominantMetric.toFloat()).coerceIn(0f, 1f) }, modifier = Modifier .fillMaxWidth() @@ -427,7 +428,6 @@ fun InteractionItem(interaction: ChatInteractionInfoModel) { .clip(CircleShape), color = MaterialTheme.colorScheme.primary, trackColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.15f), - drawStopIndicator = {} ) Spacer(modifier = Modifier.height(8.dp)) Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { diff --git a/presentation/src/main/java/org/monogram/presentation/features/webview/InternalWebView.kt b/presentation/src/main/java/org/monogram/presentation/features/webview/InternalWebView.kt index aac74693..c45e568c 100644 --- a/presentation/src/main/java/org/monogram/presentation/features/webview/InternalWebView.kt +++ b/presentation/src/main/java/org/monogram/presentation/features/webview/InternalWebView.kt @@ -35,7 +35,7 @@ import org.monogram.presentation.features.webview.components.OptionsSheet import org.monogram.presentation.features.webview.components.WebViewTopBar import java.io.ByteArrayInputStream -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun InternalWebView( url: String, @@ -394,7 +394,7 @@ fun InternalWebView( exit = fadeOut(animationSpec = tween(500)) + shrinkVertically(), modifier = Modifier.align(Alignment.TopCenter) ) { - LinearProgressIndicator( + LinearWavyProgressIndicator( progress = { progress }, modifier = Modifier.fillMaxWidth(), color = MaterialTheme.colorScheme.primary, diff --git a/presentation/src/main/java/org/monogram/presentation/settings/about/AboutContent.kt b/presentation/src/main/java/org/monogram/presentation/settings/about/AboutContent.kt index 6b59bd5e..0bfa3b3a 100644 --- a/presentation/src/main/java/org/monogram/presentation/settings/about/AboutContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/settings/about/AboutContent.kt @@ -37,7 +37,7 @@ import org.monogram.presentation.core.ui.ItemPosition import org.monogram.presentation.core.ui.SettingsItem import org.monogram.presentation.core.util.AppUtils -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun AboutContent(component: AboutComponent) { val updateState by component.updateState.collectAsState() @@ -336,6 +336,7 @@ private fun UpdateSection(state: UpdateState, component: AboutComponent) { } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable private fun DownloadingUpdateItem(state: UpdateState.Downloading) { Surface( @@ -383,14 +384,13 @@ private fun DownloadingUpdateItem(state: UpdateState.Downloading) { } Spacer(modifier = Modifier.height(12.dp)) val animatedProgress by animateFloatAsState(targetValue = state.progress, label = "progress") - LinearProgressIndicator( + LinearWavyProgressIndicator( progress = { animatedProgress }, modifier = Modifier .fillMaxWidth() .height(6.dp), color = Color(0xFFF9AB00), trackColor = Color(0xFFF9AB00).copy(alpha = 0.2f), - strokeCap = StrokeCap.Round ) } } diff --git a/presentation/src/main/java/org/monogram/presentation/settings/networkUsage/NetworkUsageContent.kt b/presentation/src/main/java/org/monogram/presentation/settings/networkUsage/NetworkUsageContent.kt index 1b8ab12f..221938b7 100644 --- a/presentation/src/main/java/org/monogram/presentation/settings/networkUsage/NetworkUsageContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/settings/networkUsage/NetworkUsageContent.kt @@ -425,6 +425,7 @@ private fun NetworkTabBody( } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable private fun UsageRowItem( category: NetworkUsageCategory, @@ -501,7 +502,7 @@ private fun UsageRowItem( color = MaterialTheme.colorScheme.onSurfaceVariant ) Spacer(modifier = Modifier.height(6.dp)) - LinearProgressIndicator( + LinearWavyProgressIndicator( progress = { visualProgress }, modifier = Modifier .fillMaxWidth(0.8f) diff --git a/presentation/src/main/java/org/monogram/presentation/settings/storage/StorageUsageContent.kt b/presentation/src/main/java/org/monogram/presentation/settings/storage/StorageUsageContent.kt index 3e3ba052..fa3399de 100644 --- a/presentation/src/main/java/org/monogram/presentation/settings/storage/StorageUsageContent.kt +++ b/presentation/src/main/java/org/monogram/presentation/settings/storage/StorageUsageContent.kt @@ -563,6 +563,7 @@ fun StorageChartHeader( } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun StorageItemRow( chatUsage: ChatStorageUsageModel, @@ -646,7 +647,7 @@ fun StorageItemRow( color = MaterialTheme.colorScheme.onSurfaceVariant ) Spacer(modifier = Modifier.height(6.dp)) - LinearProgressIndicator( + LinearWavyProgressIndicator( progress = { relativeProgress }, modifier = Modifier .fillMaxWidth(0.8f)