From 62c075c5bfb4aca9e808c457a6cb16985fea31ca Mon Sep 17 00:00:00 2001 From: Varun Jain Date: Tue, 4 Jun 2024 18:16:11 +0530 Subject: [PATCH] TP-68566 | Outbound calling - Call status widget (#11131) --- .../data/firestore/ChatFireStoreDatabase.kt | 63 +++++++++++- .../java/com/navi/chat/db/utils/ChatUtils.kt | 5 +- .../navi/chat/provider/MessageOperation.kt | 4 +- .../firestore/FireStoreDataProvider.kt | 6 +- .../chat/ui/fragments/NaviChatFragment.kt | 73 ++++++++++++++ .../navi/chat/utils/ChatJsonDeserializer.kt | 9 +- .../com/navi/chat/utils/NaviChatAnalytics.kt | 3 +- ...g_rounded_top_corner_purple_fill_color.xml | 31 ++++++ .../bg_rounded_top_corner_red_fill_color.xml | 31 ++++++ ...hat_call_status_wait_time_breach_nudge.xml | 47 +++++++++ .../chat_call_status_wait_time_nudge.xml | 47 +++++++++ .../res/layout/fragment_common_navi_chat.xml | 42 +++++++- .../src/main/res/values/colors.xml | 1 + .../NaviChatCallStatusWidgetInfo.kt | 34 +++++++ .../response/NaviChatCallStatusWidget.kt | 85 ++++++++++++++++ .../response/NaviChatControllerWidget.kt | 21 +++- .../com/navi/naviwidgets/utils/Constants.kt | 10 +- .../viewholder/NaviChatCallStatusWidgetVH.kt | 42 ++++++++ .../NaviChatViewHolderFactoryImpl.kt | 5 +- .../widgets/NaviChatCallStatusWidgetLayout.kt | 96 +++++++++++++++++++ .../ic_navi_chat_received_call_message_bg.xml | 17 ++++ .../ic_navi_chat_received_message_bg.xml | 9 +- .../layout/layout_navi_chat_call_status.xml | 49 ++++++++++ .../layout_navi_chat_call_status_item.xml | 59 ++++++++++++ 24 files changed, 773 insertions(+), 16 deletions(-) create mode 100644 android/navi-chat/src/main/res/drawable/bg_rounded_top_corner_purple_fill_color.xml create mode 100644 android/navi-chat/src/main/res/drawable/bg_rounded_top_corner_red_fill_color.xml create mode 100644 android/navi-chat/src/main/res/layout/chat_call_status_wait_time_breach_nudge.xml create mode 100644 android/navi-chat/src/main/res/layout/chat_call_status_wait_time_nudge.xml create mode 100644 android/navi-widgets/src/main/java/com/navi/naviwidgets/interfaces/NaviChatCallStatusWidgetInfo.kt create mode 100644 android/navi-widgets/src/main/java/com/navi/naviwidgets/models/response/NaviChatCallStatusWidget.kt create mode 100644 android/navi-widgets/src/main/java/com/navi/naviwidgets/viewholder/NaviChatCallStatusWidgetVH.kt create mode 100644 android/navi-widgets/src/main/java/com/navi/naviwidgets/widgets/NaviChatCallStatusWidgetLayout.kt create mode 100644 android/navi-widgets/src/main/res/drawable/ic_navi_chat_received_call_message_bg.xml create mode 100644 android/navi-widgets/src/main/res/layout/layout_navi_chat_call_status.xml create mode 100644 android/navi-widgets/src/main/res/layout/layout_navi_chat_call_status_item.xml diff --git a/android/navi-chat/src/main/java/com/navi/chat/data/firestore/ChatFireStoreDatabase.kt b/android/navi-chat/src/main/java/com/navi/chat/data/firestore/ChatFireStoreDatabase.kt index 2729aa4afd..8bdb46459a 100644 --- a/android/navi-chat/src/main/java/com/navi/chat/data/firestore/ChatFireStoreDatabase.kt +++ b/android/navi-chat/src/main/java/com/navi/chat/data/firestore/ChatFireStoreDatabase.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2022-2023 by Navi Technologies Limited + * * Copyright © 2022-2024 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -26,6 +26,7 @@ import com.navi.chat.utils.NaviChatAnalytics.Companion.LISTEN_TO_CONTROLLER_WIDG import com.navi.chat.utils.NaviChatAnalytics.Companion.LISTEN_TO_FIRESTORE_CLIENT_CHANGES import com.navi.chat.utils.NaviChatAnalytics.Companion.LISTEN_TO_FIRESTORE_FOR_MESSAGE_STATUS import com.navi.chat.utils.NaviChatAnalytics.Companion.LISTEN_TO_FIRESTORE_SERVER_CHANGES +import com.navi.chat.utils.NaviChatAnalytics.Companion.LISTEN_TO_FIRESTORE_SERVER_UPDATES import com.navi.chat.utils.NaviChatAnalytics.Companion.MESSAGE_ADDED_TO_FIRESTORE import com.navi.chat.utils.NaviChatAnalytics.Companion.MODIFIED import com.navi.chat.utils.NaviChatAnalytics.Companion.NAVI_CHAT_WIDGET @@ -197,6 +198,66 @@ class ChatFireStoreDatabase { } } + fun listenToFireStoreServerUpdates(path: String, messageOperation: MessageOperation) { + ChatFireStore.getFireStoreReference(path) + .get() + .addOnSuccessListener { + crmEventTracker.sendEvent( + LISTENER_ATTACHED_TO_FIRESTORE_SUCCESSFULLY, + hashMapOf(PATH to path, SOURCE to LISTEN_TO_FIRESTORE_SERVER_UPDATES) + ) + listenerToFirestoreChangesList.add( + ChatFireStore.getFireStoreReference(path).addSnapshotListener { value, errorEx + -> + if (errorEx != null) { + crmEventTracker.sendEvent( + ERROR_LISTENING_TO_FIRESTORE_CHANGES, + hashMapOf( + PATH to path, + ERROR to errorEx.toString(), + SOURCE to LISTEN_TO_FIRESTORE_SERVER_UPDATES + ) + ) + return@addSnapshotListener + } + crmEventTracker.sendEvent( + SUCCESS_LISTENING_TO_FIRESTORE_CHANGES, + hashMapOf(PATH to path, SOURCE to LISTEN_TO_FIRESTORE_SERVER_UPDATES) + ) + + value?.let { + value.documentChanges.forEach { dc -> + when (dc.type) { + DocumentChange.Type.ADDED -> {} + DocumentChange.Type.MODIFIED -> { + if ( + dc.document.data[NAVI_CHAT_WIDGET_NAME] == + NaviChatCallStatusWidget.WIDGET_NAME + ) { + messageOperation.updateCallStatusWidget( + transformFirestoreToWidgetModel(dc.document.data) + ) + } + } + DocumentChange.Type.REMOVED -> {} + } + } + } + } + ) + } + .addOnFailureListener { + crmEventTracker.sendEvent( + NOT_ABLE_TO_ATTACH_LISTENER_TO_FIRESTORE, + hashMapOf( + PATH to path, + ERROR to it.toString(), + SOURCE to LISTEN_TO_FIRESTORE_SERVER_UPDATES + ) + ) + } + } + fun listenToFirestoreChanges( path: String, latestMessageTimeStamp: Timestamp?, diff --git a/android/navi-chat/src/main/java/com/navi/chat/db/utils/ChatUtils.kt b/android/navi-chat/src/main/java/com/navi/chat/db/utils/ChatUtils.kt index 6727af9367..c8c0e89a72 100644 --- a/android/navi-chat/src/main/java/com/navi/chat/db/utils/ChatUtils.kt +++ b/android/navi-chat/src/main/java/com/navi/chat/db/utils/ChatUtils.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2022-2023 by Navi Technologies Limited + * * Copyright © 2022-2024 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -67,6 +67,9 @@ fun transformFirestoreToWidgetModel(data: Map): NaviChatWidget = convertMapToJson(data) as NaviChatTransactionStatusWidget } + NaviChatCallStatusWidget.WIDGET_NAME -> { + convertMapToJson(data) as NaviChatCallStatusWidget + } else -> { NaviChatMessageWidget() } diff --git a/android/navi-chat/src/main/java/com/navi/chat/provider/MessageOperation.kt b/android/navi-chat/src/main/java/com/navi/chat/provider/MessageOperation.kt index 337bb9fb4b..6f100d2de6 100644 --- a/android/navi-chat/src/main/java/com/navi/chat/provider/MessageOperation.kt +++ b/android/navi-chat/src/main/java/com/navi/chat/provider/MessageOperation.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2022-2023 by Navi Technologies Limited + * * Copyright © 2022-2024 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -30,4 +30,6 @@ interface MessageOperation { fun updateMessageReceipts(widgetModel: NaviChatWidget) fun updateServerMessageReceipts(document: DocumentReference?) + + fun updateCallStatusWidget(widgetModel: NaviChatWidget) } diff --git a/android/navi-chat/src/main/java/com/navi/chat/provider/firestore/FireStoreDataProvider.kt b/android/navi-chat/src/main/java/com/navi/chat/provider/firestore/FireStoreDataProvider.kt index 6d312a9c1f..df1722a326 100644 --- a/android/navi-chat/src/main/java/com/navi/chat/provider/firestore/FireStoreDataProvider.kt +++ b/android/navi-chat/src/main/java/com/navi/chat/provider/firestore/FireStoreDataProvider.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2022-2023 by Navi Technologies Limited + * * Copyright © 2022-2024 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -53,6 +53,10 @@ class FireStoreDataProvider : ChatDataProvider, LifecycleObserver { path = fireStoreDataProviderModel.writePath, messageOperation = messageOperation ) + chatFireStoreDatabase.listenToFireStoreServerUpdates( + path = fireStoreDataProviderModel.readPath, + messageOperation = messageOperation + ) } } diff --git a/android/navi-chat/src/main/java/com/navi/chat/ui/fragments/NaviChatFragment.kt b/android/navi-chat/src/main/java/com/navi/chat/ui/fragments/NaviChatFragment.kt index 7c09b597db..eeb54afb1b 100644 --- a/android/navi-chat/src/main/java/com/navi/chat/ui/fragments/NaviChatFragment.kt +++ b/android/navi-chat/src/main/java/com/navi/chat/ui/fragments/NaviChatFragment.kt @@ -164,6 +164,7 @@ class NaviChatFragment : BaseFragment(), WidgetCallback, MessageOperation, Toolb private var botTypingStatusHandler = Handler(Looper.getMainLooper()) private var showCsatHandler = Handler(Looper.getMainLooper()) private var timerHandler = Handler(Looper.getMainLooper()) + private var callStatusHandler = Handler(Looper.getMainLooper()) private var textWatcherForTimer: TextWatcher? = null private var textWatcherForCharLimit: TextWatcher? = null private var textWatcherForSendAnimation: TextWatcher? = null @@ -657,6 +658,26 @@ class NaviChatFragment : BaseFragment(), WidgetCallback, MessageOperation, Toolb } } + private fun setCallStatusWaitTimeNudgeData(waitTimeConfig: WaitTimeConfig?) { + scrollChatToLatestMessageReceived() + binding.chatCallStatusWaitTimeBreachNudgeLayout.root.setVisibilityState(GONE) + binding.chatCallStatusWaitTimeNudgeLayout.root.setVisibilityState(VISIBLE) + binding.chatCallStatusWaitTimeNudgeLayout.apply { + waitTimeConfig?.imgUrl?.let { ivIcon.showWhenDataIsAvailable(imageUrl = it) } + waitTimeConfig?.waitTimeMessage?.let { tvTitle.text = it } + } + } + + private fun setCallStatusWaitTimeBreachNudgeData(waitTimeConfig: WaitTimeConfig?) { + scrollChatToLatestMessageReceived() + binding.chatCallStatusWaitTimeNudgeLayout.root.setVisibilityState(GONE) + binding.chatCallStatusWaitTimeBreachNudgeLayout.root.setVisibilityState(VISIBLE) + binding.chatCallStatusWaitTimeBreachNudgeLayout.apply { + waitTimeConfig?.imgUrl?.let { ivIcon.showWhenDataIsAvailable(imageUrl = it) } + waitTimeConfig?.waitTimeBreachMessage?.let { tvTitle.text = it } + } + } + private fun observeNetworkConnectivity() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { viewLifecycleOwner.lifecycleScope.launchWhenStarted { @@ -703,6 +724,8 @@ class NaviChatFragment : BaseFragment(), WidgetCallback, MessageOperation, Toolb private fun updateNetworkConnectivityNudge( networkConnectivityNudgeData: NetworkConnectivityNudgeData ) { + binding.chatCallStatusWaitTimeNudgeLayout.root.setVisibilityState(GONE) + binding.chatCallStatusWaitTimeBreachNudgeLayout.root.setVisibilityState(GONE) binding.networkConnectivityNudgeLayout.root.setVisibilityState(View.VISIBLE) binding.networkConnectivityNudgeLayout.root.setOnClickListener {} @@ -1194,6 +1217,24 @@ class NaviChatFragment : BaseFragment(), WidgetCallback, MessageOperation, Toolb } } + override fun updateCallStatusWidget(widgetModel: NaviChatWidget) { + if ( + widgetModel.widgetNameForBaseAdapter == NaviChatCallStatusWidget.WIDGET_NAME && + widgetModel is NaviChatCallStatusWidget + ) { + chatRVAdapter.list + .findIndexed { _, it -> + (it is NaviChatCallStatusWidget) && (it.messageId == widgetModel.messageId) + } + .apply { + this?.let { + (it.first as? NaviChatCallStatusWidget)?.widgetData = widgetModel.widgetData + updateItemInChatAdapter(it.second) + } + } + } + } + override fun updateServerMessageReceipts(document: DocumentReference?) { try { if (updateMessageReceipts) { @@ -1628,6 +1669,9 @@ class NaviChatFragment : BaseFragment(), WidgetCallback, MessageOperation, Toolb hideKeyboard(context = context, view = binding.etFreeText) } } + if (naviChatControllerWidget.widgetData?.controllerConfig == null) { + hideWaitTimeNudges() + } naviChatControllerWidget.widgetData?.controllerConfig?.let { config -> config.showAttachment?.let { showAttachment -> if (showAttachment) { @@ -1696,6 +1740,29 @@ class NaviChatFragment : BaseFragment(), WidgetCallback, MessageOperation, Toolb ) } } + if (config.waitTimeConfig == null) { + hideWaitTimeNudges() + } + config.waitTimeConfig?.let { voiceCallConfig -> + if (binding.networkConnectivityNudgeLayout.root.visibility == GONE) { + if ( + System.currentTimeMillis().minus(voiceCallConfig.startTime ?: 0) <= + (voiceCallConfig.timerDuration?.toLong() ?: 0L) + ) { + callStatusHandler.removeCallbacksAndMessages(null) + val remainingTimeToShowWaitTimeBreachNudge = + (voiceCallConfig.startTime ?: 0L) + + (voiceCallConfig.timerDuration ?: 0L) - System.currentTimeMillis() + setCallStatusWaitTimeNudgeData(voiceCallConfig) + callStatusHandler.postDelayed( + { setCallStatusWaitTimeBreachNudgeData(voiceCallConfig) }, + remainingTimeToShowWaitTimeBreachNudge + ) + } else { + setCallStatusWaitTimeBreachNudgeData(voiceCallConfig) + } + } + } } naviChatControllerWidget.languageSelectionWidgetData?.let { languageSelectionWidgetData -> languageSelectionWidgetData.isLanguageSelectionEnabled?.let { isLanguageSelectionEnabled @@ -1731,6 +1798,11 @@ class NaviChatFragment : BaseFragment(), WidgetCallback, MessageOperation, Toolb } } + private fun hideWaitTimeNudges() { + binding.chatCallStatusWaitTimeNudgeLayout.root.visibility = GONE + binding.chatCallStatusWaitTimeBreachNudgeLayout.root.visibility = GONE + } + private fun setTextWatcher() { textWatcherForTimer = object : TextWatcher { @@ -2017,6 +2089,7 @@ class NaviChatFragment : BaseFragment(), WidgetCallback, MessageOperation, Toolb botTypingStatusHandler.removeCallbacksAndMessages(null) typingStatusHandler.removeCallbacksAndMessages(null) showCsatHandler.removeCallbacksAndMessages(null) + callStatusHandler.removeCallbacksAndMessages(null) fileUploadManager.cancelUploads() naviChatSharedViewModel.resetNumberOfMessagesSent() naviChatSharedViewModel.resetNumberOfOptionsSelected() diff --git a/android/navi-chat/src/main/java/com/navi/chat/utils/ChatJsonDeserializer.kt b/android/navi-chat/src/main/java/com/navi/chat/utils/ChatJsonDeserializer.kt index 1318ea9fec..79dacd03ec 100644 --- a/android/navi-chat/src/main/java/com/navi/chat/utils/ChatJsonDeserializer.kt +++ b/android/navi-chat/src/main/java/com/navi/chat/utils/ChatJsonDeserializer.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2022-2023 by Navi Technologies Limited + * * Copyright © 2022-2024 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -14,6 +14,7 @@ import com.google.gson.JsonDeserializer import com.google.gson.JsonElement import com.navi.naviwidgets.models.NaviChatWidget import com.navi.naviwidgets.models.response.NaviChatActivityRedirectionWidget +import com.navi.naviwidgets.models.response.NaviChatCallStatusWidget import com.navi.naviwidgets.models.response.NaviChatControllerWidget import com.navi.naviwidgets.models.response.NaviChatConversationStatusWidget import com.navi.naviwidgets.models.response.NaviChatCsatRatingWidget @@ -175,6 +176,12 @@ object ChatJsonDeserializer : JsonDeserializer { naviChatWidget.rt_created_at = timestamp naviChatWidget } + NaviChatCallStatusWidget.WIDGET_NAME -> { + val naviChatWidget = + Gson().fromJson(jsonObject, NaviChatCallStatusWidget::class.java) + naviChatWidget.rt_created_at = timestamp + naviChatWidget + } else -> { val naviChatWidget = Gson().fromJson(jsonObject, NaviChatMessageWidget::class.java) diff --git a/android/navi-chat/src/main/java/com/navi/chat/utils/NaviChatAnalytics.kt b/android/navi-chat/src/main/java/com/navi/chat/utils/NaviChatAnalytics.kt index 42110d7a27..70372d4ecb 100644 --- a/android/navi-chat/src/main/java/com/navi/chat/utils/NaviChatAnalytics.kt +++ b/android/navi-chat/src/main/java/com/navi/chat/utils/NaviChatAnalytics.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2022-2023 by Navi Technologies Limited + * * Copyright © 2022-2024 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -158,6 +158,7 @@ class NaviChatAnalytics private constructor() { const val FAQ_PAGE_LAND = "faq_page_land" const val CHATSCREEN_TOP_BACK_BUTTON_CLICK = "chatscreen_top_back_button_click" const val SESSION_ID = "session_id" + const val LISTEN_TO_FIRESTORE_SERVER_UPDATES = "listen_to_firestore_server_updates" val naviChatAnalytics: NaviChatAnalytics by lazy { Holder.INSTANCE } } diff --git a/android/navi-chat/src/main/res/drawable/bg_rounded_top_corner_purple_fill_color.xml b/android/navi-chat/src/main/res/drawable/bg_rounded_top_corner_purple_fill_color.xml new file mode 100644 index 0000000000..592282936c --- /dev/null +++ b/android/navi-chat/src/main/res/drawable/bg_rounded_top_corner_purple_fill_color.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/navi-chat/src/main/res/drawable/bg_rounded_top_corner_red_fill_color.xml b/android/navi-chat/src/main/res/drawable/bg_rounded_top_corner_red_fill_color.xml new file mode 100644 index 0000000000..a983fa70fb --- /dev/null +++ b/android/navi-chat/src/main/res/drawable/bg_rounded_top_corner_red_fill_color.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/navi-chat/src/main/res/layout/chat_call_status_wait_time_breach_nudge.xml b/android/navi-chat/src/main/res/layout/chat_call_status_wait_time_breach_nudge.xml new file mode 100644 index 0000000000..74f60f8a37 --- /dev/null +++ b/android/navi-chat/src/main/res/layout/chat_call_status_wait_time_breach_nudge.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + diff --git a/android/navi-chat/src/main/res/layout/chat_call_status_wait_time_nudge.xml b/android/navi-chat/src/main/res/layout/chat_call_status_wait_time_nudge.xml new file mode 100644 index 0000000000..03d91c7b27 --- /dev/null +++ b/android/navi-chat/src/main/res/layout/chat_call_status_wait_time_nudge.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + diff --git a/android/navi-chat/src/main/res/layout/fragment_common_navi_chat.xml b/android/navi-chat/src/main/res/layout/fragment_common_navi_chat.xml index 733bc5b729..81eb06a1b0 100644 --- a/android/navi-chat/src/main/res/layout/fragment_common_navi_chat.xml +++ b/android/navi-chat/src/main/res/layout/fragment_common_navi_chat.xml @@ -55,11 +55,18 @@ android:layout_height="@dimen/layout_dp_0" android:visibility="gone" tools:visibility="visible" - app:layout_constraintBottom_toTopOf="@id/network_connectivity_nudge_layout" + app:layout_constraintBottom_toTopOf="@id/topBarrier" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/nctLayout" /> + + + + + + + + + app:layout_constraintTop_toBottomOf="@id/bottomBarrier" /> #1A3C0050 #FFF0EB #4B4966 + #EBE4FF diff --git a/android/navi-widgets/src/main/java/com/navi/naviwidgets/interfaces/NaviChatCallStatusWidgetInfo.kt b/android/navi-widgets/src/main/java/com/navi/naviwidgets/interfaces/NaviChatCallStatusWidgetInfo.kt new file mode 100644 index 0000000000..caf2afddec --- /dev/null +++ b/android/navi-widgets/src/main/java/com/navi/naviwidgets/interfaces/NaviChatCallStatusWidgetInfo.kt @@ -0,0 +1,34 @@ +/* + * + * * Copyright © 2024 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.navi.naviwidgets.interfaces + +import com.google.firebase.Timestamp +import com.navi.design.textview.model.TextWithStyle +import com.navi.naviwidgets.models.response.NaviChatMetaData + +interface NaviChatCallStatusWidgetInfo { + fun messageId(): String? + + fun title(): TextWithStyle? + + fun subtitle(): TextWithStyle? + + fun metaData(): NaviChatMetaData? + + fun senderName(): String? + + fun timeStamp(): Timestamp? + + fun displayIconUrl(): String? + + fun imgUrl(): String? + + fun bgColor(): String? + + fun borderColor(): String? +} diff --git a/android/navi-widgets/src/main/java/com/navi/naviwidgets/models/response/NaviChatCallStatusWidget.kt b/android/navi-widgets/src/main/java/com/navi/naviwidgets/models/response/NaviChatCallStatusWidget.kt new file mode 100644 index 0000000000..48c08525a3 --- /dev/null +++ b/android/navi-widgets/src/main/java/com/navi/naviwidgets/models/response/NaviChatCallStatusWidget.kt @@ -0,0 +1,85 @@ +/* + * + * * Copyright © 2024 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.navi.naviwidgets.models.response + +import com.google.firebase.Timestamp +import com.google.firebase.firestore.PropertyName +import com.google.firebase.firestore.ServerTimestamp +import com.google.gson.annotations.SerializedName +import com.navi.design.textview.model.TextWithStyle +import com.navi.naviwidgets.interfaces.NaviChatCallStatusWidgetInfo +import com.navi.naviwidgets.models.NaviChatWidget +import com.navi.naviwidgets.utils.* +import java.io.Serializable + +data class NaviChatCallStatusWidget( + @SerializedName(NAVI_CHAT_MESSAGE_ID) override val messageId: String? = null, + @set:PropertyName(NAVI_CHAT_WIDGET_NAME) + @get:PropertyName(NAVI_CHAT_WIDGET_NAME) + @SerializedName(NAVI_CHAT_WIDGET_NAME) + override var widgetNameForBaseAdapter: String? = WIDGET_NAME, + @get:PropertyName(NAVI_CHAT_WIDGET_DATA) + @SerializedName(NAVI_CHAT_WIDGET_DATA) + var widgetData: NaviChatCallStatusData? = null, + @get:PropertyName(NAVI_CHAT_SHOULD_DISPLAY_IN_CHAT_HISTORY) + @SerializedName(NAVI_CHAT_SHOULD_DISPLAY_IN_CHAT_HISTORY) + override val shouldDisplayInChatHistory: Boolean = true, + @ServerTimestamp + @SerializedName(NAVI_CHAT_RT_CREATED_AT) + override var rt_created_at: Timestamp? = null, + @get:PropertyName(NAVI_CHAT_SENDER_ID) + @SerializedName(NAVI_CHAT_SENDER_ID) + override val senderId: String? = null, + @get:PropertyName(NAVI_CHAT_SENDER_TYPE) + @SerializedName(NAVI_CHAT_SENDER_TYPE) + override val senderType: String? = null +) : NaviChatWidget, NaviChatCallStatusWidgetInfo, Serializable { + + companion object { + const val WIDGET_NAME = "CHAT_CALL_STATUS_WIDGET" + } + + override fun messageId(): String? = messageId + + override fun title(): TextWithStyle? = widgetData?.title + + override fun subtitle(): TextWithStyle? = widgetData?.subtitle + + override fun metaData(): NaviChatMetaData? = widgetData?.metaData + + override fun senderName(): String? = widgetData?.senderName + + override fun timeStamp(): Timestamp? = rt_created_at + + override fun displayIconUrl(): String? = widgetData?.displayIconUrl + + override fun imgUrl(): String? = widgetData?.imgUrl + + override fun bgColor(): String? = widgetData?.bgColor + + override fun borderColor(): String? = widgetData?.borderColor +} + +data class NaviChatCallStatusData( + @get:PropertyName(NAVI_CHAT_TITLE) + @SerializedName(NAVI_CHAT_TITLE) + val title: TextWithStyle? = null, + @get:PropertyName(SUB_TITLE) @SerializedName(SUB_TITLE) val subtitle: TextWithStyle? = null, + @get:PropertyName(BG_COLOR) @SerializedName(BG_COLOR) val bgColor: String? = null, + @get:PropertyName(IMAGE_URL) @SerializedName(IMAGE_URL) val imgUrl: String? = null, + @get:PropertyName(BORDER_COLOR) @SerializedName(BORDER_COLOR) val borderColor: String? = null, + @SerializedName(NAVI_CHAT_DISPLAY_ICON_URL) + @get:PropertyName(NAVI_CHAT_DISPLAY_ICON_URL) + val displayIconUrl: String? = null, + @get:PropertyName(NAVI_CHAT_META_DATA) + @SerializedName(NAVI_CHAT_META_DATA) + val metaData: NaviChatMetaData? = null, + @get:PropertyName(NAVI_CHAT_SENDER_NAME) + @SerializedName(NAVI_CHAT_SENDER_NAME) + val senderName: String? = null, +) : Serializable diff --git a/android/navi-widgets/src/main/java/com/navi/naviwidgets/models/response/NaviChatControllerWidget.kt b/android/navi-widgets/src/main/java/com/navi/naviwidgets/models/response/NaviChatControllerWidget.kt index 24e9e9eedd..cc82c266d1 100644 --- a/android/navi-widgets/src/main/java/com/navi/naviwidgets/models/response/NaviChatControllerWidget.kt +++ b/android/navi-widgets/src/main/java/com/navi/naviwidgets/models/response/NaviChatControllerWidget.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2022 by Navi Technologies Limited + * * Copyright © 2022-2024 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -79,7 +79,10 @@ data class ControllerConfig( val deleteUpiDeviceData: Boolean? = null, @SerializedName(NAVI_CHAT_CHAT_EXIT_CONFIG) @get:PropertyName(NAVI_CHAT_CHAT_EXIT_CONFIG) - val chatExitConfig: ChatExitConfig? = null + val chatExitConfig: ChatExitConfig? = null, + @SerializedName(NAVI_CHAT_WAIT_TIME_CONFIG) + @get:PropertyName(NAVI_CHAT_WAIT_TIME_CONFIG) + val waitTimeConfig: WaitTimeConfig? = null ) : Serializable data class ChatExitConfig( @@ -173,3 +176,17 @@ data class ChatLanguages( @SerializedName("display_name") val value: String? = null, @SerializedName("is_selected") val isSelected: Boolean? = null, ) : Serializable + +data class WaitTimeConfig( + @SerializedName(NAVI_CHAT_TIMER_DURATION) + @get:PropertyName(NAVI_CHAT_TIMER_DURATION) + val timerDuration: Long? = null, + @SerializedName(START_TIME) @get:PropertyName(START_TIME) val startTime: Long? = null, + @SerializedName(LOGO) @get:PropertyName(LOGO) val imgUrl: String? = null, + @SerializedName(NAVI_CHAT_WAIT_TIME_MESSAGE) + @get:PropertyName(NAVI_CHAT_WAIT_TIME_MESSAGE) + val waitTimeMessage: String? = null, + @SerializedName(NAVI_CHAT_WAIT_TIME_BREACH_MESSAGE) + @get:PropertyName(NAVI_CHAT_WAIT_TIME_BREACH_MESSAGE) + val waitTimeBreachMessage: String? = null +) : Serializable diff --git a/android/navi-widgets/src/main/java/com/navi/naviwidgets/utils/Constants.kt b/android/navi-widgets/src/main/java/com/navi/naviwidgets/utils/Constants.kt index e9fd6b8c53..e2ec291b2b 100644 --- a/android/navi-widgets/src/main/java/com/navi/naviwidgets/utils/Constants.kt +++ b/android/navi-widgets/src/main/java/com/navi/naviwidgets/utils/Constants.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2019-2023 by Navi Technologies Limited + * * Copyright © 2019-2024 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -77,6 +77,7 @@ const val NAVI_CHAT_RATING_INPUT_TYPE = "rating_input_type" const val NAVI_CHAT_RECEIPTS = "receipts" const val NAVI_CHAT_CONTROLLER_CONFIG = "controller_config" const val NAVI_CHAT_CHAT_EXIT_CONFIG = "chat_exit_config" +const val NAVI_CHAT_WAIT_TIME_CONFIG = "wait_time_config" const val ACTIVATION_CONFIG = "activation_config" const val MIN_MESSAGES_SENT_THRESHOLD = "min_messages_sent_threshold" const val MIN_OPTIONS_SELECTED_THRESHOLD = "min_options_selected_threshold" @@ -98,6 +99,8 @@ const val WIDGET_TIME_ELAPSED = "WIDGET_TIME_ELAPSED" const val NAVI_CHAT_LANGUAGE_SELECTION_WIDGET_DATA = "language_selection_widget_data" const val NAVI_CHAT_LANGUAGE_SELECTION = "is_language_selection_enabled" const val NAVI_CHAT_LIST_OF_LANGUAGES = "chat_language_options" +const val NAVI_CHAT_WAIT_TIME_MESSAGE = "wait_time_message" +const val NAVI_CHAT_WAIT_TIME_BREACH_MESSAGE = "wait_time_breach_message" const val WIDGET_ID = "WIDGET_ID" const val WIDGET_VIEWED_TIME = "WIDGET_VIEWED_TIME" const val NODE_UUID = "nodeUuid" @@ -217,3 +220,8 @@ const val PALE_BLUE = "#BED7FF" const val LIGHT_PASTEL_BLUE = "#EAF2FF" const val PRE_DIABETIC_CAROUSEL_CARD_COUNT = 20 const val VIEW_TYPE = "viewType" +const val IMAGE_URL = "image_url" +const val BG_COLOR = "bg_color" +const val SUB_TITLE = "sub_title" +const val BORDER_COLOR = "border_color" +const val START_TIME = "start_time" diff --git a/android/navi-widgets/src/main/java/com/navi/naviwidgets/viewholder/NaviChatCallStatusWidgetVH.kt b/android/navi-widgets/src/main/java/com/navi/naviwidgets/viewholder/NaviChatCallStatusWidgetVH.kt new file mode 100644 index 0000000000..dbd0746091 --- /dev/null +++ b/android/navi-widgets/src/main/java/com/navi/naviwidgets/viewholder/NaviChatCallStatusWidgetVH.kt @@ -0,0 +1,42 @@ +/* + * + * * Copyright © 2024 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.navi.naviwidgets.viewholder + +import androidx.databinding.ViewDataBinding +import com.navi.naviwidgets.callbacks.WidgetCallback +import com.navi.naviwidgets.databinding.LayoutNaviChatCallStatusBinding +import com.navi.naviwidgets.models.response.NaviChatCallStatusWidget +import com.navi.naviwidgets.widgets.NaviChatCallStatusWidgetLayout + +class NaviChatCallStatusWidgetVH(private val viewDataBinding: ViewDataBinding) : + BaseViewHolder(view = viewDataBinding.root) { + + override fun bind( + model: NaviChatCallStatusWidget, + widgetCallback: WidgetCallback, + position: Int, + totalItems: Int + ) { + if (itemView is NaviChatCallStatusWidgetLayout) { + (itemView as NaviChatCallStatusWidgetLayout).update( + info = model, + binding = (viewDataBinding as LayoutNaviChatCallStatusBinding), + position = position, + widgetCallback = widgetCallback + ) + } + } + + override fun bindError(errorData: Any?) { + /*No-op*/ + } + + override fun bindWidgetStateChanged(payload: Any?) { + /*No-op*/ + } +} diff --git a/android/navi-widgets/src/main/java/com/navi/naviwidgets/viewholder/NaviChatViewHolderFactoryImpl.kt b/android/navi-widgets/src/main/java/com/navi/naviwidgets/viewholder/NaviChatViewHolderFactoryImpl.kt index b03d7cd555..06f2fdfb07 100644 --- a/android/navi-widgets/src/main/java/com/navi/naviwidgets/viewholder/NaviChatViewHolderFactoryImpl.kt +++ b/android/navi-widgets/src/main/java/com/navi/naviwidgets/viewholder/NaviChatViewHolderFactoryImpl.kt @@ -1,6 +1,6 @@ /* * - * * Copyright © 2022-2023 by Navi Technologies Limited + * * Copyright © 2022-2024 by Navi Technologies Limited * * All rights reserved. Strictly confidential * */ @@ -49,6 +49,7 @@ class NaviChatViewHolderFactoryImpl( private val NAVI_CHAT_TRANSACTION_STATUS_ITEM_WIDGET = R.layout.layout_navi_chat_transaction_status_message_item private val NAVI_CHAT_TIMESTAMP_DIVIDER_WIDGET = R.layout.layout_chat_timestamp_divider + private val NAVI_CHAT_CALL_STATUS_WIDGET = R.layout.layout_navi_chat_call_status } override fun type(item: NaviBaseAdapterModel?): Int = @@ -78,6 +79,7 @@ class NaviChatViewHolderFactoryImpl( is NaviChatTypingStatusWidget -> NAVI_CHAT_TYPING_STATUS_WIDGET is NaviChatTransactionStatusWidget -> NAVI_CHAT_TRANSACTION_STATUS_WIDGET is NaviChatTransactionItemWidget -> NAVI_CHAT_TRANSACTION_STATUS_ITEM_WIDGET + is NaviChatCallStatusWidget -> NAVI_CHAT_CALL_STATUS_WIDGET else -> { NaviTrackEvent.trackEvent( WIDGET_NOT_HANDLED_BY_APP, @@ -116,6 +118,7 @@ class NaviChatViewHolderFactoryImpl( NaviChatTransactionStatusMessageItemVH(viewDataBinding = parent) NAVI_CHAT_TIMESTAMP_DIVIDER_WIDGET -> NaviChatTimestampDividerVH(viewDataBinding = parent) + NAVI_CHAT_CALL_STATUS_WIDGET -> NaviChatCallStatusWidgetVH(viewDataBinding = parent) UNKNOWN_WIDGET -> UnknownWidgetVH(view = parent) else -> UnknownWidgetVH(view = parent) } diff --git a/android/navi-widgets/src/main/java/com/navi/naviwidgets/widgets/NaviChatCallStatusWidgetLayout.kt b/android/navi-widgets/src/main/java/com/navi/naviwidgets/widgets/NaviChatCallStatusWidgetLayout.kt new file mode 100644 index 0000000000..1711c97643 --- /dev/null +++ b/android/navi-widgets/src/main/java/com/navi/naviwidgets/widgets/NaviChatCallStatusWidgetLayout.kt @@ -0,0 +1,96 @@ +/* + * + * * Copyright © 2024 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.navi.naviwidgets.widgets + +import android.content.Context +import android.util.AttributeSet +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.recyclerview.widget.RecyclerView +import com.navi.design.R +import com.navi.design.utils.CornerRadius +import com.navi.design.utils.dpToPx +import com.navi.design.utils.getNaviDrawable +import com.navi.design.utils.parseColorSafe +import com.navi.naviwidgets.callbacks.WidgetCallback +import com.navi.naviwidgets.databinding.LayoutNaviChatCallStatusBinding +import com.navi.naviwidgets.extensions.showWhenDataIsAvailable +import com.navi.naviwidgets.interfaces.NaviChatCallStatusWidgetInfo +import com.navi.naviwidgets.utils.convertTo12HourFormatTime +import com.navi.naviwidgets.utils.setNaviChatMessageMargin +import com.navi.naviwidgets.utils.updateLogoVisibility + +class NaviChatCallStatusWidgetLayout +@JvmOverloads +constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : + ConstraintLayout(context, attrs, defStyleAttr) { + private lateinit var binding: LayoutNaviChatCallStatusBinding + private lateinit var info: NaviChatCallStatusWidgetInfo + private lateinit var widgetCallback: WidgetCallback + private var widgetPosition: Int = Int.MAX_VALUE + + fun update( + info: NaviChatCallStatusWidgetInfo, + binding: LayoutNaviChatCallStatusBinding, + position: Int, + widgetCallback: WidgetCallback + ) { + this.binding = binding + this.info = info + this.widgetPosition = position + this.widgetCallback = widgetCallback + setProperties() + setMargin() + } + + private fun setProperties() { + with(binding) { + updateLogoVisibility( + context, + info.displayIconUrl(), + logoLayout.logo, + logoLayout.cvReceivedMessage + ) + tvReceivedMessage.tvCallStatus.showWhenDataIsAvailable(showText = info.title()) + tvReceivedMessage.tvCallDuration.showWhenDataIsAvailable(showText = info.subtitle()) + info.imgUrl()?.let { imageUrl -> + tvReceivedMessage.ivCallIcon.showWhenDataIsAvailable(imageUrl = imageUrl) + } + tvReceivedMessage.layoutCallStatusItem.background = + getNaviDrawable( + radii = + CornerRadius( + leftTop = dpToPx(TOP_CORNER_RADIUS), + rightTop = dpToPx(TOP_CORNER_RADIUS), + leftBottom = dpToPx(BOTTOM_LEFT_CORNER_RADIUS), + rightBottom = dpToPx(TOP_CORNER_RADIUS) + ), + strokeColor = info.borderColor().parseColorSafe(), + strokeWidth = dpToPx(BORDER_WIDTH).toInt(), + backgroundColor = info.bgColor().parseColorSafe() + ) + tvTimestamp.showWhenDataIsAvailable( + showText = + info.timeStamp()?.let { timeStamp -> convertTo12HourFormatTime(timeStamp) } + ) + } + } + + private fun setMargin() { + (binding.root.layoutParams as? RecyclerView.LayoutParams)?.setNaviChatMessageMargin( + bottomMargin = binding.root.context.resources.getInteger(R.integer.integer_8), + topMargin = binding.root.context.resources.getInteger(R.integer.integer_16) + ) + } + + companion object { + private const val TAG = "NaviChatCallStatusWidgetLayout" + private const val BORDER_WIDTH = 1 + private const val TOP_CORNER_RADIUS = 20 + private const val BOTTOM_LEFT_CORNER_RADIUS = 4 + } +} diff --git a/android/navi-widgets/src/main/res/drawable/ic_navi_chat_received_call_message_bg.xml b/android/navi-widgets/src/main/res/drawable/ic_navi_chat_received_call_message_bg.xml new file mode 100644 index 0000000000..974c8e9546 --- /dev/null +++ b/android/navi-widgets/src/main/res/drawable/ic_navi_chat_received_call_message_bg.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/android/navi-widgets/src/main/res/drawable/ic_navi_chat_received_message_bg.xml b/android/navi-widgets/src/main/res/drawable/ic_navi_chat_received_message_bg.xml index 332f09ab5e..a7d7d36025 100644 --- a/android/navi-widgets/src/main/res/drawable/ic_navi_chat_received_message_bg.xml +++ b/android/navi-widgets/src/main/res/drawable/ic_navi_chat_received_message_bg.xml @@ -8,9 +8,10 @@ - + \ No newline at end of file diff --git a/android/navi-widgets/src/main/res/layout/layout_navi_chat_call_status.xml b/android/navi-widgets/src/main/res/layout/layout_navi_chat_call_status.xml new file mode 100644 index 0000000000..41685c61a8 --- /dev/null +++ b/android/navi-widgets/src/main/res/layout/layout_navi_chat_call_status.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/navi-widgets/src/main/res/layout/layout_navi_chat_call_status_item.xml b/android/navi-widgets/src/main/res/layout/layout_navi_chat_call_status_item.xml new file mode 100644 index 0000000000..ceb26900b7 --- /dev/null +++ b/android/navi-widgets/src/main/res/layout/layout_navi_chat_call_status_item.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + \ No newline at end of file