/// <summary> /// we call for every turn while the topic is still active /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task <bool> ContinueTopic(IBotContext context) { // for messages if (context.Request.Type == ActivityTypes.Message) { switch (context.TopIntent?.Name) { case "showAlarms": // allow show alarm to interrupt, but it's one turn, so we show the data without changing the topic await new ShowAlarmsTopic().StartTopic(context); return(await this.PromptForMissingData(context)); case "help": // show contextual help context.ReplyWith(AddAlarmTopicView.HELP, this.Alarm); return(await this.PromptForMissingData(context)); case "cancel": // prompt to cancel context.ReplyWith(AddAlarmTopicView.CANCELPROMPT, this.Alarm); this.TopicState = TopicStates.CancelConfirmation; return(true); default: return(await ProcessTopicState(context)); } } return(true); }
/// <summary> /// Called when the default topic is started /// </summary> /// <param name="context"></param> /// <returns></returns> public Task <bool> StartTopic(IBotContext context) { switch (context.Request.Type) { case ActivityTypes.ConversationUpdate: { // greet when added to conversation var activity = context.Request.AsConversationUpdateActivity(); if (activity.MembersAdded.Where(m => m.Id == activity.Recipient.Id).Any()) { context.ReplyWith(DefaultTopicView.GREETING); context.ReplyWith(DefaultTopicView.HELP); this.Greeted = true; } } break; case ActivityTypes.Message: // greet on first message if we haven't already if (!Greeted) { context.ReplyWith(DefaultTopicView.GREETING); this.Greeted = true; } return(this.ContinueTopic(context)); } return(Task.FromResult(true)); }
/// <summary> /// Shared method to get missing information /// </summary> /// <param name="context"></param> /// <returns></returns> private async Task <bool> PromptForMissingData(IBotContext context) { // If we don't have a title (or if its too long), prompt the user to get it. if (String.IsNullOrWhiteSpace(this.Alarm.Title)) { this.TopicState = TopicStates.TitlePrompt; context.ReplyWith(AddAlarmTopicView.TITLEPROMPT, this.Alarm); return(true); } // if title exists but is not valid, then provide feedback and prompt again else if (this.Alarm.Title.Length < 1 || this.Alarm.Title.Length > 100) { this.Alarm.Title = null; this.TopicState = TopicStates.TitlePrompt; context.ReplyWith(AddAlarmTopicView.TITLEVALIDATIONPROMPT, this.Alarm); return(true); } // If we don't have a time, prompt the user to get it. if (this.Alarm.Time == null) { this.TopicState = TopicStates.TimePrompt; context.ReplyWith(AddAlarmTopicView.TIMEPROMPTFUTURE, this.Alarm); return(true); } // ask for confirmation that we want to add it context.ReplyWith(AddAlarmTopicView.ADDCONFIRMATION, this.Alarm); this.TopicState = TopicStates.AddConfirmation; return(true); }
public async Task <bool> FindAlarm(IBotContext context) { var alarms = (List <Alarm>)context.State.User[UserProperties.ALARMS]; if (alarms == null) { alarms = new List <Alarm>(); context.State.User[UserProperties.ALARMS] = alarms; } // Ensure there are alarms to delete if (alarms.Count == 0) { context.ReplyWith(DeleteAlarmTopicView.NOALARMS); return(false); } // Validate title if (!String.IsNullOrWhiteSpace(this.AlarmTitle)) { if (int.TryParse(this.AlarmTitle.Split(' ').FirstOrDefault(), out int index)) { if (index > 0 && index <= alarms.Count) { index--; // Delete selected alarm and end topic var alarm = alarms.Skip(index).First(); alarms.Remove(alarm); context.ReplyWith(DeleteAlarmTopicView.DELETEDALARM, alarm); return(false); // cancel topic } } else { var parts = this.AlarmTitle.Split(' '); var choices = alarms.FindAll(alarm => parts.Any(part => alarm.Title.Contains(part))); if (choices.Count == 0) { context.ReplyWith(DeleteAlarmTopicView.NOALARMSFOUND, this.AlarmTitle); return(false); } else if (choices.Count == 1) { // Delete selected alarm and end topic var alarm = choices.First(); alarms.Remove(alarm); context.ReplyWith(DeleteAlarmTopicView.DELETEDALARM, alarm); return(false); // cancel topic } } } // Prompt for title context.ReplyWith(DeleteAlarmTopicView.TITLEPROMPT, alarms); return(true); }
public static Task ShowAlarms(IBotContext context) { List <Alarm> alarms = GetAlarms(context); context.ReplyWith(ShowAlarmsTopicView.SHOWALARMS, alarms); return(Task.CompletedTask); }
/// <summary> /// Called when this topic is resumed after being interrupted /// </summary> /// <param name="context"></param> /// <returns></returns> public Task <bool> ResumeTopic(IBotContext context) { // simply prompt again based on our state this.TopicState = TopicStates.AddingCard; context.ReplyWith(AddAlarmTopicView.STARTTOPIC, this.Alarm); return(Task.FromResult(true)); }
/// <summary> /// Continue the topic, method which is routed to while this topic is active /// </summary> /// <param name="context"></param> /// <returns></returns> public Task <bool> ContinueTopic(IBotContext context) { var activeTopic = (ITopic)context.State.Conversation[ConversationProperties.ACTIVETOPIC]; switch (context.Request.Type) { case ActivityTypes.Message: switch (context.TopIntent?.Name) { case "addAlarm": // switch to addAlarm topic activeTopic = new AddAlarmTopic(); context.State.Conversation[ConversationProperties.ACTIVETOPIC] = activeTopic; return(activeTopic.StartTopic(context)); case "showAlarms": // switch to show alarms topic activeTopic = new ShowAlarmsTopic(); context.State.Conversation[ConversationProperties.ACTIVETOPIC] = activeTopic; return(activeTopic.StartTopic(context)); case "deleteAlarm": // switch to delete alarm topic activeTopic = new DeleteAlarmTopic(); context.State.Conversation[ConversationProperties.ACTIVETOPIC] = activeTopic; return(activeTopic.StartTopic(context)); case "help": // show help context.ReplyWith(DefaultTopicView.HELP); return(Task.FromResult(true)); default: // show our confusion context.ReplyWith(DefaultTopicView.CONFUSED); return(Task.FromResult(true)); } default: break; } return(Task.FromResult(true)); }
public static Task ShowAlarms(IBotContext context) { var alarms = (List <Alarm>)context.State.User[UserProperties.ALARMS]; if (alarms == null) { alarms = new List <Alarm>(); context.State.User[UserProperties.ALARMS] = alarms; } context.ReplyWith(ShowAlarmsTopicView.SHOWALARMS, alarms); return(Task.CompletedTask); }
/// <summary> /// Called when the add alarm topic is started /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task <bool> StartTopic(IBotContext context) { var times = context.TopIntent?.Entities.Where(entity => entity.GroupName == "AlarmTime") .Select(entity => DateTimeOffset.Parse(entity.ValueAs <string>())); this.Alarm = new Alarm() { // initialize from intent entities Title = context.TopIntent?.Entities.Where(entity => entity.GroupName == "AlarmTitle") .Select(entity => entity.ValueAs <string>()).FirstOrDefault(), // initialize from intent entities Time = times.Where(t => t > DateTime.Now).FirstOrDefault() }; if (Alarm.Time == default(DateTimeOffset)) { // use today 1 HOUR as default var defaultTime = DateTimeOffset.Now + TimeSpan.FromHours(1); Alarm.Time = new DateTimeOffset(defaultTime.Year, defaultTime.Month, defaultTime.Day, defaultTime.Hour, 0, 0, DateTimeOffset.Now.Offset); } this.TopicState = TopicStates.AddingCard; context.ReplyWith(AddAlarmTopicView.STARTTOPIC, this.Alarm); return(true); }
private async Task <bool> ProcessTopicState(IBotContext context) { string utterance = (context.Request.AsMessageActivity().Text ?? "").Trim(); // we ar eusing TopicState to remember what we last asked switch (this.TopicState) { case TopicStates.TitlePrompt: this.Alarm.Title = utterance; return(await this.PromptForMissingData(context)); case TopicStates.TimePrompt: // take first one in the future this.Alarm.Time = ((BotContext)context).GetDateTimes().Where(t => t > DateTimeOffset.Now).FirstOrDefault(); return(await this.PromptForMissingData(context)); case TopicStates.CancelConfirmation: switch (context.TopIntent.Name) { case "confirmYes": context.ReplyWith(AddAlarmTopicView.TOPICCANCELED, this.Alarm); // End current topic return(false); case "confirmNo": // Re-prompt user for current field. context.ReplyWith(AddAlarmTopicView.CANCELCANCELED, this.Alarm); return(await this.PromptForMissingData(context)); default: // prompt again to confirm the cancelation context.ReplyWith(AddAlarmTopicView.CANCELREPROMPT, this.Alarm); return(true); } case TopicStates.AddConfirmation: switch (context.TopIntent?.Name) { case "confirmYes": var alarms = (List <Alarm>)context.State.User[UserProperties.ALARMS]; if (alarms == null) { alarms = new List <Alarm>(); context.State.User[UserProperties.ALARMS] = alarms; } alarms.Add(this.Alarm); context.ReplyWith(AddAlarmTopicView.ADDEDALARM, this.Alarm); // end topic return(false); case "confirmNo": context.ReplyWith(AddAlarmTopicView.TOPICCANCELED, this.Alarm); // End current topic return(false); default: return(await this.PromptForMissingData(context)); } default: return(await this.PromptForMissingData(context)); } }
/// <summary> /// Method which is called when this topic is resumed after an interruption /// </summary> /// <param name="context"></param> /// <returns></returns> public Task <bool> ResumeTopic(IBotContext context) { // just prompt the user to ask what they want to do context.ReplyWith(DefaultTopicView.RESUMETOPIC); return(Task.FromResult(true)); }
private async Task <bool> ProcessTopicState(IBotContext context) { string utterance = (((Activity)context.Request).Text ?? "").Trim(); // we ar eusing TopicState to remember what we last asked switch (this.TopicState) { case TopicStates.AddingCard: { dynamic payload = ((Activity)context.Request).Value; if (payload != null) { if (payload.Action == "Submit") { this.Alarm.Title = payload.Title; if (DateTimeOffset.TryParse((string)payload.Day, out DateTimeOffset date)) { if (DateTimeOffset.TryParse((string)payload.Time, out DateTimeOffset time)) { this.Alarm.Time = new DateTimeOffset(date.Year, date.Month, date.Day, time.Hour, time.Minute, time.Second, date.Offset); var alarms = (List <Alarm>)context.State.User[UserProperties.ALARMS]; if (alarms == null) { alarms = new List <Alarm>(); context.State.User[UserProperties.ALARMS] = alarms; } alarms.Add(this.Alarm); context.ReplyWith(AddAlarmTopicView.ADDEDALARM, this.Alarm); // end topic return(false); } } } else if (payload.Action == "Cancel") { context.ReplyWith(AddAlarmTopicView.TOPICCANCELED, this.Alarm); // End current topic return(false); } } } return(true); case TopicStates.CancelConfirmation: { dynamic payload = ((Activity)context.Request).Value; switch (payload.Action) { case "Yes": { context.ReplyWith(AddAlarmTopicView.TOPICCANCELED, this.Alarm); // End current topic return(false); } case "No": { this.TopicState = TopicStates.AddingCard; return(await this.ContinueTopic(context)); } default: { context.ReplyWith(AddAlarmTopicView.CANCELREPROMPT, this.Alarm); return(true); } } } default: return(true); } }