From 1497be7264d7fab3a84d3cf2e231da0292420bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mustafa=20Og=C3=BCn=20=C3=96zt=C3=BCrk?= Date: Wed, 20 Oct 2021 14:52:12 +0300 Subject: [PATCH 01/15] MUIC-495: Fix URL identification issue (#101) --- .../main/java/com/glia/widgets/chat/ChatView.java | 3 ++- .../widgets/chat/helper/CustomTabActivityHelper.java | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java b/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java index ae31fcfa5..dc98f3d38 100644 --- a/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java +++ b/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java @@ -24,6 +24,7 @@ import android.text.Editable; import android.text.TextWatcher; import android.util.AttributeSet; +import android.util.Patterns; import android.view.View; import android.webkit.URLUtil; import android.widget.EditText; @@ -1328,7 +1329,7 @@ public void onRequestPermissionsResult(int requestCode, String[] permissions, in @Override public void onTextClick(String text) { - if (URLUtil.isValidUrl(text)) { + if (Patterns.WEB_URL.matcher(text).matches()) { if (CustomTabActivityHelper.hasSupportedBrowser((Utils.getActivity(this.getContext())))) { CustomTabActivityHelper.openCustomTab((Utils.getActivity(this.getContext())), text, theme.getBrandPrimaryColor(), theme.getBaseLightColor()); } else { diff --git a/widgetssdk/src/main/java/com/glia/widgets/chat/helper/CustomTabActivityHelper.java b/widgetssdk/src/main/java/com/glia/widgets/chat/helper/CustomTabActivityHelper.java index 95ab4c0ca..ccafa7b6f 100644 --- a/widgetssdk/src/main/java/com/glia/widgets/chat/helper/CustomTabActivityHelper.java +++ b/widgetssdk/src/main/java/com/glia/widgets/chat/helper/CustomTabActivityHelper.java @@ -2,6 +2,7 @@ import android.app.Activity; import android.net.Uri; +import android.webkit.URLUtil; import androidx.browser.customtabs.CustomTabColorSchemeParams; import androidx.browser.customtabs.CustomTabsClient; @@ -25,7 +26,16 @@ public static void openCustomTab(Activity activity, String url, int primaryColor builder.setDefaultColorSchemeParams(defaultColors); CustomTabsIntent customTabsIntent = builder.build(); customTabsIntent.intent.setPackage(packageName); - customTabsIntent.launchUrl(activity, Uri.parse(url)); + + String finalUrl; + + if (URLUtil.isHttpsUrl(url) || URLUtil.isHttpUrl(url)) { + finalUrl = url; + } else { + finalUrl = "https://" + url; + } + + customTabsIntent.launchUrl(activity, Uri.parse(finalUrl)); } public static boolean hasSupportedBrowser(Activity activity) { From 8687c46cae0ea2a4a8593766a45e8abebafe1ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mustafa=20Og=C3=BCn=20=C3=96zt=C3=BCrk?= Date: Wed, 20 Oct 2021 15:32:58 +0300 Subject: [PATCH 02/15] MUIC-519: Visitor can click on phone number (#106) --- .../src/main/java/com/glia/widgets/Constants.java | 2 ++ .../src/main/java/com/glia/widgets/chat/ChatView.java | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/widgetssdk/src/main/java/com/glia/widgets/Constants.java b/widgetssdk/src/main/java/com/glia/widgets/Constants.java index 2bb861bf9..22ac9035d 100644 --- a/widgetssdk/src/main/java/com/glia/widgets/Constants.java +++ b/widgetssdk/src/main/java/com/glia/widgets/Constants.java @@ -25,4 +25,6 @@ public class Constants { * Global media timer interval value */ public static final int CALL_TIMER_INTERVAL_VALUE = 1000; + + public static final String PHONE_NUMBER_REGEX = "^[+]\\s*?[0-9]{10,13}$"; } diff --git a/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java b/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java index dc98f3d38..bfb04cff4 100644 --- a/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java +++ b/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java @@ -26,7 +26,6 @@ import android.util.AttributeSet; import android.util.Patterns; import android.view.View; -import android.webkit.URLUtil; import android.widget.EditText; import android.widget.ImageButton; import android.widget.RelativeLayout; @@ -49,6 +48,7 @@ import com.airbnb.lottie.LottieProperty; import com.airbnb.lottie.model.KeyPath; import com.glia.androidsdk.chat.AttachmentFile; +import com.glia.widgets.Constants; import com.glia.widgets.R; import com.glia.widgets.UiTheme; import com.glia.widgets.chat.adapter.ChatAdapter; @@ -87,6 +87,7 @@ import java.io.File; import java.io.IOException; import java.util.List; +import java.util.regex.Pattern; import java.util.stream.Collectors; public class ChatView extends ConstraintLayout implements ChatAdapter.OnFileItemClickListener, ChatAdapter.OnImageItemClickListener, ChatAdapter.OnTextClickListener { @@ -1335,9 +1336,17 @@ public void onTextClick(String text) { } else { this.getContext().startActivity(OperatorLinksActivity.intent(this.getContext(), text, theme)); } + } else if (Pattern.matches(Constants.PHONE_NUMBER_REGEX, text)) { + composeCall(text); } } + public void composeCall(String phoneNumber) { + Intent intent = new Intent(Intent.ACTION_DIAL); + intent.setData(Uri.parse("tel:" + phoneNumber)); + (Utils.getActivity(this.getContext())).startActivity(intent); + } + public interface OnBackClickedListener { /** * Callback which is used to notify the enclosing activity or fragment when the user From ab267d60f9e758a510d21602cdcaae82a2085524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mustafa=20Og=C3=BCn=20=C3=96zt=C3=BCrk?= Date: Wed, 20 Oct 2021 15:53:41 +0300 Subject: [PATCH 03/15] MUIC-521: Visitor can click on email link (#105) --- .../src/main/java/com/glia/widgets/chat/ChatView.java | 11 +++++++++++ .../main/res/layout/chat_receive_message_content.xml | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java b/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java index bfb04cff4..2f3102873 100644 --- a/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java +++ b/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java @@ -1336,11 +1336,22 @@ public void onTextClick(String text) { } else { this.getContext().startActivity(OperatorLinksActivity.intent(this.getContext(), text, theme)); } + } else if (Patterns.EMAIL_ADDRESS.matcher(text).matches()) { + composeEmail(text); } else if (Pattern.matches(Constants.PHONE_NUMBER_REGEX, text)) { composeCall(text); } } + public void composeEmail(String email) { + Intent intent = new Intent(Intent.ACTION_SENDTO); + intent.setData(Uri.parse("mailto:")); + intent.putExtra(Intent.EXTRA_EMAIL, email); + if (intent.resolveActivity((Utils.getActivity(this.getContext())).getPackageManager()) != null) { + (Utils.getActivity(this.getContext())).startActivity(intent); + } + } + public void composeCall(String phoneNumber) { Intent intent = new Intent(Intent.ACTION_DIAL); intent.setData(Uri.parse("tel:" + phoneNumber)); diff --git a/widgetssdk/src/main/res/layout/chat_receive_message_content.xml b/widgetssdk/src/main/res/layout/chat_receive_message_content.xml index 0c58be04e..fe7a985b9 100644 --- a/widgetssdk/src/main/res/layout/chat_receive_message_content.xml +++ b/widgetssdk/src/main/res/layout/chat_receive_message_content.xml @@ -3,7 +3,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/glia_medium" - android:autoLink="web" + android:autoLink="web|email" android:background="@drawable/bg_message" android:backgroundTint="?attr/gliaSystemAgentBubbleColor" android:linksClickable="false" From dec9f1c8a1a7c3ada860a11ac4393f314fe302e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mustafa=20Og=C3=BCn=20=C3=96zt=C3=BCrk?= Date: Mon, 25 Oct 2021 12:18:21 +0300 Subject: [PATCH 04/15] MUIC-524: Operator ended engagement (#107) --- .../com/glia/widgets/call/CallController.java | 2 +- .../java/com/glia/widgets/call/CallView.java | 27 +++++++- .../java/com/glia/widgets/chat/ChatView.java | 28 ++++++++- .../chat/controller/ChatController.java | 24 ++++---- .../widgets/core/dialog/DialogController.java | 9 ++- .../widgets/core/dialog/DialogsState.java | 3 + .../java/com/glia/widgets/view/Dialogs.java | 39 ++++++++++++ .../operator_ended_engagement_dialog.xml | 61 +++++++++++++++++++ widgetssdk/src/main/res/values/strings.xml | 3 + 9 files changed, 178 insertions(+), 18 deletions(-) create mode 100644 widgetssdk/src/main/res/layout/operator_ended_engagement_dialog.xml diff --git a/widgetssdk/src/main/java/com/glia/widgets/call/CallController.java b/widgetssdk/src/main/java/com/glia/widgets/call/CallController.java index fe740eac5..0d5f9985c 100644 --- a/widgetssdk/src/main/java/com/glia/widgets/call/CallController.java +++ b/widgetssdk/src/main/java/com/glia/widgets/call/CallController.java @@ -558,7 +558,7 @@ public void onNewVisitorMediaState(VisitorMediaState visitorMediaState) { public void engagementEnded() { Logger.d(TAG, "engagementEndedByOperator"); stop(); - dialogController.showNoMoreOperatorsAvailableDialog(); + dialogController.showEngagementEndedDialog(); } @Override diff --git a/widgetssdk/src/main/java/com/glia/widgets/call/CallView.java b/widgetssdk/src/main/java/com/glia/widgets/call/CallView.java index a94e5771e..8cf113e47 100644 --- a/widgetssdk/src/main/java/com/glia/widgets/call/CallView.java +++ b/widgetssdk/src/main/java/com/glia/widgets/call/CallView.java @@ -13,8 +13,6 @@ import android.graphics.Typeface; import android.media.AudioManager; import android.net.Uri; -import android.os.Handler; -import android.os.Looper; import android.provider.Settings; import android.util.AttributeSet; import android.view.Gravity; @@ -408,6 +406,8 @@ public void navigateToChat() { post(this::showExitQueueDialog); } else if (dialogsState instanceof DialogsState.NoMoreOperatorsDialog) { post(this::showNoMoreOperatorsAvailableDialog); + } else if (dialogsState instanceof DialogsState.EngagementEndedDialog) { + post(this::showEngagementEndedDialog); } else if (dialogsState instanceof DialogsState.UpgradeDialog) { post(() -> showUpgradeDialog(((DialogsState.UpgradeDialog) dialogsState).type)); } else if (dialogsState instanceof DialogsState.StartScreenSharingDialog) { @@ -863,6 +863,29 @@ private void showAlertDialog(@StringRes int title, @StringRes int message, buttonClickListener); } + private void showEngagementEndedDialog() { + if (alertDialog != null) { + alertDialog.dismiss(); + alertDialog = null; + } + alertDialog = Dialogs.showOperatorEndedEngagementDialog( + this.getContext(), + this.theme, + v -> { + dismissAlertDialog(); + if (controller != null) { + controller.noMoreOperatorsAvailableDismissed(); + } + if (chatHeadsController != null) { + chatHeadsController.chatEndedByUser(); + } + if (onEndListener != null) { + onEndListener.onEnd(); + } + callEnded(); + }); + } + private void showNoMoreOperatorsAvailableDialog() { showAlertDialog( R.string.glia_dialog_operators_unavailable_title, diff --git a/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java b/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java index 2f3102873..370fd4484 100644 --- a/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java +++ b/widgetssdk/src/main/java/com/glia/widgets/chat/ChatView.java @@ -583,12 +583,13 @@ public void fileDownloadSuccess(AttachmentFile attachmentFile) { } else if (dialogsState instanceof DialogsState.OverlayPermissionsDialog) { post(this::showOverlayPermissionsDialog); } else if (dialogsState instanceof DialogsState.EndEngagementDialog) { - post(() -> showEndEngagementDialog( - ((DialogsState.EndEngagementDialog) dialogsState).operatorName)); + post(() -> showEndEngagementDialog(((DialogsState.EndEngagementDialog) dialogsState).operatorName)); } else if (dialogsState instanceof DialogsState.UpgradeDialog) { post(() -> showUpgradeDialog(((DialogsState.UpgradeDialog) dialogsState).type)); } else if (dialogsState instanceof DialogsState.NoMoreOperatorsDialog) { post(this::showNoMoreOperatorsAvailableDialog); + } else if (dialogsState instanceof DialogsState.EngagementEndedDialog) { + post(this::showEngagementEndedDialog); } else if (dialogsState instanceof DialogsState.StartScreenSharingDialog) { post(this::showScreenSharingDialog); } else if (dialogsState instanceof DialogsState.EndScreenSharingDialog) { @@ -1096,6 +1097,29 @@ private void showAlertDialog(@StringRes int title, buttonClickListener); } + private void showEngagementEndedDialog() { + if (alertDialog != null) { + alertDialog.dismiss(); + alertDialog = null; + } + alertDialog = Dialogs.showOperatorEndedEngagementDialog( + this.getContext(), + this.theme, + v -> { + dismissAlertDialog(); + if (controller != null) { + controller.noMoreOperatorsAvailableDismissed(); + } + if (chatHeadsController != null) { + chatHeadsController.chatEndedByUser(); + } + if (onEndListener != null) { + onEndListener.onEnd(); + } + chatEnded(); + }); + } + private void showNoMoreOperatorsAvailableDialog() { showAlertDialog( R.string.glia_dialog_operators_unavailable_title, diff --git a/widgetssdk/src/main/java/com/glia/widgets/chat/controller/ChatController.java b/widgetssdk/src/main/java/com/glia/widgets/chat/controller/ChatController.java index 6b30d9f2d..91af597e6 100644 --- a/widgetssdk/src/main/java/com/glia/widgets/chat/controller/ChatController.java +++ b/widgetssdk/src/main/java/com/glia/widgets/chat/controller/ChatController.java @@ -43,18 +43,18 @@ import com.glia.widgets.core.engagement.domain.GliaOnEngagementEndUseCase; import com.glia.widgets.core.engagement.domain.GliaOnEngagementUseCase; import com.glia.widgets.core.engagement.domain.OnUpgradeToMediaEngagementUseCase; -import com.glia.widgets.core.notification.domain.ShowVideoCallNotificationUseCase; -import com.glia.widgets.core.notification.domain.ShowAudioCallNotificationUseCase; -import com.glia.widgets.core.notification.domain.RemoveCallNotificationUseCase; -import com.glia.widgets.core.mediaupgradeoffer.MediaUpgradeOfferRepositoryCallback; -import com.glia.widgets.core.mediaupgradeoffer.MediaUpgradeOfferRepository; -import com.glia.widgets.core.fileupload.model.FileAttachment; -import com.glia.widgets.core.fileupload.domain.SupportedFileCountCheckUseCase; -import com.glia.widgets.core.fileupload.domain.RemoveFileAttachmentUseCase; -import com.glia.widgets.core.fileupload.domain.RemoveFileAttachmentObserverUseCase; -import com.glia.widgets.core.fileupload.domain.GetFileAttachmentsUseCase; -import com.glia.widgets.core.fileupload.domain.AddFileToAttachmentAndUploadUseCase; import com.glia.widgets.core.fileupload.domain.AddFileAttachmentsObserverUseCase; +import com.glia.widgets.core.fileupload.domain.AddFileToAttachmentAndUploadUseCase; +import com.glia.widgets.core.fileupload.domain.GetFileAttachmentsUseCase; +import com.glia.widgets.core.fileupload.domain.RemoveFileAttachmentObserverUseCase; +import com.glia.widgets.core.fileupload.domain.RemoveFileAttachmentUseCase; +import com.glia.widgets.core.fileupload.domain.SupportedFileCountCheckUseCase; +import com.glia.widgets.core.fileupload.model.FileAttachment; +import com.glia.widgets.core.mediaupgradeoffer.MediaUpgradeOfferRepository; +import com.glia.widgets.core.mediaupgradeoffer.MediaUpgradeOfferRepositoryCallback; +import com.glia.widgets.core.notification.domain.RemoveCallNotificationUseCase; +import com.glia.widgets.core.notification.domain.ShowAudioCallNotificationUseCase; +import com.glia.widgets.core.notification.domain.ShowVideoCallNotificationUseCase; import com.glia.widgets.core.operator.GliaOperatorMediaRepository; import com.glia.widgets.core.operator.domain.AddOperatorMediaStateListenerUseCase; import com.glia.widgets.core.queue.QueueTicketsEventsListener; @@ -1079,7 +1079,7 @@ public void newEngagementLoaded(OmnicoreEngagement engagement) { public void engagementEnded() { Logger.d(TAG, "engagementEnded"); stop(); - dialogController.showNoMoreOperatorsAvailableDialog(); + dialogController.showEngagementEndedDialog(); } public void onNewOperatorMediaState(OperatorMediaState operatorMediaState) { diff --git a/widgetssdk/src/main/java/com/glia/widgets/core/dialog/DialogController.java b/widgetssdk/src/main/java/com/glia/widgets/core/dialog/DialogController.java index 586a15fb3..9c2f23f40 100644 --- a/widgetssdk/src/main/java/com/glia/widgets/core/dialog/DialogController.java +++ b/widgetssdk/src/main/java/com/glia/widgets/core/dialog/DialogController.java @@ -1,9 +1,9 @@ package com.glia.widgets.core.dialog; import com.glia.androidsdk.comms.MediaUpgradeOffer; -import com.glia.widgets.helper.Logger; import com.glia.widgets.core.dialog.domain.SetEnableCallNotificationChannelDialogShownUseCase; import com.glia.widgets.core.dialog.domain.SetOverlayPermissionRequestDialogShownUseCase; +import com.glia.widgets.helper.Logger; import com.glia.widgets.view.DialogOfferType; import java.util.ArrayList; @@ -121,6 +121,13 @@ public void showNoMoreOperatorsAvailableDialog() { } } + public void showEngagementEndedDialog() { + if (isNoDialogShown()) { + Logger.d(TAG, "Show Engagement Ended Dialog"); + emitDialogState(new DialogsState.EngagementEndedDialog()); + } + } + public void showUnexpectedErrorDialog() { // PRIORITISE THIS ERROR AS IT IS ENGAGEMENT FATAL ERROR INDICATOR (eg. GliaException:{"details":"Queue is closed","error":"Unprocessable entity"}) for example Logger.d(TAG, "Show Unexpected error Dialog"); diff --git a/widgetssdk/src/main/java/com/glia/widgets/core/dialog/DialogsState.java b/widgetssdk/src/main/java/com/glia/widgets/core/dialog/DialogsState.java index af69dc3f3..38f6b13d7 100644 --- a/widgetssdk/src/main/java/com/glia/widgets/core/dialog/DialogsState.java +++ b/widgetssdk/src/main/java/com/glia/widgets/core/dialog/DialogsState.java @@ -16,6 +16,9 @@ class UnexpectedErrorDialog implements DialogsState { class NoMoreOperatorsDialog implements DialogsState { } + class EngagementEndedDialog implements DialogsState { + } + class ExitQueueDialog implements DialogsState { } diff --git a/widgetssdk/src/main/java/com/glia/widgets/view/Dialogs.java b/widgetssdk/src/main/java/com/glia/widgets/view/Dialogs.java index 788ee20c2..5b397a211 100644 --- a/widgetssdk/src/main/java/com/glia/widgets/view/Dialogs.java +++ b/widgetssdk/src/main/java/com/glia/widgets/view/Dialogs.java @@ -6,6 +6,7 @@ import android.graphics.Typeface; import android.view.LayoutInflater; import android.view.View; +import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; @@ -126,6 +127,44 @@ public static AlertDialog showAlertDialog(Context context, return dialog; } + public static AlertDialog showOperatorEndedEngagementDialog(Context context, UiTheme theme, View.OnClickListener buttonClickListener) { + + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context); + builder.setCancelable(false); + View customLayout = LayoutInflater.from(context).inflate(R.layout.operator_ended_engagement_dialog, null, false); + TextView titleView = customLayout.findViewById(R.id.dialog_title_view); + TextView messageView = customLayout.findViewById(R.id.dialog_message_view); + Button okButton = customLayout.findViewById(R.id.ok_button); + + int baseDarkColor = ContextCompat.getColor(context, theme.getBaseNormalColor()); + ColorStateList brandPrimaryColorStateList = ContextCompat.getColorStateList(context, theme.getBrandPrimaryColor()); + + titleView.setTextColor(baseDarkColor); + messageView.setTextColor(baseDarkColor); + okButton.setBackgroundTintList(brandPrimaryColorStateList); + + if (theme.getFontRes() != null) { + Typeface fontFamily = ResourcesCompat.getFont(context, theme.getFontRes()); + + titleView.setTypeface(fontFamily); + messageView.setTypeface(fontFamily); + } + + okButton.setOnClickListener(buttonClickListener); + builder.setView(customLayout); + + builder.setCancelable(false); + + AlertDialog dialog = builder.show(); + + dialog.getWindow() + .getDecorView() + .getBackground() + .setTint(ContextCompat.getColor(context, theme.getBaseLightColor())); + + return dialog; + } + public static AlertDialog showUpgradeDialog(Context context, UiTheme theme, DialogOfferType type, diff --git a/widgetssdk/src/main/res/layout/operator_ended_engagement_dialog.xml b/widgetssdk/src/main/res/layout/operator_ended_engagement_dialog.xml new file mode 100644 index 000000000..33f292a57 --- /dev/null +++ b/widgetssdk/src/main/res/layout/operator_ended_engagement_dialog.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + +