Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 6 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,10 @@
"enableAllProjectMcpServers": true,
"enabledMcpjsonServers": [
"mobile-mcp"
]
],
"permissions": {
"allow": [
"Bash(find widgetssdk/src/main/java/com/glia/widgets -name \"*.kt\" -type f -exec grep -l \"Logger\\\\.\\\\\\(e\\\\|w\\\\|d\\\\|i\\\\\\)\\(\" {} \\\\;)"
]
}
}
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ javaVersion = "17"

kotlinVersion = "2.1.21" # Kotlin and Dokka versions should have the same minor version to support the same kotlin version
dokkaVersion = "2.0.0" # Kotlin and Dokka versions should have the same minor version to support the same kotlin version
agpVersion = "8.13.0"
agpVersion = "8.13.2"
ktlintVersion = "13.1.0"
#Publishing
mavenPublish = "0.35.0"
Expand All @@ -20,7 +20,7 @@ javaKtorVersion = "3.3.1"
javaCoroutinesVersion = "1.10.2"
javaDokkaVersion = "2.0.0"
javaLifecycleProcessVersion = "2.9.4"
javaLintVersion = "31.13.0"
javaLintVersion = "31.13.2"
javaMaterialVersion = "1.13.0"
javaPreferenceVersion = "1.2.1"
javaRxAndroid3Version = "3.0.2"
Expand Down
2 changes: 0 additions & 2 deletions widgetssdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ android {
namespace 'com.glia.widgets'
defaultConfig {
minSdkVersion 24
versionCode widgetsVersionCode
versionName widgetsVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
Expand Down
11 changes: 10 additions & 1 deletion widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import com.glia.widgets.chat.model.ChatInputMode
import com.glia.widgets.chat.model.ChatItem
import com.glia.widgets.chat.model.ChatState
import com.glia.widgets.chat.model.CustomCardChatItem
import com.glia.widgets.chat.model.OperatorMessageItem
import com.glia.widgets.databinding.ChatViewBinding
import com.glia.widgets.di.Dependencies
import com.glia.widgets.entrywidget.EntryWidgetContract
Expand Down Expand Up @@ -161,6 +162,14 @@ internal class ChatView(context: Context, attrs: AttributeSet?, defStyleAttr: In
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
super.onItemRangeInserted(positionStart, itemCount)

for (i in positionStart until positionStart + itemCount) {
adapter.currentList.getOrNull(i)?.let { item ->
if (item is OperatorMessageItem.PlainText && !item.announced) {
binding.chatRecyclerView.announceForAccessibility(item.content)
item.announced = true
}
}
}
Comment thread
DavDo marked this conversation as resolved.
val totalItemCount = adapter.itemCount
val lastIndex = totalItemCount - 1
if (isInBottom && lastIndex != -1) {
Expand Down Expand Up @@ -714,7 +723,7 @@ internal class ChatView(context: Context, attrs: AttributeSet?, defStyleAttr: In
}

private fun setupViewActions() {
binding.chatEditText.setAccessibilityHint(R.string.general_message)
binding.chatEditText.setAccessibilityHint(localeProvider.getString(R.string.general_message))
binding.chatEditText.addTextChangedListener(textWatcher)
binding.sendButton.setOnClickListener {
val message = binding.chatEditText.text.toString().trim { it <= ' ' }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import com.glia.widgets.chat.domain.gva.IsGvaUseCase
import com.glia.widgets.chat.domain.gva.MapGvaUseCase
import com.glia.widgets.chat.model.ChatItem
import com.glia.widgets.chat.model.CustomCardChatItem
import com.glia.widgets.chat.model.OperatorChatItem
import com.glia.widgets.chat.model.OperatorMessageItem
import com.glia.widgets.chat.model.OperatorStatusItem
import com.glia.widgets.chat.model.SystemChatItem
import com.glia.widgets.chat.model.VisitorMessageItem
Expand Down Expand Up @@ -168,7 +170,7 @@ internal class AppendHistoryResponseCardOrTextItemUseCase(
}

if (message.chatMessage.content.isNotBlank()) {
chatItems += mapOperatorPlainTextUseCase(message, showChatHead && filesAttachment == null)
chatItems += mapOperatorPlainTextUseCase(message, showChatHead && filesAttachment == null, true)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ internal class AppendNewResponseCardOrTextItemUseCase(
val filesAttachment = message.chatMessage.attachment as? FilesAttachment

if (message.chatMessage.content.isNotBlank()) {
chatItems += mapOperatorPlainTextUseCase(message, filesAttachment?.files.isNullOrEmpty())
chatItems += mapOperatorPlainTextUseCase(message, filesAttachment?.files.isNullOrEmpty(), false)
}

filesAttachment?.files?.apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,16 @@ internal class MapVisitorAttachmentUseCase {
}

internal class MapOperatorPlainTextUseCase {
operator fun invoke(chatMessageInternal: ChatMessageInternal, showChatHead: Boolean): OperatorMessageItem = chatMessageInternal.run {
operator fun invoke(chatMessageInternal: ChatMessageInternal, showChatHead: Boolean, history: Boolean): OperatorMessageItem = chatMessageInternal.run {
OperatorMessageItem.PlainText(
chatMessage.id,
chatMessage.timestamp,
showChatHead,
operatorImageUrl,
operatorId,
operatorName,
chatMessage.content
chatMessage.content,
history
)
}
}
Expand All @@ -80,6 +81,7 @@ internal class MapResponseCardUseCase {
operatorId,
operatorName,
chatMessage.content,
true,
attachment.options.asList(),
attachment.imageUrl.getOrNull()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ internal sealed class OperatorMessageItem : OperatorChatItem(ChatAdapter.OPERATO
override val operatorProfileImgUrl: String?,
override val operatorId: String?,
override val operatorName: String?,
override val content: String?
override val content: String?,
var announced: Boolean
) : OperatorMessageItem() {
override fun withShowChatHead(showChatHead: Boolean): OperatorChatItem = copy(showChatHead = showChatHead)
}
Expand All @@ -124,6 +125,7 @@ internal sealed class OperatorMessageItem : OperatorChatItem(ChatAdapter.OPERATO
override val operatorId: String?,
override val operatorName: String?,
override val content: String?,
val announced: Boolean,
val singleChoiceOptions: List<SingleChoiceOption>,
val choiceCardImageUrl: String?
) : OperatorMessageItem() {
Expand All @@ -141,7 +143,8 @@ internal sealed class OperatorMessageItem : OperatorChatItem(ChatAdapter.OPERATO
operatorProfileImgUrl = operatorProfileImgUrl,
operatorId = operatorId,
operatorName = operatorName,
content = content
content = content,
announced = announced
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class AppendHistoryResponseCardOrTextItemUseCaseTest {
@Test
fun `addPlainTextAndAttachments adds OperatorMessageItem_PlainText when chatMessage content is not empty`() {
whenever(mockChatMessageInternal.chatMessageInternal.chatMessage.attachment) doReturn mock()
whenever(mapOperatorPlainTextUseCase.invoke(any(), any())) doReturn mock<OperatorMessageItem.PlainText>()
whenever(mapOperatorPlainTextUseCase.invoke(any(), any(), any())) doReturn mock<OperatorMessageItem.PlainText>()
useCase.addPlainTextAndAttachments(items, mockChatMessageInternal.chatMessageInternal, true)
assertTrue(items.count() == 1)
assertTrue(items.first() is OperatorMessageItem.PlainText)
Expand All @@ -66,7 +66,7 @@ class AppendHistoryResponseCardOrTextItemUseCaseTest {
fun `addPlainTextAndAttachments does not add OperatorMessageItem_PlainText when chatMessage content is null or empty`() {
whenever(mockChatMessageInternal.chatMessageInternal.chatMessage.attachment) doReturn mock()
whenever(mockChatMessageInternal.chatMessageInternal.chatMessage.content) doReturn ""
whenever(mapOperatorPlainTextUseCase.invoke(any(), any())) doReturn mock<OperatorMessageItem.PlainText>()
whenever(mapOperatorPlainTextUseCase.invoke(any(), any(), any())) doReturn mock<OperatorMessageItem.PlainText>()
useCase.addPlainTextAndAttachments(items, mockChatMessageInternal.chatMessageInternal, true)
assertTrue(items.isEmpty())
}
Expand All @@ -78,7 +78,7 @@ class AppendHistoryResponseCardOrTextItemUseCaseTest {
whenever(filesAttachment.files) doReturn arrayOf(file)
whenever(mapOperatorAttachmentUseCase.invoke(any(), any(), any())) doReturn mock<OperatorAttachmentItem.File>()
whenever(mockChatMessageInternal.chatMessageInternal.chatMessage.attachment) doReturn filesAttachment
whenever(mapOperatorPlainTextUseCase.invoke(any(), any())) doReturn mock<OperatorMessageItem.PlainText>()
whenever(mapOperatorPlainTextUseCase.invoke(any(), any(), any())) doReturn mock<OperatorMessageItem.PlainText>()
useCase.addPlainTextAndAttachments(items, mockChatMessageInternal.chatMessageInternal, true)
assertTrue(items.count() == 2)
assertTrue(items.first() is OperatorAttachmentItem.File)
Expand All @@ -96,7 +96,7 @@ class AppendHistoryResponseCardOrTextItemUseCaseTest {
whenever(mapOperatorAttachmentUseCase.invoke(eq(file1), any(), any())) doReturn operatorAttachment1
whenever(mapOperatorAttachmentUseCase.invoke(eq(file2), any(), any())) doReturn operatorAttachment2
whenever(mockChatMessageInternal.chatMessageInternal.chatMessage.attachment) doReturn filesAttachment
whenever(mapOperatorPlainTextUseCase.invoke(any(), any())) doReturn mock<OperatorMessageItem.PlainText>()
whenever(mapOperatorPlainTextUseCase.invoke(any(), any(), any())) doReturn mock<OperatorMessageItem.PlainText>()
useCase.addPlainTextAndAttachments(items, mockChatMessageInternal.chatMessageInternal, true)
assertTrue(items.count() == 3)
assertTrue(items.first() is OperatorAttachmentItem.File)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class AppendNewOperatorMessageUseCaseTest {
whenever(customCardAdapterTypeUseCase(any())) doReturn null
whenever(isGvaUseCase(any())) doReturn false

val operatorChatItem: OperatorChatItem = OperatorMessageItem.PlainText("id", 1, true, "img", "operator_id", "name", "content")
val operatorChatItem: OperatorChatItem = OperatorMessageItem.PlainText("id", 1, true, "img", "operator_id", "name", "content", true)
state.lastMessageWithVisibleOperatorImage = operatorChatItem

doAnswer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class AppendNewResponseCardOrTextItemUseCaseTest {

whenever(chatMessage.content) doReturn "content"
whenever(chatMessage.attachment) doReturn attachment
whenever(mapOperatorPlainTextUseCase(any(), any())) doReturn mock<OperatorMessageItem.PlainText>()
whenever(mapOperatorPlainTextUseCase(any(), any(), any())) doReturn mock<OperatorMessageItem.PlainText>()

val operatorAttachmentItemTrue = mock<OperatorAttachmentItem.Image>().apply { whenever(showChatHead) doReturn true }
val operatorAttachmentItemFalse = mock<OperatorAttachmentItem.File>().apply { whenever(showChatHead) doReturn false }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class MapOperatorPlainTextUseCaseTest {
@Test
fun `invoke returns OperatorMessageItem_PlainText with showChatHead true when true is passed`() {
mockChatMessageInternal.apply {
val message = useCase(chatMessageInternal, true)
val message = useCase(chatMessageInternal, true, true)

assertTrue(message is OperatorMessageItem.PlainText)

Expand All @@ -43,7 +43,7 @@ class MapOperatorPlainTextUseCaseTest {
@Test
fun `invoke returns OperatorMessageItem_PlainText with showChatHead false when false is passed`() {
mockChatMessageInternal.apply {
val message = useCase(chatMessageInternal, false)
val message = useCase(chatMessageInternal, false, true)

assertTrue(message is OperatorMessageItem.PlainText)
assertEquals(message.showChatHead, false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.glia.androidsdk.engagement.Survey
import com.glia.widgets.R
import com.glia.widgets.di.Dependencies
import com.glia.widgets.helper.setAccessibilityHint
import com.glia.widgets.helper.setLocaleAccessibilityHint
import com.glia.widgets.helper.setLocaleContentDescription
import com.glia.widgets.helper.setLocaleText
import com.glia.widgets.locale.LocaleProvider
Expand Down Expand Up @@ -60,7 +61,7 @@ class SurveyViewHolderTest {

every { requiredErrorView.setLocaleText(any<Int>()) } just Runs
every { titleView.setLocaleContentDescription(any<Int>()) } just Runs
every { titleView.setAccessibilityHint(any<Int>()) } just Runs
every { titleView.setLocaleAccessibilityHint(any()) } just Runs

listener = mockk(relaxed = true)
}
Expand Down Expand Up @@ -129,7 +130,7 @@ class SurveyViewHolderTest {

viewHolder.onBind(questionItem, listener)

verify(exactly = 0) { titleView.setAccessibilityHint(any<Int>()) }
verify(exactly = 0) { titleView.setLocaleAccessibilityHint(any()) }
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ internal interface SnapshotOperatorMessage : SnapshotStrings {
operatorProfileImgUrl: String? = null,
operatorId: String? = "operatorId",
operatorName: String? = "Snap Shot",
content: String?
content: String?,
announced: Boolean = false
) = OperatorMessageItem.PlainText(
id, timestamp, showChatHead, operatorProfileImgUrl, operatorId, operatorName, content
id, timestamp, showChatHead, operatorProfileImgUrl, operatorId, operatorName, content, announced
)

fun operatorMessageResponseCard(
Expand All @@ -27,10 +28,11 @@ internal interface SnapshotOperatorMessage : SnapshotStrings {
operatorId: String? = "operatorId",
operatorName: String? = "Snap Shot",
content: String?,
announced: Boolean = false,
singleChoiceOptions: List<SingleChoiceOption> = shortLengthTexts().mapIndexed { i, s -> singleChoiceOption(s, i.toString()) },
choiceCardImageUrl: String? = null
) = OperatorMessageItem.ResponseCard(
id, timestamp, showChatHead, operatorProfileImgUrl, operatorId, operatorName, content, singleChoiceOptions, choiceCardImageUrl
id, timestamp, showChatHead, operatorProfileImgUrl, operatorId, operatorName, content, announced, singleChoiceOptions, choiceCardImageUrl
)

fun singleChoiceOption(
Expand Down