-
Notifications
You must be signed in to change notification settings - Fork 1.3k
CMM-885 support HE attachments i2 #22333
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
adalpari
merged 11 commits into
feat/CMM-885-support-HE-attachments
from
feat/CMM-885-support-HE-attachments-i2
Nov 4, 2025
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
7890c15
Showing attachments previews
adalpari bbe0ae7
Typo
adalpari eb02a33
Fixing pan issue
adalpari 900cdaf
Passing attachments directly instead of searching for then when tappe…
adalpari 2a4ac16
Merge branch 'feat/CMM-885-support-HE-attachments' into feat/CMM-885-…
adalpari 315083a
Compile fix
adalpari 031fb06
Fixing the send state message
adalpari 1573520
Checking network availability
adalpari 2006d63
Saving message state when error
adalpari 80bedeb
Tests
adalpari 0e058dc
Reverting non-related commits done by mistake
adalpari File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
200 changes: 200 additions & 0 deletions
200
...ess/src/main/java/org/wordpress/android/support/he/ui/AttachmentFullscreenImagePreview.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,200 @@ | ||
| package org.wordpress.android.support.he.ui | ||
|
|
||
| import android.content.res.Configuration.UI_MODE_NIGHT_YES | ||
| import androidx.compose.foundation.background | ||
| import androidx.compose.foundation.clickable | ||
| import androidx.compose.foundation.gestures.detectTransformGestures | ||
| import androidx.compose.foundation.layout.Arrangement | ||
| import androidx.compose.foundation.layout.Box | ||
| import androidx.compose.foundation.layout.Row | ||
| import androidx.compose.foundation.layout.fillMaxSize | ||
| import androidx.compose.foundation.layout.padding | ||
| import androidx.compose.foundation.layout.size | ||
| import androidx.compose.foundation.shape.RoundedCornerShape | ||
| import androidx.compose.material.icons.Icons | ||
| import androidx.compose.material.icons.filled.Close | ||
| import androidx.compose.material3.CircularProgressIndicator | ||
| import androidx.compose.material3.Icon | ||
| import androidx.compose.material3.IconButton | ||
| import androidx.compose.material3.Surface | ||
| import androidx.compose.runtime.Composable | ||
| import androidx.compose.runtime.getValue | ||
| import androidx.compose.runtime.mutableFloatStateOf | ||
| import androidx.compose.runtime.remember | ||
| import androidx.compose.runtime.setValue | ||
| import androidx.compose.ui.Alignment | ||
| import androidx.compose.ui.Modifier | ||
| import androidx.compose.ui.graphics.Color | ||
| import androidx.compose.ui.graphics.graphicsLayer | ||
| import androidx.compose.ui.input.pointer.pointerInput | ||
| import androidx.compose.ui.layout.ContentScale | ||
| import androidx.compose.ui.platform.LocalContext | ||
| import androidx.compose.ui.res.painterResource | ||
| import androidx.compose.ui.res.stringResource | ||
| import androidx.compose.ui.semantics.contentDescription | ||
| import androidx.compose.ui.semantics.semantics | ||
| import androidx.compose.ui.tooling.preview.Preview | ||
| import androidx.compose.ui.unit.dp | ||
| import androidx.compose.ui.window.Dialog | ||
| import androidx.compose.ui.window.DialogProperties | ||
| import coil.compose.SubcomposeAsyncImage | ||
| import coil.request.ImageRequest | ||
| import org.wordpress.android.R | ||
| import org.wordpress.android.ui.compose.theme.AppThemeM3 | ||
|
|
||
| @Composable | ||
| fun AttachmentFullscreenImagePreview( | ||
| imageUrl: String, | ||
| onDismiss: () -> Unit, | ||
| onDownload: () -> Unit = {} | ||
| ) { | ||
| var scale by remember { mutableFloatStateOf(1f) } | ||
| var offsetX by remember { mutableFloatStateOf(0f) } | ||
| var offsetY by remember { mutableFloatStateOf(0f) } | ||
|
|
||
| // Load semantics | ||
| val loadingImageDescription = stringResource(R.string.he_support_loading_image) | ||
| val attachmentImageDescription = stringResource(R.string.he_support_attachment_image) | ||
| val failedToLoadImageDescription = stringResource(R.string.he_support_failed_to_load_image) | ||
|
|
||
| Dialog( | ||
| onDismissRequest = onDismiss, | ||
| properties = DialogProperties( | ||
| usePlatformDefaultWidth = false, | ||
| dismissOnBackPress = true, | ||
| dismissOnClickOutside = false | ||
| ) | ||
| ) { | ||
| Surface( | ||
| modifier = Modifier | ||
| .fillMaxSize() | ||
| .clickable(onClick = onDismiss), | ||
| color = Color.Black | ||
| ) { | ||
| Box( | ||
| modifier = Modifier.fillMaxSize() | ||
| ) { | ||
| CircularProgressIndicator( | ||
| modifier = Modifier | ||
| .align(Alignment.Center) | ||
| .semantics { | ||
| contentDescription = loadingImageDescription | ||
| } | ||
| ) | ||
| // Zoomable image | ||
| Box( | ||
| modifier = Modifier.fillMaxSize(), | ||
| contentAlignment = Alignment.Center | ||
| ) { | ||
| SubcomposeAsyncImage( | ||
| model = ImageRequest.Builder(LocalContext.current) | ||
| .data(imageUrl) | ||
| .crossfade(true) | ||
| .build(), | ||
| contentDescription = attachmentImageDescription, | ||
| modifier = Modifier | ||
| .fillMaxSize() | ||
| .graphicsLayer( | ||
| scaleX = scale, | ||
| scaleY = scale, | ||
| translationX = offsetX, | ||
| translationY = offsetY | ||
| ) | ||
| .pointerInput(Unit) { | ||
| detectTransformGestures { _, pan, zoom, _ -> | ||
| val previousScale = scale | ||
| scale = (scale * zoom).coerceIn(1f, 5f) | ||
adalpari marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| if (scale > 1f) { | ||
| // Calculate max pan bounds to prevent image from going off-screen | ||
| val maxOffsetX = (size.width * (scale - 1f)) / 2f | ||
| val maxOffsetY = (size.height * (scale - 1f)) / 2f | ||
|
|
||
| offsetX = (offsetX + pan.x).coerceIn(-maxOffsetX, maxOffsetX) | ||
| offsetY = (offsetY + pan.y).coerceIn(-maxOffsetY, maxOffsetY) | ||
| } else if (previousScale > 1f && scale == 1f) { | ||
| // Only reset when transitioning from zoomed to unzoomed | ||
| offsetX = 0f | ||
| offsetY = 0f | ||
| } | ||
adalpari marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| }, | ||
| contentScale = ContentScale.Fit, | ||
| error = { | ||
| Icon( | ||
| painter = painterResource(R.drawable.ic_image_white_24dp), | ||
| contentDescription = failedToLoadImageDescription, | ||
| tint = Color.White, | ||
| modifier = Modifier.size(48.dp) | ||
| ) | ||
| } | ||
| ) | ||
| } | ||
|
|
||
| // Top bar with close button | ||
| Row( | ||
| modifier = Modifier | ||
| .align(Alignment.TopEnd) | ||
| .padding(16.dp) | ||
| .background( | ||
| color = Color.Black.copy(alpha = 0.5f), | ||
| shape = RoundedCornerShape(24.dp) | ||
| ) | ||
| .padding(4.dp), | ||
| horizontalArrangement = Arrangement.spacedBy(4.dp) | ||
| ) { | ||
| // Download button | ||
| IconButton( | ||
| onClick = { | ||
| onDownload.invoke() | ||
| onDismiss.invoke() | ||
| } | ||
| ) { | ||
| Icon( | ||
| painter = painterResource(R.drawable.ic_get_app_white_24dp), | ||
| contentDescription = stringResource(R.string.he_support_download_attachment), | ||
| tint = Color.White, | ||
| modifier = Modifier.size(24.dp) | ||
| ) | ||
| } | ||
|
|
||
| // Close button | ||
| IconButton( | ||
| onClick = onDismiss | ||
| ) { | ||
| Icon( | ||
| imageVector = Icons.Filled.Close, | ||
| contentDescription = stringResource(R.string.close), | ||
| tint = Color.White, | ||
| modifier = Modifier.size(24.dp) | ||
| ) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Preview(showBackground = true, name = "Fullscreen Image Preview") | ||
| @Composable | ||
| private fun AttachmentFullscreenImagePreviewPreview() { | ||
| AppThemeM3(isDarkTheme = false) { | ||
| AttachmentFullscreenImagePreview( | ||
| imageUrl = "https://via.placeholder.com/800x600", | ||
| onDismiss = { }, | ||
| onDownload = { } | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| @Preview(showBackground = true, name = "Fullscreen Image Preview - Dark", uiMode = UI_MODE_NIGHT_YES) | ||
| @Composable | ||
| private fun AttachmentFullscreenImagePreviewPreviewDark() { | ||
| AppThemeM3(isDarkTheme = true) { | ||
| AttachmentFullscreenImagePreview( | ||
| imageUrl = "https://via.placeholder.com/800x600", | ||
| onDismiss = { }, | ||
| onDownload = { } | ||
| ) | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.