public void RemoveOldCenterSectionsFromThread() { var sectionsToRemove = ChatThread.Where(x => x.Direction == MessageDirection.AwkwardCenter && ChatThread.LastOrDefault() != x).ToList(); foreach (var section in sectionsToRemove) { ChatThread.Remove(section); } }
public void ToggleTyping(bool show) { var incommingChat = ChatThread.Where(x => x.Direction == MessageDirection.In); var alreadyVisible = incommingChat.Count() > 0 && incommingChat.Last().SectionType == SectionTypeEnum.Typing; if (!alreadyVisible && show) { ChatThread.Add(new Section() { SectionType = SectionTypeEnum.Typing, _id = Guid.NewGuid().ToString() }); } if (alreadyVisible && !show) { ChatThread.Remove(incommingChat.Last()); } }
public async void ProcessNode(JToken node, JToken section = null) { if (node == null) { return; } ClearButtonTimer(); //Replaceing verbs node = JToken.Parse(VerbProcessor.Process(node.ToString())); var parsedNode = node.ToObject <ChatNode>(); if (parsedNode.Buttons != null && parsedNode.Buttons.Count > 0) { ClearButtons(); } if (parsedNode.NodeType == NodeTypeEnum.ApiCall) { ToggleTyping(true); try { var paramDict = new Dictionary <string, object>(); foreach (var reqParam in parsedNode.RequiredVariables) { if (reqParam == "HISTORY") //Custom Variable { paramDict[reqParam] = ChatThread.Where(x => x.SectionType != SectionTypeEnum.Typing).ToArray(); } else { paramDict[reqParam] = ButtonActionHelper.GetSavedValue(reqParam); } } var nextNodeId = parsedNode.NextNodeId; //Default switch (parsedNode.ApiMethod.ToUpper()) { case "GET": { var query = string.Join("&", paramDict.Select(x => $"{x.Key}={Uri.EscapeDataString(x.Value + "")}")); var api = string.IsNullOrWhiteSpace(query) ? parsedNode.ApiUrl : parsedNode.ApiUrl + "?" + query; var resp = await APIHelper.HitAsync <Dictionary <string, object> >(api); if (resp.ContainsKey("NextNodeId")) { nextNodeId = resp["NextNodeId"] + ""; } ButtonActionHelper.HandleSaveMultiple(resp); } break; case "POST": { var resp = await APIHelper.HitPostAsync <Dictionary <string, object>, Dictionary <string, object> >(parsedNode.ApiUrl, paramDict); if (resp.ContainsKey("NextNodeId")) { nextNodeId = resp["NextNodeId"] + ""; } } break; default: Utils.ShowDialog($"{parsedNode.ApiMethod} ApiType Unknown!"); break; } NavigateToNode(nextNodeId); } catch (HttpRequestException ex) { ToggleTyping(false); Utils.ShowDialog(ex.ToString()); NavigateToNode(parsedNode.NextNodeId); } catch (Exception ex) { ToggleTyping(false); Utils.ShowDialog(ex.ToString()); NavigateToNode(parsedNode.NextNodeId); } } else if (node["Sections"] == null || node["Sections"].Children().Count() == 0) { ToggleTyping(false); await ProcessButtonsAsync(node); } else if (node["Sections"] != null && node["Sections"].Children().Count() > 0) { var sectionsSource = node["Sections"]; var currentSectionSource = section ?? sectionsSource.First; //Replaceing verbs currentSectionSource = JToken.Parse(VerbProcessor.Process(currentSectionSource.ToString())); SectionTypeEnum secType = (SectionTypeEnum)Enum.Parse(typeof(SectionTypeEnum), currentSectionSource["SectionType"].ToString()); Section parsedSection = null; bool showTyping = false; switch (secType) { case SectionTypeEnum.Image: parsedSection = currentSectionSource.ToObject <ImageSection>(); showTyping = true; break; case SectionTypeEnum.Text: parsedSection = currentSectionSource.ToObject <TextSection>(); break; case SectionTypeEnum.Gif: parsedSection = currentSectionSource.ToObject <GifSection>(); showTyping = true; break; case SectionTypeEnum.Video: parsedSection = currentSectionSource.ToObject <VideoSection>(); break; case SectionTypeEnum.Audio: parsedSection = currentSectionSource.ToObject <AudioSection>(); break; case SectionTypeEnum.EmbeddedHtml: parsedSection = currentSectionSource.ToObject <EmbeddedHtmlSection>(); break; case SectionTypeEnum.Link: case SectionTypeEnum.Graph: case SectionTypeEnum.Carousel: Utils.ShowDialog($"{secType} Coming soon!"); break; default: break; } if (parsedSection != null) { if (parsedSection.DelayInMs > 50 || showTyping) //Add 'typing' bubble if delay is grather than 50 ms { ToggleTyping(true); } //Wait for delay MilliSeconds and then continue with chat Dispatcher.Dispatch(async() => { var precacheSucess = await PrecacheSection(parsedSection); //Remove 'typing' bubble ToggleTyping(false); var sectionIndex = (sectionsSource.Children().ToList().FindIndex(x => x["_id"].ToString() == parsedSection._id)); if (precacheSucess) { if (sectionIndex == 0) //First section in node, send View Event { await Task.Run(async() => { try { await APIHelper.TrackEvent(Utils.GetViewEvent(parsedNode.Id, Utils.DeviceId)); } catch (Exception ex) { await Utils.ShowDialogAsync(ex.ToString()); } }); } AddIncommingSection(parsedSection); } var remainingSections = sectionsSource.Children().Count() - (sectionIndex + 1); if (remainingSections > 0) { var nextSection = sectionsSource.ElementAt(sectionIndex + 1); ProcessNode(node, nextSection); } else { await ProcessButtonsAsync(node); } }, parsedSection.DelayInMs); } } }
public async void ProcessNode(JToken node, JToken section = null) { if (node == null) { Utils.ShowDialog("Node not found!"); return; } ClearButtonTimer(); //Replacing verbs node = JToken.Parse(VerbProcessor.Process(node.ToString())); var parsedNode = node.ToObject <ChatNode>(); if (parsedNode.Buttons != null && parsedNode.Buttons.Count > 0) { ClearButtons(); } if (parsedNode.NodeType == NodeTypeEnum.HandoffToAgent) { await Utils.ShowDialogAsync("'HandoffToAgent' not supported in simulator"); } else if (parsedNode.NodeType == NodeTypeEnum.ApiCall) { ToggleTyping(true); try { var paramDict = new Dictionary <string, object>(); if (parsedNode.RequiredVariables != null) { foreach (var reqParam in parsedNode.RequiredVariables) { if (reqParam == "HISTORY") //Custom Variable { paramDict[reqParam] = ChatThread.Where(x => x.SectionType != SectionTypeEnum.Typing).ToArray(); } else { paramDict[reqParam] = ButtonActionHelper.GetSavedValue(reqParam); } } } var nextNodeId = parsedNode.NextNodeId; //Default switch (parsedNode.ApiMethod.ToUpper()) { case "GET": { var query = string.Join("&", paramDict.Select(x => $"{x.Key}={Uri.EscapeDataString(x.Value + "")}")); var api = string.IsNullOrWhiteSpace(query) ? parsedNode.ApiUrl : parsedNode.ApiUrl + (parsedNode.ApiUrl?.Contains("?") == true ? "&" : "?") + query; var resp = await APIHelper.HitAsync <JObject>(api); if (!string.IsNullOrWhiteSpace(resp["NextNodeId"] + "")) { nextNodeId = resp["NextNodeId"] + ""; } ButtonActionHelper.HandleSaveMultiple(resp.ToObject <Dictionary <string, object> >()); var apiNextNodeId = ExtractNextNodeIdFromAPIResp(parsedNode, resp); if (!string.IsNullOrWhiteSpace(apiNextNodeId)) { nextNodeId = apiNextNodeId; } } break; case "POST": { var resp = await APIHelper.HitPostAsync <Dictionary <string, object>, JObject>(parsedNode.ApiUrl, paramDict); if (!string.IsNullOrWhiteSpace(resp["NextNodeId"] + "")) { nextNodeId = resp["NextNodeId"] + ""; } var apiNextNodeId = ExtractNextNodeIdFromAPIResp(parsedNode, resp); if (!string.IsNullOrWhiteSpace(apiNextNodeId)) { nextNodeId = apiNextNodeId; } } break; default: Utils.ShowDialog($"{parsedNode.ApiMethod} ApiMethod Unsupported!"); break; } NavigateToNode(nextNodeId); } catch (Exception ex) { ToggleTyping(false); Utils.ShowDialog($"API[{parsedNode.ApiMethod}]: {parsedNode.ApiUrl }\r\nRequired Vars: {(parsedNode.RequiredVariables == null ? "" : string.Join(",", parsedNode.RequiredVariables))}\r\nError: " + ex.Message); NavigateToNode(parsedNode.NextNodeId); } } else if (node["Sections"] == null || node["Sections"].Children().Count() == 0) { ToggleTyping(false); await ProcessButtonsAsync(node); } else if (node["Sections"] != null && node["Sections"].Children().Count() > 0) { var sectionsSource = node["Sections"]; var currentSectionSource = section ?? sectionsSource.First; //Replacing verbs currentSectionSource = JToken.Parse(VerbProcessor.Process(currentSectionSource.ToString())); SectionTypeEnum secType = (SectionTypeEnum)Enum.Parse(typeof(SectionTypeEnum), currentSectionSource["SectionType"].ToString()); Section parsedSection = null; bool showTyping = false; switch (secType) { case SectionTypeEnum.Image: parsedSection = currentSectionSource.ToObject <ImageSection>(); showTyping = true; break; case SectionTypeEnum.Text: parsedSection = currentSectionSource.ToObject <TextSection>(); break; case SectionTypeEnum.Gif: parsedSection = currentSectionSource.ToObject <GifSection>(); showTyping = true; break; case SectionTypeEnum.Video: parsedSection = currentSectionSource.ToObject <VideoSection>(); break; case SectionTypeEnum.Audio: parsedSection = currentSectionSource.ToObject <AudioSection>(); break; case SectionTypeEnum.EmbeddedHtml: parsedSection = currentSectionSource.ToObject <EmbeddedHtmlSection>(); break; case SectionTypeEnum.PrintOTP: parsedSection = currentSectionSource.ToObject <PrintOTPSection>(); break; case SectionTypeEnum.Carousel: { parsedSection = currentSectionSource.ToObject <CarouselSection>(); (parsedSection as CarouselSection).Items = VerbProcessor.ProcessCarousalItems((parsedSection as CarouselSection).Items, parsedNode); } break; case SectionTypeEnum.Link: case SectionTypeEnum.Graph: Utils.ShowDialog($"{secType} Coming soon!"); break; default: break; } #if DEBUG if (Debugger.IsAttached) { if (parsedSection != null) { parsedSection.DelayInMs = 0; } } else { if (parsedSection != null && parsedSection.DelayInMs <= 0) { parsedSection.DelayInMs = 2000; } } #endif if (parsedSection != null) { if (parsedSection.DelayInMs > 50 || showTyping) //Add 'typing' bubble if delay is greater than 50 ms { ToggleTyping(true); } //Wait for delay MilliSeconds and then continue with chat Dispatcher.Dispatch(async() => { var precacheSucess = await PrecacheSection(parsedSection); //Remove 'typing' bubble ToggleTyping(false); var sectionIndex = (sectionsSource.Children().ToList().FindIndex(x => x["_id"].ToString() == parsedSection._id)); if (precacheSucess) { if (parsedNode.NodeType == NodeTypeEnum.Card) { parsedSection.Title = VerbProcessor.Process(parsedNode.CardHeader); parsedSection.Caption = VerbProcessor.Process(parsedNode.CardFooter); if (parsedNode.Placement == null || parsedNode.Placement == Placement.Incoming) { AddIncommingSection(parsedSection); } else if (parsedNode.Placement == Placement.Outgoing) { AddOutgoingSection(parsedSection); } else if (parsedNode.Placement == Placement.Center) { AddCenterSection(parsedSection); } } else { AddIncommingSection(parsedSection); } } var remainingSections = sectionsSource.Children().Count() - (sectionIndex + 1); if (remainingSections > 0) { var nextSection = sectionsSource.ElementAt(sectionIndex + 1); ProcessNode(node, nextSection); } else { await ProcessButtonsAsync(node); } }, parsedSection.DelayInMs); } } }