Skip to content
Merged
Show file tree
Hide file tree
Changes from 153 commits
Commits
Show all changes
155 commits
Select commit Hold shift + click to select a range
80d4ed3
Adding basic UI
adalpari Oct 17, 2025
4836d41
Renaming
adalpari Oct 17, 2025
37541d0
Some styling
adalpari Oct 17, 2025
51b01a7
Renaming and dummy data
adalpari Oct 17, 2025
6c83ae3
Using proper "new conversation icon"
adalpari Oct 17, 2025
8d7ea50
Conversation details screen
adalpari Oct 17, 2025
a0a146b
Creating the reply bottomsheet
adalpari Oct 17, 2025
eebc0ab
Linking to the support screen
adalpari Oct 17, 2025
37676c8
bottomsheet fix
adalpari Oct 17, 2025
703f4c4
Mov navigation form activity to viewmodel
adalpari Oct 20, 2025
f6be7fd
Adding create ticket screen
adalpari Oct 20, 2025
d345864
More screen adjustments
adalpari Oct 20, 2025
05773ec
Extracting common code
adalpari Oct 20, 2025
b442787
Margin fix
adalpari Oct 20, 2025
cf4762e
detekt
adalpari Oct 20, 2025
7d318b1
Style
adalpari Oct 20, 2025
1ab8f3b
Merge branch 'trunk' into feat/CMM-843-Create-the-Ask-the-HE-entry-UI
adalpari Oct 20, 2025
d585a4a
New ticket check
adalpari Oct 20, 2025
8c651fc
Creating tests
adalpari Oct 20, 2025
fdf926b
Merge branch 'feat/CMM-843-Create-the-Ask-the-HE-entry-UI' of https:/…
adalpari Oct 20, 2025
3515fd0
Creating repository and load conversations function
adalpari Oct 21, 2025
3d99919
Adding createConversation function
adalpari Oct 21, 2025
0be28b4
Creating loadConversation func
adalpari Oct 21, 2025
40a5880
Loading conversations form the viewmodel
adalpari Oct 21, 2025
a55994e
Adding loading spinner
adalpari Oct 21, 2025
c82458c
Pull to refresh
adalpari Oct 21, 2025
73a434a
Proper ionitialization
adalpari Oct 21, 2025
087d07a
Adding empty screen
adalpari Oct 21, 2025
3b5a1e5
Handling send new conversation
adalpari Oct 21, 2025
4febc3d
Show loading when sending
adalpari Oct 21, 2025
e1215a9
New ticket creation fix
adalpari Oct 21, 2025
98cbb1f
Using snackbar for errors
adalpari Oct 21, 2025
5d421d3
Error handling
adalpari Oct 21, 2025
af8e1dd
Answering conversation
adalpari Oct 21, 2025
cad1eec
Adding some test to the repository
adalpari Oct 21, 2025
481ae11
More tests!
adalpari Oct 21, 2025
4e0b242
Merge branch 'trunk' into feat/CMM-872-support-HE-conversations-and-t…
adalpari Oct 22, 2025
95c80bd
Compile fixes
adalpari Oct 22, 2025
d36882e
Similarities improvements
adalpari Oct 22, 2025
563f58b
Using snackbar in bots activity
adalpari Oct 22, 2025
ab8ca28
Extracting EmptyConversationsView
adalpari Oct 22, 2025
034288e
Renaming
adalpari Oct 22, 2025
049df3e
Extracting VM and UI common code
adalpari Oct 22, 2025
15ab84e
Extracting navigation common code
adalpari Oct 22, 2025
53085d0
Renaming VMs for clarification
adalpari Oct 22, 2025
8c057bf
More refactor
adalpari Oct 22, 2025
a4ed792
Capitalise text fields
adalpari Oct 22, 2025
ccef4b7
Updating rs library
adalpari Oct 22, 2025
be6a5f2
Loading conversation UX
adalpari Oct 22, 2025
f023bf8
Style fix
adalpari Oct 22, 2025
d33e512
Fixing scaffolds paddings
adalpari Oct 22, 2025
ca5af7a
userID fix
adalpari Oct 22, 2025
972641d
Fixing the padding problem in bot chat when the keyboard is opened
adalpari Oct 22, 2025
d328103
Apply padding to create ticket screen when the keyboard is opened
adalpari Oct 22, 2025
4501d9a
Fixing scroll state in reply bottomsheet
adalpari Oct 22, 2025
c2baa18
Adding tests for the new common viewmodel
adalpari Oct 22, 2025
6aa8de1
Fixing AIBotSupportViewModel tests
adalpari Oct 22, 2025
204afef
detekt
adalpari Oct 22, 2025
a304d67
Improvements int he conversation interaction
adalpari Oct 22, 2025
6ee853b
Adding tests for HE VM
adalpari Oct 22, 2025
d0a549c
Merge branch 'trunk' into feat/CMM-872-support-HE-conversations-and-t…
adalpari Oct 22, 2025
bc476a7
Merge remote-tracking branch 'origin/trunk' into feat/CMM-872-support…
adalpari Oct 23, 2025
a13ae5b
Saving draft state
adalpari Oct 23, 2025
49f1af3
Properly navigating when a ticket is selected
adalpari Oct 23, 2025
e394c7a
Error parsing improvement
adalpari Oct 23, 2025
a6c421c
accessToken suggestion improvements
adalpari Oct 23, 2025
dbcb453
General suggestions
adalpari Oct 23, 2025
03f00fe
Send message error UX improvement
adalpari Oct 23, 2025
c117fcf
Fixing tests
adalpari Oct 23, 2025
d40d1d2
Converting the UI to more AndroidMaterial style
adalpari Oct 23, 2025
d318c2d
Bots screen renaming
adalpari Oct 23, 2025
c12f0fd
Bots screens renaming
adalpari Oct 23, 2025
1466115
Merge branch 'feat/CMM-872-support-HE-conversations-and-tickets-logic…
adalpari Oct 23, 2025
1d4a490
Make NewTicket screen more Android Material theme as well
adalpari Oct 24, 2025
7232fb2
Adding preview for EmptyConversationsView
adalpari Oct 24, 2025
a6e3e65
Button fix
adalpari Oct 24, 2025
19fcdf6
detekt
adalpari Oct 24, 2025
c41d801
Merge branch 'trunk' into feat/CMM-884-support-Iterate-over-the-whole…
adalpari Oct 27, 2025
6ddffcf
Ticket selection change
adalpari Oct 27, 2025
30fb83f
Supporting markdown text
adalpari Oct 27, 2025
3f908f2
detekt
adalpari Oct 27, 2025
1f6f555
Improving MarkdownUtils
adalpari Oct 27, 2025
727644c
Formatting text in the repository layer instead the ui
adalpari Oct 27, 2025
3eb939c
Renaming
adalpari Oct 27, 2025
455c100
Fixing tests
adalpari Oct 27, 2025
a07d01c
Support pagination
adalpari Oct 27, 2025
b8fe4af
Triggering in the 4th element
adalpari Oct 27, 2025
0ef0205
detekt
adalpari Oct 27, 2025
836f3dd
TODO for debug purposes
adalpari Oct 27, 2025
e126063
Claude PR suggestions
adalpari Oct 27, 2025
ce8deba
Put ConversationListView in common between bots and HE
adalpari Oct 28, 2025
fa2f147
Empty and error state
adalpari Oct 28, 2025
971499a
Skip site capitalization
adalpari Oct 28, 2025
6ecf89d
Adding a11c labels
adalpari Oct 28, 2025
3edc398
Adding headings labels
adalpari Oct 28, 2025
ded3f34
adding accessible labels to chat bubbles
adalpari Oct 28, 2025
d8c4468
detekt
adalpari Oct 28, 2025
f97d4e8
Fixing tests
adalpari Oct 28, 2025
1294e3d
PR suggestion about bot chat bubble
adalpari Oct 28, 2025
f8dc40e
Fixing tests
adalpari Oct 28, 2025
983ea0d
Updating rust
adalpari Oct 28, 2025
471312e
Adding attachments UI
adalpari Oct 28, 2025
4744542
Parsing markdown more exhaustively
adalpari Oct 28, 2025
ce4641f
New links support
adalpari Oct 28, 2025
55d37a5
Detekt
adalpari Oct 28, 2025
8314472
Supporting in conversation as well
adalpari Oct 28, 2025
af50df5
Keeping the screen when select images
adalpari Oct 29, 2025
8223d9e
Add attachments to the message data class
adalpari Oct 29, 2025
2b75327
Showing attachments in the UI
adalpari Oct 29, 2025
49082a2
Downloading attachments
adalpari Oct 29, 2025
6e93ffd
detekt
adalpari Oct 29, 2025
1c6300d
Support pagination
adalpari Oct 27, 2025
53ec089
Triggering in the 4th element
adalpari Oct 27, 2025
7370761
detekt
adalpari Oct 27, 2025
7bd8919
TODO for debug purposes
adalpari Oct 27, 2025
9016a82
Claude PR suggestions
adalpari Oct 27, 2025
88fc5d2
Detekt
adalpari Oct 29, 2025
3d1ab98
Merge branch 'feat/CMM-883-support-Oddie-bot-conversation-pagination'…
adalpari Oct 29, 2025
d8affd9
Removing testing code
adalpari Oct 29, 2025
260ded1
Updating RS library version
adalpari Oct 30, 2025
109cc41
Opening images in fullscreen
adalpari Oct 30, 2025
0d782f0
Improving full screen image UX
adalpari Oct 30, 2025
e0d2955
Merge branch 'feat/CMM-883-support-Oddie-bot-conversation-pagination'…
adalpari Oct 30, 2025
f15af11
Improving semantics
adalpari Oct 30, 2025
c39e5ca
Merge branch 'trunk' into feat/CMM-885-support-HE-attachments
adalpari Oct 30, 2025
81d6d28
Extracting strings
adalpari Oct 30, 2025
5c31d48
Using rs PR fix
adalpari Oct 31, 2025
0f67996
Showing attachment preview
adalpari Oct 31, 2025
3343a03
Clearing attachments on new ticket screen close
adalpari Oct 31, 2025
f3e40c9
Removing selected images limit
adalpari Oct 31, 2025
ad1382a
Unifying attachments handling inside the VM
adalpari Oct 31, 2025
5dd1432
Using a launcher instead of startActivityForResult
adalpari Oct 31, 2025
72bad43
Remove unused parameter
adalpari Oct 31, 2025
f7795db
Handling temp files inside the VM
adalpari Oct 31, 2025
94bb5d8
Removing files
adalpari Oct 31, 2025
5a51b11
detekt
adalpari Oct 31, 2025
d1a9aaf
Throwing copy file error
adalpari Oct 31, 2025
310d9df
Extracting some individual composables from HEConversation screen file
adalpari Oct 31, 2025
09f138a
Reducing arguments
adalpari Oct 31, 2025
b0ebf82
Catch file creation error
adalpari Oct 31, 2025
848235f
Using proper file extension
adalpari Oct 31, 2025
9a502b2
General improvements
adalpari Oct 31, 2025
9f5ec65
Update RS version and some fixes
adalpari Oct 31, 2025
ce18ff0
Extracting temp attachment utils
adalpari Oct 31, 2025
9903bfb
Adding new tests
adalpari Oct 31, 2025
9ac2bd9
Some refactoring
adalpari Oct 31, 2025
c197b7c
Merge branch 'trunk' into feat/CMM-885-support-HE-attachments
adalpari Oct 31, 2025
9871cd8
Merge remote-tracking branch 'origin/trunk' into feat/CMM-885-support…
adalpari Oct 31, 2025
6daee20
Removing attachments preview to open a dedicated PR
adalpari Oct 31, 2025
3687944
Useless changes
adalpari Oct 31, 2025
529123f
Useless changes
adalpari Oct 31, 2025
602b014
Minor refactor
adalpari Nov 3, 2025
e65b8cc
String fix
adalpari Nov 3, 2025
e6ec19c
CMM-885 support HE attachments i2 (#22333)
adalpari Nov 4, 2025
3a4c1ab
Merge branch 'trunk' into feat/CMM-885-support-HE-attachments
adalpari Nov 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.wordpress.android.support.he.ui

import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.net.Uri
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
Expand All @@ -10,28 +11,23 @@ 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.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Reply
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
Expand All @@ -40,6 +36,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import kotlinx.coroutines.launch
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalResources
Expand All @@ -52,11 +49,11 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
import org.wordpress.android.R
import org.wordpress.android.support.aibot.util.formatRelativeTime
import org.wordpress.android.support.he.model.SupportConversation
import org.wordpress.android.support.he.model.SupportMessage
import org.wordpress.android.support.he.util.AttachmentActionsListener
import org.wordpress.android.support.he.util.generateSampleHESupportConversations
import org.wordpress.android.ui.compose.components.MainTopAppBar
import org.wordpress.android.ui.compose.components.NavigationIcons
Expand All @@ -72,7 +69,9 @@ fun HEConversationDetailScreen(
messageSendResult: HESupportViewModel.MessageSendResult? = null,
onBackClick: () -> Unit,
onSendMessage: (message: String, includeAppLogs: Boolean) -> Unit,
onClearMessageSendResult: () -> Unit = {}
onClearMessageSendResult: () -> Unit = {},
attachments: List<Uri> = emptyList(),
attachmentActionsListener: AttachmentActionsListener,
) {
val listState = rememberLazyListState()
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
Expand Down Expand Up @@ -139,7 +138,7 @@ fun HEConversationDetailScreen(
) { message ->
MessageItem(
message = message,
timestamp = formatRelativeTime(message.createdAt, resources)
timestamp = formatRelativeTime(message.createdAt, resources),
)
}

Expand All @@ -157,7 +156,7 @@ fun HEConversationDetailScreen(
}

if (showBottomSheet) {
ReplyBottomSheet(
HEConversationReplyBottomSheet(
sheetState = sheetState,
isSending = isSendingMessage,
messageSendResult = messageSendResult,
Expand All @@ -181,7 +180,9 @@ fun HEConversationDetailScreen(
draftMessageText = ""
draftIncludeAppLogs = false
onClearMessageSendResult()
}
},
attachments = attachments,
attachmentActionsListener = attachmentActionsListener
)
}
}
Expand Down Expand Up @@ -351,106 +352,6 @@ private fun ReplyButton(
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ReplyBottomSheet(
sheetState: androidx.compose.material3.SheetState,
isSending: Boolean = false,
messageSendResult: HESupportViewModel.MessageSendResult? = null,
initialMessageText: String = "",
initialIncludeAppLogs: Boolean = false,
onDismiss: (currentMessage: String, currentIncludeAppLogs: Boolean) -> Unit,
onSend: (String, Boolean) -> Unit,
onMessageSentSuccessfully: () -> Unit
) {
var messageText by remember { mutableStateOf(initialMessageText) }
var includeAppLogs by remember { mutableStateOf(initialIncludeAppLogs) }
val scrollState = rememberScrollState()

// Close the sheet when sending completes successfully
LaunchedEffect(messageSendResult) {
when (messageSendResult) {
is HESupportViewModel.MessageSendResult.Success -> {
// Message sent successfully, close the sheet and clear draft
onDismiss("", false)
onMessageSentSuccessfully()
}
is HESupportViewModel.MessageSendResult.Failure -> {
// Message failed to send, draft is saved onDismiss
// The error will be shown via snackbar from the Activity
onDismiss("", false)
}
null -> {
// No result yet, do nothing
}
}
}

ModalBottomSheet(
onDismissRequest = { onDismiss(messageText, includeAppLogs) },
sheetState = sheetState
) {
Column(
modifier = Modifier
.fillMaxWidth()
.imePadding()
.verticalScroll(scrollState)
.padding(horizontal = 16.dp)
.padding(bottom = 32.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 24.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
TextButton(
onClick = { onDismiss(messageText, includeAppLogs) },
enabled = !isSending
) {
Text(
text = stringResource(R.string.cancel),
style = MaterialTheme.typography.titleMedium
)
}

Text(
text = stringResource(R.string.he_support_reply_button),
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold,
modifier = Modifier.semantics { heading() }
)

TextButton(
onClick = { onSend(messageText, includeAppLogs) },
enabled = messageText.isNotBlank() && !isSending
) {
if (isSending) {
CircularProgressIndicator(
modifier = Modifier.size(20.dp),
strokeWidth = 2.dp
)
} else {
Text(
text = stringResource(R.string.he_support_send_button),
style = MaterialTheme.typography.titleMedium
)
}
}
}

TicketMainContentView(
messageText = messageText,
includeAppLogs = includeAppLogs,
onMessageChanged = { message -> messageText = message },
onIncludeAppLogsChanged = { checked -> includeAppLogs = checked },
enabled = !isSending
)
}
}
}

@Preview(showBackground = true, name = "HE Conversation Detail")
@Composable
private fun HEConversationDetailScreenPreview() {
Expand All @@ -462,7 +363,15 @@ private fun HEConversationDetailScreenPreview() {
snackbarHostState = snackbarHostState,
conversation = sampleConversation,
onBackClick = { },
onSendMessage = { _, _ -> }
onSendMessage = { _, _ -> },
attachmentActionsListener = object : AttachmentActionsListener {
override fun onAddImageClick() {
// stub
}
override fun onRemoveImage(uri: Uri) {
// stub
}
}
)
}
}
Expand All @@ -478,7 +387,15 @@ private fun HEConversationDetailScreenPreviewDark() {
snackbarHostState = snackbarHostState,
conversation = sampleConversation,
onBackClick = { },
onSendMessage = { _, _ -> }
onSendMessage = { _, _ -> },
attachmentActionsListener = object : AttachmentActionsListener {
override fun onAddImageClick() {
// stub
}
override fun onRemoveImage(uri: Uri) {
// stub
}
}
)
}
}
Expand All @@ -494,7 +411,15 @@ private fun HEConversationDetailScreenWordPressPreview() {
snackbarHostState = snackbarHostState,
conversation = sampleConversation,
onBackClick = { },
onSendMessage = { _, _ -> }
onSendMessage = { _, _ -> },
attachmentActionsListener = object : AttachmentActionsListener {
override fun onAddImageClick() {
// stub
}
override fun onRemoveImage(uri: Uri) {
// stub
}
}
)
}
}
Expand All @@ -511,7 +436,15 @@ private fun HEConversationDetailScreenPreviewWordPressDark() {
isLoading = true,
conversation = sampleConversation,
onBackClick = { },
onSendMessage = { _, _ -> }
onSendMessage = { _, _ -> },
attachmentActionsListener = object : AttachmentActionsListener {
override fun onAddImageClick() {
// stub
}
override fun onRemoveImage(uri: Uri) {
// stub
}
}
)
}
}
Loading