/// <summary> /// Search for, and show details related to a single trip, if the trip can be /// found. This demonstrates a simple response flow in Cortana. /// </summary> /// <param name="destination">The destination, expected to be in the phrase list.</param> /// <returns></returns> private async Task SendCompletionMessageForDestination(string destination) { // If this operation is expected to take longer than 0.5 seconds, the task must // provide a progress response to Cortana prior to starting the operation, and // provide updates at most every 5 seconds. string loadingTripToDestination = string.Format( cortanaResourceMap.GetValue("LoadingTripToDestination", cortanaContext).ValueAsString, destination); await ShowProgressScreen(loadingTripToDestination); Model.TripStore store = new Model.TripStore(); await store.LoadTrips(); // Look for the specified trip. The destination *should* be pulled from the grammar we // provided, and the subsequently updated phrase list, so it should be a 1:1 match, including case. // However, we might have multiple trips to the destination. For now, we just pick the first. IEnumerable<Model.Trip> trips = store.Trips.Where(p => p.Destination == destination); var userMessage = new VoiceCommandUserMessage(); var destinationsContentTiles = new List<VoiceCommandContentTile>(); if (trips.Count() == 0) { // In this scenario, perhaps someone has modified data on your service outside of your // control. If you're accessing a remote service, having a background task that // periodically refreshes the phrase list so it's likely to be in sync is ideal. // This is unlikely to occur for this sample app, however. string foundNoTripToDestination = string.Format( cortanaResourceMap.GetValue("FoundNoTripToDestination", cortanaContext).ValueAsString, destination); userMessage.DisplayMessage = foundNoTripToDestination; userMessage.SpokenMessage = foundNoTripToDestination; } else { // Set a title message for the page. string message = ""; if (trips.Count() > 1) { message = cortanaResourceMap.GetValue("PluralUpcomingTrips", cortanaContext).ValueAsString; } else { message = cortanaResourceMap.GetValue("SingularUpcomingTrip", cortanaContext).ValueAsString; } userMessage.DisplayMessage = message; userMessage.SpokenMessage = message; // file in tiles for each destination, to display information about the trips without // launching the app. foreach (Model.Trip trip in trips) { int i = 1; var destinationTile = new VoiceCommandContentTile(); // To handle UI scaling, Cortana automatically looks up files with FileName.scale-<n>.ext formats based on the requested filename. // See the VoiceCommandService\Images folder for an example. destinationTile.ContentTileType = VoiceCommandContentTileType.TitleWith68x68IconAndText; destinationTile.Image = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///AdventureWorks.VoiceCommands/Images/GreyTile.png")); destinationTile.AppLaunchArgument = string.Format("destination={0}", trip.Destination); destinationTile.Title = trip.Destination; if (trip.StartDate != null) { destinationTile.TextLine1 = trip.StartDate.Value.ToString(dateFormatInfo.LongDatePattern); } else { destinationTile.TextLine1 = trip.Destination + " " + i; } destinationsContentTiles.Add(destinationTile); i++; } } var response = VoiceCommandResponse.CreateResponse(userMessage, destinationsContentTiles); if (trips.Count() > 0) { response.AppLaunchArgument = string.Format("destination={0}", destination); } await voiceServiceConnection.ReportSuccessAsync(response); }
/// <summary> /// Handle the Trip Cancellation task. This task demonstrates how to prompt a user /// for confirmation of an operation, show users a progress screen while performing /// a long-running task, and showing a completion screen. /// </summary> /// <param name="destination">The name of a destination, expected to match the phrase list.</param> /// <returns></returns> private async Task SendCompletionMessageForCancellation(string destination) { // Begin loading data to search for the target store. If this operation is going to take a long time, // for instance, requiring a response from a remote web service, consider inserting a progress screen // here, in order to prevent Cortana from timing out. string progressScreenString = string.Format( cortanaResourceMap.GetValue("ProgressLookingForTripToDest", cortanaContext).ValueAsString, destination); await ShowProgressScreen(progressScreenString); Model.TripStore store = new Model.TripStore(); await store.LoadTrips(); // We might have multiple trips to the destination. For now, we just pick the first. IEnumerable<Model.Trip> trips = store.Trips.Where(p => p.Destination == destination); Model.Trip trip = null; if (trips.Count() > 1) { // If there is more than one trip, provide a disambiguation screen rather than just picking one // however, more advanced logic here might be ideal (ie, if there's a significant number of items, // you may want to just fall back to a link to your app where you can provide a deeper search experience. string disambiguationDestinationString = string.Format( cortanaResourceMap.GetValue("DisambiguationWhichTripToDest", cortanaContext).ValueAsString, destination); string disambiguationRepeatString = cortanaResourceMap.GetValue("DisambiguationRepeat", cortanaContext).ValueAsString; trip = await DisambiguateTrips(trips, disambiguationDestinationString, disambiguationRepeatString); } else { // One or no trips exist with that destination, so retrieve it, or return null. trip = trips.FirstOrDefault(); } var userPrompt = new VoiceCommandUserMessage(); VoiceCommandResponse response; if (trip == null) { var userMessage = new VoiceCommandUserMessage(); // In this scenario, perhaps someone has modified data on your service outside of this // apps control. If you're accessing a remote service, having a background task that // periodically refreshes the phrase list so it's likely to be in sync is ideal. // This is unlikely to occur for this sample app, however. string noSuchTripToDestination = string.Format( cortanaResourceMap.GetValue("NoSuchTripToDestination", cortanaContext).ValueAsString, destination); userMessage.DisplayMessage = userMessage.SpokenMessage = noSuchTripToDestination; response = VoiceCommandResponse.CreateResponse(userMessage); await voiceServiceConnection.ReportSuccessAsync(response); } else { // Prompt the user for confirmation that we've selected the correct trip to cancel. string cancelTripToDestination = string.Format( cortanaResourceMap.GetValue("CancelTripToDestination", cortanaContext).ValueAsString, destination); userPrompt.DisplayMessage = userPrompt.SpokenMessage = cancelTripToDestination; var userReprompt = new VoiceCommandUserMessage(); string confirmCancelTripToDestination = string.Format( cortanaResourceMap.GetValue("ConfirmCancelTripToDestination", cortanaContext).ValueAsString, destination); userReprompt.DisplayMessage = userReprompt.SpokenMessage = confirmCancelTripToDestination; response = VoiceCommandResponse.CreateResponseForPrompt(userPrompt, userReprompt); var voiceCommandConfirmation = await voiceServiceConnection.RequestConfirmationAsync(response); // If RequestConfirmationAsync returns null, Cortana's UI has likely been dismissed. if (voiceCommandConfirmation != null) { if (voiceCommandConfirmation.Confirmed == true) { string cancellingTripToDestination = string.Format( cortanaResourceMap.GetValue("CancellingTripToDestination", cortanaContext).ValueAsString, destination); await ShowProgressScreen(cancellingTripToDestination); // Perform the operation to remote the trip from the app's data. // Since the background task runs within the app package of the installed app, // we can access local files belonging to the app without issue. await store.DeleteTrip(trip); // Provide a completion message to the user. var userMessage = new VoiceCommandUserMessage(); string cancelledTripToDestination = string.Format( cortanaResourceMap.GetValue("CancelledTripToDestination", cortanaContext).ValueAsString, destination); userMessage.DisplayMessage = userMessage.SpokenMessage = cancelledTripToDestination; response = VoiceCommandResponse.CreateResponse(userMessage); await voiceServiceConnection.ReportSuccessAsync(response); } else { // Confirm no action for the user. var userMessage = new VoiceCommandUserMessage(); string keepingTripToDestination = string.Format( cortanaResourceMap.GetValue("KeepingTripToDestination", cortanaContext).ValueAsString, destination); userMessage.DisplayMessage = userMessage.SpokenMessage = keepingTripToDestination; response = VoiceCommandResponse.CreateResponse(userMessage); await voiceServiceConnection.ReportSuccessAsync(response); } } } }
private async Task LoadingTripToDestination(string destination) { // If this operation is expected to take longer than 0.5 seconds, the task must // provide a progress response to Cortana prior to starting the operation, and // provide updates at most every 5 seconds. string loadingTripToDestination = string.Format( cortanaResourceMap.GetValue("LoadingTripToDestination", cortanaContext).ValueAsString, destination); await ShowProgressScreen(loadingTripToDestination); Model.TripStore store = new Model.TripStore(); await store.LoadTrips(); // Look for the specified trip. The destination *should* be pulled from the grammar we // provided, and the subsequently updated phrase list, so it should be a 1:1 match, including case. // However, we might have multiple trips to the destination. For now, we just pick the first. IEnumerable <Model.Trip> trips = store.Trips.Where(p => p.Destination == destination); var userMessage = new VoiceCommandUserMessage(); var destinationsContentTiles = new List <VoiceCommandContentTile>(); if (trips.Count() == 0) { // In this scenario, perhaps someone has modified data on your service outside of your // control. If you're accessing a remote service, having a background task that // periodically refreshes the phrase list so it's likely to be in sync is ideal. // This is unlikely to occur for this sample app, however. string foundNoTripToDestination = string.Format( cortanaResourceMap.GetValue("FoundNoTripToDestination", cortanaContext).ValueAsString, destination); userMessage.DisplayMessage = foundNoTripToDestination; userMessage.SpokenMessage = foundNoTripToDestination; } else { // Set a title message for the page. string message = ""; if (trips.Count() > 1) { message = cortanaResourceMap.GetValue("PluralUpcomingTrips", cortanaContext).ValueAsString; } else { message = cortanaResourceMap.GetValue("SingularUpcomingTrip", cortanaContext).ValueAsString; } userMessage.DisplayMessage = message; userMessage.SpokenMessage = message; // file in tiles for each destination, to display information about the trips without // launching the app. foreach (Model.Trip trip in trips) { int i = 1; var destinationTile = new VoiceCommandContentTile(); // To handle UI scaling, Cortana automatically looks up files with FileName.scale-<n>.ext formats based on the requested filename. // See the VoiceCommandService\Images folder for an example. destinationTile.ContentTileType = VoiceCommandContentTileType.TitleWith68x68IconAndText; destinationTile.Image = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///ListenApp.VoiceCommands/Images/GreyTile.png")); destinationTile.AppLaunchArgument = trip.Destination; destinationTile.Title = trip.Destination; if (trip.StartDate != null) { destinationTile.TextLine1 = trip.StartDate.Value.ToString(dateFormatInfo.LongDatePattern); } else { destinationTile.TextLine1 = trip.Destination + " " + i; } destinationsContentTiles.Add(destinationTile); i++; } } var response = VoiceCommandResponse.CreateResponse(userMessage, destinationsContentTiles); if (trips.Count() > 0) { response.AppLaunchArgument = destination; } await voiceServiceConnection.ReportSuccessAsync(response); }
/// <summary> /// Handle the Trip Cancellation task. This task demonstrates how to prompt a user /// for confirmation of an operation, show users a progress screen while performing /// a long-running task, and showing a completion screen. /// </summary> /// <param name="destination">The name of a destination, expected to match the phrase list.</param> /// <returns></returns> private async Task SendCompletionMessageForCancellation(string destination) { // Begin loading data to search for the target store. If this operation is going to take a long time, // for instance, requiring a response from a remote web service, consider inserting a progress screen // here, in order to prevent Cortana from timing out. string progressScreenString = string.Format( cortanaResourceMap.GetValue("ProgressLookingForTripToDest", cortanaContext).ValueAsString, destination); await ShowProgressScreen(progressScreenString); Model.TripStore store = new Model.TripStore(); await store.LoadTrips(); // We might have multiple trips to the destination. For now, we just pick the first. IEnumerable <Model.Trip> trips = store.Trips.Where(p => p.Destination == destination); Model.Trip trip = null; if (trips.Count() > 1) { // If there is more than one trip, provide a disambiguation screen rather than just picking one // however, more advanced logic here might be ideal (ie, if there's a significant number of items, // you may want to just fall back to a link to your app where you can provide a deeper search experience. string disambiguationDestinationString = string.Format( cortanaResourceMap.GetValue("DisambiguationWhichTripToDest", cortanaContext).ValueAsString, destination); string disambiguationRepeatString = cortanaResourceMap.GetValue("DisambiguationRepeat", cortanaContext).ValueAsString; trip = await DisambiguateTrips(trips, disambiguationDestinationString, disambiguationRepeatString); } else { // One or no trips exist with that destination, so retrieve it, or return null. trip = trips.FirstOrDefault(); } var userPrompt = new VoiceCommandUserMessage(); VoiceCommandResponse response; if (trip == null) { var userMessage = new VoiceCommandUserMessage(); // In this scenario, perhaps someone has modified data on your service outside of this // apps control. If you're accessing a remote service, having a background task that // periodically refreshes the phrase list so it's likely to be in sync is ideal. // This is unlikely to occur for this sample app, however. string noSuchTripToDestination = string.Format( cortanaResourceMap.GetValue("NoSuchTripToDestination", cortanaContext).ValueAsString, destination); userMessage.DisplayMessage = userMessage.SpokenMessage = noSuchTripToDestination; response = VoiceCommandResponse.CreateResponse(userMessage); await voiceServiceConnection.ReportSuccessAsync(response); } else { // Prompt the user for confirmation that we've selected the correct trip to cancel. string cancelTripToDestination = string.Format( cortanaResourceMap.GetValue("CancelTripToDestination", cortanaContext).ValueAsString, destination); userPrompt.DisplayMessage = userPrompt.SpokenMessage = cancelTripToDestination; var userReprompt = new VoiceCommandUserMessage(); string confirmCancelTripToDestination = string.Format( cortanaResourceMap.GetValue("ConfirmCancelTripToDestination", cortanaContext).ValueAsString, destination); userReprompt.DisplayMessage = userReprompt.SpokenMessage = confirmCancelTripToDestination; //REVERT var cancelledContentTiles = new List <VoiceCommandContentTile>(); if (xyz != null) { cancelledContentTiles.Add(xyz); } response = VoiceCommandResponse.CreateResponseForPrompt(userPrompt, userReprompt, cancelledContentTiles); var voiceCommandConfirmation = await voiceServiceConnection.RequestConfirmationAsync(response); // If RequestConfirmationAsync returns null, Cortana's UI has likely been dismissed. if (voiceCommandConfirmation != null) { if (voiceCommandConfirmation.Confirmed == true) { string cancellingTripToDestination = string.Format( cortanaResourceMap.GetValue("CancellingTripToDestination", cortanaContext).ValueAsString, destination); await ShowProgressScreen(cancellingTripToDestination); // Perform the operation to remote the trip from the app's data. // Since the background task runs within the app package of the installed app, // we can access local files belonging to the app without issue. await store.DeleteTrip(trip); // Provide a completion message to the user. var userMessage = new VoiceCommandUserMessage(); string cancelledTripToDestination = string.Format( cortanaResourceMap.GetValue("CancelledTripToDestination", cortanaContext).ValueAsString, destination); userMessage.DisplayMessage = userMessage.SpokenMessage = cancelledTripToDestination; response = VoiceCommandResponse.CreateResponse(userMessage, cancelledContentTiles); //REVERT cancelledContentTiles response.AppLaunchArgument = destination; //REVERT await voiceServiceConnection.ReportSuccessAsync(response); } else { // Confirm no action for the user. var userMessage = new VoiceCommandUserMessage(); string keepingTripToDestination = string.Format( cortanaResourceMap.GetValue("KeepingTripToDestination", cortanaContext).ValueAsString, destination); userMessage.DisplayMessage = userMessage.SpokenMessage = keepingTripToDestination; response = VoiceCommandResponse.CreateResponse(userMessage); response.AppLaunchArgument = destination; //REVERT await voiceServiceConnection.ReportSuccessAsync(response); } } } }
/// <summary> /// Search for, and show details related to a single trip, if the trip can be /// found. This demonstrates a simple response flow in Cortana. /// </summary> /// <param name="destination">The destination, expected to be in the phrase list.</param> /// <returns></returns> private async Task SendCompletionMessageForDestination(string destination) { // If this operation is expected to take longer than 0.5 seconds, the task must // provide a progress response to Cortana prior to starting the operation, and // provide updates at most every 5 seconds. await ShowProgressScreen("Adventure Works is loading details about trip to " + destination); Model.TripStore store = new Model.TripStore(); await store.LoadTrips(); // Look for the specified trip. The destination *should* be pulled from the grammar we // provided, and the subsequently updated phrase list, so it should be a 1:1 match, including case. // However, we might have multiple trips to the destination. For now, we just pick the first. IEnumerable <Model.Trip> trips = store.Trips.Where(p => p.Destination == destination); var userMessage = new VoiceCommandUserMessage(); var destinationsContentTiles = new List <VoiceCommandContentTile>(); if (trips.Count() == 0) { // In this scenario, perhaps someone has modified data on your service outside of your // control. If you're accessing a remote service, having a background task that // periodically refreshes the phrase list so it's likely to be in sync is ideal. // This is unlikely to occur for this sample app, however. userMessage.DisplayMessage = "Sorry, you don't have any trips to " + destination; userMessage.SpokenMessage = "Sorry, you don't have any trips to " + destination; } else { // Set a title message for the page. string message = ""; if (trips.Count() > 1) { message = "Here are your upcoming trips."; } else { message = "Here's your upcoming trip."; } userMessage.DisplayMessage = message; userMessage.SpokenMessage = message; // file in tiles for each destination, to display information about the trips without // launching the app. foreach (Model.Trip trip in trips) { int i = 1; var destinationTile = new VoiceCommandContentTile(); destinationTile.ContentTileType = VoiceCommandContentTileType.TitleWith68x68IconAndText; destinationTile.Image = await Package.Current.InstalledLocation.GetFileAsync("AdventureWorks.VoiceCommands\\Images\\GreyTile.png"); destinationTile.AppLaunchArgument = string.Format("destination={0}", trip.Destination); destinationTile.Title = trip.Destination; if (trip.StartDate != null) { destinationTile.TextLine1 = string.Format("{0:dddd MMMM dd yyyy}", trip.StartDate ); } else { destinationTile.TextLine1 = trip.Destination + " " + i; } destinationsContentTiles.Add(destinationTile); i++; } } var response = VoiceCommandResponse.CreateResponse(userMessage, destinationsContentTiles); if (trips.Count() > 0) { response.AppLaunchArgument = string.Format("destination={0}", destination); } await voiceServiceConnection.ReportSuccessAsync(response); }
/// <summary> /// Handle the Trip Cancellation task. This task demonstrates how to prompt a user /// for confirmation of an operation, show users a progress screen while performing /// a long-running task, and showing a completion screen. /// </summary> /// <param name="destination">The name of a destination, expected to match the phrase list.</param> /// <returns></returns> private async Task SendCompletionMessageForCancellation(string destination) { // Begin loading data to search for the target store. If this operation is going to take a long time, // for instance, requiring a response from a remote web service, consider inserting a progress screen // here, in order to prevent Cortana from timing out. await ShowProgressScreen("Looking for a trip to " + destination); Model.TripStore store = new Model.TripStore(); await store.LoadTrips(); // We might have multiple trips to the destination. For now, we just pick the first. IEnumerable <Model.Trip> trips = store.Trips.Where(p => p.Destination == destination); Model.Trip trip = null; if (trips.Count() > 1) { // If there is more than one trip, provide a disambiguation screen rather than just picking one // however, more advanced logic here might be ideal (ie, if there's a significant number of items, // you may want to just fall back to a link to your app where you can provide a deeper search experience. trip = await DisambiguateTrips( trips, "Which trip to " + destination + " did you want to cancel?", "Which one do you want to cancel?"); } else { // One or no trips exist with that destination, so retrieve it, or return null. trip = trips.FirstOrDefault(); } var userPrompt = new VoiceCommandUserMessage(); VoiceCommandResponse response; if (trip == null) { var userMessage = new VoiceCommandUserMessage(); // In this scenario, perhaps someone has modified data on your service outside of this // apps control. If you're accessing a remote service, having a background task that // periodically refreshes the phrase list so it's likely to be in sync is ideal. // This is unlikely to occur for this sample app, however. userMessage.DisplayMessage = userMessage.SpokenMessage = "Sorry, you don't have any trips to " + destination; response = VoiceCommandResponse.CreateResponse(userMessage); await voiceServiceConnection.ReportSuccessAsync(response); } else { // Prompt the user for confirmation that we've selected the correct trip to cancel. userPrompt.DisplayMessage = userPrompt.SpokenMessage = "Cancel this trip to " + destination + "?"; var userReprompt = new VoiceCommandUserMessage(); userReprompt.DisplayMessage = userReprompt.SpokenMessage = "Did you want to cancel this trip to " + destination + "?"; response = VoiceCommandResponse.CreateResponseForPrompt(userPrompt, userReprompt); var voiceCommandConfirmation = await voiceServiceConnection.RequestConfirmationAsync(response); // If RequestConfirmationAsync returns null, Cortana's UI has likely been dismissed. if (voiceCommandConfirmation != null) { if (voiceCommandConfirmation.Confirmed == true) { await ShowProgressScreen("Cancelling the trip to " + destination); // Perform the operation to remote the trip from the app's data. // Since the background task runs within the app package of the installed app, // we can access local files belonging to the app without issue. await store.DeleteTrip(trip); // Provide a completion message to the user. var userMessage = new VoiceCommandUserMessage(); userMessage.DisplayMessage = userMessage.SpokenMessage = "Cancelled the trip to " + destination; response = VoiceCommandResponse.CreateResponse(userMessage); await voiceServiceConnection.ReportSuccessAsync(response); } else { // Confirm no action for the user. var userMessage = new VoiceCommandUserMessage(); userMessage.DisplayMessage = userMessage.SpokenMessage = "Okay, Keeping the trip to " + destination; response = VoiceCommandResponse.CreateResponse(userMessage); await voiceServiceConnection.ReportSuccessAsync(response); } } } }