diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIFileView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIFileView.kt index ac759cd2ce..5f448fdcdb 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIFileView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIFileView.kt @@ -115,7 +115,7 @@ fun CIFileView( CircularProgressIndicator( Modifier.size(32.dp), color = if (isInDarkTheme()) FileDark else FileLight, - strokeWidth = 4.dp + strokeWidth = 3.dp ) } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIImageView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIImageView.kt index 8599dc9137..eb261a4ff0 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIImageView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIImageView.kt @@ -2,6 +2,7 @@ package chat.simplex.app.views.chat.item import android.graphics.Bitmap import android.os.Build.VERSION.SDK_INT +import androidx.annotation.StringRes import androidx.compose.foundation.Image import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.* @@ -9,8 +10,7 @@ import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.Icon import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check -import androidx.compose.material.icons.outlined.ArrowDownward -import androidx.compose.material.icons.outlined.MoreHoriz +import androidx.compose.material.icons.outlined.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -18,6 +18,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.layoutId import androidx.compose.ui.platform.* @@ -53,6 +54,16 @@ fun CIImageView( ) } + @Composable + fun fileIcon(icon: ImageVector, @StringRes stringId: Int) { + Icon( + icon, + stringResource(stringId), + Modifier.fillMaxSize(), + tint = Color.White + ) + } + @Composable fun loadingIndicator() { if (file != null) { @@ -68,31 +79,13 @@ fun CIImageView( FileProtocol.XFTP -> progressIndicator() FileProtocol.SMP -> {} } - is CIFileStatus.SndTransfer -> - progressIndicator() - is CIFileStatus.SndComplete -> - Icon( - Icons.Filled.Check, - stringResource(R.string.icon_descr_image_snd_complete), - Modifier.fillMaxSize(), - tint = Color.White - ) - is CIFileStatus.RcvAccepted -> - Icon( - Icons.Outlined.MoreHoriz, - stringResource(R.string.icon_descr_waiting_for_image), - Modifier.fillMaxSize(), - tint = Color.White - ) - is CIFileStatus.RcvTransfer -> - progressIndicator() - is CIFileStatus.RcvInvitation -> - Icon( - Icons.Outlined.ArrowDownward, - stringResource(R.string.icon_descr_asked_to_receive), - Modifier.fillMaxSize(), - tint = Color.White - ) + is CIFileStatus.SndTransfer -> progressIndicator() + is CIFileStatus.SndComplete -> fileIcon(Icons.Filled.Check, R.string.icon_descr_image_snd_complete) + is CIFileStatus.SndCancelled -> fileIcon(Icons.Outlined.Close, R.string.icon_descr_file) + is CIFileStatus.RcvInvitation -> fileIcon(Icons.Outlined.ArrowDownward, R.string.icon_descr_asked_to_receive) + is CIFileStatus.RcvAccepted -> fileIcon(Icons.Outlined.MoreHoriz, R.string.icon_descr_waiting_for_image) + is CIFileStatus.RcvTransfer -> progressIndicator() + is CIFileStatus.RcvCancelled -> fileIcon(Icons.Outlined.Close, R.string.icon_descr_file) else -> {} } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIVideoView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIVideoView.kt index 5ba1d1498b..5ba59bce5d 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIVideoView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/CIVideoView.kt @@ -3,8 +3,10 @@ package chat.simplex.app.views.chat.item import android.graphics.Bitmap import android.graphics.Rect import android.net.Uri +import androidx.annotation.StringRes import androidx.compose.foundation.* import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CornerSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* import androidx.compose.material.icons.Icons @@ -15,6 +17,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.* import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.* import androidx.compose.ui.platform.* import androidx.compose.ui.res.stringResource @@ -251,6 +254,30 @@ private fun progressIndicator() { ) } +@Composable +private fun fileIcon(icon: ImageVector, @StringRes stringId: Int) { + Icon( + icon, + stringResource(stringId), + Modifier.fillMaxSize(), + tint = Color.White + ) +} + +@Composable +private fun progressCircle(progress: Long, total: Long) { + val angle = 360f * (progress.toDouble() / total.toDouble()).toFloat() + val strokeWidth = with(LocalDensity.current) { 2.dp.toPx() } + val strokeColor = Color.White + Surface( + Modifier.drawRingModifier(angle, strokeColor, strokeWidth), + color = Color.Transparent, + shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)) + ) { + Box(Modifier.size(16.dp)) + } +} + @Composable private fun loadingIndicator(file: CIFile?) { if (file != null) { @@ -267,30 +294,21 @@ private fun loadingIndicator(file: CIFile?) { FileProtocol.SMP -> {} } is CIFileStatus.SndTransfer -> - progressIndicator() - is CIFileStatus.SndComplete -> - Icon( - Icons.Filled.Check, - stringResource(R.string.icon_descr_video_snd_complete), - Modifier.fillMaxSize(), - tint = Color.White - ) - is CIFileStatus.RcvAccepted -> - Icon( - Icons.Outlined.MoreHoriz, - stringResource(R.string.icon_descr_waiting_for_video), - Modifier.fillMaxSize(), - tint = Color.White - ) + when (file.fileProtocol) { + FileProtocol.XFTP -> progressCircle(file.fileStatus.sndProgress, file.fileStatus.sndTotal) + FileProtocol.SMP -> progressIndicator() + } + is CIFileStatus.SndComplete -> fileIcon(Icons.Filled.Check, R.string.icon_descr_video_snd_complete) + is CIFileStatus.SndCancelled -> fileIcon(Icons.Outlined.Close, R.string.icon_descr_file) + is CIFileStatus.RcvInvitation -> fileIcon(Icons.Outlined.ArrowDownward, R.string.icon_descr_video_asked_to_receive) + is CIFileStatus.RcvAccepted -> fileIcon(Icons.Outlined.MoreHoriz, R.string.icon_descr_waiting_for_video) is CIFileStatus.RcvTransfer -> - progressIndicator() - is CIFileStatus.RcvInvitation -> - Icon( - Icons.Outlined.ArrowDownward, - stringResource(R.string.icon_descr_video_asked_to_receive), - Modifier.fillMaxSize(), - tint = Color.White - ) + if (file.fileProtocol == FileProtocol.XFTP && file.fileStatus.rcvProgress < file.fileStatus.rcvTotal) { + progressCircle(file.fileStatus.rcvProgress, file.fileStatus.rcvTotal) + } else { + progressIndicator() + } + is CIFileStatus.RcvCancelled -> fileIcon(Icons.Outlined.Close, R.string.icon_descr_file) else -> {} } } diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift index d53639cd29..aa1ae322b6 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/CIImageView.swift @@ -90,29 +90,27 @@ struct CIImageView: View { case .xftp: progressView() case .smp: EmptyView() } - case .sndTransfer: - progressView() - case .sndComplete: - Image(systemName: "checkmark") - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 10, height: 10) - .foregroundColor(.white) - .padding(13) - case .rcvAccepted: - Image(systemName: "ellipsis") - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 14, height: 14) - .foregroundColor(.white) - .padding(11) - case .rcvTransfer: - progressView() + case .sndTransfer: progressView() + case .sndComplete: fileIcon("checkmark", 10, 13) + case .sndCancelled: fileIcon("xmark", 10, 13) + case .rcvInvitation: fileIcon("arrow.down", 10, 13) + case .rcvAccepted: fileIcon("ellipsis", 14, 11) + case .rcvTransfer: progressView() + case .rcvCancelled: fileIcon("xmark", 10, 13) default: EmptyView() } } } + private func fileIcon(_ icon: String, _ size: CGFloat, _ padding: CGFloat) -> some View { + Image(systemName: icon) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: size, height: size) + .foregroundColor(.white) + .padding(padding) + } + private func progressView() -> some View { ProgressView() .progressViewStyle(.circular)