Translate message attachment in bot framework - c#

I was trying the multi-language chat bot in bot framework. https://github.com/Microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/17.multilingual-bot.
I was successful in translating ordinary message with no attachment. But I'm having a problem with attachment like herocard or suggestedcard.
var reply = stepContext.Context.Activity.CreateReply();
var card = new HeroCard();
card.Buttons = new List<CardAction>()
{
new CardAction() { Title = "1. All lights are green.", Type = ActionTypes.ImBack, Value = "All lights are green." },
new CardAction() { Title = "2. DSL light is OFF/Red/Blinking Green.", Type = ActionTypes.ImBack, Value = "DSL light is OFF/Red/Blinking Green." },
new CardAction() { Title = "3. Internet light is OFF/Red/Amber or blinking red and green.", Type = ActionTypes.ImBack, Value = "Internet light is OFF/Red/Amber or blinking red and green." },
new CardAction() { Title = "4. Power light is OFF/Red/Amber or blinking.", Type = ActionTypes.ImBack, Value = "Power light is OFF/Red/Amber or blinking." },
};
reply.Attachments = new List<Attachment>() { card.ToAttachment() };
reply.AttachmentLayout = AttachmentLayoutTypes.List;
var options = new PromptOptions()
{
Prompt = reply,
};
await stepContext.Context.SendActivityAsync(reply, cancellationToken);
Thanks!

You need to check if there are any attachments. I have some middleware that sets the speak on message and use the following code:
if (string.IsNullOrEmpty(message.Text))
{
if (message.Attachments[0].Content is HeroCard attachment)
{
message.Speak = TextToSpeechHelper.ConvertTextToSpeechText(attachment.Text);
}
}
else
{
message.Speak = TextToSpeechHelper.ConvertTextToSpeechText(message.Text);
}
You'd have to adjust it to set the text and translate.
Below is a full example of what my middleware is. Keep in mind this middleware sets the speak to the text and sets the input hint.
public class TextToSpeechMiddleware : IMiddleware
{
private readonly IEnumerable<string> ignoreList;
public TextToSpeechMiddleware(string speakIgnore)
{
ignoreList = GetSpeakIgnore(speakIgnore);
}
public Task OnTurnAsync(ITurnContext turnContext, NextDelegate next, CancellationToken cancellationToken = default(CancellationToken))
{
turnContext.OnSendActivities(OnSendActivities);
turnContext.OnUpdateActivity(OnUpdateActivity);
return next(cancellationToken);
}
private static IEnumerable<string> GetSpeakIgnore(string value)
{
string[] ignoreList = value.Split(';');
return ignoreList.Select(i => i.Trim())
.Where(i => !string.IsNullOrEmpty(i));
}
private Task<ResourceResponse> OnUpdateActivity(ITurnContext turnContext, Activity activity, Func<Task<ResourceResponse>> next)
{
ConvertTextToSpeech(activity);
return next();
}
private Task<ResourceResponse[]> OnSendActivities(ITurnContext turnContext, List<Activity> activities, Func<Task<ResourceResponse[]>> next)
{
foreach (Activity currentActivity in activities.Where(a => a.Type == ActivityTypes.Message))
{
ConvertTextToSpeech(currentActivity);
}
return next();
}
private void ConvertTextToSpeech(Activity message)
{
Activity initialMessage = message;
try
{
if (message.Type == ActivityTypes.Message)
{
bool ignoredSpeak = false;
if (string.IsNullOrEmpty(message.Speak))
{
if (string.IsNullOrEmpty(message.Text))
{
if (message.Attachments[0].Content is HeroCard attachment)
{
message.Speak = TextToSpeechHelper.ConvertTextToSpeechText(attachment.Text);
}
}
else
{
message.Speak = TextToSpeechHelper.ConvertTextToSpeechText(message.Text);
}
message.Speak = message.Speak.Trim();
if (ignoreList.Where(i => message.Speak.ToLower().StartsWith(i.ToLower())).Count() != 0)
{
message.Speak = null;
ignoredSpeak = true;
}
}
else if (string.IsNullOrWhiteSpace(message.Speak))
{
message.Speak = " ";
}
if ((!string.IsNullOrEmpty(message.Speak) && (message.Speak.EndsWith("?") || message.Speak.StartsWith("Is this correct?")))
|| (!string.IsNullOrEmpty(message.Text) && message.Text.EndsWith("?"))
|| ignoredSpeak)
{
message.InputHint = InputHints.ExpectingInput;
}
// IOs won't work with expecting input
if (message.Recipient.Name.EndsWith(":ios"))
{
message.InputHint = InputHints.AcceptingInput;
}
}
// Logic needed to increase speech speed.
// if (!string.IsNullOrEmpty(message.Speak))
// {
// message.Speak = #"<speak version='1.0' " + "xmlns='http://www.w3.org/2001/10/synthesis' xml:lang='en-GB'><prosody rate=\"1.5\">" + message.Speak + "</prosody></speak>";
// }
}
catch (Exception)
{
message = initialMessage;
}
}
}

Related

'Unable to deserialize content' when updating Microsoft calendar events in batch on retry

I'm working on an application based on .NET Framework 4.8. I'm using Microsoft Batching API. The below are code snippets
public async Task<List<BatchResponse>> UpdateEventsInBatchAsync(string accessToken, Dictionary<int, Tuple<string, OfficeEvent>> absEvents)
{
var httpMethod = new HttpMethod("PATCH");
var batches = GetUpdateRequestBatches(absEvents, httpMethod);
var graphClient = GetGraphClient(accessToken);
var batchResponses = new List<BatchResponse>();
foreach (var batch in batches)
{
try
{
var batchResponseList = await ExecuteBatchRequestAsync(graphClient, batch).ConfigureAwait(false);
batchResponses.AddRange(batchResponseList);
}
catch (ClientException exc)
{
_logService.LogException("Error while processing update batch", exc);
batchResponses.Add(new BatchResponse
{ StatusCode = HttpStatusCode.InternalServerError, ReasonPhrase = exc.Message });
}
catch (Exception exc)
{
_logService.LogException("Error while processing update batch", exc);
batchResponses.Add(new BatchResponse { StatusCode = HttpStatusCode.InternalServerError, ReasonPhrase = exc.Message });
}
}
return batchResponses;
}
The respective methods used in the above code are mentioned below in respective order-
GetUpdateRequestBatches
private IEnumerable<BatchRequestContent> GetUpdateRequestBatches(Dictionary<int, Tuple<string, OfficeEvent>> absEvents, HttpMethod httpMethod)
{
var batches = new List<BatchRequestContent>();
var batchRequestContent = new BatchRequestContent();
const int maxNoBatchItems = 20;
var batchItemsCount = 0;
foreach (var kvp in absEvents)
{
System.Diagnostics.Debug.Write($"{kvp.Key} --- ");
System.Diagnostics.Debug.WriteLine(_serializer.SerializeObject(kvp.Value.Item2));
var requestUri = $"{_msOfficeBaseApiUrl}/me/events/{kvp.Value.Item1}";
var httpRequestMessage = new HttpRequestMessage(httpMethod, requestUri)
{
Content = _serializer.SerializeAsJsonContent(kvp.Value.Item2)
};
var requestStep = new BatchRequestStep(kvp.Key.ToString(), httpRequestMessage);
batchRequestContent.AddBatchRequestStep(requestStep);
batchItemsCount++;
// Max number of 20 request per batch. So we need to send out multiple batches.
if (batchItemsCount > 0 && batchItemsCount % maxNoBatchItems == 0)
{
batches.Add(batchRequestContent);
batchRequestContent = new BatchRequestContent();
batchItemsCount = 0;
}
}
if (batchRequestContent.BatchRequestSteps.Count < maxNoBatchItems)
{
batches.Add(batchRequestContent);
}
if (batches.Count == 0)
{
batches.Add(batchRequestContent);
}
return batches;
}
GetGraphClient
private static GraphServiceClient GetGraphClient(string accessToken)
{
var graphClient = new GraphServiceClient(new DelegateAuthenticationProvider(requestMessage =>
{
requestMessage
.Headers
.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
return Task.FromResult(0);
}));
return graphClient;
}
ExecuteBatchRequestAsync
private async Task<List<BatchResponse>> ExecuteBatchRequestAsync(IBaseClient graphClient, BatchRequestContent batch)
{
BatchResponseContent response = await graphClient.Batch.Request().PostAsync(batch);
Dictionary<string, HttpResponseMessage> responses = await response.GetResponsesAsync();
var batchResponses = new List<BatchResponse>();
var failedReqKeys = new Dictionary<string, TimeSpan>();
foreach (var key in responses.Keys)
{
using (HttpResponseMessage httpResponseMsg = await response.GetResponseByIdAsync(key))
{
var responseContent = await httpResponseMsg.Content.ReadAsStringAsync();
string eventId = null;
var reasonPhrase = httpResponseMsg.ReasonPhrase;
if (!string.IsNullOrWhiteSpace(responseContent))
{
var eventResponse = JObject.Parse(responseContent);
eventId = (string)eventResponse["id"];
// If still null, then might error have occurred
if (eventId == null)
{
var errorResponse = _serializer.DeserializeObject<ErrorResponse>(responseContent);
var error = errorResponse?.Error;
if (error != null)
{
if (httpResponseMsg.StatusCode == (HttpStatusCode)429)
{
System.Diagnostics.Debug.WriteLine($"{httpResponseMsg.StatusCode} {httpResponseMsg.Content}");
var executionDelay = httpResponseMsg.Headers.RetryAfter.Delta ?? TimeSpan.FromSeconds(5);
failedReqKeys.Add(key, executionDelay);
continue;
}
reasonPhrase = $"{error.Code} - {error.Message}";
}
}
}
var batchResponse = new BatchResponse
{
Key = key,
EventId = eventId,
StatusCode = httpResponseMsg.StatusCode,
ReasonPhrase = reasonPhrase
};
batchResponses.Add(batchResponse);
}
}
if (failedReqKeys.Count == 0) return batchResponses;
return await HandleFailedRequestsAsync(graphClient, failedReqKeys, batch, batchResponses).ConfigureAwait(false);
}
HandleFailedRequestsAsync
private async Task<List<BatchResponse>> HandleFailedRequestsAsync(IBaseClient graphClient, Dictionary<string, TimeSpan> failedReqKeys, BatchRequestContent batch, List<BatchResponse> batchResponses)
{
// Sleep for the duration as suggested in RetryAfter
var sleepDuration = failedReqKeys.Values.Max();
Thread.Sleep(sleepDuration);
var failedBatchRequests = batch.BatchRequestSteps.Where(b => failedReqKeys.Keys.Contains(b.Key)).ToList();
var failedBatch = new BatchRequestContent();
foreach (var kvp in failedBatchRequests)
{
failedBatch.AddBatchRequestStep(kvp.Value);
}
var failedBatchResponses = await ExecuteBatchRequestAsync(graphClient, failedBatch);
batchResponses.AddRange(failedBatchResponses);
return batchResponses;
}
I'm getting an error as on the first line in method ExecuteBatchRequestAsync as
Microsoft.Graph.ClientException: Code: invalidRequest
Message: Unable to deserialize content.
---> System.ObjectDisposedException: Cannot access a closed Stream.
Can anyone nudge me where I'm doing wrong?

ReceiveDetections Method is Calling Multiple Times

I am scanning QR CODE but the problem is ReceiveDetections method is calling multiple times even after a successful scan.How can I prevent calling the api multiple times after a successful call.
here is the code snippet
public void ReceiveDetections(Detections detections)
{
SparseArray qrcodes = detections.DetectedItems;
if (qrcodes.Size() != 0)
{
txtscankanbancloseResult.Post(async () =>
{
Vibrator vibrator = (Vibrator)GetSystemService(Context.VibratorService);
vibrator.Vibrate(1000);
txtscankanbancloseResult.Text = ((Barcode)qrcodes.ValueAt(0)).RawValue;
try
{
var client = new HttpClient();
var uri = new Uri(string.Format(AppStatics.clsStatic.url + "//Kanban/SaveKanbanStatus"));
List<string> lstskanban = new List<string>();
String myDate = DateTime.Now.ToString("dd-MMM-yyyy");
string adateddate = DateTime.Now.ToString("dd-MMM-yyyy hh:mm:ss");
JsonScankanbanclose objjscan = new JsonScankanbanclose();
lstskanban.Add(txtscankanbancloseResult.Text);
objjscan.UpdateBy = SingletonSession.Instance().getUsername();
objjscan.KANBANNOList = lstskanban;
objjscan.IsKANBANClosed = true;
string jsonData = JsonConvert.SerializeObject(objjscan);
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(uri, content);
var result = await response.Content.ReadAsStringAsync();
if (response.ReasonPhrase == "OK")
{
JArray scanresult = JArray.Parse(result);
Scanlist objscan = new Scanlist();
if (ScanSucessfull.Count == 0)
{
objscan.KanbanID = "Kanban NO";
objscan.KanbanQty = "Kanban Qty";
ScanSucessfull.Add(objscan);
objscan = new Scanlist();
}
// Scanlist item = ScanSucessfull.Find(c => c.KanbanID == scanresult[0]["KANBANID"].ToString());
//int itemPosition = ScanSucessfull.BinarySearch(scanresult[0]["KANBANID"].ToString());
//if (itemPosition.cou=="")
//{
objscan.KanbanID = scanresult[0]["KANBANNumber"].ToString();
objscan.KanbanQty = scanresult[0]["Qty"].ToString();
ScanSucessfull.Add(objscan);
//}
var adapter = new CustomAdapterScan(this, ScanSucessfull);
lstviewscankanbanclose.SetAdapter(adapter);
lstviewscankanbanclose.Clickable = false;
//lstview.Enabled = false;
lstviewscankanbanclose.ItemSelected += null;
mPlayer = Android.Media.MediaPlayer.Create(this, Resource.Raw.successful);
currentSong = Resource.Raw.successful;
mPlayer.SeekTo(1);
mPlayer.Start();
//Toast.MakeText(this, , ToastLength.Short).Show();
Helper.ShowToastMessage(this, Color.DarkGreen, "Data Save Sucessfully..", ToastLength.Short);
_kanbancount++;
txtscankanbanclosekanbancount.Text = "Kanban Count:" + " " + _kanbancount;
txtscankanbanclosekanbancount.Visibility = ViewStates.Visible;
}
else
{
string[] result1 = result.Split(':');
string[] result2 = result1[1].Split('"');
string[] result3 = result2[1].Split('"');
mPlayer = Android.Media.MediaPlayer.Create(this, Resource.Raw.fail);
// mPlayer.SeekTo(2);
currentSong = Resource.Raw.fail;
mPlayer.Start();
//Toast.MakeText(this, result3[0].ToString(), ToastLength.Short).Show();
Helper.ShowToastMessage(this, Color.DarkRed, result3[0].ToString(), ToastLength.Short);
}
// dialog.Hide();
cameraSource.Start(surfaceView.Holder);
//txtResult.Text = "";
}
catch (System.Exception ex)
{
Helper.ShowToastMessage(this, Color.DarkRed, ex.Message, ToastLength.Short);
//Toast.MakeText(this, ex.Message.ToString(), ToastLength.Short).Show();
// txtResult.Text = "";
txtscankanbancloseResult.Visibility = ViewStates.Invisible;
//cameraSource.Start(surfaceView.Holder);
}
});
using (var h = new Handler(Looper.MainLooper))
h.Post(() =>
{
cameraSource.Stop();
// Toast.MakeText(this, "This Kanban Already Scanned....", ToastLength.Short).Show();
});
}
}
Here is the code where I crate and open the camera source to scan the QR code
private void btnkanbanscan_Click(object sender, EventArgs e)
{
try
{
#region validation
if (spnSiteID.SelectedItemPosition < 0)
{
throw new Exception("Please Select Site...");
}
if (spnLocation.SelectedItemPosition < 0)
{
throw new Exception("Please Select Location..");
}
if (spnInspactionType.SelectedItemPosition < 0)
{
throw new Exception("Please Select Inspection Type..");
}
#endregion
LayoutInflater layoutInflater = LayoutInflater.From(this);
View scanview = LayoutInflater.Inflate(Resource.Layout.scan_popup, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.SetView(scanview);
surfaceView = scanview.FindViewById<SurfaceView>(Resource.Id.spvscan);
dialog = alertDialogBuilder.Create();
dialog.SetCanceledOnTouchOutside(false);
dialog.Show();
barcodeDetector = new BarcodeDetector.Builder(this)
.SetBarcodeFormats(BarcodeFormat.Code128 | BarcodeFormat.QrCode)
.Build();
cameraSource = new CameraSource.Builder(this, barcodeDetector)
.SetRequestedPreviewSize(480, 480)
.SetAutoFocusEnabled(true)
.Build();
surfaceView.Holder.AddCallback(this);
barcodeDetector.SetProcessor(this);
surfaceView.Visibility = ViewStates.Visible;
_definemethod = "KANBAN";
}
catch (Exception ex)
{
Helper.ShowToastMessage(this, Color.DarkRed, ex.Message, ToastLength.Short);
//Toast.MakeText(this, ex.Message.ToString(), ToastLength.Short).Show();
}
}
NCTB: I noticed that after opening the dialog to scan the QR CODE the ReceiveDetections method get called frequently and the scanned value comes in detections parameter .which is normal and it supposed to do so.But the problem is after a successful scan it should not call anymore.

C# MS Teams Bot cannot render with Date input

I encountered a “date” issue with Bot in TEAMS, The date value cannot render at LeaveRequest() properly. However, the same bot works fine in Bot Emulator.
Following is my sample code. How to fix (or workaround) this issue?
Select a date from date picker and submit
System does not render the first field value.
public class EchoBot
{
public static Attachment LeaveRequest()
{
AdaptiveSchemaVersion schemaVersion = new AdaptiveSchemaVersion(1, 0);
AdaptiveCard card = new AdaptiveCard(schemaVersion);
card.Body.Add(new AdaptiveTextBlock()
{
Text = "Enter new Date",
Size = AdaptiveTextSize.Large,
Weight = AdaptiveTextWeight.Bolder
});
AdaptiveDateInput fromDate = new AdaptiveDateInput()
{
Id = "FromDate",
Placeholder = "From Date"
};
card.Body.Add(fromDate);
AdaptiveTextInput toDate = new AdaptiveTextInput()
{
Id = "ToDate",
Placeholder = "To Date",
Value = DateTime.Today.ToUniversalTime().ToString("u")
};
card.Body.Add(toDate);
card.Actions.Add(new AdaptiveSubmitAction()
{
Title = "Submit"
});
Attachment cardAttachment = new Attachment()
{
ContentType = AdaptiveCard.ContentType,
Content = card
};
return cardAttachment;
}
}
public class RootDialog : IDialog<object>
{
public async Task StartAsync(IDialogContext context)
{
context.Wait(MessageReceivedAsync);
}
public virtual async Task MessageReceivedAsync(IDialogContext context,
IAwaitable<IMessageActivity> result)
{
var activity = await result as Activity;
Boolean first = true;
if (activity.Value != null)
{
var jObjectValue = activity.Value as JObject;
var fromDateString = jObjectValue.Value<string>("FromDate");
var toDateString = jObjectValue.Value<string>("ToDate");
await context.PostAsync($"from Date Entered: {fromDateString}");
await context.PostAsync($"to Date Entered: {toDateString}");
first = false;
}
if (first)
{
var reply = activity.CreateReply();
var card = EchoBot.LeaveRequest();
var msg = context.MakeMessage();
msg.Attachments.Add(card);
await context.PostAsync(msg);
}
}
}
Thanks for reaching out!! This is a known issue. We have a bug on this and we are working on getting this fixed.

Skype bot is not updating the response with HeroCard

working on QnAMaker. The bot responses well with both Text and HeroCard responses on the Emulator and the WebChat. However, it is not sending the formatted HeroCard via my channel(Skype). I have rebuilt the application using build.cmd. Restarted the Azure services. Still no help.
// BasicQnAMakerDialog.cs:
public RootDialog() : base(new QnAMakerService
(new QnAMakerAttribute(
RootDialog.GetSetting("QnAAuthKey") == null ? ConfigurationManager.AppSettings["QnAAuthKey"] : ConfigurationManager.AppSettings["QnAAuthKey"],
Utils.GetAppSetting("QnAKnowledgebaseId") == null ? ConfigurationManager.AppSettings["QnAKnowledgebaseId"] : ConfigurationManager.AppSettings["QnAKnowledgebaseId"],
"Not sure how to help with that. Try asking about the ALOTB, Pricing, Technology and scope to find more info or get in touch with sriram.chandrasekaran#epsilon.com", 0.5, 1,
Utils.GetAppSetting("QnAEndpointHostName") == null ? ConfigurationManager.AppSettings["QnAEndpointHostName"] : ConfigurationManager.AppSettings["QnAEndpointHostName"])))
{
}
//override method
protected override async Task RespondFromQnAMakerResultAsync(IDialogContext context, IMessageActivity message, QnAMakerResults result)
{
var answer = result.Answers.First().Answer;
Activity reply = ((Activity)context.Activity).CreateReply();
string[] qnaAnswerData = answer.Split(';');
int dataSize = qnaAnswerData.Length;
if (dataSize > 1 && dataSize <= 6)
{
var attachment = GetSelectedCard(answer);
reply.Attachments.Add(attachment as Attachment);
await context.PostAsync(reply);
}
else
{
await context.Forward(new BasicQnAMakerDialog(), AfterAnswerAsync, message, CancellationToken.None);
await context.PostAsync(reply);
}
}
private static Attachment GetSelectedCard(string answer)
{
int len = answer.Split(';').Length;
switch (len)
{
case 4: return GetHeroCard(answer);
default: return GetHeroCard(answer);
}
}
private static Attachment GetHeroCard(string answer)
{
string[] qnaAnswerData = answer.Split(';');
string title = qnaAnswerData[0];
string description = qnaAnswerData[1];
string url = qnaAnswerData[2];
string imageURL = qnaAnswerData[3];
HeroCard card = new HeroCard
{
Title = title,
Subtitle = description,
};
card.Buttons = new List<CardAction>
{
new CardAction(ActionTypes.OpenUrl, "Learn More", value: url)
};
card.Images = new List<CardImage>
{
new CardImage( url = imageURL)
};
return card.ToAttachment();
}

Message body empty on quickblox ios in xamarin native c#

i've translated the quickblox's sample app for Xamarin forms in Xamarin iOS and Android native.
Everything works "except" that the retrieving of the message fails.
I send the message from one client, and the event is catched from the other chat occupant:
XMPP: DispatchEvents ====> <message id="580735ed335fb760ae0017ec" xmlns="jabber:client" from="18029700-46533#chat.quickblox.com/1220770403-quickblox-68179" type="chat" to="18976912-46533#chat.quickblox.com"><extraParams xmlns="jabber:client"><save_to_history>1</save_to_history><dialog_id>5800aea1a28f9a1c1f000010</dialog_id><message_id>580735ed335fb760ae0017ec</message_id><date_sent>1476867565</date_sent></extraParams><body>test+message</body><thread>5800aea1a28f9a1c1f000010</thread></message>
XMPP: OnMessageReceived ====> From: 18029700 To: 18976912 Body: DateSent 1476867565 FullXmlMessage: <message id="580735ed335fb760ae0017ec" xmlns="jabber:client" from="18029700-46533#chat.quickblox.com/1220770403-quickblox-68179" type="chat" to="18976912-46533#chat.quickblox.com"><extraParams xmlns="jabber:client"><save_to_history>1</save_to_history><dialog_id>5800aea1a28f9a1c1f000010</dialog_id><message_id>580735ed335fb760ae0017ec</message_id><date_sent>1476867565</date_sent></extraParams><body>test+message</body><thread>5800aea1a28f9a1c1f000010</thread></message>
as you can see the Body part into the event OnMessageReceived is empty!
But the html part in the end of this snippet contains the message "test+message"
this is the PrivateChat Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using QbChat.Pcl.Repository;
using Quickblox.Sdk.GeneralDataModel.Models;
using Quickblox.Sdk.Modules.ChatXmppModule;
using Quickblox.Sdk.Modules.UsersModule.Models;
using UIKit;
using Xmpp.Im;
namespace KeepInTouch.iOS
{
public partial class PrivateChat : BaseChat
{
PrivateChatManager privateChatManager;
public PrivateChat(string dialogId, string nibname) : base(dialogId, nibname) { }
public async override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
AppDelegate.R.NavController.SetNavigationBarHidden(true, true);
await MessageProvider.Reconnect();
}
public override void ViewDidLoad()
{
base_tb_chat = tb_chat;
base_txt_chat = txt_chat;
base.ViewDidLoad();
view_top.BackgroundColor = UIColor.FromPatternImage(UIImage.FromFile("navbar_top_kit.png"));
tb_chat.TableFooterView = new UIView();
IsBusyIndicatorVisible = true;
var dialog = Database.Instance().GetDialog(dialogId);
var opponentId = dialog.OccupantIds.Split(',').Select(int.Parse).First(id => id != QbChat.UserId);
ChatXmppClient xmpc = QbChat.QbProvider.GetXmppClient();
privateChatManager = xmpc.GetPrivateChatManager(opponentId, dialogId);
privateChatManager.MessageReceived += OnMessageReceived;
DialogName = dialog.Name;
//xmpc.MessageReceived += OnMessageReceived;
btn_chat.TouchUpInside += async delegate {
await SendMessageCommandExecute();
txt_chat.Text = "";
};
txt_chat.ShouldReturn += (textField) => {
textField.ResignFirstResponder();
return true;
};
txt_chat.EditingChanged += async delegate {
MessageText = txt_chat.Text;
await MessageProvider.Reconnect();
};
btn_back.TouchUpInside += delegate {
DismissViewController(false, null);
};
IsBusyIndicatorVisible = true;
Task.Factory.StartNew(async () => {
var users = await QbChat.QbProvider.GetUsersByIdsAsync(dialog.OccupantIds);
var opponentUser = users.FirstOrDefault(u => u.Id != QbChat.UserId);
if (opponentUser != null && opponentUser.BlobId.HasValue) {
await QbChat.QbProvider.GetImageAsync(opponentUser.BlobId.Value).ContinueWith((task, result) => {
//var bytes =
task.ConfigureAwait(true).GetAwaiter().GetResult();
}, TaskScheduler.FromCurrentSynchronizationContext());
}
opponentUsers = new List<User> { opponentUser };
await LoadMessages();
InvokeOnMainThread(() =>
IsBusyIndicatorVisible = false
);
});
}
async void OnMessageReceived(object sender, MessageEventArgs messageEventArgs)
{
if (messageEventArgs.MessageType == MessageType.Chat ||
messageEventArgs.MessageType == MessageType.Groupchat) {
string decodedMessage = System.Net.WebUtility.UrlDecode(messageEventArgs.Message.MessageText);
var messageTable = new MessageTable();
messageTable.SenderId = messageEventArgs.Message.SenderId;
messageTable.DialogId = messageEventArgs.Message.ChatDialogId;
messageTable.DateSent = messageEventArgs.Message.DateSent;
if (messageEventArgs.Message.NotificationType != 0) {
if (messageEventArgs.Message.NotificationType == NotificationTypes.GroupUpdate) {
if (messageEventArgs.Message.AddedOccupantsIds.Any()) {
var userIds = new List<int>(messageEventArgs.Message.AddedOccupantsIds);
userIds.Add(messageEventArgs.Message.SenderId);
var users = await QbChat.QbProvider.GetUsersByIdsAsync(string.Join(",", userIds));
var addedUsers = users.Where(u => u.Id != messageEventArgs.Message.SenderId);
var senderUser = users.First(u => u.Id == messageEventArgs.Message.SenderId);
messageTable.Text = senderUser.FullName + " added users: " + string.Join(",", addedUsers.Select(u => u.FullName));
} else if (messageEventArgs.Message.DeletedOccupantsIds.Any()) {
var userIds = new List<int>(messageEventArgs.Message.DeletedOccupantsIds);
var users = await QbChat.QbProvider.GetUsersByIdsAsync(string.Join(",", userIds));
messageTable.Text = string.Join(",", users.Select(u => u.FullName)) + " left this room";
}
//var dialogInfo = await QbChat.QbProvider.GetDialogAsync(messageEventArgs.Message.ChatDialogId);
//if (dialogInfo == null)
//{
// return;
//}
//var dialog = new DialogTable(dialogInfo);
//Database.Instance().SaveDialog(dialog);
}
} else {
messageTable.Text = decodedMessage;
}
await SetRecepientName(messageTable);
Messages.Add(messageTable);
InvokeOnMainThread(async () => {
tb_chat.ReloadData();
await ScrollList();
});
}
}
public async Task LoadMessages()
{
List<Message> messages;
try {
messages = await QbChat.QbProvider.GetMessagesAsync(dialogId);
} catch (Exception ex) {
Console.WriteLine(ex);
return;
}
if (messages != null) {
messages = messages.OrderBy(message => message.DateSent).ToList();
foreach (var message in messages) {
var chatMessage = new MessageTable();
chatMessage.DateSent = message.DateSent;
chatMessage.SenderId = message.SenderId;
chatMessage.MessageId = message.Id;
if (message.RecipientId.HasValue)
chatMessage.RecepientId = message.RecipientId.Value;
chatMessage.DialogId = message.ChatDialogId;
chatMessage.IsRead = message.Read == 1;
await SetRecepientName(chatMessage);
chatMessage.Text = System.Net.WebUtility.UrlDecode(message.MessageText);
InvokeOnMainThread(() =>
Messages.Add(chatMessage)
);
}
InvokeOnMainThread(async () => {
tb_chat.ReloadData();
await ScrollList();
});
}
}
async Task SendMessageCommandExecute()
{
var message = MessageText != null ? MessageText.Trim() : string.Empty;
if (!string.IsNullOrEmpty(message)) {
var m = new MessageTable();
m.SenderId = QbChat.UserId;
m.Text = message;
m.DialogId = dialogId;
m.RecepientFullName = "Me";
try {
await MessageProvider.Reconnect();
var encodedMessage = System.Net.WebUtility.UrlEncode(message);
privateChatManager.SendMessage(encodedMessage);
} catch (Exception ex) {
Console.WriteLine(ex);
return;
}
long unixTimestamp = DateTime.UtcNow.Ticks - new DateTime(1970, 1, 1).Ticks;
unixTimestamp /= TimeSpan.TicksPerSecond;
m.DateSent = unixTimestamp;
m.ID = Database.Instance().SaveMessage(m);
var dialog = Database.Instance().GetDialog(dialogId);
dialog.LastMessage = m.Text;
dialog.LastMessageSent = DateTime.UtcNow;
Database.Instance().SaveDialog(dialog, true);
Messages.Add(m);
MessageText = "";
InvokeOnMainThread(async () => {
tb_chat.ReloadData();
await ScrollList();
});
}
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
}
}
}
long story short the sdk receive the message but apparently fail to parse the body message. fire the handler but if empty don't call the privateChatManager.MessageReceived.
could anyone help please?
Thank you

Categories

Resources